import {useEffect, useState, type FormEvent} from "react"; import {useNavigate, useParams} from "react-router-dom"; import {toast} from "sonner"; import {newsApi, ApiError, isValidationErrorPayload} from "@/api"; import {Button} from "@/components/ui/button"; import {Input} from "@/components/ui/input"; import {Label} from "@/components/ui/label"; import {Textarea} from "@/components/ui/textarea"; import {Card, CardContent} from "@/components/ui/card"; // ISO (UTC) → value for (local time, without seconds). function isoToLocalInput(iso?: string): string { if (!iso) return ""; const d = new Date(iso); const pad = (n: number) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`; } export function NewsEditPage() { const {id} = useParams(); const editing = Boolean(id); const navigate = useNavigate(); const [form, setForm] = useState({title: "", body: "", published: true, publish_at: ""}); const [fieldErrors, setFieldErrors] = useState>({}); const [loading, setLoading] = useState(editing); const [busy, setBusy] = useState(false); useEffect(() => { if (!id) return; newsApi.get(id) .then(n => setForm({title: n.title, body: n.body, published: n.published, publish_at: isoToLocalInput(n.publish_at)})) .catch(() => toast.error("News item not found")) .finally(() => setLoading(false)); }, [id]); const submit = async (e: FormEvent) => { e.preventDefault(); setBusy(true); setFieldErrors({}); // datetime-local → ISO (UTC). Empty — no schedule (we omit publish_at). const payload = { title: form.title, body: form.body, published: form.published, publish_at: form.publish_at ? new Date(form.publish_at).toISOString() : undefined, }; try { if (editing && id) { await newsApi.update(id, payload); } else { await newsApi.create(payload); } toast.success(editing ? "Saved" : "News item created"); navigate("/news"); } catch (err) { if (err instanceof ApiError) { if (isValidationErrorPayload(err.body?.payload)) { setFieldErrors(err.body!.payload.fieldErrors); } toast.error(err.body?.message ?? "Failed to save"); } else { toast.error("Network unavailable"); } } finally { setBusy(false); } }; const fieldError = (k: string) => fieldErrors[k]?.[0]; if (loading) return Loading…; return ( {editing ? "Edit news item" : "New news item"} Title setForm({...form, title: e.target.value})} /> {fieldError("title") && {fieldError("title")}} Body setForm({...form, body: e.target.value})} /> {fieldError("body") && {fieldError("body")}} Publish at (optional) setForm({...form, publish_at: e.target.value})} /> A future date → the draft is published by the publisher worker on schedule. {fieldError("publish_at") && {fieldError("publish_at")}} setForm({...form, published: e.target.checked})} /> Published {busy ? "…" : "Save"} navigate("/news")}>Cancel ); }
Loading…