docs + fix: Leads module doc, badges onsite doc, license access fix, QR log cleanup
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
|
||||
207
documentation/MODULE__AE_Events_Badges_Onsite.md
Normal file
207
documentation/MODULE__AE_Events_Badges_Onsite.md
Normal file
@@ -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 |
|
||||
235
documentation/MODULE__AE_Events_Exhibitor_Leads.md
Normal file
235
documentation/MODULE__AE_Events_Exhibitor_Leads.md
Normal file
@@ -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]/`
|
||||
@@ -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);
|
||||
|
||||
@@ -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<string, { key: string; updated_on: string }>;
|
||||
// Value shape: key = passcode/email used; type = 'shared' | 'licensed'; entries expire after a configurable max age.
|
||||
auth_exhibit_kv: Record<string, { key: string; type: string; updated_on: string }>;
|
||||
edit_license_li: boolean;
|
||||
// Key = exhibit ID (random), value = last-used tab name.
|
||||
tab: Record<string, string>;
|
||||
|
||||
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -225,8 +225,10 @@
|
||||
</div>
|
||||
|
||||
<div class="card p-0 divide-y divide-surface-500/10 overflow-hidden shadow-md">
|
||||
<!-- Licenses (Administrator Access Only for now) -->
|
||||
{#if $ae_loc.administrator_access}
|
||||
<!-- Licenses — visible to: Aether admins OR someone signed in with the shared exhibit passcode.
|
||||
Spec: "A client staff (Trusted Access or above) or someone signed in with an Exhibit passcode
|
||||
can add/edit/remove licenses." — PROJECT__AE_Events_Exhibitor_Leads_v3.md -->
|
||||
{#if $ae_loc.administrator_access || $events_loc.leads.auth_exhibit_kv?.[exhibit_id]?.type === 'shared'}
|
||||
<div class="p-0">
|
||||
<button
|
||||
class="w-full p-4 flex items-center justify-between hover:bg-surface-500/5 transition-colors group"
|
||||
@@ -236,7 +238,7 @@
|
||||
<div class="bg-primary-500/10 p-2 rounded-lg text-primary-500"><Users size="1.2em" /></div>
|
||||
<div class="text-left">
|
||||
<div class="font-bold text-sm">Exhibit Leads Licensees</div>
|
||||
<div class="text-xs opacity-50">Manage assigned users and codes (Admin Only)</div>
|
||||
<div class="text-xs opacity-50">Manage assigned users and codes</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if show_license_mgmt}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user