TypeScript 97.6%
SQL 1.4%
JavaScript 0.5%
1"use client";23import { useRouter } from "next/navigation";4import { WifiOff, ServerCrash, Wrench, AlertCircle, RefreshCw } from "lucide-react";5import { Button } from "@/components/ui";6import { describeError } from "@/lib/use-api";7import { ApiClientError } from "@/lib/api";8import { cn } from "@/lib/utils";910/** Polished error state for connection loss, server outage and maintenance. */11export function ApiErrorState({ error, retry, className, compact }: { error: unknown; retry?: () => void; className?: string; compact?: boolean }) {12 const d = describeError(error);13 const Icon = d.kind === "network" ? WifiOff : d.kind === "maintenance" ? Wrench : d.kind === "server" ? ServerCrash : AlertCircle;14 return (15 <div className={cn("surface rounded-lg text-center", compact ? "px-4 py-6" : "px-6 py-12", className)} role="alert">16 <div className={cn("mx-auto grid place-items-center rounded-full bg-surface-2 text-fg-2", compact ? "mb-3 h-10 w-10" : "mb-4 h-14 w-14", d.kind === "maintenance" && "text-accent")}>17 <Icon className={compact ? "h-5 w-5" : "h-6 w-6"} />18 </div>19 <h3 className={cn("font-semibold tracking-tight", compact ? "text-base" : "text-lg")}>{d.title}</h3>20 <p className="mx-auto mt-1.5 max-w-sm text-sm text-fg-3">{d.description}</p>21 {retry ? (22 <Button variant="secondary" size={compact ? "sm" : "md"} className="mt-5" onClick={retry}>23 <RefreshCw className="h-4 w-4" /> Try again24 </Button>25 ) : null}26 </div>27 );28}2930/** Server components can't retry in place — this reloads the route from the client. */31export function ServerUnavailable({ className, compact }: { className?: string; compact?: boolean }) {32 const router = useRouter();33 return <ApiErrorState error={new ApiClientError(503, "UNAVAILABLE", "Server unavailable. Please try again shortly.")} retry={() => router.refresh()} className={className} compact={compact} />;34}35