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';
|
$events_loc.leads.tracking__qry__sort_order = 'created_desc';
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Tab State ---
|
// --- Tab State (Sticky via Store) ---
|
||||||
let active_tab = $state('list'); // 'start', 'add', 'list', 'manage'
|
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'
|
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
|
function set_active_tab(new_tab: string) {
|
||||||
let is_signed_in = $state(true);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
let tracking_id_li: Array<string> = $state([]);
|
// Mock sign-in state for now
|
||||||
let search_debounce_timer: any = null;
|
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_search_id = 0;
|
||||||
let last_executed_key = '';
|
let last_executed_key = '';
|
||||||
let log_lvl = 1;
|
let log_lvl = 1;
|
||||||
@@ -257,28 +263,28 @@
|
|||||||
|
|
||||||
function toggle_main_tab() {
|
function toggle_main_tab() {
|
||||||
if (active_tab === 'add') {
|
if (active_tab === 'add') {
|
||||||
active_tab = 'list';
|
set_active_tab('list');
|
||||||
previous_main_tab = 'list';
|
previous_main_tab = 'list';
|
||||||
} else {
|
} else {
|
||||||
active_tab = 'add';
|
set_active_tab('add');
|
||||||
previous_main_tab = 'add';
|
previous_main_tab = 'add';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle_manage_tab() {
|
function toggle_manage_tab() {
|
||||||
if (active_tab === 'manage') {
|
if (active_tab === 'manage') {
|
||||||
active_tab = previous_main_tab;
|
set_active_tab(previous_main_tab);
|
||||||
} else {
|
} else {
|
||||||
active_tab = 'manage';
|
set_active_tab('manage');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section
|
<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 -->
|
||||||
<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">
|
<div class="flex flex-col min-w-0">
|
||||||
<h1 class="text-base sm:text-lg font-bold truncate leading-tight">
|
<h1 class="text-base sm:text-lg font-bold truncate leading-tight">
|
||||||
{$lq__exhibit_obj?.name ?? 'Exhibitor'}
|
{$lq__exhibit_obj?.name ?? 'Exhibitor'}
|
||||||
|
|||||||
@@ -68,24 +68,32 @@
|
|||||||
|
|
||||||
<div class="lead-manual-search space-y-4 w-full">
|
<div class="lead-manual-search space-y-4 w-full">
|
||||||
<form
|
<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(); }}
|
onsubmit={(e) => { e.preventDefault(); handle_search(); }}
|
||||||
>
|
>
|
||||||
<div class="relative grow">
|
<div class="flex flex-col md:flex-row items-center justify-center gap-1 grow">
|
||||||
<Search class="absolute left-3 top-1/2 -translate-y-1/2 opacity-50" size="1.2em" />
|
|
||||||
<input
|
<input
|
||||||
type="search"
|
type="search"
|
||||||
bind:value={search_query}
|
bind:value={search_query}
|
||||||
placeholder="Name, email, or badge ID..."
|
placeholder="Attendee name, email, or badge ID..."
|
||||||
class="input pl-10 w-full"
|
class="input text-lg font-mono grow transition-all w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn preset-filled-primary" disabled={searching}>
|
|
||||||
{#if searching}
|
<div class="flex flex-row items-center justify-center gap-1">
|
||||||
<LoaderCircle class="animate-spin mr-2" size="1.2em" />
|
<button
|
||||||
{/if}
|
type="submit"
|
||||||
Search
|
class="btn btn-lg preset-tonal-primary border border-primary-500 hover:preset-tonal-primary text-2xl font-bold w-48 transition-all"
|
||||||
</button>
|
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>
|
</form>
|
||||||
|
|
||||||
{#if results.length > 0}
|
{#if results.length > 0}
|
||||||
|
|||||||
@@ -14,7 +14,13 @@
|
|||||||
|
|
||||||
let { exhibit_id }: Props = $props();
|
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) {
|
function handle_lead_added(badge: any) {
|
||||||
console.log('Lead successfully added:', badge.full_name);
|
console.log('Lead successfully added:', badge.full_name);
|
||||||
@@ -30,7 +36,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="flex-1 btn btn-sm py-3 flex items-center justify-center gap-2 rounded-lg transition-all duration-200"
|
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'}
|
class:preset-filled-primary={mode === 'qr'}
|
||||||
onclick={() => mode = 'qr'}
|
onclick={() => set_mode('qr')}
|
||||||
>
|
>
|
||||||
<QrCode size="1.2em" />
|
<QrCode size="1.2em" />
|
||||||
<span class="font-bold">Scan QR</span>
|
<span class="font-bold">Scan QR</span>
|
||||||
@@ -39,7 +45,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
class="flex-1 btn btn-sm py-3 flex items-center justify-center gap-2 rounded-lg transition-all duration-200"
|
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'}
|
class:preset-filled-primary={mode === 'search'}
|
||||||
onclick={() => mode = 'search'}
|
onclick={() => set_mode('search')}
|
||||||
>
|
>
|
||||||
<Search size="1.2em" />
|
<Search size="1.2em" />
|
||||||
<span class="font-bold">Search</span>
|
<span class="font-bold">Search</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user