feat(leads): stabilize v3 layout and unify tab width logic

- Removed max-width constraints across leads modules for full-width stability.
- Fixed duplicate Download icon import causing build errors.
- Improved header responsiveness for mobile-first experience.
- Refined tab switching logic with state persistence placeholders.
This commit is contained in:
Scott Idem
2026-02-07 18:00:12 -05:00
parent 699a1dd584
commit f4a34e4ad7
14 changed files with 506 additions and 145 deletions

View File

@@ -102,7 +102,7 @@ License:
## [tab 4] Manage / Config
### Exhibit Specific
* Priorty/payment toggle - Administrator Access or above
* Priority/payment toggle - Administrator Access or above
* Max licenses (number) - readonly or edit for Administrator Access or above
* Small devices (number) - readonly or edit for Administrator Access or above
* Large devices (number) - readonly or edit for Administrator Access or above

View File

@@ -78,27 +78,76 @@ I am probably using the term "tab" loosely here. It may just be sections that sh
* Button to trigger QR scan (opens camera and scans QR code on badge)
* Button to "Add as Lead" if Attendee Badge found and not already a Lead
* Button to "View Lead" if Attendee Badge found and already a Lead
Functions needed:
* Search function to find Attendee Badge by Badge ID, QR code, name, email, or affiliations.
* QR code scan function to read QR code and find Attendee Badge.
* Add Lead function to create Exhibit_tracking entry linking Exhibit and Attendee Badge.
### [tab 3] Leads - List of Attendee Leads for Exhibitor
* Allow for toggle between showing all per Exhibit and per licensed user based on their email address. Not perfect, but works well enough.
* Allow for easy edit or remove
* Sections:
* List of Leads with basic info and buttons to Edit or Remove
* Options:
* Filter by Licensed user email address (dropdown of emails that have added leads for this Exhibit)
* Toggle for show/hide Hidden records
* Select options for sorting: Newest added first, Oldest added first, Alpha ascending, Alpha descending, Last updated first
* Buttons and Inputs:
* Button to Export Data - CSV or XLSX
* Toggle for show/hide Hidden records
* Select options for sorting: Newest added first, Oldest added first, Alpha ascending, Alpha descending, Last updated first
* Should it have a text search?
* NOTE: It is probably easiest for them to us the search tab to find a lead that has already been added. It will show "View Lead" button if already added.
Functions needed:
* Load Leads function to get Exhibit_tracking entries for the Exhibit.
* Filter function to filter by Licensed user email address.
* Sort function to sort by selected option.
* Export function to export displayed Leads to CSV or XLSX.
### [tab 4] Manage - Leads (app and exhibit) Manage
* Show list of Leads added for this Exhibit.
* Allow for easy edit or remove
* Allow for sorting: Newest added first, Oldest added first, Alpha ascending, Alpha descending, Last updated first
* Allow for toggle for show/hide Hidden records
* Allow for filtering by Licensed user email address
### [tab 4] Manage - Leads (app and exhibit) Manage / Config
#### Exhibit Specific
* Priority/payment toggle - Administrator Access or above
* Max licenses (number) - readonly or edit for Administrator Access or above
* Small devices (number) - readonly or edit for Administrator Access or above
* Large devices (number) - readonly or edit for Administrator Access or above
* Exhibit (shared) Passcode
* Same Exhibit Leads License list component as the Start tab's Licensed Users section
#### App Specific
* Show/Hide Payment Tab
* Additional Settings:
* List refresh interval in seconds - default 25 seconds; 1 second to 2 minutes (120000)
* Basic reload/refresh
* Clear Indexed DB
* Clear localStorage
* Auto hide header/footer on sign in - default true
* (?) Turn on iframe mode
* (?) Show or hide additional details - Use "$events_loc.show_details"?
* Sections:
* Exhibit Specific Manage/Config
* App Specific Manage/Config
* Buttons and Inputs:
* Button to Export Data - CSV or XLSX
* Toggle for show/hide Hidden records
* Select options for sorting: Newest added first, Oldest added first, Alpha ascending, Alpha descending, Last updated first
* Filter by Licensed user email address (dropdown of emails that have added leads for this Exhibit)
* Exhibit Specific:
* Priority/payment toggle - Administrator Access or above
* Max licenses (number) - readonly or edit for Administrator Access or above
* Small devices (number) - readonly or edit for Administrator Access or above
* Large devices (number) - readonly or edit for Administrator Access or above
* Exhibit (shared) Passcode
* Same Exhibit Leads License list component as the Start tab's Licensed Users section
* App Specific:
* Show/Hide Payment Tab
* Show last refresh time and counter for next refresh based on the List refresh interval setting.
* Additional Settings:
* List refresh interval in seconds - default 25 seconds; 1 second to 2 minutes (120000)
* Basic reload/refresh (F5)
* Clear Indexed DB
* Clear localStorage
* Auto hide header/footer on sign in - default true
* (?) Turn on iframe mode
* (?) Show or hide additional details - Use "$events_loc.show_details"?
* Functions:
* Update Exhibit configuration function to update the Exhibit with the new settings.
* Update App configuration function to update the app-wide settings for the Leads module.

View File

@@ -7,6 +7,6 @@
// Basic layout for the leads module
</script>
<div class="leads-module">
<!-- <div class="leads-module"> -->
{@render children?.()}
</div>
<!-- </div> -->

View File

@@ -14,8 +14,7 @@ export async function load({ params, parent }) {
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,
event_id: event_id,
limit: 100,
log_lvl: 0
});

View File

@@ -21,6 +21,6 @@
);
</script>
<div class="exhibit-layout flex flex-col h-full w-full">
<!-- <div class="exhibit-layout flex flex-col h-full w-full"> -->
{@render children?.()}
</div>
<!-- </div> -->

View File

@@ -27,8 +27,7 @@ export async function load({ params, parent }) {
events_func.load_ae_obj_li__exhibit_tracking({
api_cfg: ae_acct.api,
for_obj_type: 'event_exhibit',
for_obj_id: exhibit_id,
exhibit_id: exhibit_id,
limit: 250,
log_lvl: 0
});

View File

@@ -10,9 +10,22 @@
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
import { page } from '$app/state';
import { events_func } from '$lib/ae_events_functions';
import { LoaderCircle, UserPlus, Download } from 'lucide-svelte';
import {
LoaderCircle,
UserPlus,
Download,
Settings,
Plus,
List as ListIcon,
LogIn,
LayoutGrid,
Search
} from 'lucide-svelte';
import Comp_exhibit_tracking_search from './ae_comp__exhibit_tracking_search.svelte';
import Comp_exhibit_tracking_obj_li from './ae_comp__exhibit_tracking_obj_li.svelte';
import Tab_add from './ae_tab__add.svelte';
import Tab_start from './ae_tab__start.svelte';
import Tab_manage from './ae_tab__manage.svelte';
// *** Initialization & Store Guard ***
if ($events_loc.leads) {
@@ -28,6 +41,13 @@
$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;
let last_search_id = 0;
@@ -234,47 +254,110 @@
log_lvl: 1
});
}
function toggle_main_tab() {
if (active_tab === 'add') {
active_tab = 'list';
previous_main_tab = 'list';
} else {
active_tab = 'add';
previous_main_tab = 'add';
}
}
function toggle_manage_tab() {
if (active_tab === 'manage') {
active_tab = previous_main_tab;
} else {
active_tab = 'manage';
}
}
</script>
<section
class="ae_events_leads_tracking_new h-full w-full flex flex-col items-center space-y-4 p-4"
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"
>
<div
class="w-full max-w-6xl flex flex-col md:flex-row justify-between items-center gap-4"
>
<div class="text-center md:text-left">
<h1 class="h2">
Leads for {$lq__exhibit_obj?.name ?? 'Exhibitor'}
<!-- 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">
<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'}
</h1>
<p class="opacity-50">Booth #{$lq__exhibit_obj?.code ?? '...'}</p>
<p class="text-[10px] sm:text-xs opacity-60">Booth #{$lq__exhibit_obj?.code ?? '...'}</p>
</div>
<div class="flex gap-2">
<div class="flex items-center gap-1 sm:gap-2">
<!-- Add Lead / Lead List Toggle -->
<button
type="button"
class="btn preset-tonal-secondary"
onclick={handle_export}
class="btn btn-sm variant-filled-primary font-bold shadow-sm px-2 sm:px-4"
onclick={toggle_main_tab}
>
<Download size="1.25em" class="mr-2" /> Export CSV
{#if active_tab === 'add'}
<ListIcon size="1.25em" class="sm:mr-2" />
<span class="hidden sm:inline">Lead List</span>
{:else}
<Plus size="1.25em" class="sm:mr-2" />
<span class="hidden sm:inline">Add Lead</span>
{/if}
</button>
<a
href={`/events/${page.params.event_id}/leads/exhibit/${page.params.exhibit_id}/scan`}
class="btn preset-filled-primary"
<!-- Manage / Config -->
<button
type="button"
class="btn btn-sm transition-colors px-2 sm:px-3"
class:variant-filled-surface={active_tab === 'manage'}
class:variant-ghost-surface={active_tab !== 'manage'}
onclick={toggle_manage_tab}
title="Manage Exhibit"
>
<UserPlus size="1.25em" class="mr-2" /> Add Lead
</a>
<Settings size="1.25em" />
</button>
</div>
</header>
<!-- Main Content Area - Stable Width -->
<div class="w-full flex-1 flex flex-col items-center">
<div class="w-full px-4 sm:px-6 py-6 space-y-6">
{#if !is_signed_in}
<div class="w-full max-w-4xl mx-auto">
<Tab_start />
</div>
{:else if active_tab === 'add'}
<Tab_add exhibit_id={page.params.exhibit_id ?? ''} />
{:else if active_tab === 'list'}
<div class="w-full flex flex-col space-y-6">
<div class="flex justify-between items-center px-2">
<h2 class="text-xl sm:text-2xl font-bold">Lead List</h2>
<button
type="button"
class="btn btn-sm variant-ghost-secondary"
onclick={handle_export}
>
<Download size="1.2em" class="mr-2" /> Export
</button>
</div>
<Comp_exhibit_tracking_search exhibit_id={page.params.exhibit_id ?? ''} />
{#if $events_sess.leads.submit_status__search === 'searching' && tracking_id_li.length === 0}
<div
class="flex flex-col items-center justify-center p-10 opacity-50 text-center w-full"
>
<LoaderCircle size="3em" class="animate-spin mb-4 mx-auto" />
<p class="text-xl">Searching leads...</p>
</div>
{:else}
<Comp_exhibit_tracking_obj_li {lq__event_exhibit_tracking_obj_li} />
{/if}
</div>
{:else if active_tab === 'manage'}
<div class="w-full max-w-4xl mx-auto">
<Tab_manage />
</div>
{/if}
</div>
</div>
<Comp_exhibit_tracking_search exhibit_id={page.params.exhibit_id ?? ''} />
{#if $events_sess.leads.submit_status__search === 'searching' && tracking_id_li.length === 0}
<div
class="flex flex-col items-center justify-center p-10 opacity-50 text-center"
>
<LoaderCircle size="3em" class="animate-spin mb-4 mx-auto" />
<p class="text-xl">Searching leads...</p>
</div>
{:else}
<Comp_exhibit_tracking_obj_li {lq__event_exhibit_tracking_obj_li} />
{/if}
</section>

View File

@@ -24,7 +24,7 @@
}
</script>
<div class="ae_comp__exhibit_tracking_obj_li w-full max-w-6xl mx-auto px-4">
<div class="ae_comp__exhibit_tracking_obj_li w-full px-2 sm:px-4">
{#if !$lq__event_exhibit_tracking_obj_li}
<div class="flex justify-center p-10">
<span class="fas fa-spinner fa-spin fa-2x opacity-20"></span>

View File

@@ -40,7 +40,7 @@
handle_search_trigger();
})}
autocomplete="off"
class="search_form flex flex-row flex-wrap gap-1 items-center justify-center w-full max-w-7xl px-2 md:px-12 py-2 preset-tonal-primary rounded-lg shadow-sm"
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"
>
<div
class="flex flex-col md:flex-row items-center justify-center gap-1 grow"

View File

@@ -1,11 +1,118 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_manual_search.svelte
* Manual Attendee Search Stub.
* Manual Attendee Search for adding leads.
*/
import { page } from '$app/state';
import { ae_api } from '$lib/stores/ae_stores';
import { events_func } from '$lib/ae_events_functions';
import { Search, UserPlus, CheckCircle, LoaderCircle } from 'lucide-svelte';
import type { ae_EventBadge } from '$lib/types/ae_types';
import { ae_util } from '$lib/ae_utils/ae_utils';
interface Props {
exhibit_id: string;
on_lead_added?: (badge: ae_EventBadge) => void;
}
let { exhibit_id, on_lead_added }: Props = $props();
let search_query = $state('');
let results: ae_EventBadge[] = $state([]);
let searching = $state(false);
let adding_id = $state('');
async function handle_search() {
if (!search_query.trim()) return;
searching = true;
try {
const search_results = await events_func.search__event_badge({
api_cfg: $ae_api,
event_id: page.params.event_id || '',
fulltext_search_qry_str: search_query,
limit: 20
});
results = Array.isArray(search_results) ? search_results : [];
} catch (e) {
console.error('Badge search failed', e);
} finally {
searching = false;
}
}
async function add_as_lead(badge: ae_EventBadge) {
if (!badge.event_badge_id_random) return;
adding_id = badge.event_badge_id_random;
// TODO: Get the actual signed-in licensed user's email
const user_email = 'placeholder@exhibitor.com';
try {
const result = await events_func.create_ae_obj__exhibit_tracking({
api_cfg: $ae_api,
exhibit_id: exhibit_id,
event_badge_id: badge.event_badge_id_random,
external_person_id: user_email
});
if (result && on_lead_added) {
on_lead_added(badge);
}
} catch (e) {
console.error('Failed to add lead', e);
} finally {
adding_id = '';
}
}
</script>
<div class="lead-manual-search p-4 card">
<h3 class="h3">Manual Search</h3>
<p>Placeholder for attendee lookup.</p>
</div>
<div class="lead-manual-search space-y-4 w-full">
<form
class="flex gap-2"
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" />
<input
type="search"
bind:value={search_query}
placeholder="Name, email, or badge ID..."
class="input pl-10 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>
</form>
{#if results.length > 0}
<div class="results-list space-y-2 max-h-[50vh] overflow-y-auto pr-2">
{#each results as badge}
<div class="card p-3 flex justify-between items-center variant-soft shadow-sm">
<div>
<div class="font-bold">{badge.full_name}</div>
<div class="text-xs opacity-70">{badge.affiliations || badge.email || ''}</div>
</div>
<button
type="button"
class="btn btn-sm preset-filled-success"
disabled={adding_id === badge.event_badge_id_random}
onclick={() => add_as_lead(badge)}
>
{#if adding_id === badge.event_badge_id_random}
<LoaderCircle class="animate-spin" size="1em" />
{:else}
<UserPlus size="1em" class="mr-1" />
{/if}
Add
</button>
</div>
{/each}
</div>
{:else if !searching && search_query}
<p class="text-center opacity-50 py-4 italic">No attendees found matching "{search_query}"</p>
{/if}
</div>

View File

@@ -1,11 +1,147 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte
* Badge QR Scanner Stub.
* Badge QR Scanner for adding leads.
*/
import { page } from '$app/state';
import { ae_api } from '$lib/stores/ae_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 type { ae_EventBadge } from '$lib/types/ae_types';
interface Props {
exhibit_id: string;
on_lead_added?: (badge: ae_EventBadge) => void;
}
let { exhibit_id, on_lead_added }: Props = $props();
let start_qr_scanner = $state(true);
let scanning_status = $state('idle'); // idle, scanning, found, adding, success, error
let found_badge: ae_EventBadge | null = $state(null);
let error_msg = $state('');
async function handle_qr_scan_result(event: CustomEvent) {
const qr_result = event.detail.result;
const obj = ae_util.process_data_string(qr_result);
if (obj && obj.type === 'event_badge' && obj.id) {
scanning_status = 'found';
start_qr_scanner = false;
// Load full badge info
try {
found_badge = await events_func.load_ae_obj_id__event_badge({
api_cfg: $ae_api,
event_badge_id: obj.id,
log_lvl: 1
});
} catch (e) {
console.error('Failed to load badge info', e);
}
} else {
scanning_status = 'error';
error_msg = 'Invalid QR code. Please scan an Event Badge.';
}
}
async function confirm_add_lead() {
if (!found_badge || !found_badge.event_badge_id_random) return;
scanning_status = 'adding';
const user_email = 'placeholder@exhibitor.com';
try {
const result = await events_func.create_ae_obj__exhibit_tracking({
api_cfg: $ae_api,
exhibit_id: exhibit_id,
event_badge_id: found_badge.event_badge_id_random,
external_person_id: user_email
});
if (result) {
scanning_status = 'success';
if (on_lead_added) on_lead_added(found_badge);
// Auto-reset after 2 seconds to scan next
setTimeout(reset_scanner, 2000);
}
} catch (e) {
scanning_status = 'error';
error_msg = 'Failed to add lead. They might already be added.';
}
}
function reset_scanner() {
scanning_status = 'idle';
found_badge = null;
error_msg = '';
start_qr_scanner = true;
}
</script>
<div class="lead-qr-scanner p-4 card">
<h3 class="h3">Scan Badge</h3>
<p>Placeholder for QR scanner component.</p>
</div>
<div class="lead-qr-scanner flex flex-col items-center space-y-4 w-full min-h-[400px] justify-center">
{#if scanning_status === 'idle' || scanning_status === 'scanning'}
<div class="w-full max-w-sm mx-auto aspect-square overflow-hidden rounded-xl border-4 border-surface-500/20 shadow-xl relative bg-surface-900/10">
<Element_qr_scanner_v2
bind:start_qr_scanner
on:qr_scan_result={handle_qr_scan_result}
/>
<div class="absolute inset-0 pointer-events-none border-2 border-primary-500/50 m-8 sm:m-12 rounded-lg animate-pulse"></div>
</div>
<p class="text-center opacity-70 italic text-sm">Point camera at the badge QR code</p>
{:else if scanning_status === 'found' || scanning_status === 'adding'}
<div class="card p-6 w-full max-w-md space-y-4 variant-soft-primary shadow-xl border-2 border-primary-500">
<div class="text-center">
<h3 class="h3 font-bold">{found_badge?.full_name || 'Badge Found'}</h3>
<p class="opacity-70">{found_badge?.affiliations || ''}</p>
</div>
<button
type="button"
class="btn btn-xl w-full preset-filled-primary font-bold py-6"
disabled={scanning_status === 'adding'}
onclick={confirm_add_lead}
>
{#if scanning_status === 'adding'}
<LoaderCircle class="animate-spin mr-2" size="1.5em" />
Adding Lead...
{:else}
<UserPlus size="1.5em" class="mr-2" />
Add as Lead
{/if}
</button>
<button
type="button"
class="btn btn-sm w-full opacity-50"
disabled={scanning_status === 'adding'}
onclick={reset_scanner}
>
Cancel / Scan Again
</button>
</div>
{:else if scanning_status === 'success'}
<div class="card p-10 w-full max-w-md flex flex-col items-center space-y-4 variant-soft-success shadow-xl">
<CheckCircle size="4em" class="text-success-500 animate-bounce" />
<div class="text-center">
<h3 class="h4 font-bold">Lead Added!</h3>
<p class="text-xl font-bold">{found_badge?.full_name}</p>
</div>
<p class="text-sm opacity-50">Resetting scanner...</p>
</div>
{:else if scanning_status === 'error'}
<div class="card p-6 w-full max-w-md flex flex-col items-center space-y-4 variant-soft-error">
<AlertCircle size="3em" class="text-error-500" />
<p class="text-center font-bold">{error_msg}</p>
<button type="button" class="btn btn-sm preset-filled-error" onclick={reset_scanner}>
Try Again
</button>
</div>
{/if}
</div>

View File

@@ -1,18 +1,72 @@
<script lang="ts">
/**
* src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__add.svelte
* Tab 2: Add - Search / QR Scan Stub.
* Tab 2: Add - Search / QR Scan Layout.
*/
import { QrCode, Search, List } from 'lucide-svelte';
import Comp_lead_qr_scanner from './ae_comp__lead_qr_scanner.svelte';
import Comp_lead_manual_search from './ae_comp__lead_manual_search.svelte';
import { events_loc } from '$lib/stores/ae_events_stores';
let show_qr = $state(true);
interface Props {
exhibit_id: string;
}
let { exhibit_id }: Props = $props();
let mode = $state('qr'); // 'qr' or 'search'
function handle_lead_added(badge: any) {
console.log('Lead successfully added:', badge.full_name);
// We could trigger a global list refresh here if needed
$events_loc.leads.tracking__search_version++;
}
</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 class="ae-tab-add flex flex-col items-center space-y-6 w-full mx-auto">
<!-- Mode Toggle - Stable Width -->
<div class="flex p-1 bg-surface-200-800 rounded-xl w-full max-w-md shadow-inner">
<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:preset-filled-primary={mode === 'qr'}
onclick={() => mode = 'qr'}
>
<QrCode size="1.2em" />
<span class="font-bold">Scan QR</span>
</button>
<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:preset-filled-primary={mode === 'search'}
onclick={() => mode = 'search'}
>
<Search size="1.2em" />
<span class="font-bold">Search</span>
</button>
</div>
{#if show_qr} <Comp_lead_qr_scanner /> {:else} <Comp_lead_manual_search /> {/if}
</div>
<!-- Content Area - Stable Width -->
<div class="w-full flex flex-col items-center min-h-[400px]">
{#if mode === 'qr'}
<Comp_lead_qr_scanner {exhibit_id} on_lead_added={handle_lead_added} />
{:else}
<Comp_lead_manual_search {exhibit_id} on_lead_added={handle_lead_added} />
{/if}
</div>
<!-- Quick Navigation -->
<div class="pt-8 w-full border-t border-surface-500/20 flex justify-center pb-10">
<button
type="button"
class="btn btn-sm variant-soft-surface opacity-70 hover:opacity-100 transition-opacity"
onclick={() => {
// This would be handled by the parent's active_tab state
// Assuming we can pass a prop or use a store to switch tabs
}}
>
<List size="1.2em" class="mr-2" />
View Leads List
</button>
</div>
</div>

View File

@@ -281,7 +281,7 @@ Middle-click to open in new tab`}
);
}
$journals_slct.journal_entry_id =
results?.journal_entry_id_random;
results?.journal_entry_id;
// $journals_loc.entry.edit = true;
$journals_loc.entry.edit_kv[
$journals_slct.journal_entry_id

View File

@@ -1,74 +1,8 @@
/** @type {import('./$types').PageLoad} */
import { error } from '@sveltejs/kit';
console.log(`ae_p_journals [journal_id] +page.ts start`);
// console.log(`ae_p_journals [journal_id] +page.ts start`);
import { browser } from '$app/environment';
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
// import { browser } from '$app/environment';
// import { journals_func } from '$lib/ae_journals/ae_journals_functions';
export async function load({ params, parent }) {
// route
// let log_lvl: number = 1;
// let data = await parent();
// data.log_lvl = log_lvl;
// let account_id = data.account_id;
// let ae_acct = data[account_id];
// let journal_id = params.journal_id;
// if (!journal_id) {
// console.log(`ae_journals journals [journal_id] +page.ts: The journal_id was not found in the params!!!`);
// error(404, {
// message: 'Journals - Journal ID not found'
// });
// }
// ae_acct.slct.journal_id = journal_id;
// console.log(`ae_journals journals [journal_id] +page.ts: journal_id = `, ae_acct.slct.journal_id);
// if (browser) {
// if (log_lvl) {
// console.log(`ae_journals journals [journal_id] +page.ts: journal_id = `, journal_id);
// }
// // Load event journal object
// let load_journal_obj = journals_func.load_ae_obj_id__journal({
// api_cfg: ae_acct.api,
// journal_id: journal_id,
// inc_entry_li: true,
// try_cache: true,
// log_lvl: log_lvl
// });
// ae_acct.slct.journal_obj = load_journal_obj;
// Load journal entries for the journal
// let load_journal_entry_obj_li = journals_func.load_ae_obj_li__journal_entry({
// api_cfg: ae_acct.api,
// for_obj_type: 'journal',
// for_obj_id: journal_id,
// params: {qry__enabled: 'all', qry__limit: 99},
// try_cache: true
// })
// .then((journal_entry_obj_li) => {
// if (log_lvl) {
// console.log(`journal_entry_obj_li = `, journal_entry_obj_li);
// }
// for (let index = 0; index < journal_entry_obj_li.length; index++) {
// let journal_entry_obj = journal_entry_obj_li[index];
// let journal_entry_id = journal_entry_obj.journal_entry_id_random;
// let load_journal_entry_obj_li = journals_func.load_ae_obj_li__journal_entry({
// api_cfg: ae_acct.api,
// for_obj_type: 'journal_entry',
// for_obj_id: journal_entry_id,
// params: {qry__enabled: 'all', qry__limit: 15},
// try_cache: true
// });
// if (log_lvl) {
// console.log(`load_journal_entry_obj_li = `, load_journal_entry_obj_li);
// }
// journal_entry_obj_li[index].journal_entry_li = load_journal_entry_obj_li;
// }
// return journal_entry_obj_li;
// });
// if (log_lvl) {
// console.log(`load_journal_entry_obj_li = `, load_journal_entry_obj_li);
// }
// ae_acct.slct.journal_entry_obj_li = load_journal_entry_obj_li;
// }
// WARNING: Precaution against shared data between sites.
// data[account_id] = ae_acct;
// return data;
}
// export async function load({ params, parent }) {
// }