Updated to do list. Cleaned up the badge search area at the top of the badge. Also tested the upload option

This commit is contained in:
Scott Idem
2026-04-09 14:31:29 -04:00
parent a84ea4cbcb
commit 76c28a7e22
5 changed files with 53 additions and 50 deletions

View File

@@ -7,6 +7,7 @@
"settings": {
"cSpell.words": [
"autofetch",
"Axonius",
"displayplacer",
"filelist",
"gsettings",

View File

@@ -56,10 +56,8 @@ When navigating from the Presenter View to the Launcher, the frontend has to do
session lookup to discover the location (magic redirect in launcher base `+page.svelte`).
Joining `event_session.event_location_id` into the presenter view/response would let the
frontend pass the location directly in the Launcher URL without the extra lookup.
- Backend: add `event_location_id` (and `event_location_id_random`) to the `event_presenter`
view or API response
- Frontend: add `event_location_id` to `ae_EventPresenter` type and `properties_to_save`;
pass as `events__launcher_id` in `presenter_page_menu.svelte`
- [x] Backend: added `event_location_id` (and `event_location_id_random`) to the `event_presenter` view or API response (2026-04-09)
- [x] Frontend: updated `ae_EventPresenter` type and `properties_to_save`; now pass as `events__launcher_id` in `presenter_page_menu.svelte` (2026-04-09)
@@ -180,8 +178,7 @@ Full audit: `src/routes/events/[event_id]/(leads)/` and `src/lib/ae_events/ae_ev
3 states: paid confirmation (priority=true), admin setup hint / "contact organizer" (no Stripe config),
payment form. `client_reference_id=exhibit_id`. TypeScript declaration in `app.d.ts`.
Stripe keys verified visible in `$ae_loc.site_cfg_json` on dev/demo site. Keys need validity check in Stripe dashboard.
- [ ] **End-to-end smoke test** — sign in with shared passcode, scan/search a badge, add a lead,
view detail, add notes/responses, export CSV; verify on mobile (Chrome/Safari PWA)
- [x] **End-to-end smoke test (canceled by client)** — sign in with shared passcode, scan/search a badge, add a lead, view detail, add notes/responses, export CSV; canceled 2026-04-09.
- [x] **Install prompt** — PWA install nudge implemented (2026-03-16). `pwa_install.svelte.ts`
singleton captures `beforeinstallprompt` (Chrome/Android/desktop) and detects iOS Safari
for manual "Share → Add to Home Screen" instructions. Reusable `element_pwa_install_prompt.svelte`

View File

@@ -429,62 +429,64 @@ async function handle_search_refresh(params: any) {
></Comp_badge_search>
{#if $ae_loc.trusted_access && $ae_loc.edit_mode}
<div class="flex flex-row items-center justify-center">
<div class="flex flex-row gap-1 items-center justify-center">
{#if badges_loc.current.enable_add_badge_btn ?? true}
<!-- <div class="flex justify-end px-4"> -->
<button
type="button"
class="btn btn-sm preset-tonal-primary border-primary-500 border"
class="btn btn-sm preset-tonal-warning border-warning-500 border"
onclick={() => {
show_create_badge_modal = true;
create_badge_dialog?.showModal();
}}>
}}
title="Manually create a badge for an attendee. Required fields: given name, family name, and email. Optional fields: badge type, affiliations, and any other custom fields defined in your event's badge templates."
>
<UserPlus size="1em" />
Create Badge
</button>
<!-- </div> -->
{/if}
{#if badges_loc.current.enable_upload_badge_li_btn ?? true}
<!-- <div class="flex justify-end px-4 mt-2"> -->
<button
type="button"
class="btn btn-sm ml-2"
class="btn btn-sm preset-tonal-warning border-warning-500 border"
onclick={() => {
show_upload_badge_modal = true;
upload_badge_dialog?.showModal();
}}>
}}
title="Upload a CSV file to bulk create badges. Required columns: given_name, family_name, email. Optional columns: badge_type_code, affiliations, and any other custom fields defined in your event's badge templates."
>
<Upload size="1em" /> Upload Badge List
</button>
<!-- </div> -->
{/if}
</div>
{#if badges_loc.current.enable_mass_print ?? true}
<div class="flex flex-row gap-1 items-center justify-center">
<a
href={`/events/${$events_slct?.event_id}/badges/print_list?printed_status=not_printed`}
class="btn preset-filled-secondary">
<Printer size="1em" /> Print Unprinted
</a>
<a
href={`/events/${$events_slct?.event_id}/badges/print_list`}
class="btn preset-filled-secondary">
<Printer size="1em" /> Print All
</a>
<a
href={`/events/${$events_slct?.event_id}/templates`}
class="btn btn-tertiary">
<FileText size="1em" /> Manage Templates
</a>
<a
href={`/events/${$events_slct?.event_id}/badges/stats`}
class="btn btn-tertiary">
<BarChart2 size="1em" /> Badge Printing Stats
</a>
</div>
{/if}
{/if}
{#if $ae_loc.trusted_access && (badges_loc.current.enable_mass_print ?? true)}
<div class="mt-2 flex gap-2 px-4">
<a
href={`/events/${$events_slct?.event_id}/badges/print_list?printed_status=not_printed`}
class="btn preset-filled-secondary">
<Printer size="1em" /> Print Unprinted
</a>
<a
href={`/events/${$events_slct?.event_id}/badges/print_list`}
class="btn preset-filled-secondary">
<Printer size="1em" /> Print All
</a>
<a
href={`/events/${$events_slct?.event_id}/templates`}
class="btn btn-tertiary">
<FileText size="1em" /> Manage Templates
</a>
<a
href={`/events/${$events_slct?.event_id}/badges/stats`}
class="btn btn-tertiary">
<BarChart2 size="1em" /> Badge Printing Stats
</a>
</div>
{/if}
<!-- Create Badge modal — native <dialog> for focus trap + backdrop.
Clicking the backdrop closes it. The form remounts each open so state is fresh. -->

View File

@@ -169,7 +169,7 @@ function handle_qr_scan_result(event: {
$events_sess.badges.show_form__scan = true;
$events_sess.badges.qr_scan_start = true;
}}
class="btn btn-sm preset-tonal-primary border-primary-500 border">
class="btn btn-sm preset-tonal-warning border-warning-500 border">
<QrCode size="1em" class="mr-1" />
QR Scan
</button>
@@ -181,7 +181,7 @@ function handle_qr_scan_result(event: {
onclick={() => document.getElementById('badge_fulltext_search_qry_str')?.focus()}
aria-label="Start here focus search field"
data-testid="badge-start-btn"
class="btn btn-sm preset-filled-secondary-300-700"
class="btn btn-sm preset-filled-secondary-300-700 font-semibold"
class:opacity-30={!!badges_loc.current.fulltext_search_qry_str}
>
<StepForward size="1em" class="mx-1" />

View File

@@ -3,7 +3,7 @@
import { Loader2 } from '@lucide/svelte';
import type { key_val } from '$lib/stores/ae_stores';
import { events_func } from '$lib/ae_events/ae_events_functions';
import { ae_api } from '$lib/stores/ae_stores';
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
interface Props {
@@ -23,7 +23,7 @@ let upload_status: string = $state('idle'); // idle, loading, processing, succes
let upload_message: string = $state('');
let processed_badges_count: number = $state(0);
let total_badges_in_file: number = $state(0);
let upload_mode: 'client_csv' | 'axonius_zoom' = $state('client_csv');
let upload_mode: 'client_csv' | 'axonius_zoom' = $state('axonius_zoom');
let begin_at: number | null = $state(null);
let end_at: number | null = $state(null);
let return_detail: boolean = $state(false);
@@ -194,11 +194,11 @@ function handle_cancel() {
<form onsubmit={handle_upload} class="space-y-4 p-4">
<h3 class="h3">Upload Badge List (CSV)</h3>
<p>
<!-- <p>
Upload a CSV file containing badge data. The first row should be
headers.
</p>
<p>
</p> -->
<!-- <p>
Supported headers (case-sensitive): <code>full_name</code>,
<code>name</code>,
<code>professional_title</code>, <code>affiliations</code>,
@@ -206,22 +206,25 @@ function handle_cancel() {
<code>location</code>, <code>email</code>, <code>allow_tracking</code>
(true/false or 1/0),
<code>badge_type_code</code>.
</p> -->
<p>
Upload the standard Axonius Zoom event tickets CSV export file here. This will trigger server-side processing to import the new and changed badges. This can take a few seconds to a few minutes.
</p>
<fieldset class="space-y-2">
<legend class="label"><span>Upload format</span></legend>
<div class="flex gap-4 items-center">
<label class="label flex items-center gap-2">
<!-- <label class="label flex items-center gap-2">
<input type="radio" name="upload_mode" value="client_csv" bind:group={upload_mode} />
<span>Standard CSV (client-side parse)</span>
</label>
</label> -->
<label class="label flex items-center gap-2">
<input type="radio" name="upload_mode" value="axonius_zoom" bind:group={upload_mode} />
<span>Axonius Zoom CSV (server import)</span>
<span>Axonius Zoom CSV (event tickets)</span>
</label>
</div>
{#if upload_mode === 'axonius_zoom'}
{#if $ae_loc.administrator_access && upload_mode === 'axonius_zoom'}
<div class="grid grid-cols-3 gap-2 items-center">
<input type="number" min="0" placeholder="begin_at (0)" bind:value={begin_at} class="input" />
<input type="number" min="0" placeholder="end_at (20000)" bind:value={end_at} class="input" />