import { useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { ArrowLeft, House, Lock, Send, Clock3 } from "lucide-react"; 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 { Spinner } from "@/components/ui/spinner"; import { Badge } from "@/components/ui/badge"; import AppBreadcrumb from "@/components/generic/Breadcrumb/AppBreadcrumb"; import { PageMeta } from "@/contexts/MetadataContext"; import { AdminNotificationTemplateProvider, useAdminNotificationTemplates, } from "@/contexts/AdminNotificationTemplateContext"; import { NOTIFICATION_TEMPLATE_PLACEHOLDERS } from "@/data/notificationTemplatePlaceholders.data"; import { STATUS_META, hasPendingChanges } from "@/data/notificationTemplateStatus.data"; import { cn } from "@/lib/utils"; function SectionCard({ title, children }) { return (
{title &&

{title}

} {children}
); } function FieldError({ message }) { if (!message) return null; return

{message}

; } function EditNotificationTemplateInner() { const navigate = useNavigate(); const { id } = useParams(); const { template, loading, fetchTemplate, updateTemplate } = useAdminNotificationTemplates(); const [label, setLabel] = useState(""); const [title, setTitle] = useState(""); const [message, setMessage] = useState(""); const [errors, setErrors] = useState({}); useEffect(() => { if (id) fetchTemplate(id); }, [id]); useEffect(() => { if (template) { setLabel(template.label ?? ""); // Prefer whatever's pending (unpublished) over the live version, so // reopening a template with pending changes resumes editing them. setTitle(template.draft_title ?? template.title ?? ""); setMessage(template.draft_message ?? template.message ?? ""); } }, [template]); const status = STATUS_META[template?.status] ?? STATUS_META.draft; const pending = hasPendingChanges(template); const knownPlaceholders = NOTIFICATION_TEMPLATE_PLACEHOLDERS[template?.type] ?? null; const validate = () => { const e = {}; if (!label.trim()) e.label = "Label is required."; if (!title.trim()) e.title = "Title is required."; if (!message.trim()) e.message = "Message is required."; setErrors(e); return !Object.keys(e).length; }; const handleSave = async (publish) => { if (!validate()) return; const result = await updateTemplate(id, { label: label.trim(), title: title.trim(), message: message.trim(), publish, }); if (result) navigate("/admin/announcement-templates"); }; return (
, to: "/admin" }, { label: "Announcements", to: "/admin/announcements" }, { label: "Templates", to: "/admin/announcement-templates" }, { label: template?.label ?? "Edit" }, ]} />

Edit Announcement Template

{template && ( {status.label} )}

Update this template's title and message.

{pending && (

This template has pending changes that haven't gone out yet — the version currently used is the last one you published. Press Publish below to apply these edits, or Save as Draft to keep working without publishing.

)}

This is a system notification — code fires it by referencing this exact type, so the type is locked. Label, title and message are still fully editable.

Cannot be changed — this is what code looks up.

setLabel(e.target.value)} placeholder="e.g. Tasks Overdue (Admin)" />
setTitle(e.target.value)} placeholder="e.g. Tasks Overdue" />

Message

Plain text only — no HTML, no conditional logic, just straight{" "} {"{{placeholder}}"} tokens.

{(knownPlaceholders !== null) && (

Available placeholders

{knownPlaceholders.length ? (
{knownPlaceholders.map((ph) => ( {`{{${ph}}}`} ))}
) : (

This template has no dynamic placeholders.

)}
)}