feat(leads): persistent tab states and unified search UI
- Implemented sticky tab persistence using local storage via events_loc store. - Aligned Manual Search form styling with Lead List search for UI consistency. - Updated tab switching logic to support historical navigation within exhibits. - Center-aligned and stabilized Add Lead content area.
This commit is contained in:
@@ -41,15 +41,21 @@
|
||||
$events_loc.leads.tracking__qry__sort_order = 'created_desc';
|
||||
}
|
||||
|
||||
// --- Tab State ---
|
||||
let active_tab = $state('list'); // 'start', 'add', 'list', 'manage'
|
||||
let previous_main_tab = $state('list'); // To remember if we were on 'add' or 'list' before going to 'manage'
|
||||
|
||||
// Mock sign-in state for now
|
||||
let is_signed_in = $state(true);
|
||||
|
||||
let tracking_id_li: Array<string> = $state([]);
|
||||
let search_debounce_timer: any = null;
|
||||
// --- Tab State (Sticky via Store) ---
|
||||
let active_tab = $derived($events_loc.leads.tab?.[page.params.exhibit_id ?? ''] ?? 'list');
|
||||
let previous_main_tab = $state('list'); // To remember if we were on 'add' or 'list' before going to 'manage'
|
||||
|
||||
function set_active_tab(new_tab: string) {
|
||||
const exhibit_id = page.params.exhibit_id;
|
||||
if (!exhibit_id) return;
|
||||
if (!$events_loc.leads.tab) $events_loc.leads.tab = {};
|
||||
$events_loc.leads.tab[exhibit_id] = new_tab;
|
||||
}
|
||||
|
||||
// Mock sign-in state for now
|
||||
let is_signed_in = $state(true);
|
||||
|
||||
let tracking_id_li: Array<string> = $state([]); let search_debounce_timer: any = null;
|
||||
let last_search_id = 0;
|
||||
let last_executed_key = '';
|
||||
let log_lvl = 1;
|
||||
@@ -257,28 +263,28 @@
|
||||
|
||||
function toggle_main_tab() {
|
||||
if (active_tab === 'add') {
|
||||
active_tab = 'list';
|
||||
set_active_tab('list');
|
||||
previous_main_tab = 'list';
|
||||
} else {
|
||||
active_tab = 'add';
|
||||
set_active_tab('add');
|
||||
previous_main_tab = 'add';
|
||||
}
|
||||
}
|
||||
|
||||
function toggle_manage_tab() {
|
||||
if (active_tab === 'manage') {
|
||||
active_tab = previous_main_tab;
|
||||
set_active_tab(previous_main_tab);
|
||||
} else {
|
||||
active_tab = 'manage';
|
||||
set_active_tab('manage');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section
|
||||
class="ae_events_leads_tracking_new h-full min-w-lg md:min-w-md w-full flex flex-col items-center justify-center overflow-x-hidden outline-2 outline-red-600"
|
||||
class="ae_events_leads_tracking_new h-full w-full flex flex-col items-center overflow-x-hidden"
|
||||
>
|
||||
<!-- Header -->
|
||||
<header class="grow-w w-full bg-surface-100-900 border-b border-surface-500/20 px-4 py-2 sticky top-0 z-10 flex items-center justify-between gap-4 shadow-sm">
|
||||
<header class="w-full bg-surface-100-900 border-b border-surface-500/20 px-4 py-2 sticky top-0 z-10 flex items-center justify-between gap-4 shadow-sm">
|
||||
<div class="flex flex-col min-w-0">
|
||||
<h1 class="text-base sm:text-lg font-bold truncate leading-tight">
|
||||
{$lq__exhibit_obj?.name ?? 'Exhibitor'}
|
||||
|
||||
@@ -68,24 +68,32 @@
|
||||
|
||||
<div class="lead-manual-search space-y-4 w-full">
|
||||
<form
|
||||
class="flex gap-2"
|
||||
class="search_form flex flex-row flex-wrap gap-1 items-center justify-center w-full px-2 py-2 preset-tonal-primary rounded-lg shadow-sm"
|
||||
onsubmit={(e) => { e.preventDefault(); handle_search(); }}
|
||||
>
|
||||
<div class="relative grow">
|
||||
<Search class="absolute left-3 top-1/2 -translate-y-1/2 opacity-50" size="1.2em" />
|
||||
<div class="flex flex-col md:flex-row items-center justify-center gap-1 grow">
|
||||
<input
|
||||
type="search"
|
||||
bind:value={search_query}
|
||||
placeholder="Name, email, or badge ID..."
|
||||
class="input pl-10 w-full"
|
||||
placeholder="Attendee name, email, or badge ID..."
|
||||
class="input text-lg font-mono grow transition-all w-full"
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn preset-filled-primary" disabled={searching}>
|
||||
{#if searching}
|
||||
<LoaderCircle class="animate-spin mr-2" size="1.2em" />
|
||||
{/if}
|
||||
Search
|
||||
</button>
|
||||
|
||||
<div class="flex flex-row items-center justify-center gap-1">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-lg preset-tonal-primary border border-primary-500 hover:preset-tonal-primary text-2xl font-bold w-48 transition-all"
|
||||
disabled={searching}
|
||||
>
|
||||
{#if searching}
|
||||
<LoaderCircle class="animate-spin mx-1" size="1.2em" />
|
||||
{:else}
|
||||
<Search class="mx-1" size="1.2em" />
|
||||
{/if}
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{#if results.length > 0}
|
||||
|
||||
@@ -14,7 +14,13 @@
|
||||
|
||||
let { exhibit_id }: Props = $props();
|
||||
|
||||
let mode = $state('qr'); // 'qr' or 'search'
|
||||
// Use store for persistence (Stickiness)
|
||||
let mode = $derived($events_loc.leads.tab_add_mode?.[exhibit_id] ?? 'qr');
|
||||
|
||||
function set_mode(new_mode: string) {
|
||||
if (!$events_loc.leads.tab_add_mode) $events_loc.leads.tab_add_mode = {};
|
||||
$events_loc.leads.tab_add_mode[exhibit_id] = new_mode;
|
||||
}
|
||||
|
||||
function handle_lead_added(badge: any) {
|
||||
console.log('Lead successfully added:', badge.full_name);
|
||||
@@ -30,7 +36,7 @@
|
||||
type="button"
|
||||
class="flex-1 btn btn-sm py-3 flex items-center justify-center gap-2 rounded-lg transition-all duration-200"
|
||||
class:preset-filled-primary={mode === 'qr'}
|
||||
onclick={() => mode = 'qr'}
|
||||
onclick={() => set_mode('qr')}
|
||||
>
|
||||
<QrCode size="1.2em" />
|
||||
<span class="font-bold">Scan QR</span>
|
||||
@@ -39,7 +45,7 @@
|
||||
type="button"
|
||||
class="flex-1 btn btn-sm py-3 flex items-center justify-center gap-2 rounded-lg transition-all duration-200"
|
||||
class:preset-filled-primary={mode === 'search'}
|
||||
onclick={() => mode = 'search'}
|
||||
onclick={() => set_mode('search')}
|
||||
>
|
||||
<Search size="1.2em" />
|
||||
<span class="font-bold">Search</span>
|
||||
|
||||
Reference in New Issue
Block a user