refactor(badges): move hide toggle + print count editor to individual badge view

Hide/Unhide and print count edit belong on the per-badge page (print controls
staff section), not the search list — the list was getting too crowded.

- ae_comp__badge_obj_li: removed hide toggle, print count input, and the
  ae_api/events_func imports that were only there to support them
- ae_comp__badge_print_controls: added Hide Badge button (Trusted, top of staff
  section) and Print Count editor (Admin+, below hide); both reuse the existing
  save_field/field_save_status pattern for consistent spinner/done/error feedback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-04-13 22:44:58 -04:00
parent bf31f13650
commit 5203104fef
2 changed files with 69 additions and 83 deletions

View File

@@ -112,6 +112,7 @@ let is_auth = $derived($ae_loc.authenticated_access === true);
// This component NEVER writes to $ae_loc.edit_mode. Read-only usage only:
// — used here to allow reprinting an already-printed badge when global edit mode is active.
let is_global_edit_mode = $derived($ae_loc.edit_mode === true);
let is_admin = $derived($ae_loc.administrator_access === true);
// --- Per-template controls config ---
// Stored in event_badge_template.other_json as { controls_cfg: { shown?, auth_editable? } }.
@@ -1554,6 +1555,72 @@ let allow_tracking_open = $derived(
<div class="ctrl-accordion" class:open={staff_open}>
<div class="ctrl-accordion-inner space-y-1 pt-0.5">
<!-- === HIDE BADGE ===
Removes this badge from search results for all users.
Use for duplicates, test records, or badges that should not be printed.
Trusted + Edit Mode. Visible even when badge is already hidden so staff
can recover it without needing to enable Show Hidden in search first. -->
<div class="flex items-center gap-2 px-2 py-1">
<button
type="button"
class="btn btn-sm w-full justify-between"
class:preset-tonal-warning={$lq__event_badge_obj?.hide}
class:preset-tonal-surface={!$lq__event_badge_obj?.hide}
disabled={field_save_status['hide'] === 'saving'}
onclick={() => save_field('hide', { hide: !$lq__event_badge_obj?.hide })}
title={$lq__event_badge_obj?.hide
? 'Badge is hidden — click to unhide and restore to search results'
: 'Hide this badge from search results'}>
<span class="flex items-center gap-1.5">
{#if field_save_status['hide'] === 'saving'}
<LoaderCircle size="13" class="animate-spin shrink-0" />
{$lq__event_badge_obj?.hide ? 'Unhiding…' : 'Hiding…'}
{:else if $lq__event_badge_obj?.hide}
<Eye size="13" class="shrink-0" />
Unhide Badge
{:else}
<EyeOff size="13" class="shrink-0" />
Hide Badge
{/if}
</span>
{#if field_save_status['hide'] === 'done'}
<Check size="13" class="text-success-500 shrink-0" />
{/if}
</button>
</div>
<!-- === PRINT COUNT (Admin+) ===
Correction tool for when the physical count diverges from the DB
(e.g. badge was printed offline or kiosk count reset). Does NOT
change print_first_datetime / print_last_datetime — timestamps
are only written by the actual Print Badge action. -->
{#if is_admin}
<div class="px-2 py-1">
<p class="field-label mb-1">
Print Count
<span class="ml-1 text-[9px] font-normal text-gray-400 normal-case tracking-normal">Admin · timestamps unchanged</span>
</p>
<div class="flex items-center gap-2">
<input
type="number"
min="0"
value={print_count}
onblur={(e) => {
const v = Math.max(0, Math.round(Number((e.currentTarget as HTMLInputElement).value)));
if (v !== print_count) save_field('print_count', { print_count: v });
}}
onkeydown={(e) => { if (e.key === 'Enter') (e.currentTarget as HTMLInputElement).blur(); }}
disabled={field_save_status['print_count'] === 'saving'}
class="input input-sm w-20 text-center font-mono" />
{#if field_save_status['print_count'] === 'saving'}
<LoaderCircle size="13" class="animate-spin opacity-70" />
{:else if field_save_status['print_count'] === 'done'}
<Check size="13" class="text-success-500" />
{/if}
</div>
</div>
{/if}
<!-- Chrome visibility toggle: hides page header + sys bar for a clean workspace.
Keyboard shortcut [H] does the same thing from anywhere on the page. -->
<div class="flex items-center gap-2 px-2 py-1">