Commit Graph
169 Commits
Author SHA1 Message Date
joshuaandClaude Opus 5.5 2d6c840614 Type the reports page and turn lint back on in builds
ReportsV2 gets typed API responses (funnel, feedback summary, coupon
redemptions, cashup audit, consent) and derived rows. Master-order
quantities move into a per-row map, so an option name can no longer
overwrite a fixed column. Consent row types move to src/types. Removes
unused export helpers and state.

With the frontend now at zero lint errors and warnings, next build runs
ESLint again (eslint.ignoreDuringBuilds is gone).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 235da5bf61 Type the at-the-door page and share pricing helpers
Each door panel and modal gets typed props; unused setError/setInfo/
onCreated props are dropped. The current early-bird price helpers move
to src/lib/pricing.ts (shared with manual registration), dead fallbacks
for a legacy registration 'options' field are removed, and the refund
history now shows a refund's reason (stored in its status field) instead
of a 'reason' field that never exists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 f6581eb441 Type payments and user dashboard pages
Moves the duplicated registration-option pricing helper into
src/lib/pricing.ts and drops an unused users list from payments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 0a8788afff Type supervisor forms, manual registration and events pages
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 b560d0d340 Type registrations, email and WhatsApp messaging pages
Adds typed payloads and results for the email/WhatsApp attendee and
broadcast endpoints. The WhatsApp page's messageDirty flag becomes a ref
(it only gated the template effect), and a no-op branch in the email
template effect is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 b2439a781e Type more frontend pages and fix their hook dependencies
Cashup, users, profile, consent, allocations, event options, forms,
event tickets, ticket scanning and manual registration now use real
types. Data loaders are wrapped in useCallback and listed as effect
dependencies. Also adds shared Attendee, Section and form response
types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 545f3d913e Add shared API types and type the smaller frontend pages
Expand src/types with User, Event, EventOption, Registration, Payment,
Ticket, paginated results and dashboard stats, modelled on the Prisma
schema. apiFetch now defaults to unknown instead of any. Dashboard
loaders are wrapped in useCallback so their effects can list them as
dependencies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:01 +02:00
joshuaandClaude Opus 5.5 619b5b9a93 Type caught errors as unknown in the frontend
Replace `catch (e: any)` with `catch (e)` and read the message through a
new errorMessage() helper. ApiError.data gets a real type, and
useDismissingState's setter keeps one identity across renders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:00 +02:00
joshuaandClaude Opus 5.5 958a5a5950 Fix frontend lint: links, unused code, quotes, img elements
- Internal links use next/link instead of <a> (no full page reload).
- Remove dead code: RegisterForm's unreachable Yoco checkout branch, the
  unused AttendeeForms on the registration success page, unused Geist
  fonts, and assorted unused variables and catch bindings.
- Escape quotes in JSX text; replace @ts-ignore in apiFetch with a cast.
- Keep the intentional raw <img> elements (data URLs, runtime API host)
  with a documented lint exception; the event editor uses ApiImage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 11:10:00 +02:00
joshuaandClaude Opus 5.5 f2be3a8b45 Upgrade to Prisma 7 and clear npm audit advisories
- Prisma 5.22 -> 7.10 using the @prisma/adapter-pg driver adapter; the
  datasource URL moves to backend/prisma.config.js. All clients are built
  in src/config/db.js, and index.js reuses the shared client.
- Backend: patch follow-redirects, drop nodemon for `node --watch`, and use
  js-yaml 4 for the Jest coverage loader. npm audit reports 0.
- Frontend: override postcss-selector-parser to 7.1.7 (Tailwind 3 output
  is unchanged). braces has no patched release and stays, build/lint only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 09:58:11 +02:00
joshua ce22f44f7c Merge branch 'fix/mobile-cookie-banner' v1.25.1 2026-10-20 12:47:41 +02:00
joshuaandClaude Opus 5.5 30b567f091 Bump to 1.25.1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:47:36 +02:00
joshuaandClaude Opus 5.5 0b22eca0fb Lift cookie banner and help button above mobile bottom nav
The cookie consent banner was fixed at bottom-0 under the z-50 BottomNav, so
on mobile it was hidden. It now sits above the nav (h-16 + safe-area) and
publishes its height as --cookie-banner-h, which HelpFab adds to its offset
so the banner no longer covers the help button either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:47:13 +02:00
joshua 5529811119 Merge branch 'feat/yoco-settings' v1.25.0 2026-10-20 10:28:57 +02:00
joshuaandClaude Opus 5.5 1f0b2b1425 Bump to 1.25.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:28:53 +02:00
joshuaandClaude Opus 5.5 865a16abe9 Store Yoco secrets in the database; add Yoco settings tab
The Yoco secret key and webhook secret now live in AppSetting (AES-256-GCM
encrypted), with .env as a fallback. A new Site Settings → Yoco tab shows
them masked card-style, registers a webhook with Yoco (storing the secret it
returns) or accepts one entered by hand, and lists/deletes the account's
webhooks. Generic settings endpoints never read or write these keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:28:50 +02:00
joshua 921b94a66a Merge branch 'feat/privacy-transfer-accept' v1.24.0 2026-10-19 18:46:43 +02:00
joshuaandClaude Opus 5.5 b3bfbe486c Bump to 1.24.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:46:25 +02:00
joshuaandClaude Opus 5.5 686616cc18 Require acceptance for ticket transfers; privacy and legal updates
Transfers now send the new holder a link (to the email/phone typed) and
only complete once they accept; they can decline and the sender can
cancel. No response reveals whether contact details belong to an
account, and attendee account links are no longer sent to payers.
Terms of Use and Privacy Policy are updated for all features since
1.12, with a full cookie policy and a "Cookie settings" control. The
/docs route list now covers every mounted route, and account
activation auto-login is fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CP62L9JxHomA36aYP1ekCe
2026-10-19 18:46:15 +02:00
joshua cd42ca375e Merge branch 'feat/impersonate-user' v1.23.0 2026-10-19 18:25:10 +02:00
joshuaandClaude Opus 5.5 ccb4db919a Bump to 1.23.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:25:08 +02:00
joshuaandClaude Opus 5.5 2b453b00e6 Add read-only admin impersonation
Admins (with 2FA) can view the site as a non-admin user for up to 30
minutes, with a required reason and a "Viewing as" banner. It is
strictly read-only: a guard mounted before every route refuses any
write made with an impersonation token, protect/optionalAuth check the
session is live, and GET handlers skip the price-refresh writes. Start,
end, reason and every page/API call (including blocked attempts) are
audited; optional email to the user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CP62L9JxHomA36aYP1ekCe
2026-10-19 18:25:02 +02:00
joshua fb8ce5f86d Merge branch 'feat/funnel-stats' v1.22.0 2026-10-19 18:14:29 +02:00
joshuaandClaude Opus 5.5 4cd89b1a60 Bump to 1.22.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:14:24 +02:00
joshuaandClaude Opus 5.5 cc62f52ab3 Add registration funnel stats
First-party, consent-based funnel tracking: a cookie notice asks once,
and only visitors who allow it get an anonymous visit id. Event page
views and registration starts are tracked from the browser; submit and
paid come from the registration. Adds the Registration funnel report
(conversion per stage, daily trend, by source/device/ticket option), a
conversion tile on the supervisor/admin dashboards, short-link source
tagging, and a daily rollup of raw rows older than 90 days.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CP62L9JxHomA36aYP1ekCe
2026-10-19 18:14:18 +02:00
joshua 238fcd6fd7 Merge branch 'feat/feedback-forms' v1.21.0 2026-10-19 15:28:48 +02:00
joshuaandClaude Opus 5.5 78b64329cc Bump to 1.21.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:28:42 +02:00
joshuaandClaude Opus 5.5 afcc14cbb3 Add post-event feedback forms
A Feedback step in the event wizard builds a survey that is sent at a
chosen time to everyone who checked in (or everyone registered), with
personal links and one reminder after 3 days. Answers can be anonymous.
Adds rating (1-5 stars) and multiple-choice field types, also usable on
attendee forms, and a Feedback summary report with response rate,
average ratings, choice breakdowns, comments and event comparison.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:28:29 +02:00
joshua 1b92fae76c Merge branch 'feat/sponsor-a-spot' v1.20.0 2026-10-19 15:04:40 +02:00
joshuaandClaude Opus 5.5 4c76c77005 Bump to 1.20.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:04:37 +02:00
joshuaandClaude Opus 5.5 93cff6099e Add sponsor a spot
Events can allow sponsorships: a "Sponsor a spot" button lets anyone
(guests included) pay through Yoco for whole spots or a custom amount,
anonymously or with a name and message. Payments land as event
donations in a sponsorship pool that supervisors assign with the
existing donation flow. Adds optional public progress towards a goal,
a sponsor receipt and Automations thank-you, pool columns in the
Donations report, and sponsorship labels/filter in Payments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 15:04:29 +02:00
joshua 7bcaec6284 Merge branch 'feat/room-allocation' v1.19.0 2026-10-19 14:45:09 +02:00
joshuaandClaude Opus 5.5 2f4fd7c040 Bump to 1.19.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:45:06 +02:00
joshuaandClaude Opus 5.5 1516e104df Add rooms & groups allocation
Supervisors can split an event's named attendees into allocation sets
(rooms, small groups, buses) with capacity, gender and leader per group,
using a drag-and-drop board or auto-allocate (keep bookings together or
split them). Adds printable group and master lists (medical view
audited), the group on tickets and in My Events, messaging by group,
a "My groups" page for leaders, and an optional per-event gender
question for named attendees.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:44:58 +02:00
joshua e9588aeba8 Merge branch 'feat/ticket-transfer' v1.18.0 2026-10-19 14:23:34 +02:00
joshuaandClaude Opus 5.5 83df90b531 Bump to 1.18.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:23:31 +02:00
joshuaandClaude Opus 5.5 87ffe3b84b Add ticket transfer
Payers and holders can hand a ticket to someone else before the event.
The new holder gets a new QR code (and an inactive account with an
activation link if they're new); the old code stops working and scans
of it, online or in offline sync, say it was transferred. One place can
be split off a shared group ticket. Transfers can be turned off per
event (supervisors can always transfer from At the door), youth events
need the new holder's own consent, and every transfer is audited.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:23:24 +02:00
joshua 9a4bf51ad4 Merge branch 'feat/offline-scanning' v1.17.0 2026-10-19 14:06:40 +02:00
joshuaandClaude Opus 5.5 d84663f901 Bump to 1.17.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:06:34 +02:00
joshuaandClaude Opus 5.5 be621c49a2 Add offline ticket scanning
Staff can lock a section (or the whole event) to their device, download
its tickets and keep scanning with no connection. Scans are queued in
IndexedDB and synced idempotently when back online; conflicts go into a
sync report for supervisors, who can also force-release a lost device.
The server now validates scan sections and refuses scans in a scope
locked to another device. Adds a web app manifest and a service worker
for the scanner page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 14:06:22 +02:00
joshua edf7c3052b Merge branch 'feat/waitlist' v1.16.0 2026-10-19 13:43:20 +02:00
joshuaandClaude Opus 5.5 f66968768f Bump to 1.16.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:43:16 +02:00
joshuaandClaude Opus 5.5 2166f94247 Add waitlist for sold-out tickets
Events can take a waitlist for sold-out lines. When places free up
(cancellation, smaller booking, higher stock limit) the next person is
offered them with a claim link and the places are held for a set time;
unclaimed offers expire and move on, with optional partial offers. Stock
is now counted in one place (utils/stock.js), including held places,
and manual registrations and booking edits are now stock-checked. Adds a
supervisor waitlist page, My Events waitlists, and the daily summary count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:43:10 +02:00
joshua bae9675485 Merge branch 'feat/parental-consent' v1.15.0 2026-10-19 13:25:02 +02:00
joshuaandClaude Opus 5.5 13fd3a4cbb Bump to 1.15.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:24:57 +02:00
joshuaandClaude Opus 5.5 809b6a11d7 Add parental consent for youth events
Youth events need a name and date of birth for every attendee, and a
parent/guardian's details for under-18s. Parents get an email and
WhatsApp link to a consent page that records the signed name, time, IP,
device and exact consent text; medical and emergency details are stored
encrypted. Tickets are issued but check-in is blocked until consent is
given (supervisor override audited). A daily job sends reminders and
purges medical details after the retention period. Adds a supervisor
consent tracker, consent status and medical list reports, and clears
consent data when an account is anonymised.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 13:24:44 +02:00
joshua f1e0b62c73 Merge branch 'feat/group-tickets' v1.14.0 2026-10-19 12:12:52 +02:00
joshuaandClaude Opus 5.5 72ecf500c8 Bump to 1.14.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:12:44 +02:00
joshuaandClaude Opus 5.5 df0bf09a0e Add group tickets with named attendees
Events can take a name (and optional email/phone) for each main-ticket
place. Each named person gets their own quantity-1 ticket and attendee
form; unnamed places share one ticket. Tickets go to the payer or to each
person, attendees matching one existing account are linked to it, and
the payer can edit names and send form links from My Events. Ticket
generation is now planned per line (utils/attendees.js), free
registrations use the same generator, and guest registration matches
accounts by phone too, refusing conflicting email/phone pairs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:12:33 +02:00
joshua 4b413788ac Merge branch 'feat/coupon-codes' v1.13.0 2026-10-19 11:43:36 +02:00