diff --git a/app/admin/[character]/[page]/page.tsx b/app/admin/[character]/[page]/page.tsx index 2376607..93f6f6c 100644 --- a/app/admin/[character]/[page]/page.tsx +++ b/app/admin/[character]/[page]/page.tsx @@ -20,5 +20,5 @@ export default async function StructuredEditorPage({ params }: { params: Promise if (!guide) notFound(); const [catalog, content] = await Promise.all([getActiveCatalog(), getPublicGuide(guide.slug)]); if (!catalog || !content) notFound(); - return

{guide.name}

{guide.sections.find((section) => section.slug === page)?.title ?? page}

({ id: group.id, name: group.name, rows: group.rows.map((row) => ({ firstArtifactKey: row.firstArtifactKey, secondArtifactKey: row.secondArtifactKey, percent: row.percent })) })), artifactProfile: content.artifactProfile, constellations: content.constellations, teams: content.teams.map((team) => ({ title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ characterKey: member.characterKey, damage: member.damage })) })), extras: content.extras.map((section) => ({ title: section.title, rows: section.rows.map((row) => ({ mediaId: row.mediaId, heading: row.heading, body: row.body, percent: row.percent, imageUrl: row.imageUrl })) })) }} />
; + return

{guide.name}

{guide.sections.find((section) => section.slug === page)?.title ?? page}

item.key === guide.characterKey)?.constellations ?? []} initial={{ weapons: content.weapons, artifactGroups: content.artifactGroups.map((group) => ({ id: group.id, name: group.name, rows: group.rows.map((row) => ({ firstArtifactKey: row.firstArtifactKey, secondArtifactKey: row.secondArtifactKey, percent: row.percent })) })), artifactProfile: content.artifactProfile, constellations: content.constellations, teams: content.teams.map((team) => ({ title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ characterKey: member.characterKey, damage: member.damage })) })), extras: content.extras.map((section) => ({ title: section.title, rows: section.rows.map((row) => ({ mediaId: row.mediaId, heading: row.heading, body: row.body, percent: row.percent, imageUrl: row.imageUrl })) })) }} />
; } diff --git a/components/admin/autosave-status.tsx b/components/admin/autosave-status.tsx new file mode 100644 index 0000000..3c20a83 --- /dev/null +++ b/components/admin/autosave-status.tsx @@ -0,0 +1,13 @@ +import { AlertCircleIcon, CheckIcon, ClockIcon } from "lucide-react"; + +import { Badge } from "@/components/ui/badge"; +import { Spinner } from "@/components/ui/spinner"; +import type { AutosaveState } from "@/hooks/use-autosave"; + +export function AutosaveStatus({ state }: { state: AutosaveState }) { + if (state === "saving") return Saving…; + if (state === "unsaved") return Waiting to save…; + if (state === "incomplete") return Complete required fields; + if (state === "error") return Autosave failed; + return Saved; +} diff --git a/components/admin/guide-overview-form.tsx b/components/admin/guide-overview-form.tsx index f632268..b2dc6fa 100644 --- a/components/admin/guide-overview-form.tsx +++ b/components/admin/guide-overview-form.tsx @@ -1,23 +1,25 @@ "use client"; import Image from "next/image"; -import { useRouter } from "next/navigation"; -import { SaveIcon } from "lucide-react"; -import { useState, useTransition } from "react"; -import { toast } from "sonner"; +import { useState } from "react"; import { saveGuideOverview } from "@/app/admin/actions"; +import { AutosaveStatus } from "@/components/admin/autosave-status"; import { MediaUploader } from "@/components/admin/media-uploader"; -import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { Field, FieldDescription, FieldGroup, FieldLabel } from "@/components/ui/field"; -import { Spinner } from "@/components/ui/spinner"; import { Textarea } from "@/components/ui/textarea"; +import { useAutosave } from "@/hooks/use-autosave"; export function GuideOverviewForm({ guide }: { guide: { id: string; version: number; overview: string; coverMediaId: string; coverUrl: string; name: string } }) { - const router = useRouter(); const [overview, setOverview] = useState(guide.overview); const [cover, setCover] = useState({ id: guide.coverMediaId, url: guide.coverUrl }); - const [pending, startTransition] = useTransition(); - return Overviewภาพและข้อความนี้แสดงบนหน้าแรกและส่วนแนะนำของ GuideGuide Image
{`Guide
setCover(asset)} />
Overview