Files
buzz-sheet/components/admin/autosave-status.tsx
T

142 lines
4.6 KiB
TypeScript

import { AlertCircleIcon, CheckIcon, ClockIcon } from "lucide-react";
import { useState } from "react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
import type { AutosaveState } from "@/hooks/use-autosave";
export function AutosaveStatus({
state,
issues = [],
onSave,
conflictVersion,
canOverwrite = false,
onReloadLatest,
onOverwrite,
}: {
state: AutosaveState;
issues?: readonly string[];
onSave?: () => void;
conflictVersion?: number | null;
canOverwrite?: boolean;
onReloadLatest?: () => void;
onOverwrite?: () => void;
}) {
const [showIssues, setShowIssues] = useState(false);
if (state === "saving")
return (
<Badge variant="secondary">
<Spinner data-icon="inline-start" />
Saving…
</Badge>
);
if (state === "unsaved")
return (
<Badge variant="outline">
<ClockIcon data-icon="inline-start" />
Waiting to save…
</Badge>
);
if (state === "incomplete")
return (
<div className="flex flex-col items-end gap-2">
<Button
type="button"
variant="outline"
size="sm"
onClick={() => setShowIssues((current) => !current)}
aria-expanded={showIssues}
>
<AlertCircleIcon data-icon="inline-start" />
{showIssues ? "ซ่อนรายการ" : "ตรวจสอบข้อมูลที่ยังไม่ครบ"}
</Button>
{showIssues ? (
<Alert variant="destructive" className="max-w-md">
<AlertCircleIcon aria-hidden="true" />
<AlertTitle>กรุณากรอกข้อมูลให้ครบ</AlertTitle>
<AlertDescription>
<div className="flex flex-col gap-2">
<p>
แก้ไขรายการด้านล่าง แล้วระบบจะบันทึกให้อัตโนมัติ
ข้อมูลที่กรอกไว้ยังไม่หาย
</p>
{issues.length ? (
<ul className="flex flex-col gap-1">
{issues.map((issue, index) => (
<li key={`${issue}-${index}`}>{issue}</li>
))}
</ul>
) : null}
</div>
</AlertDescription>
</Alert>
) : null}
</div>
);
if (state === "conflict")
return (
<Alert
id="autosave-conflict"
variant="destructive"
className="max-w-xl scroll-m-6"
>
<AlertCircleIcon aria-hidden="true" />
<AlertTitle>มีการบันทึกข้อมูลใหม่จากผู้แก้ไขคนอื่น</AlertTitle>
<AlertDescription>
<div className="flex flex-col gap-3">
<p>
ระบบหยุด Autosave ไว้เพื่อไม่ให้ Draft นี้เขียนทับข้อมูลล่าสุด
{conflictVersion ? ` (version ${conflictVersion})` : ""}
</p>
<div className="flex flex-wrap gap-2">
{onReloadLatest ? (
<Button
type="button"
variant="outline"
size="sm"
onClick={onReloadLatest}
>
โหลดข้อมูลล่าสุด
</Button>
) : null}
{onOverwrite ? (
<Button
type="button"
variant="destructive"
size="sm"
disabled={!canOverwrite}
onClick={onOverwrite}
>
เขียนทับด้วย Draft นี้
</Button>
) : null}
</div>
</div>
</AlertDescription>
</Alert>
);
if (state === "error")
return (
<div className="flex items-center gap-2">
<Badge variant="destructive">
<AlertCircleIcon data-icon="inline-start" />
Autosave failed
</Badge>
{onSave ? (
<Button type="button" variant="outline" size="sm" onClick={onSave}>
Save now
</Button>
) : null}
</div>
);
return (
<Badge variant="secondary">
<CheckIcon data-icon="inline-start" />
Saved
</Badge>
);
}