import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query"; import { Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, DataTable, EmptyState, type ColumnDef, } from "@godxjp/ui/data-display"; import { SkeletonTable } from "@godxjp/ui/feedback"; import { Flex, PageContainer } from "@godxjp/ui/layout"; import { DataState } from "@godxjp/ui/query"; /** * DataState · drives skeleton / error / empty / success for ONE useQuery block. * It IS the conditional; never branch on isPending/isError yourself. Composed * only from real @godxjp/ui components + @tanstack/react-query. */ const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); type Invoice = { id: string; partner: string; status: "active" | "pending" }; const invoices: Invoice[] = [ { id: "INV-0312", partner: "株式会社ベトヤ", status: "active" }, { id: "INV-0311", partner: "ハノイ物流", status: "pending" }, ]; const columns: ColumnDef[] = [ { key: "id", header: "請求書番号" }, { key: "partner", header: "取引先" }, { key: "status", header: "状態", render: (row) => }, ]; function SuccessBlock() { const query = useQuery({ queryKey: ["ds-success"], queryFn: async () => invoices }); return ( } isEmpty={(d) => d.length === 0} empty={} > {(d) => r.id} />} ); } function LoadingBlock() { const query = useQuery({ queryKey: ["ds-loading"], queryFn: () => new Promise(() => {}), }); return ( }> {(d) => r.id} />} ); } function ErrorBlock() { const query = useQuery({ queryKey: ["ds-error"], queryFn: async () => { throw new Error("サーバーエラー (503) · 取得に失敗しました"); }, }); return ( }> {(d) => r.id} />} ); } function PrerequisiteBlock() { // A tenant-scoped query stays disabled until an organization is selected (`enabled:false`). // It reads as pending with fetchStatus "idle" — DataState shows the prerequisite, not a skeleton. const query = useQuery({ queryKey: ["ds-prerequisite"], queryFn: async () => invoices, enabled: false, }); return ( } prerequisite={ } > {(d) => r.id} />} ); } function AuthErrorBlock() { // A 401 / expired token never resolves by retrying — DataState offers session renewal instead. const query = useQuery({ queryKey: ["ds-auth-error"], queryFn: async () => { throw new Error("Access token invalid"); }, }); return ( } onAuthError={() => window.location.assign("/login")} > {(d) => r.id} />} ); } export default function Demo() { return ( Success Resolved data renders through the children function. Loading (skeleton) The skeleton prop renders during the pending phase. Prerequisite (disabled query) An `enabled:false` query is unstarted, not loading. The prerequisite slot renders instead of an endless skeleton. Error · transient (retry) A 5xx/network failure is retryable, so AlertQueryError offers Retry automatically. Error · auth (session renewal) A 401 / expired token routes to session renewal via `onAuthError`, never a blind retry, and never surfaces the raw token message. ); }