From 111ef76d1485dec4a689a58d6f213a32632fff6c Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Sun, 8 Feb 2026 23:03:35 -0500 Subject: [PATCH] Fix Lead List filtering and resolve Svelte 5 subscription crash - Refactored Lead List to use direct observable subscription for better reactivity. - Implemented in-memory 'Hard Guard' filter to ensure licensee selection is strictly enforced. - Fixed 'TypeError: s.subscribe is not a function' by removing legacy $ prefix from resolved props. - Resolved TypeScript typing errors in Lead Detail and Search components. - Migrated Badge Search icons to Lucide. --- .../ae_events/ae_events__exhibit_tracking.ts | 6 +- .../badges/ae_comp__badge_search.svelte | 12 ++-- .../leads/exhibit/[exhibit_id]/+page.svelte | 60 ++++++++++++++----- .../ae_comp__exhibit_tracking_obj_li.svelte | 8 +-- .../lead/[exhibit_tracking_id]/+page.svelte | 6 +- 5 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/lib/ae_events/ae_events__exhibit_tracking.ts b/src/lib/ae_events/ae_events__exhibit_tracking.ts index 54d1d818..07b71cab 100644 --- a/src/lib/ae_events/ae_events__exhibit_tracking.ts +++ b/src/lib/ae_events/ae_events__exhibit_tracking.ts @@ -442,8 +442,8 @@ export async function search__exhibit_tracking({ log_lvl = 0 }: { api_cfg: any; - event_id: string; - event_exhibit_id: string; + event_id: string | undefined; + event_exhibit_id: string | undefined; fulltext_search_qry_str?: string | null; qry_group?: string | null; qry_external_person_id?: string | null; @@ -460,6 +460,8 @@ export async function search__exhibit_tracking({ console.log(`*** search__exhibit_tracking() *** exhibit_id=${event_exhibit_id} ft=${fulltext_search_qry_str}`); } + if (!event_id || !event_exhibit_id) return []; + const search_query: any = { q: fulltext_search_qry_str || '', and: [ diff --git a/src/routes/events/[event_id]/(badges)/badges/ae_comp__badge_search.svelte b/src/routes/events/[event_id]/(badges)/badges/ae_comp__badge_search.svelte index ddf4a1f6..fbd03742 100644 --- a/src/routes/events/[event_id]/(badges)/badges/ae_comp__badge_search.svelte +++ b/src/routes/events/[event_id]/(badges)/badges/ae_comp__badge_search.svelte @@ -171,9 +171,9 @@ class="btn btn-lg preset-tonal-success border border-success-500 hover:preset-tonal-success text-2xl font-bold w-48 transition-all" > {#if $events_sess.badges.search_status === 'loading'} - + {:else} - + {/if} Search @@ -222,7 +222,7 @@ }} class="btn btn-sm preset-tonal-primary border border-primary-500" > - + QR Scan {:else} @@ -235,7 +235,7 @@ }} class="btn btn-sm preset-tonal-primary border border-primary-500" > - + Search {/if} @@ -250,9 +250,9 @@ title="Toggle using the ID list or not." > {#if $events_loc.badges.use_id_li} - + {:else} - + {/if} Use ID List diff --git a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/+page.svelte b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/+page.svelte index f1b0c9f2..c344c778 100644 --- a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/+page.svelte +++ b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/+page.svelte @@ -71,23 +71,43 @@ $events_loc.leads.tab[exhibit_id] = new_tab; } - let tracking_id_li: Array = $state([]); let search_debounce_timer: any = null; + let tracking_id_li: Array = $state([]); + let search_debounce_timer: any = null; let last_search_id = 0; let last_executed_key = ''; let log_lvl = 1; - // Stable LiveQuery Pattern - let lq__event_exhibit_tracking_obj_li = $derived.by(() => { + // --- NEW: Direct Reactive List Pattern --- + let raw_lead_li: any[] = $state([]); + + // Final filtered list that the UI actually sees + // Applying the HARD GUARD here ensures that no matter where the data came from + // (API or IDB), it MUST match the selected licensee. + let filtered_lead_li = $derived.by(() => { + const licensee_filter = search_params.licensee_email; + if (licensee_filter === 'all') return raw_lead_li; + + return raw_lead_li.filter(lead => { + const capturer = lead.external_person_id || lead.group; + return capturer === licensee_filter; + }); + }); + + // Subscribe to the Lead List + $effect(() => { const ids = tracking_id_li; const exhibit_id = page.params.exhibit_id; + const has_search = !!$events_loc.leads.tracking__qry__search_text; - return liveQuery(async () => { + const observable = liveQuery(async () => { + // 1. Specific IDs provided (from API Search or Manual Entry) if (Array.isArray(ids) && ids.length > 0) { const results = await db_events.exhibit_tracking.bulkGet(ids); return results.filter((item) => item !== undefined); } - if (exhibit_id && !$events_loc.leads.tracking__qry__search_text) { + // 2. Fallback broad search (Initial load or no search text) + if (exhibit_id && !has_search) { return await db_events.exhibit_tracking .where('event_exhibit_id') .equals(exhibit_id) @@ -97,10 +117,16 @@ return []; }); + + const subscription = observable.subscribe(res => { + raw_lead_li = res; + }); + + return () => subscription.unsubscribe(); }); // Exhibit Info - let lq__exhibit_obj = liveQuery(() => { + const lq__exhibit_obj = liveQuery(() => { const exhibit_id = page.params.exhibit_id; if (!exhibit_id) return undefined; return db_events.exhibit.get(exhibit_id); @@ -183,16 +209,18 @@ // 1. FAST PATH: Local IDB Search if (!remote_first) { try { + const target_exhibit_id = exhibit_id; + const target_licensee_email = params.licensee_email; + let local_results = await db_events.exhibit_tracking .where('event_exhibit_id') - .equals(exhibit_id) + .equals(target_exhibit_id) .filter((tracking) => { // 1. Licensee Email Filter - if (params.licensee_email !== 'all') { - if (tracking.external_person_id !== params.licensee_email) return false; + if (target_licensee_email !== 'all') { + if (tracking.external_person_id !== target_licensee_email) return false; } - // 2. Text Search Filter if (qry_str) { const name = ( tracking.event_badge_full_name ?? '' @@ -284,12 +312,16 @@ order_by_li = { created_on: 'DESC' }; } + const q_event_id: string = page.params.event_id ?? ''; + const q_exhibit_id: string = exhibit_id ?? ''; + const q_licensee_email: string | null = (params.licensee_email !== 'all') ? (params.licensee_email ?? '') : null; + const results = await events_func.search__exhibit_tracking({ api_cfg: $ae_api, - event_id: page.params.event_id || '', - event_exhibit_id: exhibit_id, + event_id: q_event_id, + event_exhibit_id: q_exhibit_id, fulltext_search_qry_str: qry_str || null, - qry_external_person_id: params.licensee_email !== 'all' ? params.licensee_email : null, + qry_external_person_id: q_licensee_email, order_by_li, limit: 150 }); @@ -463,7 +495,7 @@

Searching leads...

{:else} - + {/if} {:else if active_tab === 'manage'} diff --git a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_tracking_obj_li.svelte b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_tracking_obj_li.svelte index dae311d7..35e6a90b 100644 --- a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_tracking_obj_li.svelte +++ b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_tracking_obj_li.svelte @@ -25,11 +25,11 @@
- {#if !$lq__event_exhibit_tracking_obj_li} + {#if !lq__event_exhibit_tracking_obj_li}
- {:else if $lq__event_exhibit_tracking_obj_li.length === 0} + {:else if lq__event_exhibit_tracking_obj_li.length === 0}

No leads found yet.

@@ -40,12 +40,12 @@

- {$lq__event_exhibit_tracking_obj_li.length} Leads Collected + {lq__event_exhibit_tracking_obj_li.length} Leads Collected
- {#each $lq__event_exhibit_tracking_obj_li as event_tracking_obj} + {#each lq__event_exhibit_tracking_obj_li as event_tracking_obj}