fix(leads): persist licensed auth across reloads; manage tab UX fixes

**Session persistence bug** — leads_loc_defaults was missing __version: 1.
store_versions.ts wipes ae_leads_loc when parsed.__version !== 1 (always true
when the field is absent), so every page reload cleared auth_exhibit_kv and
forced re-login. Adding __version: 1 to both the interface and defaults fixes
this for all auth types.

**Manage tab fixes:**
- Description: collapsed by default with ChevronDown/Up toggle — same pattern
  as session_view.svelte. Avoids long promo copy dominating the manage screen.
- Staff Passcode: removed duplicate green plain-text display for admins; the
  Element_ae_obj_field_editor already shows the value (was showing twice).
- Booth Identifier: replaced static read-only display with Element_ae_obj_field_editor
  so the booth code (exhibit.code) is editable inline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-04-06 17:19:35 -04:00
parent f95243a9c7
commit 10e9206ca4
2 changed files with 51 additions and 31 deletions

View File

@@ -7,6 +7,7 @@
*/ */
export interface LeadsLocState { export interface LeadsLocState {
__version: number;
show_option__paid_tab: boolean; show_option__paid_tab: boolean;
show_content__scan_alert: boolean; show_content__scan_alert: boolean;
show_content__scan_requirements: boolean; show_content__scan_requirements: boolean;
@@ -78,6 +79,7 @@ export interface LeadsSessState {
// Persisted leads config — survives browser sessions. // Persisted leads config — survives browser sessions.
export const leads_loc_defaults: LeadsLocState = { export const leads_loc_defaults: LeadsLocState = {
__version: 1,
show_option__paid_tab: true, show_option__paid_tab: true,
show_content__scan_alert: true, // Workaround for QR scanner edge-case bug. show_content__scan_alert: true, // Workaround for QR scanner edge-case bug.
show_content__scan_requirements: true, show_content__scan_requirements: true,

View File

@@ -17,6 +17,7 @@ import Comp_exhibit_payment from './ae_comp__exhibit_payment.svelte';
import { import {
ChevronDown, ChevronDown,
ChevronRight, ChevronRight,
ChevronUp,
Clock, Clock,
CreditCard, CreditCard,
Database, Database,
@@ -62,6 +63,7 @@ let updating = $state(false);
let show_license_mgmt = $state(false); let show_license_mgmt = $state(false);
let show_custom_questions = $state(false); let show_custom_questions = $state(false);
let show_billing = $state(false); let show_billing = $state(false);
let desc_expanded = $state(false);
function handle_signout() { function handle_signout() {
if (confirm('Sign out from this booth?')) { if (confirm('Sign out from this booth?')) {
@@ -212,26 +214,40 @@ function handle_signout() {
</p> </p>
</div> </div>
<!-- Description --> <!-- Description — collapsed by default (can be long) -->
<div class="card preset-tonal-surface p-4 shadow-sm"> <div class="card preset-tonal-surface p-4 shadow-sm">
<div class="label mb-2"> <button
<span type="button"
class="text-xs font-black tracking-widest uppercase opacity-40" class="focus-visible:ring-primary-500 flex w-full items-center justify-between gap-2 rounded text-left focus-visible:ring-2"
onclick={() => (desc_expanded = !desc_expanded)}
aria-expanded={desc_expanded}>
<span class="text-xs font-black tracking-widest uppercase opacity-40"
>Booth Description / Promo</span> >Booth Description / Promo</span>
</div> <span class="shrink-0 text-xs opacity-40">
<Element_ae_obj_field_editor {#if desc_expanded}
object_type="event_exhibit" <ChevronUp size="1em" />
object_id={exhibit_id} {:else}
field_name="description" <ChevronDown size="1em" />
field_type="tiptap" {/if}
current_value={$lq__exhibit_obj?.description} </span>
display_block={true} </button>
class_li="text-sm" {#if desc_expanded}
on_success={() => <div class="mt-3">
events_func.load_ae_obj_id__event_exhibit({ <Element_ae_obj_field_editor
api_cfg: $ae_api, object_type="event_exhibit"
exhibit_id object_id={exhibit_id}
})} /> field_name="description"
field_type="tiptap"
current_value={$lq__exhibit_obj?.description}
display_block={true}
class_li="text-sm"
on_success={() =>
events_func.load_ae_obj_id__event_exhibit({
api_cfg: $ae_api,
exhibit_id
})} />
</div>
{/if}
</div> </div>
</div> </div>
</section> </section>
@@ -256,14 +272,6 @@ function handle_signout() {
Staff Passcode Staff Passcode
</div> </div>
<!-- Add a clear read-only display for admins to see the code at a glance -->
{#if $ae_loc.administrator_access}
<div
class="text-primary-500 mb-2 font-mono text-xl font-bold tracking-widest">
{$lq__exhibit_obj?.staff_passcode || '----'}
</div>
{/if}
<Element_ae_obj_field_editor <Element_ae_obj_field_editor
object_type="event_exhibit" object_type="event_exhibit"
object_id={exhibit_id} object_id={exhibit_id}
@@ -288,14 +296,24 @@ function handle_signout() {
<!-- Booth Code --> <!-- Booth Code -->
<div class="card bg-surface-500/5 border-surface-500/10 border p-4"> <div class="card bg-surface-500/5 border-surface-500/10 border p-4">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div class="flex-1">
<div <div
class="text-[10px] font-black tracking-widest uppercase opacity-40"> class="mb-1 text-[10px] font-black tracking-widest uppercase opacity-40">
Booth Identifier Booth Identifier
</div> </div>
<div class="font-mono text-xl font-bold"> <Element_ae_obj_field_editor
#{$lq__exhibit_obj?.code || 'N/A'} object_type="event_exhibit"
</div> object_id={exhibit_id}
field_name="code"
field_type="text"
current_value={$lq__exhibit_obj?.code}
display_block={true}
class_li="font-mono text-xl font-bold"
on_success={() =>
events_func.load_ae_obj_id__event_exhibit({
api_cfg: $ae_api,
exhibit_id
})} />
</div> </div>
<Info size="1.5em" class="opacity-20" /> <Info size="1.5em" class="opacity-20" />
</div> </div>