1"use client";
2
3import { useState } from "react";
4import { AlertTriangle } from "lucide-react";
5import { useOfflineStatus } from "@/hooks/use-offline-status";
6import { ReviewFailedDialog } from "./ReviewFailedDialog";
7
8
18export function OfflineBanner() {
19 const status = useOfflineStatus();
20 const [reviewOpen, setReviewOpen] = useState(false);
21
22 if (!status.bannerVisible) return null;
23
24 return (
25 <>
26 <div
27 data-testid="offline-banner"
28 role="status"
29 aria-live="polite"
30 className="flex items-center justify-center gap-2 border-b border-amber-200 bg-amber-50 px-3 py-1.5 text-xs text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200"
31 >
32 <AlertTriangle className="size-3.5 shrink-0" aria-hidden />
33 <span>
34 You're offline — changes are saved on this device
35 {status.pendingCount > 0 ? (
36 <>
37 {" "}
38 · <strong className="font-semibold">{status.pendingCount}</strong>{" "}
39 pending
40 </>
41 ) : null}
42 </span>
43 {status.showReviewLink ? (
44 <button
45 type="button"
46 data-testid="review-failed-changes"
47 onClick={() => setReviewOpen(true)}
48 className="ml-1 shrink-0 rounded font-medium underline underline-offset-2 hover:opacity-80"
49 >
50 Review failed changes
51 </button>
52 ) : null}
53 </div>
54 {reviewOpen ? <ReviewFailedDialog onClose={() => setReviewOpen(false)} /> : null}
55 </>
56 );
57}
58