feat(admin): add OfflineBanner with online status + pending sync count
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { getQueuedActions } from "@/lib/offline/queue";
|
||||
|
||||
export function OfflineBanner() {
|
||||
const [online, setOnline] = useState(true);
|
||||
const [pendingCount, setPendingCount] = useState(0);
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
setOnline(navigator.onLine);
|
||||
const onOnline = () => setOnline(true);
|
||||
const onOffline = () => setOnline(false);
|
||||
window.addEventListener("online", onOnline);
|
||||
window.addEventListener("offline", onOffline);
|
||||
|
||||
const interval = setInterval(async () => {
|
||||
const actions = await getQueuedActions();
|
||||
setPendingCount(actions.filter((a) => a.status === "pending" || a.status === "in-flight").length);
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("online", onOnline);
|
||||
window.removeEventListener("offline", onOffline);
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!mounted || (online && pendingCount === 0)) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
className="sticky top-0 z-40 w-full px-4 py-2 text-sm font-semibold"
|
||||
style={{
|
||||
backgroundColor: online ? "var(--color-warning-soft)" : "var(--color-danger-soft)",
|
||||
color: online ? "var(--color-warning)" : "var(--color-danger)",
|
||||
}}
|
||||
>
|
||||
{online ? (
|
||||
<>Syncing {pendingCount} pending action{pendingCount === 1 ? "" : "s"}…</>
|
||||
) : (
|
||||
<>You're offline. Changes will sync when you reconnect.</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default OfflineBanner;
|
||||
Reference in New Issue
Block a user