"use server"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { contentMutationService, createContentMutationInvocation, } from "@/features/housekeeping/domains/content/services/mutations"; import { createCorrelationId } from "@/features/housekeeping/foundation/contracts"; import { requirePermission } from "@/lib/admin/guard"; import { PERMS } from "@/lib/permissions"; function formValues(formData: FormData): Record { return Object.fromEntries( Array.from(formData.entries(), ([key, value]) => [ key, typeof value === "string" ? value : value.name, ]), ); } async function executeTheme( operation: | "theme.update" | "theme.apply-preset" | "theme.custom-change" | "theme.apply-custom", input: Record, ) { const staff = await requirePermission(PERMS.SETTINGS_EDIT); return contentMutationService.execute( createContentMutationInvocation(staff, createCorrelationId()), operation, input, ); } export async function saveTheme(formData: FormData): Promise { const result = await executeTheme("theme.update", { values: formValues(formData), }); if (result.ok) revalidatePath("/", "layout"); redirect("/admin/theme?saved=1"); } export async function applyPreset(formData: FormData): Promise { const name = String(formData.get("preset") ?? "").normalize("NFC"); const result = await executeTheme("theme.apply-preset", { preset: name }); if (result.ok) revalidatePath("/", "layout"); redirect( result.ok ? `/admin/theme?preset=${encodeURIComponent(name)}` : "/admin/theme", ); } export async function saveCustomTheme(formData: FormData): Promise { const name = String(formData.get("name") ?? "") .normalize("NFC") .trim(); if (!name) redirect("/admin/theme"); const result = await executeTheme("theme.custom-change", { action: "create", name, }); if (result.ok) revalidatePath("/admin/theme"); redirect("/admin/theme?savedTheme=1"); } export async function applyCustomTheme(formData: FormData): Promise { const id = String(formData.get("id") ?? "") .normalize("NFC") .trim(); if (!id) redirect("/admin/theme"); const result = await executeTheme("theme.apply-custom", { id }); if (result.ok) revalidatePath("/", "layout"); const name = result.ok && typeof result.data.output?.name === "string" ? result.data.output.name : ""; redirect( result.ok ? `/admin/theme?theme=${encodeURIComponent(name)}` : "/admin/theme", ); } export async function renameCustomTheme(formData: FormData): Promise { const id = String(formData.get("id") ?? "") .normalize("NFC") .trim(); const name = String(formData.get("name") ?? "") .normalize("NFC") .trim(); if (!id || !name) redirect("/admin/theme"); const result = await executeTheme("theme.custom-change", { action: "rename", id, name, }); if (result.ok) revalidatePath("/admin/theme"); redirect("/admin/theme?renamed=1"); } export async function deleteCustomTheme(formData: FormData): Promise { const id = String(formData.get("id") ?? "") .normalize("NFC") .trim(); if (!id) redirect("/admin/theme"); const result = await executeTheme("theme.custom-change", { action: "delete", id, }); if (result.ok) revalidatePath("/admin/theme"); redirect("/admin/theme?deletedTheme=1"); }