2 Commits

Author SHA1 Message Date
Scott Idem
deea250a85 fix(badges): add fallback badge_type_code_li when template has no badge_type_list
badge_type_code_li was returning [] when the template had no badge_type_list,
causing the Badge Type field to be hidden entirely in the Staff section.
Add same fallback default as create form and search filter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 18:07:24 -04:00
Scott Idem
4d43fd8a67 fix(badges): move Badge Type field to top of Staff section
Was at the bottom after print position controls — now first item in
Staff Adjustments, before Hide/Unhide Badge, where staff expect it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 18:03:50 -04:00

View File

@@ -269,13 +269,27 @@ async function handle_print_badge() {
// --- Badge type list from template --- // --- Badge type list from template ---
// Each item: { code: string, name: string }. Used for the badge type dropdown. // Each item: { code: string, name: string }. Used for the badge type dropdown.
// Falls back to a default list when the template has no badge_type_list configured.
// Keep in sync with ae_comp__badge_search.svelte and ae_comp__badge_create_form.svelte.
// TODO: drive all three from the template so this is event-agnostic.
const default_badge_type_code_li = [
{ code: 'attendee', name: 'In-Person Attendee' },
{ code: 'sponsor', name: 'Adapt26 Sponsor' },
{ code: 'staff', name: 'Staff' },
{ code: 'guest', name: 'Guest' },
{ code: 'volunteer', name: 'Volunteer' },
{ code: 'member', name: 'Member' },
{ code: 'nonmember', name: 'Non-Member' },
{ code: 'test', name: 'Test' }
];
let badge_type_code_li = $derived.by((): { code: string; name: string }[] => { let badge_type_code_li = $derived.by((): { code: string; name: string }[] => {
const raw = $lq__event_badge_template_obj?.badge_type_list; const raw = $lq__event_badge_template_obj?.badge_type_list;
if (!raw) return []; if (!raw) return default_badge_type_code_li;
try { try {
return JSON.parse(raw); const parsed = JSON.parse(raw);
return Array.isArray(parsed) && parsed.length > 0 ? parsed : default_badge_type_code_li;
} catch { } catch {
return []; return default_badge_type_code_li;
} }
}); });
@@ -1661,6 +1675,92 @@ let allow_tracking_open = $derived(
<div class="ctrl-accordion" class:open={staff_open}> <div class="ctrl-accordion" class:open={staff_open}>
<div class="ctrl-accordion-inner space-y-1 pt-0.5"> <div class="ctrl-accordion-inner space-y-1 pt-0.5">
<!-- === BADGE TYPE === (only when template defines badge_type_list) -->
{#if badge_type_code_li.length > 0}
<div
class="field-card overflow-hidden rounded-lg"
class:field-card--active={active_field === 'badge_type'}>
<div class="flex items-center gap-2 px-2 py-1">
<div class="min-w-0 flex-1">
<p class="field-label">Badge Type</p>
{#if badge_type_display}
<p class="truncate leading-snug">
{badge_type_display}
</p>
{:else}
<p class="text-xs text-gray-400 italic">
Tap ✎ to assign
</p>
{/if}
</div>
<button
type="button"
class="btn btn-xs preset-tonal-primary shrink-0 transition-colors"
onclick={() => toggle_field('badge_type')}
aria-expanded={active_field === 'badge_type'}
aria-controls="field-form-badge-type"
title="Edit badge type"
aria-label="Edit badge type">
{#if active_field === 'badge_type'}<ChevronDown
size="12" />{:else}<Pencil
size="12" />{/if}
</button>
</div>
<div
class="ctrl-accordion"
class:open={active_field === 'badge_type'}>
<div class="ctrl-accordion-inner">
<div
id="field-form-badge-type"
class="border-t border-gray-200 bg-gray-50 px-2 pt-1.5 pb-2 dark:border-gray-700 dark:bg-gray-800">
<select
id="ctrl-badge-type"
name="ctrl-badge-type"
class="select w-full"
bind:this={select_ref_badge_type}
bind:value={edit_badge_type_code}>
<option value={null}
> Select badge type —</option>
{#each badge_type_code_li as item (item.code)}
<option value={item.code}
>{item.name}</option>
{/each}
</select>
{@render field_actions(
'badge_type',
() =>
save_field('badge_type', {
badge_type_code_override:
edit_badge_type_code,
// Keep badge_type_override in sync with the name.
// See PROJECT__AE_Events_Badges_Review_Print.md for edge-case notes.
badge_type_override:
edit_badge_type_code
? (badge_type_code_li.find(
(item) =>
item.code ===
edit_badge_type_code
)?.name ??
edit_badge_type_code)
: null
}),
() => cancel_field('badge_type'),
$lq__event_badge_obj?.badge_type_code_override
? () =>
save_field('badge_type', {
badge_type_code_override:
null,
badge_type_override: null
})
: undefined,
is_dirty_badge_type
)}
</div>
</div>
</div>
</div>
{/if}
<!-- === HIDE BADGE === <!-- === HIDE BADGE ===
Removes this badge from search results for all users. Removes this badge from search results for all users.
Use for duplicates, test records, or badges that should not be printed. Use for duplicates, test records, or badges that should not be printed.
@@ -1935,92 +2035,6 @@ let allow_tracking_open = $derived(
{/if} {/if}
</div> </div>
<!-- === BADGE TYPE === (only when template defines badge_type_list) -->
{#if badge_type_code_li.length > 0}
<div
class="field-card overflow-hidden rounded-lg"
class:field-card--active={active_field ===
'badge_type'}>
<div class="flex items-center gap-2 px-2 py-1">
<div class="min-w-0 flex-1">
<p class="field-label">Badge Type</p>
{#if badge_type_display}
<p class="truncate leading-snug">
{badge_type_display}
</p>
{:else}
<p class="text-xs text-gray-400 italic">
Tap ✎ to assign
</p>
{/if}
</div>
<button
type="button"
class="btn btn-xs preset-tonal-primary shrink-0 transition-colors"
onclick={() => toggle_field('badge_type')}
aria-expanded={active_field === 'badge_type'}
aria-controls="field-form-badge-type"
title="Edit badge type"
aria-label="Edit badge type">
{#if active_field === 'badge_type'}<ChevronDown
size="12" />{:else}<Pencil
size="12" />{/if}
</button>
</div>
<div
class="ctrl-accordion"
class:open={active_field === 'badge_type'}>
<div class="ctrl-accordion-inner">
<div
id="field-form-badge-type"
class="border-t border-gray-200 bg-gray-50 px-2 pt-1.5 pb-2 dark:border-gray-700 dark:bg-gray-800">
<select
id="ctrl-badge-type"
name="ctrl-badge-type"
class="select w-full"
bind:this={select_ref_badge_type}
bind:value={edit_badge_type_code}>
<option value={null}
> Select badge type —</option>
{#each badge_type_code_li as item (item.code)}
<option value={item.code}
>{item.name}</option>
{/each}
</select>
{@render field_actions(
'badge_type',
() =>
save_field('badge_type', {
badge_type_code_override:
edit_badge_type_code,
// Keep badge_type_override in sync with the name.
// See PROJECT__AE_Events_Badges_Review_Print.md for edge-case notes.
badge_type_override:
edit_badge_type_code
? (badge_type_code_li.find(
(item) =>
item.code ===
edit_badge_type_code
)?.name ??
edit_badge_type_code)
: null
}),
() => cancel_field('badge_type'),
$lq__event_badge_obj?.badge_type_code_override
? () =>
save_field('badge_type', {
badge_type_code_override:
null,
badge_type_override: null
})
: undefined,
is_dirty_badge_type
)}
</div>
</div>
</div>
</div>
{/if}
</div> </div>
<!-- ctrl-accordion-inner staff --> <!-- ctrl-accordion-inner staff -->
</div> </div>