diff --git a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_manual_search.svelte b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_manual_search.svelte index 66239994..ddf4452d 100644 --- a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_manual_search.svelte +++ b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_manual_search.svelte @@ -4,10 +4,12 @@ * Manual Attendee Search for adding leads. */ import { page } from '$app/state'; + import { liveQuery } from 'dexie'; + import { db_events } from '$lib/ae_events/db_events'; import { ae_api } from '$lib/stores/ae_stores'; import { events_loc } from '$lib/stores/ae_events_stores'; import { events_func } from '$lib/ae_events_functions'; - import { Search, UserPlus, CheckCircle, LoaderCircle } from 'lucide-svelte'; + import { Search, UserPlus, CheckCircle, LoaderCircle, Eye } from 'lucide-svelte'; import type { ae_EventBadge } from '$lib/types/ae_types'; import { ae_util } from '$lib/ae_utils/ae_utils'; @@ -18,6 +20,24 @@ let { exhibit_id, on_lead_added }: Props = $props(); + // Track existing leads to prevent duplicates in UI + let existing_leads_map = $derived( + liveQuery(async () => { + const leads = await db_events.exhibit_tracking + .where('event_exhibit_id') + .equals(exhibit_id) + .toArray(); + + // Map badge_id -> tracking_id + const map = new Map(); + leads.forEach(l => { + const b_id = l.event_badge_id_random || l.event_badge_id?.toString(); + if (b_id) map.set(b_id, l.event_exhibit_tracking_id_random || l.event_exhibit_tracking_id?.toString()); + }); + return map; + }) + ); + let search_query = $state(''); let results: ae_EventBadge[] = $state([]); let searching = $state(false); @@ -105,19 +125,30 @@
{badge.full_name}
{badge.affiliations || badge.email || ''}
- + + {#if $existing_leads_map?.has(badge.event_badge_id_random)} + + + View + + {:else} + + {/if} {/each} diff --git a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte index e0f72040..9ae57d2d 100644 --- a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte +++ b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte @@ -4,12 +4,14 @@ * Badge QR Scanner for adding leads. */ import { page } from '$app/state'; + import { liveQuery } from 'dexie'; + import { db_events } from '$lib/ae_events/db_events'; import { ae_api } from '$lib/stores/ae_stores'; import { events_loc } from '$lib/stores/ae_events_stores'; import { events_func } from '$lib/ae_events_functions'; import Element_qr_scanner_v2 from '$lib/element_qr_scanner_v2.svelte'; import { ae_util } from '$lib/ae_utils/ae_utils'; - import { LoaderCircle, UserPlus, CheckCircle, AlertCircle } from 'lucide-svelte'; + import { LoaderCircle, UserPlus, CheckCircle, AlertCircle, Eye } from 'lucide-svelte'; import type { ae_EventBadge } from '$lib/types/ae_types'; interface Props { @@ -19,9 +21,27 @@ let { exhibit_id, on_lead_added }: Props = $props(); + // Track existing leads to prevent duplicates + let existing_leads_map = $derived( + liveQuery(async () => { + const leads = await db_events.exhibit_tracking + .where('event_exhibit_id') + .equals(exhibit_id) + .toArray(); + + const map = new Map(); + leads.forEach(l => { + const b_id = l.event_badge_id_random || l.event_badge_id?.toString(); + if (b_id) map.set(b_id, l.event_exhibit_tracking_id_random || l.event_exhibit_tracking_id?.toString()); + }); + return map; + }) + ); + let start_qr_scanner = $state(true); - let scanning_status = $state('idle'); // idle, scanning, found, adding, success, error + let scanning_status = $state('idle'); // idle, scanning, found, adding, success, error, already_added let found_badge: ae_EventBadge | null = $state(null); + let existing_tracking_id = $state(''); let error_msg = $state(''); async function handle_qr_scan_result(event: CustomEvent) { @@ -29,9 +49,16 @@ const obj = ae_util.process_data_string(qr_result); if (obj && obj.type === 'event_badge' && obj.id) { - scanning_status = 'found'; start_qr_scanner = false; + // Check if already exists + if ($existing_leads_map?.has(obj.id)) { + scanning_status = 'already_added'; + existing_tracking_id = $existing_leads_map.get(obj.id); + } else { + scanning_status = 'found'; + } + // Load full badge info try { found_badge = await events_func.load_ae_obj_id__event_badge({ @@ -97,6 +124,32 @@

Point camera at the badge QR code

+ {:else if scanning_status === 'already_added'} +
+
+ +

Already Captured

+

{found_badge?.full_name || 'Attendee'}

+

This attendee is already in your leads list.

+
+ + + + View Lead Details + + + +
+ {:else if scanning_status === 'found' || scanning_status === 'adding'}