112 lines
4.1 KiB
TypeScript
112 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { EyeIcon, EyeOffIcon } from "lucide-react";
|
|
import { useRouter } from "next/navigation";
|
|
import { useState, useTransition } from "react";
|
|
import { toast } from "sonner";
|
|
|
|
import { setStructuredGuideVisibility } from "@/app/admin/actions";
|
|
import {
|
|
AlertDialog,
|
|
AlertDialogAction,
|
|
AlertDialogCancel,
|
|
AlertDialogContent,
|
|
AlertDialogDescription,
|
|
AlertDialogFooter,
|
|
AlertDialogHeader,
|
|
AlertDialogTitle,
|
|
} from "@/components/ui/alert-dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Spinner } from "@/components/ui/spinner";
|
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export function GuideVisibilityControl({
|
|
guideId,
|
|
guideName,
|
|
isPublic,
|
|
version,
|
|
className,
|
|
}: {
|
|
guideId: string;
|
|
guideName: string;
|
|
isPublic: boolean;
|
|
version: number;
|
|
className?: string;
|
|
}) {
|
|
const router = useRouter();
|
|
const [pending, startTransition] = useTransition();
|
|
const [open, setOpen] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const updateVisibility = (nextPublic: boolean) => {
|
|
startTransition(async () => {
|
|
setError(null);
|
|
const result = await setStructuredGuideVisibility(guideId, {
|
|
isPublic: nextPublic,
|
|
expectedVersion: version,
|
|
});
|
|
if (result.status !== "saved") {
|
|
const message = result.message ?? "เปลี่ยนสถานะ Guide ไม่สำเร็จ";
|
|
setError(message);
|
|
toast.error(message);
|
|
return;
|
|
}
|
|
toast.success(nextPublic ? "เผยแพร่ไกด์แล้ว" : "ซ่อนไกด์จากเว็บไซต์แล้ว");
|
|
setOpen(false);
|
|
router.refresh();
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className={cn("flex flex-wrap items-center gap-2", className)}>
|
|
<Button
|
|
type="button"
|
|
variant={isPublic ? "outline" : "default"}
|
|
size="sm"
|
|
disabled={pending}
|
|
aria-haspopup="dialog"
|
|
aria-expanded={open}
|
|
onClick={() => setOpen(true)}
|
|
>
|
|
{pending ? <Spinner data-icon="inline-start" /> : isPublic ? <EyeOffIcon data-icon="inline-start" /> : <EyeIcon data-icon="inline-start" />}
|
|
{isPublic ? "ซ่อนจากเว็บไซต์" : "เผยแพร่ไกด์"}
|
|
</Button>
|
|
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
<AlertDialogContent>
|
|
<AlertDialogHeader>
|
|
<AlertDialogTitle>
|
|
{isPublic ? `ซ่อน ${guideName} จากเว็บไซต์?` : `เผยแพร่ ${guideName} ให้ทุกคนดู?`}
|
|
</AlertDialogTitle>
|
|
<AlertDialogDescription>
|
|
{isPublic
|
|
? "Guide จะหายจากหน้าเว็บไซต์และลิงก์สาธารณะจะเปิดไม่ได้ แต่ยังแก้ไขได้ใน Admin"
|
|
: "Guide จะแสดงบนหน้าเว็บไซต์และทุกคนจะเปิดดูผ่านลิงก์สาธารณะได้"}
|
|
</AlertDialogDescription>
|
|
</AlertDialogHeader>
|
|
{error ? (
|
|
<Alert variant="destructive">
|
|
<AlertTitle>ยังเผยแพร่ไม่ได้</AlertTitle>
|
|
<AlertDescription>{error}</AlertDescription>
|
|
</Alert>
|
|
) : null}
|
|
<AlertDialogFooter>
|
|
<AlertDialogCancel disabled={pending}>ยกเลิก</AlertDialogCancel>
|
|
<AlertDialogAction
|
|
variant={isPublic ? "destructive" : "default"}
|
|
disabled={pending}
|
|
onClick={(event) => {
|
|
event.preventDefault();
|
|
updateVisibility(!isPublic);
|
|
}}
|
|
>
|
|
{pending && <Spinner data-icon="inline-start" />}
|
|
{isPublic ? "ยืนยันการซ่อน" : "ยืนยันการเผยแพร่"}
|
|
</AlertDialogAction>
|
|
</AlertDialogFooter>
|
|
</AlertDialogContent>
|
|
</AlertDialog>
|
|
</div>
|
|
);
|
|
}
|