/** * Map a saved BadgeBatch (config) into CreateBadgePanel form state. */ import type { BadgeBatchRecord, BadgeLayoutElementPayload } from "../../../services/api/badgeBatches"; import type { BadgeBackgroundImageLayout, BadgeLayoutElement } from "./badgeLayout"; import { defaultBackgroundImageLayout, defaultLayoutForFields, parseBackgroundImageLayout } from "./badgeLayout"; export type BadgeFormState = { formName: string; formEventId: string; sizePreset: "a6" | "a7" | "4x3in" | "4x6in" | "custom"; customW: string; customH: string; orientation: "portrait" | "landscape"; includeFaculty: boolean; includeParticipants: boolean; participantScope: "all" | "participant_list"; participantListId: string; backgroundMode: "image" | "color"; backgroundColor: string; backgroundImageUrl: string; backgroundImageLayout: BadgeBackgroundImageLayout; enabledFields: string[]; layoutElements: BadgeLayoutElement[]; customTexts: { id: string; text: string }[]; customImages: { id: string; imageUrl: string }[]; outputFormat: "pdf" | "png" | "jpeg"; badgeTypeLabel: string; }; function eventIdFromBatch(batch: BadgeBatchRecord): string { const ev = batch.event; if (typeof ev === "string") return ev; if (ev && typeof ev === "object" && "_id" in ev) return String(ev._id); return ""; } function duplicateExportName(name: string): string { const base = (name || "Badge export").trim(); const copy = `Copy of ${base}`; return copy.length > 120 ? `${copy.slice(0, 117)}…` : copy; } function asConfig(batch: BadgeBatchRecord): Record { return (batch.config && typeof batch.config === "object" ? batch.config : {}) as Record; } function str(v: unknown, fallback = ""): string { return typeof v === "string" ? v : fallback; } function bool(v: unknown, fallback: boolean): boolean { return typeof v === "boolean" ? v : fallback; } function numStr(v: unknown, fallback: string): string { if (typeof v === "number" && Number.isFinite(v)) return String(v); return fallback; } function sizePresetFromConfig(c: Record): BadgeFormState["sizePreset"] { const p = str(c.sizePreset, "a6"); if (p === "a7" || p === "4x3in" || p === "4x6in" || p === "custom") return p; return "a6"; } function layoutFromConfig(c: Record): BadgeLayoutElement[] { const raw = c.layout; if (!Array.isArray(raw) || raw.length === 0) return []; return raw .filter((el): el is BadgeLayoutElementPayload => el != null && typeof el === "object" && typeof (el as BadgeLayoutElementPayload).id === "string") .map((el) => ({ ...el })) as BadgeLayoutElement[]; } function customTextsFromConfig(c: Record, layout: BadgeLayoutElement[]): { id: string; text: string }[] { const fromConfig = Array.isArray(c.customTexts) ? c.customTexts .filter((x): x is { id: string; text: string } => x != null && typeof x === "object" && typeof (x as { id: string }).id === "string") .map((x) => ({ id: String(x.id), text: String((x as { text?: string }).text ?? "") })) : []; if (fromConfig.length) return fromConfig; return layout .filter((el) => el.kind === "custom_text") .map((el) => ({ id: el.id, text: str(el.text, "Your text") })); } function customImagesFromConfig(c: Record, layout: BadgeLayoutElement[]): { id: string; imageUrl: string }[] { const fromConfig = Array.isArray(c.customImages) ? c.customImages .filter((x): x is { id: string; imageUrl: string } => x != null && typeof x === "object" && typeof (x as { id: string }).id === "string") .map((x) => ({ id: String(x.id), imageUrl: String((x as { imageUrl?: string }).imageUrl ?? "") })) : []; if (fromConfig.length) return fromConfig; return layout .filter((el) => el.kind === "custom_image") .map((el) => ({ id: el.id, imageUrl: str(el.imageUrl, "") })) .filter((x) => x.imageUrl); } export function formStateFromBadgeBatch(batch: BadgeBatchRecord): BadgeFormState { const c = asConfig(batch); const bgColor = str(c.backgroundColor, "#0B4DD1"); const bgImageUrl = str(c.backgroundImageUrl, ""); const bgMode = bgImageUrl.trim() ? "image" : str(c.backgroundMode, "color") === "image" ? "image" : "color"; const backgroundImageLayout = parseBackgroundImageLayout(c.backgroundImageLayout) ?? (bgImageUrl.trim() ? defaultBackgroundImageLayout() : defaultBackgroundImageLayout()); const fields = Array.isArray(c.fields) ? c.fields.map((f) => String(f)) : ["name", "title", "org", "qr"]; let layoutElements = layoutFromConfig(c); if (!layoutElements.length && fields.length) { layoutElements = defaultLayoutForFields(fields, bgColor, bgMode); } const customTexts = customTextsFromConfig(c, layoutElements); const customImages = customImagesFromConfig(c, layoutElements); const scope = str(c.participantScope, "all") === "participant_list" ? "participant_list" : "all"; const out = str(c.outputFormat, "pdf"); const outputFormat: BadgeFormState["outputFormat"] = out === "png" || out === "jpeg" ? out : "pdf"; return { formName: duplicateExportName(batch.name), formEventId: eventIdFromBatch(batch), sizePreset: sizePresetFromConfig(c), customW: numStr(c.widthMm, "105"), customH: numStr(c.heightMm, "148"), orientation: str(c.orientation, "portrait") === "landscape" ? "landscape" : "portrait", includeFaculty: bool(c.includeFaculty, true), includeParticipants: bool(c.includeParticipants, true), participantScope: scope, participantListId: c.participantListId != null ? String(c.participantListId) : "", backgroundMode: bgMode, backgroundColor: bgColor, backgroundImageUrl: bgImageUrl, backgroundImageLayout, enabledFields: fields, layoutElements, customTexts, customImages, outputFormat, badgeTypeLabel: str(c.badgeTypeLabel, "Attendee"), }; }