diff --git a/src/app/hq-command/dashboard/applications/page.tsx b/src/app/hq-command/dashboard/applications/page.tsx index c533670..1e2cd78 100644 --- a/src/app/hq-command/dashboard/applications/page.tsx +++ b/src/app/hq-command/dashboard/applications/page.tsx @@ -10,6 +10,7 @@ import { Maximize2, Minimize2, ChevronDown, FolderOpen, Upload, FolderPlus, ChevronRight, File, ArrowUpFromLine, Search, Grid3X3, LayoutList, Copy, Check } from "lucide-react"; import { getApplications, createApplication, updateApplicationData, toggleApplication, deleteApplication } from "./actions"; +import { useHqUi } from "@/components/hq/Toast"; // AssetBucketBrowser is the unified picker. The applications page uses an @@ -245,6 +246,7 @@ function MarkdownEditor({ name, defaultValue = "", required, rows = 12, placehol // ───────────────────────────────────────────────────────────────────────────── export default function ApplicationsManager() { + const ui = useHqUi(); const router = useRouter(); const [apps, setApps] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -273,8 +275,14 @@ export default function ApplicationsManager() { formData.append("sectionsJson", JSON.stringify(sections)); formData.append("dashboardMetricsJson", JSON.stringify(dashboardMetrics)); const res = await updateApplicationData(formData); - if (res.error) { alert("Error saving data: " + res.error); } - else { setEditingApp(null); await fetchApps(); router.refresh(); } + if (res.error) { + ui.toast(`Error saving data: ${res.error}`, "error"); + } else { + ui.toast("Application saved.", "success"); + setEditingApp(null); + await fetchApps(); + router.refresh(); + } setIsSubmitting(false); }; @@ -311,7 +319,18 @@ export default function ApplicationsManager() {

{app.title}

/{app.slug}

{isPopulated ? Populated : Pending Setup} -
+
); })} diff --git a/src/app/hq-command/dashboard/health/page.tsx b/src/app/hq-command/dashboard/health/page.tsx index d5a2221..4217829 100644 --- a/src/app/hq-command/dashboard/health/page.tsx +++ b/src/app/hq-command/dashboard/health/page.tsx @@ -7,8 +7,10 @@ import { DownloadCloud, ShieldAlert, UploadCloud, Loader2, CheckCircle2 } from "lucide-react"; import { getSystemMetrics, exportDatabase, restoreDatabase } from "./actions"; +import { useHqUi } from "@/components/hq/Toast"; export default function SystemHealth() { + const ui = useHqUi(); const [metrics, setMetrics] = useState(null); const [isExporting, setIsExporting] = useState(false); @@ -54,7 +56,7 @@ export default function SystemHealth() { document.body.removeChild(a); URL.revokeObjectURL(url); } else { - alert(res.error || "Export failed."); + ui.toast(res.error || "Export failed.", "error"); } setIsExporting(false); }; diff --git a/src/app/hq-command/dashboard/heritage/page.tsx b/src/app/hq-command/dashboard/heritage/page.tsx index 8c36d02..9c8ed20 100644 --- a/src/app/hq-command/dashboard/heritage/page.tsx +++ b/src/app/hq-command/dashboard/heritage/page.tsx @@ -15,6 +15,7 @@ import { reorderHeritageSections, createHeritageStub, } from "./actions"; +import { useHqUi } from "@/components/hq/Toast"; interface SectionRow { id: string; @@ -33,6 +34,7 @@ const TYPE_META: Record([]); const [loading, setLoading] = useState(true); const [savingId, setSavingId] = useState(null); @@ -72,8 +74,15 @@ export default function HeritageManager() { }; const handleDelete = async (id: string) => { - if (!confirm("Delete this section? This cannot be undone.")) return; + const ok = await ui.confirm({ + title: "Delete section", + message: "Permanently remove this section from the heritage page. This cannot be undone.", + confirmLabel: "Delete section", + destructive: true, + }); + if (!ok) return; await deleteHeritageSection(id); + ui.toast("Section deleted.", "success"); await load(); }; diff --git a/src/app/hq-command/dashboard/hero/page.tsx b/src/app/hq-command/dashboard/hero/page.tsx index 5dfcce7..ddec46d 100644 --- a/src/app/hq-command/dashboard/hero/page.tsx +++ b/src/app/hq-command/dashboard/hero/page.tsx @@ -19,6 +19,7 @@ import { importFootageFiles, type FootageFile, } from "./actions"; +import { useHqUi } from "@/components/hq/Toast"; interface SlideRow { id: string; @@ -38,6 +39,7 @@ function safeParseJson(json: string | null | undefined, fallback: T): any { } export default function HeroDashboard() { + const ui = useHqUi(); const [slides, setSlides] = useState([]); const [loading, setLoading] = useState(true); const [savingId, setSavingId] = useState(null); @@ -142,8 +144,15 @@ export default function HeroDashboard() { }; const handleDelete = async (id: string) => { - if (!confirm("Delete this slide? The image file stays on disk and can be re-added.")) return; + const ok = await ui.confirm({ + title: "Delete slide", + message: "Removes the slide from the carousel. The image file stays on disk and can be re-imported later.", + confirmLabel: "Delete slide", + destructive: true, + }); + if (!ok) return; await deleteHeroSlide(id); + ui.toast("Slide deleted.", "success"); await loadSlides(); }; diff --git a/src/app/hq-command/dashboard/network/page.tsx b/src/app/hq-command/dashboard/network/page.tsx index 009e269..2ba2098 100644 --- a/src/app/hq-command/dashboard/network/page.tsx +++ b/src/app/hq-command/dashboard/network/page.tsx @@ -17,6 +17,7 @@ import { getApplications } from "../applications/actions"; // AssetBucketBrowser is the unified picker — single source of truth across HQ. // Aliased to AssetManager so existing JSX call sites remain untouched. import AssetBucketBrowser from "@/components/hq/AssetBucketBrowser"; +import { useHqUi } from "@/components/hq/Toast"; const AssetManager = AssetBucketBrowser; // ───────────────────────────────────────────────────────────────────────────── @@ -176,6 +177,7 @@ function MarkdownEditorCyan({ name, defaultValue = "", required, rows = 10, plac // ───────────────────────────────────────────────────────────────────────────── export default function NetworkManager() { + const ui = useHqUi(); const [nodes, setNodes] = useState([]); const [appsList, setAppsList] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -262,7 +264,18 @@ export default function NetworkManager() { setIsSavingCaseStudy(false); }; - const handleDelete = async (id: string) => { if (confirm("Delete this deployment?")) { await deleteNode(id); fetchNodesAndApps(); } }; + const handleDelete = async (id: string) => { + const ok = await ui.confirm({ + title: "Delete deployment", + message: "Permanently remove this case from the global map. The asset folder on disk is kept for safety.", + confirmLabel: "Delete deployment", + destructive: true, + }); + if (!ok) return; + await deleteNode(id); + ui.toast("Deployment deleted.", "success"); + fetchNodesAndApps(); + }; const handleToggle = async (id: string, status: boolean) => { await toggleNodeStatus(id, status); fetchNodesAndApps(); }; const availableTabs = [ diff --git a/src/app/hq-command/dashboard/news/page.tsx b/src/app/hq-command/dashboard/news/page.tsx index d042753..b53c812 100644 --- a/src/app/hq-command/dashboard/news/page.tsx +++ b/src/app/hq-command/dashboard/news/page.tsx @@ -17,6 +17,7 @@ import { getNewsArticles, createNewsArticle, updateNewsArticle, deleteNewsArticl // AssetBucketBrowser is the unified picker — single source of truth across HQ. // Aliased to AssetManager so existing JSX call sites remain untouched. import AssetBucketBrowser from "@/components/hq/AssetBucketBrowser"; +import { useHqUi } from "@/components/hq/Toast"; const AssetManager = AssetBucketBrowser; // ───────────────────────────────────────────────────────────────────────────── @@ -153,6 +154,7 @@ function MarkdownEditorCyan({ name, defaultValue = "", required, rows = 12, plac // ───────────────────────────────────────────────────────────────────────────── export default function NewsManager() { + const ui = useHqUi(); const [articles, setArticles] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isModalOpen, setIsModalOpen] = useState(false); @@ -197,7 +199,16 @@ export default function NewsManager() { }; const handleDelete = async (id: string) => { - if (confirm("Delete this article?")) { await deleteNewsArticle(id); fetchArticles(); } + const ok = await ui.confirm({ + title: "Delete article", + message: "Permanently remove this news article. The asset folder on disk is preserved for safety.", + confirmLabel: "Delete article", + destructive: true, + }); + if (!ok) return; + await deleteNewsArticle(id); + ui.toast("Article deleted.", "success"); + fetchArticles(); }; return ( diff --git a/src/app/hq-command/dashboard/parts/page.tsx b/src/app/hq-command/dashboard/parts/page.tsx index c930960..eccd8bc 100644 --- a/src/app/hq-command/dashboard/parts/page.tsx +++ b/src/app/hq-command/dashboard/parts/page.tsx @@ -15,6 +15,7 @@ import { getParts, createPart, updatePart, deletePart, togglePartStatus, getPart // AssetBucketBrowser is the unified picker — single source of truth across HQ. // Aliased to AssetManager so existing JSX call sites remain untouched. import AssetBucketBrowser from "@/components/hq/AssetBucketBrowser"; +import { useHqUi } from "@/components/hq/Toast"; const AssetManager = AssetBucketBrowser; // ───────────────────────────────────────────────────────────────────────────── @@ -98,6 +99,7 @@ function MarkdownEditorAmber({ name, defaultValue = "", required, rows = 8, plac // ───────────────────────────────────────────────────────────────────────────── export default function PartsManager() { + const ui = useHqUi(); const [parts, setParts] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isCreateOpen, setIsCreateOpen] = useState(false); @@ -189,7 +191,18 @@ export default function PartsManager() {

{part.title}

{part.sku}

{part.showPrice && part.price ? €{part.price.toFixed(2)} : Quote Based} -
+
))} diff --git a/src/app/hq-command/dashboard/timeline/page.tsx b/src/app/hq-command/dashboard/timeline/page.tsx index 8a13c6f..d75ad39 100644 --- a/src/app/hq-command/dashboard/timeline/page.tsx +++ b/src/app/hq-command/dashboard/timeline/page.tsx @@ -16,6 +16,7 @@ import { createTimelineStub, seedTimeline, } from "./actions"; +import { useHqUi } from "@/components/hq/Toast"; interface EventRow { id: string; @@ -28,6 +29,7 @@ interface EventRow { } export default function TimelineManager() { + const ui = useHqUi(); const [events, setEvents] = useState([]); const [loading, setLoading] = useState(true); const [seeding, setSeeding] = useState(false); @@ -65,8 +67,15 @@ export default function TimelineManager() { }; const handleDelete = async (id: string) => { - if (!confirm("Delete this milestone? This cannot be undone.")) return; + const ok = await ui.confirm({ + title: "Delete milestone", + message: "Permanently remove this milestone from the company timeline. This cannot be undone.", + confirmLabel: "Delete milestone", + destructive: true, + }); + if (!ok) return; await deleteTimelineEvent(id); + ui.toast("Milestone deleted.", "success"); await load(); }; diff --git a/src/app/hq-command/dashboard/users/page.tsx b/src/app/hq-command/dashboard/users/page.tsx index c5deb88..a049c30 100644 --- a/src/app/hq-command/dashboard/users/page.tsx +++ b/src/app/hq-command/dashboard/users/page.tsx @@ -5,8 +5,10 @@ import Link from "next/link"; import Image from "next/image"; import { ArrowLeft, Users, Plus, Trash2, ShieldCheck, KeyRound, Loader2, X, Settings } from "lucide-react"; import { getUsers, createUser, deleteUser, updateUser } from "./actions"; +import { useHqUi } from "@/components/hq/Toast"; export default function UsersManager() { + const ui = useHqUi(); const [users, setUsers] = useState([]); const [isLoading, setIsLoading] = useState(true); @@ -74,10 +76,18 @@ export default function UsersManager() { }; const handleDelete = async (id: string) => { - if (confirm("Are you sure you want to revoke this architect's access? This cannot be undone.")) { - const res = await deleteUser(id); - if (res.error) alert(res.error); - else fetchUsers(); + const ok = await ui.confirm({ + title: "Revoke architect access", + message: "Permanently remove this admin account. They will lose access to the Command Center immediately. This cannot be undone.", + confirmLabel: "Revoke access", + destructive: true, + }); + if (!ok) return; + const res = await deleteUser(id); + if (res.error) ui.toast(res.error, "error"); + else { + ui.toast("Architect access revoked.", "success"); + fetchUsers(); } };