Badges: persist template controls_cfg; fix onchange syntax in template form

This commit is contained in:
Scott Idem
2026-04-09 15:10:03 -04:00
parent 76c28a7e22
commit d05420d9c1
2 changed files with 106 additions and 14 deletions

View File

@@ -121,18 +121,27 @@ interface ControlsCfg {
shown?: string[];
auth_editable?: string[];
}
let template_controls_cfg = $derived(
(() => {
try {
const parsed = JSON.parse(
$lq__event_badge_template_obj?.other_json ?? '{}'
);
return (parsed?.controls_cfg ?? null) as ControlsCfg | null;
} catch {
return null;
let template_controls_cfg = $derived.by((): ControlsCfg | null => {
try {
const raw = $lq__event_badge_template_obj?.cfg_json ?? null;
if (raw) {
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
if (parsed?.controls_cfg) return parsed.controls_cfg as ControlsCfg;
}
})()
);
} catch {
// fall through to other_json fallback
}
try {
const raw2 = $lq__event_badge_template_obj?.other_json ?? null;
if (raw2) {
const parsed2 = typeof raw2 === 'string' ? JSON.parse(raw2) : raw2;
return (parsed2?.controls_cfg ?? null) as ControlsCfg | null;
}
} catch {
return null;
}
return null;
});
// Default auth-editable fields when the template has no explicit config.
// Covers the fields an attendee most commonly needs to fix at the badge table.

View File

@@ -57,6 +57,10 @@ let cfg_show_qr_back = $state(true);
let cfg_hide_title = $state(false);
let cfg_hide_affiliations = $state(false);
let cfg_hide_location = $state(false);
// Controls menu config (per-template) — which fields the controls panel shows
// and which fields authenticated users may edit. Stored under cfg_json.controls_cfg
let cfg_controls_shown: string[] = $state([]);
let cfg_controls_auth_editable: string[] = $state([]);
// Body text color (hex)
let cfg_body_text_color = $state('#000000');
// Alignment overrides: 'left' | 'center' | 'right' | 'justify'
@@ -128,6 +132,13 @@ async function load_template(id: string) {
cfg_hide_affiliations = parsed_cfg.hasOwnProperty('hide_affiliations') ? !!parsed_cfg.hide_affiliations : false;
cfg_hide_location = parsed_cfg.hasOwnProperty('hide_location') ? !!parsed_cfg.hide_location : false;
// Controls menu cfg (preferred location: cfg_json.controls_cfg)
const parsed_controls = parsed_cfg?.controls_cfg ?? parsed_cfg?.controlsCfg ?? parsed_cfg?.controls ?? null;
cfg_controls_shown = Array.isArray(parsed_controls?.shown) ? [...parsed_controls.shown] : [];
cfg_controls_auth_editable = Array.isArray(parsed_controls?.auth_editable)
? [...parsed_controls.auth_editable]
: [];
// Body text color (hex-only). Prefer explicit hex keys.
const _hex_candidate = parsed_cfg.body_text_color_hex ?? parsed_cfg.body_text_color ?? parsed_cfg.text_color ?? '';
if (typeof _hex_candidate === 'string' && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(_hex_candidate.trim())) {
@@ -195,6 +206,12 @@ async function handle_submit() {
cfg_obj.qr_alignment.front = cfg_qr_alignment_front;
cfg_obj.qr_alignment.back = cfg_qr_alignment_back;
// Controls menu config: which fields the controls panel shows and which
// fields authenticated users may edit. Stored under cfg_json.controls_cfg
cfg_obj.controls_cfg = cfg_obj.controls_cfg || {};
if (cfg_controls_shown && cfg_controls_shown.length > 0) cfg_obj.controls_cfg.shown = [...cfg_controls_shown];
if (cfg_controls_auth_editable && cfg_controls_auth_editable.length > 0) cfg_obj.controls_cfg.auth_editable = [...cfg_controls_auth_editable];
// Body text color (hex-only)
if (typeof cfg_body_text_color === 'string' && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(cfg_body_text_color.trim())) {
cfg_obj.body_text_color = cfg_body_text_color.trim();
@@ -258,6 +275,17 @@ async function handle_submit() {
function handle_cancel() {
if (oncancel) oncancel();
}
// Toggle helpers for controls_cfg arrays
function toggle_cfg_controls_shown(key: string) {
if (cfg_controls_shown.includes(key)) cfg_controls_shown = cfg_controls_shown.filter((k) => k !== key);
else cfg_controls_shown = [...cfg_controls_shown, key];
}
function toggle_cfg_controls_auth_editable(key: string) {
if (cfg_controls_auth_editable.includes(key)) cfg_controls_auth_editable = cfg_controls_auth_editable.filter((k) => k !== key);
else cfg_controls_auth_editable = [...cfg_controls_auth_editable, key];
}
</script>
<form onsubmit={prevent_default(handle_submit)} class="space-y-4 p-4">
@@ -453,9 +481,64 @@ function handle_cancel() {
</p>
</label>
</div>
<p class="text-xs text-surface-400 italic">
These values are saved into <code>cfg_json</code>. Existing cfg_json keys are preserved.
</p>
<div class="border-t pt-2">
<h4 class="font-semibold">Controls Menu Toggles</h4>
<p class="text-xs text-surface-400 italic">Controls which fields appear in the print controls panel and which fields authenticated users may edit.</p>
<div class="grid grid-cols-2 gap-2 mt-2">
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_shown.includes('name')} onchange={() => toggle_cfg_controls_shown('name')} />
<span>Show Full Name</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_shown.includes('title')} onchange={() => toggle_cfg_controls_shown('title')} />
<span>Show Title</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_shown.includes('affiliations')} onchange={() => toggle_cfg_controls_shown('affiliations')} />
<span>Show Affiliations</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_shown.includes('location')} onchange={() => toggle_cfg_controls_shown('location')} />
<span>Show Location</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_shown.includes('pronouns')} onchange={() => toggle_cfg_controls_shown('pronouns')} />
<span>Show Pronouns</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_shown.includes('allow_tracking')} onchange={() => toggle_cfg_controls_shown('allow_tracking')} />
<span>Show Lead Scanning</span>
</label>
</div>
<p class="text-xs text-surface-400 italic mt-2">Authenticated users may edit:</p>
<div class="grid grid-cols-2 gap-2 mt-2">
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_auth_editable.includes('title')} onchange={() => toggle_cfg_controls_auth_editable('title')} />
<span>Title</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_auth_editable.includes('affiliations')} onchange={() => toggle_cfg_controls_auth_editable('affiliations')} />
<span>Affiliations</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_auth_editable.includes('location')} onchange={() => toggle_cfg_controls_auth_editable('location')} />
<span>Location</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_auth_editable.includes('allow_tracking')} onchange={() => toggle_cfg_controls_auth_editable('allow_tracking')} />
<span>Lead Scanning</span>
</label>
<label class="label flex items-center gap-2">
<input type="checkbox" class="checkbox" checked={cfg_controls_auth_editable.includes('pronouns')} onchange={() => toggle_cfg_controls_auth_editable('pronouns')} />
<span>Pronouns</span>
</label>
</div>
<p class="text-xs text-surface-400 italic">
These values are saved into <code>cfg_json</code>. Existing cfg_json keys are preserved.
</p>
</div>
</div>
{/if}
</section>