# PROJECT: AE Events Badges — Review Form & Print Font Controls **Created:** 2026-02-27 **Branch:** `ae_app_3x_llm` **Priority:** HIGH — first live event is Axonius, NYC, mid-April 2026 **Owner:** Scott Idem / One Sky IT --- ## Context The Events Badges module is mostly complete for navigation and search. Two key pieces of functional UI remain unbuilt and are needed before the first show: 1. **Badge Review Form** — `ae_comp__badge_review_form.svelte` is currently a stub. It needs actual field rendering, edit inputs gated by access level, save/cancel API calls, and display-only sections (QR code, print status, option/ticket checkmarks). 2. **Badge Print Font Controls** — The print page header needs screen-only controls (hidden during `window.print()`) to bump font sizes for the name, professional title, affiliations, and location sections before printing. These only affect the `ae_comp__badge_obj_view.svelte` render — not the page layout/template structural dimensions. Read `documentation/MODULE__AE_Events_Badges.md` for full module context before starting. --- ## MANDATORY: Before You Start 1. Run `ae_describe event_badge` (MCP tool) to confirm which fields actually exist in the DB. Several fields in the spec below may need to be added to `properties_to_save` in `src/lib/ae_events/ae_events__event_badge.ts` if they are not already saved to IDB. 2. Fields to specifically confirm exist in `event_badge` schema: - `pronouns`, `pronouns_override` - `phone`, `phone_override` - `allow_tracking` - `agree_to_tc` - `other_1_code` through `other_8_code` (the "option" fields) - `ticket_1_code` through `ticket_8_code` - `registration_type`, `registration_type_code` - `registration_type_override`, `registration_type_code_override` 3. Run `npx svelte-check` before committing. Baseline is **77 errors** (all pre-existing, none in the badge module files). Do not introduce new errors. 4. Do NOT write to `$ae_loc.edit_mode` from any badge component. This was a critical bug (fixed 2026-02-27). See `documentation/AE__Permissions_and_Security.md`. --- ## TASK 1: Badge Review Form (HIGH PRIORITY) ### File to build `src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_review_form.svelte` This component is already imported and used by `review/+page.svelte`. Props it receives: ```typescript interface Props { event_id: string; event_badge_id: string; lq__event_badge_obj: any; // Svelte 5 store from liveQuery can_edit_fields: string[]; // Which fields this user can edit is_staff: boolean; // True if trusted_access or higher log_lvl?: number; } ``` `can_edit_fields` values: - `['*']` — administrator (all fields) - Array of field names — specific editable fields - `[]` — read-only (shouldn't normally reach this component, but handle it) ### Helper Use a helper derived inside the component: ```typescript function can_edit(field: string): boolean { return can_edit_fields.includes('*') || can_edit_fields.includes(field); } ``` ### Save / Cancel Pattern Follow the Journals module pattern (`src/lib/ae_journals/`). Key points: - Use `import { events_func } from '$lib/ae_events_functions'` - Call `events_func.update_ae_obj__event_badge({ event_badge_id, event_id, data_kv })` - Only send changed fields in `data_kv` (compare against `$lq__event_badge_obj` values) - Show save/cancel buttons only when something has changed (`has_changes` derived) - Show a success/error state briefly after save (1-2 seconds, then reset) - Cancel resets local state back to `$lq__event_badge_obj` values - Use `data-testid="badge-review-save-btn"` and `data-testid="badge-review-cancel-btn"` ### Save API Call ```typescript await events_func.update_ae_obj__event_badge({ api_cfg: $ae_api, // from ae_loc store or passed as prop — check how ae_comp__badge_obj_view.svelte does it event_badge_id: event_badge_id, event_id: event_id, data_kv: { /* only changed fields */ } }); ``` Check `ae_comp__badge_obj_view.svelte` for the existing save pattern — it already works and can be used as reference. --- ### Section 1: Display-Only Status Bar (all access levels) Always show at top of form. Read-only. No edit controls. ``` Print Status: [Not yet printed] OR [Printed 3× — first: Jan 5 2026, last: Jan 5 2026] ``` Use `$lq__event_badge_obj.print_count`, `print_first_datetime`, `print_last_datetime`. Format datetimes with `ae_util.iso_datetime_formatter(dt, 'datetime_iso_12_no_seconds')`. Import `ae_util` from `$lib/ae_utils/ae_utils`. --- ### Section 2: QR Code (all access levels) Display the attendee's badge QR code. This is the same QR code shown on the printed badge itself — scanning it at the badge station triggers automatic badge search and print. **Check the legacy AE Badge version for existing QR generation code.** Look in: - `src/lib/ae_events/` for any QR-related utilities - `ae_comp__badge_obj_view.svelte` — the badge render component almost certainly generates a QR code already for the printed badge. Reuse that logic/component if possible. The QR code value should encode the badge ID or a URL that resolves to the badge. --- ### Section 3: Editable Fields Render each field as: read-only display when `!can_edit(field)`, or an `` / `