refactor(leads): modularize exhibitor leads logic and stub v3 UI

This commit is contained in:
Scott Idem
2026-02-07 16:43:33 -05:00
parent f8f65139a7
commit 699a1dd584
21 changed files with 813 additions and 408 deletions

View File

@@ -48,11 +48,11 @@ Represents a single lead captured by an exhibitor. It links an exhibitor to an a
- `/events/[event_id]/(leads)`: The main entry point for the Leads module within a specific event, typically displays a list of available exhibits.
- `+page.svelte`: Renders the list of exhibits.
- `+page.ts`: Loads the data for available exhibits using `events_func.handle_load_ae_obj_li__exhibit`.
- `+page.ts`: Loads the data for available exhibits using `events_func.load_ae_obj_li__exhibit`.
- `+layout.svelte`/`+layout.ts`: Provides a common layout and data for the module, including a submenu.
- `/events/[event_id]/(leads)/exhibit/[slug]`: Dynamic route for managing leads for a specific exhibitor within an event. The `[slug]` corresponds to `event_exhibit_id`.
- `+page.svelte`: The primary interface for an exhibitor, orchestrating lead capture and management components.
- `+page.ts`: Loads specific `Exhibit` data and associated `Exhibit_tracking` (leads) using `events_func.handle_load_ae_obj_id__exhibit` and `events_func.handle_load_ae_obj_li__exhibit_tracking`.
- `+page.ts`: Loads specific `Exhibit` data and associated `Exhibit_tracking` (leads) using `events_func.load_ae_obj_id__exhibit` and `events_func.load_ae_obj_li__exhibit_tracking`.
### Core Components (within `src/routes/events/[event_id]/(leads)/exhibit/[slug]/`)

View File

@@ -0,0 +1,25 @@
/**
* src/routes/events/[event_id]/(leads)/leads/+layout.ts
* Leads Module Level Layout Loader.
*/
import { browser } from '$app/environment';
import { events_func } from '$lib/ae_events_functions';
export async function load({ params, parent }) {
const parent_data = await parent();
const account_id = parent_data.account_id;
const ae_acct = parent_data[account_id];
const event_id = params.event_id;
if (browser) {
events_func.load_ae_obj_id__event({
api_cfg: ae_acct.api,
event_id: event_id,
log_lvl: 0
});
}
return {
...parent_data
};
}

View File

@@ -0,0 +1,25 @@
/**
* src/routes/events/[event_id]/(leads)/leads/+page.ts
* Exhibit Finder Page Loader.
*/
import { browser } from '$app/environment';
import { events_func } from '$lib/ae_events_functions';
export async function load({ params, parent }) {
const parent_data = await parent();
const account_id = parent_data.account_id;
const ae_acct = parent_data[account_id];
const event_id = params.event_id;
if (browser && event_id) {
events_func.load_ae_obj_li__exhibit({
api_cfg: ae_acct.api,
for_obj_type: 'event',
for_obj_id: event_id,
limit: 100,
log_lvl: 0
});
}
return {};
}

View File

@@ -0,0 +1,26 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/+layout.svelte
* Exhibitor Dashboard Layout.
*/
interface Props {
children?: import('svelte').Snippet;
}
let { children }: Props = $props();
import { events_slct } from '$lib/stores/ae_events_stores';
import { liveQuery } from 'dexie';
import { db_events } from '$lib/ae_events/db_events';
let lq__exhibit_obj = $derived(
liveQuery(async () => {
if (!$events_slct.exhibit_id) return null;
return await db_events.exhibit.get($events_slct.exhibit_id);
})
);
</script>
<div class="exhibit-layout flex flex-col h-full w-full">
{@render children?.()}
</div>

View File

@@ -0,0 +1,38 @@
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/+layout.ts
* Exhibitor Dashboard Loader.
*/
import { browser } from '$app/environment';
import { events_func } from '$lib/ae_events_functions';
import { events_slct } from '$lib/stores/ae_events_stores';
export async function load({ params, parent }) {
const parent_data = await parent();
const account_id = parent_data.account_id;
const ae_acct = parent_data[account_id];
const exhibit_id = params.exhibit_id;
// Sync to store for components
events_slct.update(s => {
s.exhibit_id = exhibit_id;
return s;
});
if (browser && exhibit_id) {
events_func.load_ae_obj_id__exhibit({
api_cfg: ae_acct.api,
exhibit_id: exhibit_id,
log_lvl: 0
});
events_func.load_ae_obj_li__exhibit_tracking({
api_cfg: ae_acct.api,
for_obj_type: 'event_exhibit',
for_obj_id: exhibit_id,
limit: 250,
log_lvl: 0
});
}
return {};
}

View File

@@ -228,7 +228,7 @@
const exhibit_id = page.params.exhibit_id;
if (!exhibit_id) return;
await events_func.handle_download_export__event_exhibit_tracking({
await events_func.download_export__event_exhibit_tracking({
api_cfg: $ae_api,
exhibit_id: exhibit_id,
log_lvl: 1

View File

@@ -0,0 +1,11 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_license_list.svelte
* Exhibitor License Management Stub.
*/
</script>
<div class="exhibit-license-list p-4 card">
<h3 class="h3">Staff Licenses</h3>
<p>Placeholder for license assignment logic.</p>
</div>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_payment.svelte
* Leads Payment Stub.
*/
</script>
<div class="exhibit-payment p-4 card">
<h3 class="h3">Payment & Licensing</h3>
<p>Placeholder for Stripe integration.</p>
</div>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__exhibit_signin.svelte
* Exhibitor Login Form Stub.
*/
</script>
<div class="exhibit-signin p-4 card">
<h3 class="h3">Exhibitor Sign In</h3>
<p>Placeholder for login logic.</p>
</div>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_manual_search.svelte
* Manual Attendee Search Stub.
*/
</script>
<div class="lead-manual-search p-4 card">
<h3 class="h3">Manual Search</h3>
<p>Placeholder for attendee lookup.</p>
</div>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte
* Badge QR Scanner Stub.
*/
</script>
<div class="lead-qr-scanner p-4 card">
<h3 class="h3">Scan Badge</h3>
<p>Placeholder for QR scanner component.</p>
</div>

View File

@@ -0,0 +1,18 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__add.svelte
* Tab 2: Add - Search / QR Scan Stub.
*/
import Comp_lead_qr_scanner from './ae_comp__lead_qr_scanner.svelte';
import Comp_lead_manual_search from './ae_comp__lead_manual_search.svelte';
let show_qr = $state(true);
</script>
<div class="ae-tab-add p-4 space-y-4">
<div class="flex gap-2">
<button type="button" class="btn btn-sm" onclick={() => show_qr = true}>QR</button>
<button type="button" class="btn btn-sm" onclick={() => show_qr = false}>Search</button>
</div>
{#if show_qr} <Comp_lead_qr_scanner /> {:else} <Comp_lead_manual_search /> {/if}
</div>

View File

@@ -0,0 +1,17 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__list.svelte
* Tab 3: Leads List Stub.
*/
import Comp_exhibit_tracking_obj_li from './ae_comp__exhibit_tracking_obj_li.svelte';
interface Props {
lq__event_exhibit_tracking_obj_li: any;
}
let { lq__event_exhibit_tracking_obj_li }: Props = $props();
</script>
<div class="ae-tab-list p-4 space-y-4">
<h3 class="h3">Captured Leads</h3>
<Comp_exhibit_tracking_obj_li {lq__event_exhibit_tracking_obj_li} />
</div>

View File

@@ -0,0 +1,25 @@
/**
* src/routes/events/[event_id]/(leads)/leads/lead/[exhibit_tracking_id]/+page.ts
* Lead Detail Page Loader.
* Responsible for loading a single exhibit tracking record and its associated badge data.
*/
import { browser } from '$app/environment';
import { events_func } from '$lib/ae_events_functions';
export async function load({ params, parent }) {
const parent_data = await parent();
const account_id = parent_data.account_id;
const ae_acct = parent_data[account_id];
const exhibit_tracking_id = params.exhibit_tracking_id;
if (browser && exhibit_tracking_id) {
// Refresh the specific Lead (Tracking) object
events_func.load_ae_obj_id__exhibit_tracking({
api_cfg: ae_acct.api,
exhibit_tracking_id: exhibit_tracking_id,
log_lvl: 0
});
}
return {};
}

View File

@@ -0,0 +1,11 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/lead/[exhibit_tracking_id]/ae_comp__lead_detail_form.svelte
* Lead Detail Form Stub.
*/
</script>
<div class="lead-detail-form p-4 card">
<h3 class="h3">Lead Details</h3>
<p>Placeholder for qualifiers and notes.</p>
</div>