feat: leads — add show/hide hidden records toggle + update stale README gaps
- Add Eye/EyeOff toggle to exhibit tracking search bar; wired to existing $events_loc.leads.show_hidden store field - Guard + init the show_hidden field in +page.svelte - Add show_hidden to search_params so toggling triggers a refresh - Apply hide filter in local IDB search path (skip hidden unless toggled) - Pass hidden: 'not_hidden' | 'all' to API search__exhibit_tracking call - Apply hide filter in filtered_lead_li for the broad liveQuery fallback path - README: remove stale allow_tracking/PWA/export gaps; add Implemented section; fix ae_events_functions import path (moved to ae_events/ subdir) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -109,13 +109,22 @@ Two scan modes (toggled per exhibit):
|
||||
|
||||
## Known Gaps / Not Yet Implemented
|
||||
|
||||
- **`allow_tracking` gate** — spec says badge must have `allow_tracking = true` before a lead can
|
||||
be added. Neither the QR scanner nor manual search enforce this yet.
|
||||
- **Payment / Stripe** — `ae_comp__exhibit_payment.svelte` is a stub. The payment tab can be
|
||||
hidden via the "Show Payment Tab" toggle in the Manage tab's App Settings.
|
||||
- **Export endpoint** — `download_export__event_exhibit_tracking` calls a legacy V1 endpoint
|
||||
(`/event/exhibit/{id}/tracking/export`). Verify it's live on the backend before demoing export.
|
||||
- **PWA install prompt** — spec calls for nudging exhibitors to install as a PWA on the Start tab.
|
||||
- **License management access for shared-passcode users** — spec says booth staff signed in via
|
||||
the shared passcode should be able to manage licenses. Currently gated behind
|
||||
`$ae_loc.administrator_access` only (in `ae_tab__manage.svelte`).
|
||||
|
||||
## Implemented (previously listed as gaps)
|
||||
|
||||
- **`allow_tracking` gate** — enforced in both `ae_comp__lead_qr_scanner.svelte` and
|
||||
`ae_comp__lead_manual_search.svelte`. Badges without `allow_tracking = true` are blocked.
|
||||
- **Show/hide hidden records** — toggle in `ae_comp__exhibit_tracking_search.svelte`; filters
|
||||
local IDB search, API search (`hidden` param), and `filtered_lead_li` in `+page.svelte`.
|
||||
- **Export endpoint** — `download_export__event_exhibit_tracking` uses V3 action endpoint
|
||||
`/v3/action/event_exhibit/{id}/tracking_export`. Gated on `leads_api_access === true`.
|
||||
- **PWA install prompt** — `element_pwa_install_prompt.svelte` placed on the Start tab.
|
||||
Handles Chrome/Android native install and iOS Safari manual instructions.
|
||||
|
||||
---
|
||||
|
||||
@@ -123,4 +132,4 @@ Two scan modes (toggled per exhibit):
|
||||
|
||||
`src/lib/ae_events/ae_events__exhibit.ts` — exhibit load, search, create, update
|
||||
`src/lib/ae_events/ae_events__exhibit_tracking.ts` — tracking load, search, create, update, export
|
||||
Both are aggregated into `events_func` via `src/lib/ae_events_functions.ts`.
|
||||
Both are aggregated into `events_func` via `src/lib/ae_events/ae_events_functions.ts`.
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
$events_loc.leads.tracking__qry__sort_order = 'created_desc';
|
||||
if (typeof $events_loc.leads.refresh_interval_sec === 'undefined')
|
||||
$events_loc.leads.refresh_interval_sec = 25;
|
||||
if (typeof $events_loc.leads.show_hidden === 'undefined')
|
||||
$events_loc.leads.show_hidden = false;
|
||||
}
|
||||
|
||||
// --- Sign-In State (Derived) ---
|
||||
@@ -74,9 +76,12 @@
|
||||
// (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;
|
||||
|
||||
const show_hidden = search_params.show_hidden;
|
||||
|
||||
return raw_lead_li.filter(lead => {
|
||||
// Exclude hidden leads unless show_hidden is toggled on
|
||||
if (!show_hidden && lead.hide) return false;
|
||||
if (licensee_filter === 'all') return true;
|
||||
const capturer = lead.external_person_id || lead.group;
|
||||
return capturer === licensee_filter;
|
||||
});
|
||||
@@ -138,7 +143,8 @@
|
||||
sort: $events_loc.leads.tracking__qry__sort_order,
|
||||
licensee_email: licensee_email,
|
||||
exhibit_id: page.params.exhibit_id,
|
||||
remote_first: $events_loc.leads.tracking__qry__remote_first
|
||||
remote_first: $events_loc.leads.tracking__qry__remote_first,
|
||||
show_hidden: $events_loc.leads.show_hidden ?? false
|
||||
};
|
||||
});
|
||||
|
||||
@@ -205,7 +211,10 @@
|
||||
.where('event_exhibit_id')
|
||||
.equals(target_exhibit_id)
|
||||
.filter((tracking) => {
|
||||
// 1. Licensee Email Filter
|
||||
// 1. Hide filter — exclude hidden records unless show_hidden is on
|
||||
if (!params.show_hidden && tracking.hide) return false;
|
||||
|
||||
// 2. Licensee Email Filter
|
||||
if (target_licensee_email !== 'all') {
|
||||
if (tracking.external_person_id !== target_licensee_email) return false;
|
||||
}
|
||||
@@ -313,6 +322,7 @@
|
||||
event_exhibit_id: q_exhibit_id,
|
||||
fulltext_search_qry_str: qry_str || null,
|
||||
qry_external_person_id: q_licensee_email,
|
||||
hidden: params.show_hidden ? 'all' : 'not_hidden',
|
||||
order_by_li,
|
||||
limit: 150
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
let { exhibit_id, log_lvl = 0 }: Props = $props();
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import { Library, LoaderCircle, RemoveFormatting, Search } from '@lucide/svelte';
|
||||
import { Eye, EyeOff, Library, LoaderCircle, RemoveFormatting, Search } from '@lucide/svelte';
|
||||
import { untrack } from 'svelte';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { events_loc, events_sess } from '$lib/stores/ae_events_stores';
|
||||
@@ -165,6 +165,27 @@
|
||||
<div
|
||||
class="flex flex-row flex-wrap items-center justify-center gap-2 opacity-70 hover:opacity-100 transition-all"
|
||||
>
|
||||
<!-- Show/Hide hidden records toggle — always visible -->
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center gap-1 cursor-pointer px-2 py-1 rounded-token text-xs font-semibold transition-colors"
|
||||
class:preset-tonal-warning={$events_loc.leads.show_hidden}
|
||||
class:preset-tonal-surface={!$events_loc.leads.show_hidden}
|
||||
onclick={() => {
|
||||
$events_loc.leads.show_hidden = !$events_loc.leads.show_hidden;
|
||||
handle_search_trigger();
|
||||
}}
|
||||
title={$events_loc.leads.show_hidden ? 'Showing hidden leads — click to hide them' : 'Hidden leads excluded — click to show all'}
|
||||
>
|
||||
{#if $events_loc.leads.show_hidden}
|
||||
<Eye size="1em" />
|
||||
<span>Showing Hidden</span>
|
||||
{:else}
|
||||
<EyeOff size="1em" />
|
||||
<span>Hidden Excluded</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
{#if $ae_loc.edit_mode}
|
||||
<label
|
||||
class="flex items-center gap-1 cursor-pointer bg-surface-200-800 px-2 py-1 rounded-token text-xs font-semibold"
|
||||
|
||||
Reference in New Issue
Block a user