feat(machines): robust probe for machine details + clear error/not-found states\n\n- Probe Convex (browser) and server route when query is undefined or null\n- Tri-state fallback (undefined|null|data) to disambiguate not-found\n- Restore skeleton + not-found + error rendering with actionable retry\n- No behavior change when data is available
This commit is contained in:
parent
c640e288b1
commit
39726b360e
1 changed files with 51 additions and 7 deletions
|
|
@ -24,11 +24,11 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
|||
const single = useQuery(api.machines.getById, queryArgs)
|
||||
|
||||
// Fallback via HTTP in caso de o Convex React demorar/ficar preso em loading
|
||||
const [fallback, setFallback] = useState<Record<string, unknown> | null>(null)
|
||||
const [fallback, setFallback] = useState<Record<string, unknown> | null | undefined>(undefined)
|
||||
const [loadError, setLoadError] = useState<string | null>(null)
|
||||
const [retryTick, setRetryTick] = useState(0)
|
||||
const timer = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const shouldLoad = single === undefined && !fallback && Boolean(machineId)
|
||||
const shouldLoad = (single === undefined || single === null) && fallback === undefined && Boolean(machineId)
|
||||
|
||||
useEffect(() => {
|
||||
if (!shouldLoad) return
|
||||
|
|
@ -58,7 +58,7 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
|||
const res = await fetch(`/api/admin/machines/${machineId}/details`, { credentials: "include" })
|
||||
if (res.ok) {
|
||||
const data = (await res.json()) as Record<string, unknown>
|
||||
setFallback(data)
|
||||
setFallback(data ?? null)
|
||||
setLoadError(null)
|
||||
} else {
|
||||
let message = `Falha ao carregar (HTTP ${res.status})`
|
||||
|
|
@ -70,7 +70,11 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
|||
} catch {
|
||||
// ignore
|
||||
}
|
||||
setLoadError(message)
|
||||
if (res.status == 404) {
|
||||
setFallback(null)
|
||||
} else {
|
||||
setLoadError(message)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
setLoadError("Erro de rede ao carregar os dados da máquina.")
|
||||
|
|
@ -96,12 +100,12 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
|||
}, [shouldLoad, machineId, retryTick])
|
||||
|
||||
const machine: MachinesQueryItem | null = useMemo(() => {
|
||||
const source = single ?? fallback
|
||||
const source = single ?? (fallback === undefined ? undefined : fallback)
|
||||
if (source === undefined || source === null) return source as null
|
||||
return normalizeMachineItem(source)
|
||||
}, [single, fallback])
|
||||
const isLoading = single === undefined && !fallback && !loadError
|
||||
const isNotFound = single === null && !fallback
|
||||
const isLoading = single === undefined && fallback === undefined && !loadError
|
||||
const isNotFound = (single === null || fallback === null) && !loadError
|
||||
|
||||
const onRetry = () => {
|
||||
setLoadError(null)
|
||||
|
|
@ -114,6 +118,46 @@ export function AdminMachineDetailsClient({ tenantId: _tenantId, machineId }: {
|
|||
// ignore
|
||||
}
|
||||
}
|
||||
if (loadError && !machine) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="space-y-3 p-6">
|
||||
<p className="text-sm font-medium text-red-600">Falha ao carregar os dados da máquina</p>
|
||||
<p className="text-sm text-muted-foreground">{loadError}</p>
|
||||
<div className="pt-2 flex items-center gap-2">
|
||||
<Button size="sm" onClick={onRetry}>Tentar novamente</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="space-y-3 p-6">
|
||||
<Skeleton className="h-6 w-64" />
|
||||
<Skeleton className="h-4 w-80" />
|
||||
<Skeleton className="h-48 w-full" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
if (isNotFound) {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent className="space-y-3 p-6">
|
||||
<p className="text-sm font-medium text-red-600">Máquina não encontrada</p>
|
||||
<p className="text-sm text-muted-foreground">Verifique o identificador e tente novamente.</p>
|
||||
<div className="pt-2 flex items-center gap-2">
|
||||
<Button size="sm" onClick={onRetry}>Recarregar</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
return <MachineDetails machine={machine} />
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue