From 9a7954fa3619918495153fdaa60f655d206996ba Mon Sep 17 00:00:00 2001 From: gunshiz Date: Fri, 4 Sep 2026 18:01:14 +0700 Subject: [PATCH] feat : add toast when delete --- .../admin/delete-confirmation-dialog.tsx | 10 +- components/admin/structured-dashboard.tsx | 265 ++++++++++++++++-- 2 files changed, 252 insertions(+), 23 deletions(-) diff --git a/components/admin/delete-confirmation-dialog.tsx b/components/admin/delete-confirmation-dialog.tsx index f1cb8df..c27cfed 100644 --- a/components/admin/delete-confirmation-dialog.tsx +++ b/components/admin/delete-confirmation-dialog.tsx @@ -1,6 +1,7 @@ "use client"; import type { ComponentProps, ReactNode } from "react"; +import { toast } from "sonner"; import { AlertDialog, @@ -23,6 +24,7 @@ interface DeleteConfirmationDialogProps { children?: ReactNode; open?: ComponentProps["open"]; onOpenChange?: ComponentProps["onOpenChange"]; + showSuccessToast?: boolean; } export function DeleteConfirmationDialog({ @@ -34,7 +36,13 @@ export function DeleteConfirmationDialog({ children, open, onOpenChange, + showSuccessToast = true, }: DeleteConfirmationDialogProps) { + const handleConfirm = async () => { + await onConfirm(); + if (showSuccessToast) toast.success("ลบสำเร็จ!"); + }; + return ( {trigger ? ( @@ -47,7 +55,7 @@ export function DeleteConfirmationDialog({ ยกเลิก - + {confirmLabel} diff --git a/components/admin/structured-dashboard.tsx b/components/admin/structured-dashboard.tsx index e9f3845..a3ed379 100644 --- a/components/admin/structured-dashboard.tsx +++ b/components/admin/structured-dashboard.tsx @@ -3,52 +3,273 @@ import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/navigation"; -import { PlusIcon, RefreshCwIcon, RotateCcwIcon, Trash2Icon } from "lucide-react"; +import { + PlusIcon, + RefreshCwIcon, + RotateCcwIcon, + Trash2Icon, +} from "lucide-react"; import { useTransition } from "react"; import { toast } from "sonner"; -import { deleteStructuredGuide, moveGuideToTrash, restoreStructuredGuide, startCatalogSync } from "@/app/admin/actions"; +import { + deleteStructuredGuide, + moveGuideToTrash, + restoreStructuredGuide, + startCatalogSync, +} from "@/app/admin/actions"; import { DeleteConfirmationDialog } from "@/components/admin/delete-confirmation-dialog"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; -import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyTitle } from "@/components/ui/empty"; +import { + Card, + CardAction, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { + Empty, + EmptyContent, + EmptyDescription, + EmptyHeader, + EmptyTitle, +} from "@/components/ui/empty"; import { Spinner } from "@/components/ui/spinner"; -type GuideCard = { id: string; characterKey: string; name: string; overview: string; coverUrl: string; version: number; updatedAt: Date; trashedAt: Date | null }; +type GuideCard = { + id: string; + characterKey: string; + name: string; + overview: string; + coverUrl: string; + version: number; + updatedAt: Date; + trashedAt: Date | null; +}; -export function StructuredDashboard({ guides, trash, catalogVersion, latestCatalogVersion }: { guides: GuideCard[]; trash: GuideCard[]; catalogVersion: string | null; latestCatalogVersion: string | null }) { +export function StructuredDashboard({ + guides, + trash, + catalogVersion, + latestCatalogVersion, +}: { + guides: GuideCard[]; + trash: GuideCard[]; + catalogVersion: string | null; + latestCatalogVersion: string | null; +}) { const router = useRouter(); const [pending, startTransition] = useTransition(); const catalogReady = Boolean(catalogVersion); - const updateAvailable = Boolean(catalogVersion && latestCatalogVersion && catalogVersion !== latestCatalogVersion); + const updateAvailable = Boolean( + catalogVersion && + latestCatalogVersion && + catalogVersion !== latestCatalogVersion, + ); - function run(action: () => Promise<{ status: string; message?: string }>, success: string) { + function run( + action: () => Promise<{ status: string; message?: string }>, + success: string, + ) { startTransition(async () => { const result = await action(); if (result.status === "error") toast.error(result.message); - else { toast.success(success); router.refresh(); } + else { + toast.success(success); + router.refresh(); + } }); } return (
-
Lunaris ที่ Sync: {catalogVersion ? `v${catalogVersion}` : "ยังไม่ Sync"}{latestCatalogVersion ? updateAvailable ? `มีอัปเดต: v${latestCatalogVersion}` : `ล่าสุด: v${latestCatalogVersion}` : "ตรวจสอบเวอร์ชันล่าสุดไม่ได้"}
-
+
+ + Lunaris ที่ Sync:{" "} + {catalogVersion ? `v${catalogVersion}` : "ยังไม่ Sync"} + + + {latestCatalogVersion + ? updateAvailable + ? `มีอัปเดต: v${latestCatalogVersion}` + : `ล่าสุด: v${latestCatalogVersion}` + : "ตรวจสอบเวอร์ชันล่าสุดไม่ได้"} + +
+
+ + +
{guides.length ? ( -
{guides.map((guide) => ( - - แก้ไข Guide {guide.name} -
{`Guide
- {guide.name}{guide.overview}v{guide.version} -

แก้ไขล่าสุด {new Date(guide.updatedAt).toLocaleString("th-TH")}

- } title={`ย้าย ${guide.name} ไปถังขยะ?`} description="Guide จะหายจากหน้าเว็บไซต์ทันที และสามารถกู้คืนได้ภายหลัง" confirmLabel="ย้ายไปถังขยะ" onConfirm={() => run(() => moveGuideToTrash(guide.id), "ย้ายไปถังขยะแล้ว")}>ย้าย {guide.name} ไปถังขยะ -
- ))}
- ) : ยังไม่มี GuideSync Catalog แล้วเลือกตัวละครเพื่อสร้าง Guide แรก} - {trash.length ?

ถังขยะ

Guide ที่ซ่อนไว้จากเว็บไซต์

{trash.map((guide) => {guide.name}{guide.overview}
} title={`ลบ ${guide.name} ถาวร?`} description="ข้อมูล Weapons, Artifacts, Constellations, Team และ Extra ทั้งหมดจะกู้คืนไม่ได้" confirmLabel="ยืนยันลบถาวร" onConfirm={() => run(() => deleteStructuredGuide(guide.id), "ลบ Guide ถาวรแล้ว")}>ลบถาวร
)}
: null} +
+ {guides.map((guide) => ( + + + แก้ไข Guide {guide.name} + +
+ {`Guide +
+ + {guide.name} + + {guide.overview} + + + v{guide.version} + + + +

+ แก้ไขล่าสุด{" "} + {new Date(guide.updatedAt).toLocaleString("th-TH")} +

+
+ + + + } + title={`ย้าย ${guide.name} ไปถังขยะ?`} + description="Guide จะหายจากหน้าเว็บไซต์ทันที และสามารถกู้คืนได้ภายหลัง" + confirmLabel="ย้ายไปถังขยะ" + onConfirm={() => + run(() => moveGuideToTrash(guide.id), "ลบสำเร็จ!") + } + > + + ย้าย {guide.name} ไปถังขยะ + + +
+ ))} +
+ ) : ( + + + ยังไม่มี Guide + + Sync Catalog แล้วเลือกตัวละครเพื่อสร้าง Guide แรก + + + + + + + )} + {trash.length ? ( +
+
+

ถังขยะ

+

+ Guide ที่ซ่อนไว้จากเว็บไซต์ +

+
+
+ {trash.map((guide) => ( + + + {guide.name} + {guide.overview} + +
+ + + } + title={`ลบ ${guide.name} ถาวร?`} + description="ข้อมูล Weapons, Artifacts, Constellations, Team และ Extra ทั้งหมดจะกู้คืนไม่ได้" + confirmLabel="ยืนยันลบถาวร" + onConfirm={() => + run( + () => deleteStructuredGuide(guide.id), + "ลบสำเร็จ!", + ) + } + > + + ลบถาวร + +
+
+
+
+ ))} +
+
+ ) : null}
); }