Files
joshua 37681aec50 Add paginated payment history to user dashboard
Users can now view their own payments (excluding donations) with
server-side pagination (25/page), date range, method, and
payment/refund filters, both on the API and the new client page.
2026-07-23 18:02:53 +02:00
..
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 17:08:28 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00
2026-07-23 15:26:47 +02:00

Hope Events — Frontend

Next.js 15 (App Router) frontend for the Hope Events platform used by Hope Family Church (events.hopehenley.co.za).


Table of Contents

  1. Overview
  2. Tech Stack
  3. Prerequisites
  4. Installation
  5. Environment Variables
  6. Running the App
  7. Project Structure
  8. Pages & Routes
  9. Authentication & Roles
  10. Payment Flow
  11. Notifications
  12. Deployment
  13. Troubleshooting

Overview

The frontend handles:

  • Public event listings and event detail pages
  • User registration, login, and account management
  • Attendee registration and Yoco checkout
  • Ticket viewing and delivery
  • Staff ticket scanning (QR scanner)
  • Supervisor tools: event management, payments, bulk messaging (email + WhatsApp), reports, at-the-door check-in
  • Admin tools: user management, WhatsApp instance management, form builder

Tech Stack

Layer Technology
Framework Next.js 15 (App Router, React 19)
Language TypeScript
Styling Tailwind CSS 3
UI Primitives Radix UI
Forms React Hook Form + Zod
Icons Lucide React
QR Scanning @zxing/browser, react-webcam
QR Generation qrcode
Date handling date-fns, react-day-picker

Prerequisites

  • Node.js 18+
  • npm
  • A running backend API (see ../backend/README.md)

Installation

cd frontend
npm install

Environment Variables

Create frontend/.env.local:

Variable Required Description
NEXT_PUBLIC_API_URL Yes Base URL of the backend API, e.g. https://api.yourdomain.com or http://localhost:5000 for local dev

Organisation name, brand colour, logo, and contact email are now stored in the database and managed via Admin → Site Settings. NEXT_PUBLIC_APP_NAME, NEXT_PUBLIC_ORG_NAME, NEXT_PUBLIC_BRAND_COLOR, and NEXT_PUBLIC_CONTACT_EMAIL are no longer needed and can be removed from your .env.local.


Running the App

# Development (Turbopack)
npm run dev

# Production build + start
npm run build
npm start

# Lint
npm run lint

Project Structure

frontend/src/
├── app/                    # Next.js App Router pages
│   ├── (auth)/             # Login, register, forgot/reset password
│   ├── [redirectUrl]/      # Event alias redirects
│   ├── activate-account/   # Account activation from email link
│   ├── dashboard/
│   │   ├── layout.tsx      # Shared dashboard shell + nav
│   │   ├── admin/          # Admin-only pages
│   │   ├── supervisor/     # Supervisor + admin pages
│   │   ├── staff/          # Staff + above pages
│   │   └── user/           # All authenticated users
│   ├── events/             # Public event listing + detail
│   ├── forms/              # Public form submission
│   ├── legal/              # Privacy policy, terms
│   ├── payment/            # Payment success/failure/cancel
│   ├── register/[eventId]/ # Event registration flow
│   ├── registration/       # Post-registration success
│   ├── reset-password/     # Password reset (token flow)
│   ├── self-service/       # Guest self-service portal
│   ├── set-banner/         # Quick banner editor (supervisor)
│   └── layout.tsx          # Root layout
├── components/             # Shared UI components
├── hooks/                  # Custom React hooks (useAuth, etc.)
└── lib/                    # Utilities (api.ts fetch wrapper, etc.)

Pages & Routes

Public

Route Description
/ Landing page
/events Public event listing — shows "Sold Out" button when all limited-stock options are exhausted; free events show "Register" without a price suffix
/events/[id] Event detail page — sold-out/registration-closed/not-yet-open states; zero-price options display "Free"; tiered low-stock badges (≤ 50 tickets: 20 %; 51200: 15 %; 2011 000: 10 %; 1 000+: 5 %)
/[redirectUrl] Event alias redirect
/register/[eventId] Registration flow — sold-out banner + disabled button when event is fully booked; tiered stock badges; variant qty controls; early-bird notice
/forms Public form submission
/legal/privacy Privacy policy
/legal/terms Terms of service
/lockdown-rules House rules page
/payment/success Yoco checkout success
/payment/failure Yoco checkout failure
/payment/cancel Yoco checkout cancelled
/registration/success Post-registration confirmation
/self-service Guest self-service (find tickets by email)
/activate-account Account activation via email link
/reset-password Password reset (token from email)

Auth

Route Description
/login Login form
/register Sign-up form
/forgot-password Request password reset

User Dashboard — /dashboard/user/

Route Description
/dashboard/user My registrations + tickets overview
/dashboard/user/profile Edit profile, notification preferences
/dashboard/user/pay Pay outstanding balance
/dashboard/user/donate Make a donation
/dashboard/user/forms Complete registration forms
/dashboard/user/reset-password Change password (authenticated)

Staff Dashboard — /dashboard/staff/

Route Description
/dashboard/staff Staff overview
/dashboard/staff/ticket-scanning QR code scanner for check-in
/dashboard/staff/event-tickets All tickets for an event

Supervisor Dashboard — /dashboard/supervisor/

Route Description
/dashboard/supervisor Supervisor overview + quick links
/dashboard/supervisor/events Create/edit/manage events — 6-step wizard (Basic Details, Items & Pricing, Sections, Form, Visibility, Attachments); form builder with up/down reorder, type badges, separate shortcut buttons for statement/heading fields; early-bird tiers with labelled deadline/price inputs; event image file upload with preview; attachments can be staged during creation (uploaded after save)
/dashboard/supervisor/event-options Manage ticket types / options
/dashboard/supervisor/payments View and manage payments
/dashboard/supervisor/manual Manual payment entry
/dashboard/supervisor/manual-registration Register an attendee manually
/dashboard/supervisor/at-the-door At-the-door check-in management
/dashboard/supervisor/email-attendees Bulk email + automations + broadcasts + scheduled
/dashboard/supervisor/whatsapp-attendees Bulk WhatsApp + automations + broadcasts + scheduled
/dashboard/supervisor/reports Generate/download/email reports
/dashboard/supervisor/forms Event form builder and response viewer — three modes: view responses (printable, page-break per submission), fill/edit responses, edit form structure; improved form builder with reorder buttons and type badges
/dashboard/supervisor/sections Manage event sections
/set-banner Quick banner editor

Admin Dashboard — /dashboard/admin/

Route Description
/dashboard/admin Admin overview
/dashboard/admin/users User management — list, inline edit, deactivate, role assignment, per-page selector (10/25/50/100), server-side search/filter by name/email/phone/role/status, "Delete data" button to anonymise a user's personal information
/dashboard/admin/registrations All registrations — filter by event, status, and fuzzy text search; expandable rows showing ticket options and form responses
/dashboard/admin/whatsapp WhatsApp instance management (WAWP)
/dashboard/admin/forms View all form responses (inherits supervisor/forms)
/dashboard/admin/settings Site Settings — organisation details, logo, brand colour, notification emails, SMTP delivery (with test connection; friendly errors + collapsible raw details on failure), legal page content

Setup — /setup

Route Description
/setup First-time setup wizard — shown automatically on a fresh deployment (empty database). Creates the first admin account and initial site settings in three steps: organisation details, admin account, branding. After completion, redirected to login.

Authentication & Roles

Auth state is managed via the useAuth hook (src/hooks/useAuth.ts). The JWT is stored in localStorage and sent as a Bearer token on every API call via src/lib/api.ts (apiFetch).

Role access matrix

Page group user staff supervisor admin
Public pages Yes Yes Yes Yes
/dashboard/user/* Yes Yes Yes Yes
/dashboard/staff/* Yes Yes Yes
/dashboard/supervisor/* Yes Yes
/dashboard/admin/* Yes

Unauthenticated users are redirected to /login. Insufficient-role users see an in-page warning.

Notification preferences

Users set their preference on the profile page:

  • email — email notifications only
  • whatsapp — WhatsApp notifications only
  • both — both channels

The supervisor bulk-messaging pages show preference indicators in user/attendee dropdowns:

  • Indigo badge — email preference matches (email/both) on the email page
  • Green badge — WhatsApp preference matches (whatsapp/both) on the WA page
  • Amber badge — preference mismatch (will still receive message)

A "Select Email/both" or "Select WhatsApp/both" quick-select button is available in each dropdown.


Payment Flow

  1. User registers for a paid event → registration created with status: pending
  2. User clicks "Pay" → calls POST /api/payments/yoco-checkout
  3. Backend returns a Yoco redirectUrl → frontend opens it in a new tab
  4. User pays on Yoco's hosted page → Yoco sends webhook to backend
  5. Backend reconciles payment, updates registration status, generates and emails tickets
  6. User sees /payment/success and tickets appear in their dashboard

Outstanding balances can be paid at any time from /dashboard/user/pay.


Notifications

Bulk Email / WhatsApp (email-attendees, whatsapp-attendees)

Both pages share the same feature set:

  • Attendees tab — send or schedule a message to attendees of a specific event; filter by payment status; templates: custom, payment reminder, event reminder, ticket delivery
  • Automations tab — schedule pre-event (1 week), final reminder (24/48 h), thank-you, and promo messages with smart default timing based on the event's dates
  • Broadcasts tab — send to a selected user list plus ad-hoc email addresses or phone numbers
  • Scheduled tab — view, edit (reschedule / update content), or cancel queued jobs

Mismatch warnings appear when selected users prefer a different channel. Falling back to all attendees if no matching-preference attendees exist.

The attendee selection dropdown is constrained to a fixed width (max-w-xs / w-64 panel) so it does not grow to fill the page on wide screens.


Deployment

  1. Push the frontend/ directory to GitHub
  2. Create a Vercel project pointing to frontend/
  3. Set env var: NEXT_PUBLIC_API_URL=https://your-api.domain.com
  4. Deploy

Self-hosted (Node.js)

npm run build
npm start   # port 3000 by default

Use nginx/Caddy as a reverse proxy.

PM2

pm2 start npm --name hope-events-frontend -- start
pm2 save && pm2 startup

Checklist

  • NEXT_PUBLIC_API_URL set to production backend URL
  • Backend FRONTEND_URL includes this frontend's origin
  • Yoco webhook URL reachable over HTTPS
  • npm run build completes without errors

Troubleshooting

Symptom Fix
4xx/5xx API calls Check NEXT_PUBLIC_API_URL is correct and reachable from the browser
CORS errors Confirm backend FRONTEND_URL includes your frontend origin
Port conflict in dev Next.js auto-selects 3001+ if 3000 is taken — keep NEXT_PUBLIC_API_URL pointing at the backend port
Images not showing Backend must serve /uploads and public/uploads must be writable
Login loop Clear localStorage and re-login; check JWT_SECRET on backend hasn't changed
QR scanner not working Browser requires camera permission; @zxing/browser requires HTTPS in production