diff --git a/src/lib/ae_events/ae_events__event_badge.ts b/src/lib/ae_events/ae_events__event_badge.ts index 51b87832..e43f0024 100644 --- a/src/lib/ae_events/ae_events__event_badge.ts +++ b/src/lib/ae_events/ae_events__event_badge.ts @@ -632,6 +632,7 @@ export const properties_to_save = [ 'print_last_datetime', 'allow_tracking', 'agree_to_tc', + 'cfg_json', 'other_1_code', 'other_2_code', 'other_3_code', diff --git a/src/lib/ae_events/db_events.ts b/src/lib/ae_events/db_events.ts index a63add75..65140c63 100644 --- a/src/lib/ae_events/db_events.ts +++ b/src/lib/ae_events/db_events.ts @@ -170,6 +170,7 @@ export interface Badge { // passcode?: null|string; + cfg_json?: null | string; // data_json?: null|string; default_qry_str?: null | string; diff --git a/src/lib/types/ae_types.ts b/src/lib/types/ae_types.ts index d6005baa..b6fd009a 100644 --- a/src/lib/types/ae_types.ts +++ b/src/lib/types/ae_types.ts @@ -507,6 +507,7 @@ export interface ae_EventBadge extends ae_BaseObj { agree_to_tc?: boolean | null; ticket_list?: any[] | null; + cfg_json?: any; data_json?: any; default_qry_str?: string | null; } diff --git a/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte b/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte index b4aad3ea..92e289d4 100644 --- a/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte +++ b/src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_print_controls.svelte @@ -624,6 +624,113 @@ let is_dirty_badge_type = $derived( null) ); +// --- Lock / Reset font sizes to badge cfg_json --- +// "Lock Sizes" saves the current font_size_* values into event_badge.cfg_json.font_sizes. +// Any kiosk that opens this badge will then load those sizes instead of auto-sizing. +// "Reset to Auto" saves null for all fields, restoring auto-sizing everywhere. +// Trusted-only — attendees at the badge table can't permanently alter the layout. +type LockStatus = 'idle' | 'saving' | 'done' | 'error'; +let lock_sizes_status: LockStatus = $state('idle'); + +// True when at least one size is non-null (i.e. user has adjusted something) +let has_any_size_override = $derived( + font_size_name !== null || + font_size_title !== null || + font_size_affiliations !== null || + font_size_location !== null +); + +// Detect whether current state differs from what is saved in badge cfg_json +// so we can highlight the button when there are unsaved size changes. +let saved_font_sizes = $derived.by(() => { + try { + const cfg = typeof $lq__event_badge_obj?.cfg_json === 'string' + ? JSON.parse($lq__event_badge_obj.cfg_json) + : ($lq__event_badge_obj?.cfg_json ?? {}); + return cfg?.font_sizes ?? null; + } catch { + return null; + } +}); +let sizes_are_dirty = $derived( + font_size_name !== (saved_font_sizes?.name ?? null) || + font_size_title !== (saved_font_sizes?.title ?? null) || + font_size_affiliations !== (saved_font_sizes?.affiliations ?? null) || + font_size_location !== (saved_font_sizes?.location ?? null) +); + +async function lock_font_sizes() { + if (!$lq__event_badge_obj?.event_badge_id) return; + lock_sizes_status = 'saving'; + try { + // Merge into existing cfg_json — preserve any other keys that may be there + const existing_cfg = (() => { + try { + return typeof $lq__event_badge_obj.cfg_json === 'string' + ? JSON.parse($lq__event_badge_obj.cfg_json) + : ($lq__event_badge_obj.cfg_json ?? {}); + } catch { return {}; } + })(); + const new_cfg = { + ...existing_cfg, + font_sizes: { + name: font_size_name, + title: font_size_title, + affiliations: font_size_affiliations, + location: font_size_location + } + }; + await events_func.update_ae_obj__event_badge({ + api_cfg: $ae_api, + event_id, + event_badge_id: $lq__event_badge_obj.event_badge_id, + data_kv: { cfg_json: JSON.stringify(new_cfg) }, + log_lvl + }); + lock_sizes_status = 'done'; + setTimeout(() => { lock_sizes_status = 'idle'; }, 1500); + } catch (err) { + console.error('Badge print controls: lock font sizes error:', err); + lock_sizes_status = 'error'; + setTimeout(() => { lock_sizes_status = 'idle'; }, 2500); + } +} + +async function reset_font_sizes_to_auto() { + // Clear all local size state + font_size_name = null; + font_size_title = null; + font_size_affiliations = null; + font_size_location = null; + if (!$lq__event_badge_obj?.event_badge_id) return; + // Persist the reset back to the badge — removes the locked sizes server-side + lock_sizes_status = 'saving'; + try { + const existing_cfg = (() => { + try { + return typeof $lq__event_badge_obj.cfg_json === 'string' + ? JSON.parse($lq__event_badge_obj.cfg_json) + : ($lq__event_badge_obj.cfg_json ?? {}); + } catch { return {}; } + })(); + const new_cfg = { ...existing_cfg }; + delete new_cfg.font_sizes; + await events_func.update_ae_obj__event_badge({ + api_cfg: $ae_api, + event_id, + event_badge_id: $lq__event_badge_obj.event_badge_id, + data_kv: { cfg_json: Object.keys(new_cfg).length ? JSON.stringify(new_cfg) : null }, + log_lvl + }); + lock_sizes_status = 'done'; + setTimeout(() => { lock_sizes_status = 'idle'; }, 1500); + } catch (err) { + console.error('Badge print controls: reset font sizes error:', err); + lock_sizes_status = 'error'; + setTimeout(() => { lock_sizes_status = 'idle'; }, 2500); + } +} + // TC modal ref for the lead scanning terms & conditions dialog let tc_dialog_ref: HTMLDialogElement | undefined; @@ -1476,6 +1583,50 @@ let allow_tracking_open = $derived( + +
+

Locked Font Sizes

+
+ + {#if saved_font_sizes || has_any_size_override} + + {/if} +
+ {#if saved_font_sizes} +

+ Sizes locked on this badge + {#if saved_font_sizes.name}· Name {saved_font_sizes.name}px{/if} + {#if saved_font_sizes.title}· Title {saved_font_sizes.title}px{/if} +

+ {/if} +
+