From 14c2635df4cbc25c0109c73832e19397861a8b53 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Fri, 20 Mar 2026 12:58:57 -0400 Subject: [PATCH] docs + fix: Leads module doc, badges onsite doc, license access fix, QR log cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add MODULE__AE_Events_Exhibitor_Leads.md — full module reference (auth model, tabs, data model, routes, offline/PWA notes, OSIT admin notes) - Add MODULE__AE_Events_Badges_Onsite.md — onsite printing guide (browser settings, CUPS/Linux setup, Zebra ZC10L section with test results, Epson stub, troubleshooting) - Archive PROJECT__AE_Events_Exhibitor_Leads_v3*.md + Zebra test day doc → history/ - Fix leads license management access: ae_tab__manage.svelte license section now visible to administrator_access OR shared-passcode sign-in (type === 'shared'); matches spec - Add type field to LeadsLocState.auth_exhibit_kv interface (was set at runtime but missing from type) - Silence QR code console noise: entry log gated at log_lvl >= 2, data URL log removed - vite.config.ts: exclude documentation/ and tests/ from Vite HMR file watcher Co-Authored-By: Claude Sonnet 4.6 --- documentation/MODULE__AE_Events_Badges.md | 2 +- .../MODULE__AE_Events_Badges_Onsite.md | 207 +++++++++++++++ .../MODULE__AE_Events_Exhibitor_Leads.md | 235 ++++++++++++++++++ .../PROJECT__AE_Events_Exhibitor_Leads_v3.md | 0 ...CT__AE_Events_Exhibitor_Leads_v3_detail.md | 0 ...JECT__AE_Events_Zebra_Hardware_Test_Day.md | 0 src/lib/ae_core/core__qr_code.ts | 6 +- .../ae_events_stores__leads_defaults.ts | 4 +- .../events/[event_id]/(leads)/README.md | 6 +- .../[exhibit_id]/ae_tab__manage.svelte | 8 +- vite.config.ts | 6 + 11 files changed, 462 insertions(+), 12 deletions(-) create mode 100644 documentation/MODULE__AE_Events_Badges_Onsite.md create mode 100644 documentation/MODULE__AE_Events_Exhibitor_Leads.md rename documentation/{ => history}/PROJECT__AE_Events_Exhibitor_Leads_v3.md (100%) rename documentation/{ => history}/PROJECT__AE_Events_Exhibitor_Leads_v3_detail.md (100%) rename documentation/{ => history}/PROJECT__AE_Events_Zebra_Hardware_Test_Day.md (100%) diff --git a/documentation/MODULE__AE_Events_Badges.md b/documentation/MODULE__AE_Events_Badges.md index e9206878..3e2eebc5 100644 --- a/documentation/MODULE__AE_Events_Badges.md +++ b/documentation/MODULE__AE_Events_Badges.md @@ -11,7 +11,7 @@ ## Overview The Badges module manages event attendee badges with support for: -- **External system imports** (iMIS, Zoom, Novi, Impexium, Confex, Cvent, and others) +- **External system imports as needed** (CSV/Excel, iMIS, Zoom, Novi, Impexium, Confex, Cvent, and others) - **Field override protection** to prevent staff/attendee edits from being overwritten by automated syncs - **Multi-tier access control** for field editing - **QR code generation** for badge scanning diff --git a/documentation/MODULE__AE_Events_Badges_Onsite.md b/documentation/MODULE__AE_Events_Badges_Onsite.md new file mode 100644 index 00000000..bf03444b --- /dev/null +++ b/documentation/MODULE__AE_Events_Badges_Onsite.md @@ -0,0 +1,207 @@ +# Aether Events — Onsite Badge Printing + +Notes on setup, process, hardware, and browser behavior for onsite badge printing at events. + +--- + +## Overview + +Aether badge printing uses the browser's native `window.print()` — no special software or print +server needed. The badge render page (`/events/[event_id]/badges/print/[badge_id]`) outputs +print-ready HTML/CSS, and the browser sends it directly to the connected printer via CUPS (Linux) +or the OS print system (macOS/Windows). + +Chrome (Chromium) is the recommended browser for onsite kiosk stations. +Firefox is a solid alternative, especially for Save-to-PDF workflows. + +--- + +## Recommended Workflow — Onsite Kiosk + +1. Open the event's badge printing page: `/events/[event_id]/badges` +2. Search for the attendee (name, badge ID, or QR scan) +3. Open the badge print page — review the rendered badge +4. Click **Print Badge** in the controls panel (or use keyboard shortcut) +5. In the browser print dialog: + - Set Margins to **None** (Chrome) or leave defaults (Firefox) + - Confirm paper/card size matches the stock loaded in the printer + - Print +6. `print_count` increments automatically on each print via the Print Badge button + +For high-volume events, consider the **rapid QR scan** mode in the Leads module or using a +dedicated kiosk session where the operator only handles physical card handoff. + +--- + +## Browser Settings + +### Chrome / Chromium (Recommended for kiosk use) + +Chrome is recommended for onsite badge printing stations. Key print dialog settings: + +| Setting | Correct value | Notes | +|---|---|---| +| Margins | **None** or **Minimum** | Default margins add URL/date headers — breaks badge centering | +| Paper size | Match card stock (e.g. 3.5" × 5.5") | Zebra driver may override this automatically | +| Background graphics | **On** | Required for colored header/footer stripe to print | +| Pages | 1 | PVC single-sided — only front should print | + +**Important:** Chrome ignores CSS `@page { size }` for Save to PDF — it defaults to letter/A4. +For physical printer output, the printer driver controls paper size. This is expected behavior. + +To lock Chrome settings for a kiosk, set Margins to "None" once and Chrome remembers per-printer. + +### Firefox + +Firefox honors CSS `@page { size }` which makes it ideal for PDF generation. +For physical printing, Firefox generally "just works" without margin adjustments. + +| Setting | Notes | +|---|---| +| Paper size | Can be set in dialog, but CSS `@page { size }` is honored | +| Margins | Default is usually fine; remove headers/footers if they appear | +| Background graphics | Enable for colored stripes and header images to print | + +### General Notes + +- **Background graphics must be enabled** in any browser — otherwise header images, footer + color stripes, and tonal backgrounds will not print. +- Private/incognito mode blocks PWA install prompts — use normal browser sessions for kiosk. +- For highest reliability, set the kiosk machine to auto-login and open Chrome to the event URL. + +--- + +## Linux / CUPS Setup + +For Linux workstations and dedicated kiosk machines running Linux: + +1. Install CUPS if not already present: `sudo pacman -S cups` (Arch) or equivalent +2. Start the CUPS service: `sudo systemctl enable --now cups` +3. Open the CUPS web UI: `http://localhost:631` +4. Add the printer and install the appropriate driver (see per-printer sections below) +5. Print a test page from CUPS to confirm card feed and quality +6. In Chrome: select the CUPS printer name under Destination in the print dialog + +On macOS and Windows, use the vendor-provided driver installer. + +--- + +## Printers + +--- + +### Zebra ZC10L — PVC Card Printer + +**Card stock:** 3.5" × 5.5" PVC cards (CR80 extended) +**Tested:** 2026-03-17 (rental test day, Arch Linux) +**Status:** Working. Confirmed suitable for Axonius NYC (mid-April 2026). + +#### Physical Setup + +- Connect via USB (the ZC10L supports USB and Ethernet) +- Load PVC card stock per the Zebra loading instructions — cards face-up, landscape +- The ZC10L prints one side (single-sided dye-sub thermal); do not attempt duplex on PVC stock + +#### Linux Driver + +- Download the Zebra ZC10L CUPS driver from zebra.com (ZC Series Linux support) +- Install the `.deb` or extract the PPD file and add to CUPS manually +- In CUPS (`http://localhost:631`), add the printer and select the ZC10L PPD +- Set default paper size to **3.5" × 5.5"** (or CR80 Extended if listed) +- Print a blank test page from CUPS before using Chrome + +> **Note:** Driver version tested: *(update here after confirming)* +> CUPS printer name used: *(update here after setup)* + +#### Chrome Print Settings (ZC10L) + +| Setting | Value | +|---|---| +| Destination | Zebra ZC10L (CUPS name) | +| Paper size | 3.5 × 5.5 in (or as set in CUPS) | +| Margins | **None** | +| Background graphics | On | +| Pages | 1 (front only) | + +#### CSS Layout + +The ZC10L uses the `badge_3.5x5.5_pvc` layout. The PVC layout CSS is at: +`src/routes/events/[event_id]/(badges)/badges/print/badge_layout_zebra_zc10l_pvc.css` + +This layout hides `.badge_back` in `@media print` — only the front face prints. +`@page { size: 3.5in 5.5in; margin: 0; }` is set in the CSS. + +#### Known Behaviors / Watch-outs + +- Chrome with **Default** margins: inserts URL/date headers, offsets badge — use **None** +- Chrome with **None** or **Minimum** margins: correct output +- Firefox: works correctly out of the box with this layout +- Physical card alignment: if the badge appears offset on the card, a CSS margin tweak may + be needed in the PVC layout file — note the offset and adjust `print_margin_cfg` once that + field is wired to the UI +- Font sizes: if name/affiliation text appears too small at physical scale, adjust via the + font size controls (+ / −) in the print controls panel; note the preferred values for this + event's template + +#### Test Results (2026-03-19) + +- Card feeds and prints without jam: ✅ +- Single-sided PVC confirmed (back does not print): ✅ +- Chrome margins None/Minimum: correct output ✅ +- Firefox: correct output ✅ +- QR code scannable from printed card: ✅ +- Print tracking (`print_count` increment): ✅ +- Font sizes / visual quality: tested; specific calibration pending client design direction +- Driver version: *(record here)* +- Physical offset needed: *(record if any)* + +--- + +### Epson — Fan-Fold / Label Printer + +**Status:** Not yet tested. Section to be filled in after testing. + +Common Epson models used for fan-fold name badge stock: TM-T88 series, C3500, LX series. +Fan-fold stock is typically 4" × 3" or 4" × 6" paper labels. + +#### CSS Layout + +Fan-fold badges would use a layout sized to the specific label stock. +A new CSS layout file will need to be created per stock size if not already present. +Naming convention: `badge_layout_epson_[model]_[size].css` + +#### Setup Notes + +*(To be filled in after testing — cover: driver source, CUPS setup, paper size, Chrome settings)* + +#### Known Behaviors + +*(To be filled in after testing)* + +--- + +## Print Tracking + +The badge print page tracks print counts per badge: + +- `print_count` — increments on each **Print Badge** button click +- `print_first_datetime` — timestamp of first print +- An amber "Printed N×" chip appears in the print page header after the first print + +The reprint shortcut (trusted access + edit mode) does **not** increment the count. +Only the **Print Badge** button path increments the count. This is intentional — reprints +for alignment or quality checks should not inflate the print count. + +--- + +## Troubleshooting + +| Symptom | Cause | Fix | +|---|---|---| +| White border around printed badge | Chrome Default margins | Change to None or Minimum | +| URL / date printed at top or bottom | Chrome Default margins | Change to None | +| Header image / stripe not printing | Background graphics disabled | Enable in print dialog | +| Badge appears on wrong-size output | Paper size mismatch | Set correct size in CUPS and/or print dialog | +| Card jams | Card stock misloaded | Re-seat cards per printer manual; check stock orientation | +| Badge content clipped | Layout overflow | Check font size — use − control to reduce if needed | +| Second blank card ejected | Duplex triggered on PVC | Confirm `.badge_back { display: none }` in print CSS for this layout | diff --git a/documentation/MODULE__AE_Events_Exhibitor_Leads.md b/documentation/MODULE__AE_Events_Exhibitor_Leads.md new file mode 100644 index 00000000..9f7a7696 --- /dev/null +++ b/documentation/MODULE__AE_Events_Exhibitor_Leads.md @@ -0,0 +1,235 @@ +# Aether Events — Exhibitor Leads Module (v3) + +**Status:** Implemented and ready for demo. Core lead capture flow works end-to-end. +**Platform:** PWA only — mobile-first, offline-capable. +**Target users:** Conference exhibitors scanning attendee badges at their booths. + +--- + +## What It Does + +The Exhibitor Leads module lets conference exhibitors capture and manage attendee leads directly +from their booth. Exhibitors scan or search attendee badges and build a list of contacts they met. +All data is cached locally (IndexedDB / Dexie.js) for spotty or offline venue Wi-Fi, with +background SWR revalidation against the API when the network is available. + +Key capabilities: + +- **Badge scanning** — QR scan or text search (name, email, affiliations, badge ID) +- **Lead list** — filterable/sortable, per-exhibitor or per-staff-member view +- **Lead detail** — custom question responses, notes (rich text), priority flag, hide/unhide +- **Export** — CSV/XLSX download of all leads for an exhibit +- **License management** — assign staff accounts (email + passcode) per max license count +- **Custom questions** — configurable per-exhibit follow-up questions (ratings, dropdowns, text) +- **Offline-first** — IndexedDB cache survives network drops; syncs on reconnect +- **PWA install** — Chrome/Android native install prompt; iOS Safari "Add to Home Screen" nudge + +--- + +## Access Levels + +Three sign-in levels are supported within this module: + +| Level | How to sign in | What they can do | +|---|---|---| +| **Aether Platform Auth** | Standard Aether login (manager/trusted access) | Full admin bypass; all exhibit data | +| **Shared Exhibit Passcode** | Enter booth's `staff_passcode` | Manage licenses, view/add leads | +| **Licensed User** | Email + individual passcode from `license_li_json` | Add and manage leads for this booth | + +Auth state is persisted in `$events_loc.leads.auth_exhibit_kv[exhibit_id]` (localStorage-backed). + +A booth only shows in the landing page search to non-admins if it is marked `priority = true` (i.e. paid). + +### `allow_tracking` Opt-In + +Attendees must have `allow_tracking = true` on their badge record to be added as a lead. +Attendees without this flag are blocked at both the QR scanner and the manual search: +- QR scan shows a "Tracking Blocked" warning card (`ShieldOff` icon) +- Manual search shows an "Opt-Out" badge per result row; the "Add as Lead" button is suppressed + +--- + +## Route Structure + +``` +/events/[event_id]/leads/ + → Exhibit search / landing page — find your booth + +/events/[event_id]/leads/exhibit/[exhibit_id]/ + → Main exhibitor view — all 4 tabs + +/events/[event_id]/leads/exhibit/[exhibit_id]/lead/[exhibit_tracking_id]/ + → Lead detail view — edit notes, custom responses, flags +``` + +--- + +## Module Tabs + +### Tab 1 — Start / Sign In + +The only tab visible when not signed in as a licensed leads user. + +- **Sign in with shared passcode** — grants booth management access (license management, passcode change) +- **Sign in as licensed user** — grants lead capture access (email + passcode) +- **PWA install prompt** — Chrome/Android native install button; iOS "Share → Add to Home Screen" instructions +- **License list** — shown when signed in via shared passcode or Aether admin; add/edit/remove staff slots + +### Tab 2 — Add Leads + +Visible only when signed in (licensed user or Aether auth). + +- **Text search** — search by name, email, affiliations, badge ID +- **QR scan** — two modes: + - **Rapid** — auto-resets after 2 seconds for the next scan (high volume) + - **Qualify** — navigates immediately to lead detail to capture notes per scan +- Results show "Add as Lead" or "View Lead" depending on whether already captured +- All new leads are linked to the capturing user's email (`external_person_id`) + +### Tab 3 — Leads List + +The main lead management view. + +- **Search** — full-text across name, email, notes (local IDB fast path + API revalidation) +- **Sort** — Newest first, Oldest first, Name A→Z, Name Z→A +- **Filter by staff member** — "All Leads" or filter by individual licensed user +- **Show/hide hidden records** — toggles `hide` filter on IDB and API results +- **Export** — downloads CSV/XLSX for the exhibit (`leads_api_access` required) + +### Tab 4 — Manage / Config + +Exhibit configuration and app settings. + +**Admin Tools** (manager_access only): +- Payment status toggle (`priority` field) +- Max licenses, small/large device counts + +**Booth Profile** (all signed-in users): +- Exhibitor name, booth description (rich text) + +**Access & Security**: +- View/change shared staff passcode +- Sign out button + +**Lead Retrieval Config**: +- Exhibit Leads Licensees — manage staff accounts (`administrator_access` only; gap: should also allow shared-passcode users — see Known Gaps) +- Qualifiers & Questions — custom question config +- Licenses & Billing — stub (Stripe not yet implemented) + +**App Settings**: +- Auto-hide header/footer toggle +- Show Payment Tab toggle +- Show Extra Details toggle +- Refresh interval (1–120 seconds, default 25s), countdown timer, last-refresh timestamp +- Reload App, Clear IDB, Hard Reset (clears localStorage) + +--- + +## Data Model + +### `event_exhibit` +One exhibitor's presence at an event. + +| Field | Purpose | +|---|---| +| `event_exhibit_id` / `event_exhibit_id_random` | Primary / URL-safe ID | +| `name` | Exhibitor display name | +| `code` | Booth number | +| `staff_passcode` | Shared sign-in code | +| `priority` | `1` = paid/active | +| `license_max` | Max licensed staff slots | +| `license_li_json` | Array of `{ full_name, email, passcode }` | +| `leads_custom_questions_json` | Array of question definitions | +| `leads_device_sm_qty` / `leads_device_lg_qty` | Device count tracking | + +### `event_exhibit_tracking` +One captured lead — links an exhibit to a badge. + +| Field | Purpose | +|---|---| +| `event_exhibit_tracking_id` | Primary key | +| `event_exhibit_id` | Parent exhibit | +| `event_badge_id` | Captured attendee's badge | +| `external_person_id` | Capturing staff's email (from license) | +| `exhibitor_notes` | Rich text notes (HTML via TipTap) | +| `responses_json` | `{ [question_code]: { response: value } }` | +| `priority` | Star/flag for high-priority leads | +| `hide` | Soft-delete / hide from list | +| Denormalized badge fields | `event_badge_full_name`, `event_badge_email`, `event_badge_affiliations`, `event_badge_professional_title` | + +--- + +## Key Files + +### Routes + +| File | Role | +|---|---| +| `leads/+page.svelte` | Exhibit search/landing | +| `leads/exhibit/[exhibit_id]/+page.svelte` | Main exhibitor view — orchestrates all tabs | +| `leads/exhibit/[exhibit_id]/+layout.svelte` / `+layout.ts` | Layout / data load | +| `leads/exhibit/[exhibit_id]/lead/[exhibit_tracking_id]/+page.svelte` | Lead detail | + +### Components + +| File | Role | +|---|---| +| `ae_tab__start.svelte` | Tab 1 — welcome, sign-in, license list | +| `ae_tab__add.svelte` | Tab 2 — QR scan + text search toggle | +| `ae_tab__manage.svelte` | Tab 4 — admin tools, booth config, app settings | +| `ae_comp__exhibit_signin.svelte` | Sign-in UI (shared passcode + licensed user) | +| `ae_comp__lead_qr_scanner.svelte` | QR scanner (rapid / qualify mode) | +| `ae_comp__lead_manual_search.svelte` | Manual badge search + add | +| `ae_comp__exhibit_tracking_search.svelte` | Lead list search/filter/sort bar | +| `ae_comp__exhibit_tracking_obj_li.svelte` | Lead list item renderer | +| `ae_comp__exhibit_license_list.svelte` | License slot manager | +| `ae_comp__exhibit_custom_questions.svelte` | Custom question config editor | +| `ae_comp__exhibit_payment.svelte` | **STUB** — Stripe placeholder | +| `ae_comp__exhibit_search.svelte` | Exhibit search on the landing page | +| `lead/ae_comp__lead_detail_form.svelte` | Custom question response editor | + +### Lib Functions + +| File | Role | +|---|---| +| `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 aggregated into `events_func` via `src/lib/ae_events/ae_events_functions.ts`. + +--- + +## Offline / PWA Notes + +- All data is stored in `db_events` (Dexie.js) — `exhibit` and `exhibit_tracking` tables +- SWR pattern: IDB cache returned immediately; background API fetch updates IDB and triggers UI refresh +- Search: local IDB first pass (fast), then API revalidation via `search__exhibit_tracking` +- `beforeinstallprompt` event captured at module load time (`src/lib/pwa/pwa_install.svelte.ts`) + — fires within ~1 second of page load, before any Svelte `$effect` runs +- iOS Safari: no native install prompt; shows "Share → Add to Home Screen" instructions instead + +--- + +## Known Gaps + +### Payment / Stripe +`ae_comp__exhibit_payment.svelte` is a stub. The Stripe integration is not implemented. +The payment tab can be hidden via "Show Payment Tab" in App Settings. + +### License Management — Shared Passcode Access +Implemented. The license section in the Manage tab is visible to Aether admins and to anyone +signed in via the shared exhibit passcode (`auth_exhibit_kv[exhibit_id].type === 'shared'`). +Guard in [ae_tab__manage.svelte](src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte): +```svelte +{#if $ae_loc.administrator_access || $events_loc.leads.auth_exhibit_kv?.[exhibit_id]?.type === 'shared'} +``` + +--- + +## OSIT Admin Notes + +- Mark `priority = 1` on an exhibit to make it visible in public search and to enable lead capture +- `license_max` controls how many licensed staff slots an exhibit can have +- Export endpoint: `GET /v3/action/event_exhibit/{id}/tracking_export` — requires `leads_api_access` +- Custom questions are stored per-exhibit in `leads_custom_questions_json` (not global) +- The exhibitor landing page link format: `/events/[event_id]/leads/exhibit/[exhibit_exhibit_id_random]/` diff --git a/documentation/PROJECT__AE_Events_Exhibitor_Leads_v3.md b/documentation/history/PROJECT__AE_Events_Exhibitor_Leads_v3.md similarity index 100% rename from documentation/PROJECT__AE_Events_Exhibitor_Leads_v3.md rename to documentation/history/PROJECT__AE_Events_Exhibitor_Leads_v3.md diff --git a/documentation/PROJECT__AE_Events_Exhibitor_Leads_v3_detail.md b/documentation/history/PROJECT__AE_Events_Exhibitor_Leads_v3_detail.md similarity index 100% rename from documentation/PROJECT__AE_Events_Exhibitor_Leads_v3_detail.md rename to documentation/history/PROJECT__AE_Events_Exhibitor_Leads_v3_detail.md diff --git a/documentation/PROJECT__AE_Events_Zebra_Hardware_Test_Day.md b/documentation/history/PROJECT__AE_Events_Zebra_Hardware_Test_Day.md similarity index 100% rename from documentation/PROJECT__AE_Events_Zebra_Hardware_Test_Day.md rename to documentation/history/PROJECT__AE_Events_Zebra_Hardware_Test_Day.md diff --git a/src/lib/ae_core/core__qr_code.ts b/src/lib/ae_core/core__qr_code.ts index f18c4309..ed81df57 100644 --- a/src/lib/ae_core/core__qr_code.ts +++ b/src/lib/ae_core/core__qr_code.ts @@ -175,10 +175,11 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {}) key, val, js, - str + str, + log_lvl = 0 } = params; - console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params); + if (log_lvl >= 2) console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params); let qr_data: string | null = null; @@ -251,7 +252,6 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {}) scale: 10, // Corresponds to box_size type: 'image/png' }); - console.log('Generated QR code data URL:', data_url); return data_url; } catch (error) { console.error('Error generating QR code:', error); diff --git a/src/lib/stores/ae_events_stores__leads_defaults.ts b/src/lib/stores/ae_events_stores__leads_defaults.ts index d313f26b..fd66b89f 100644 --- a/src/lib/stores/ae_events_stores__leads_defaults.ts +++ b/src/lib/stores/ae_events_stores__leads_defaults.ts @@ -29,8 +29,8 @@ export interface LeadsLocState { tracking__qry__sort_order: string; tracking__qry__licensee_email: string; entered_passcode: string | null; - // Value shape: { key: string; updated_on: string } — entries expire after a configurable max age. - auth_exhibit_kv: Record; + // Value shape: key = passcode/email used; type = 'shared' | 'licensed'; entries expire after a configurable max age. + auth_exhibit_kv: Record; edit_license_li: boolean; // Key = exhibit ID (random), value = last-used tab name. tab: Record; diff --git a/src/routes/events/[event_id]/(leads)/README.md b/src/routes/events/[event_id]/(leads)/README.md index 8857138a..f040411a 100644 --- a/src/routes/events/[event_id]/(leads)/README.md +++ b/src/routes/events/[event_id]/(leads)/README.md @@ -111,9 +111,6 @@ Two scan modes (toggled per exhibit): - **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. -- **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) @@ -125,6 +122,9 @@ Two scan modes (toggled per exhibit): `/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. +- **License management access for shared-passcode users** — `ae_tab__manage.svelte` license + section now visible to `administrator_access` OR `auth_exhibit_kv[id].type === 'shared'`. + Also added `type` field to `LeadsLocState.auth_exhibit_kv` interface. --- diff --git a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte index 9bb44df9..978a105f 100644 --- a/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte +++ b/src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte @@ -225,8 +225,10 @@
- - {#if $ae_loc.administrator_access} + + {#if $ae_loc.administrator_access || $events_loc.leads.auth_exhibit_kv?.[exhibit_id]?.type === 'shared'}
Exhibit Leads Licensees
-
Manage assigned users and codes (Admin Only)
+
Manage assigned users and codes
{#if show_license_mgmt} diff --git a/vite.config.ts b/vite.config.ts index 8a1df641..4a3e92ba 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,6 +7,12 @@ export default defineConfig({ tailwindcss(), sveltekit() // <-- Must come after Tailwind ], + server: { + watch: { + // Do not trigger HMR/reload for documentation or test files + ignored: ['**/documentation/**', '**/tests/**'] + } + }, build: { rollupOptions: { output: {