3d381944d2
Next.js + Express event management app for Hope Family Church.
318 lines
13 KiB
Markdown
318 lines
13 KiB
Markdown
# 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](#overview)
|
||
2. [Tech Stack](#tech-stack)
|
||
3. [Prerequisites](#prerequisites)
|
||
4. [Installation](#installation)
|
||
5. [Environment Variables](#environment-variables)
|
||
6. [Running the App](#running-the-app)
|
||
7. [Project Structure](#project-structure)
|
||
8. [Pages & Routes](#pages--routes)
|
||
9. [Authentication & Roles](#authentication--roles)
|
||
10. [Payment Flow](#payment-flow)
|
||
11. [Notifications](#notifications)
|
||
12. [Deployment](#deployment)
|
||
13. [Troubleshooting](#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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
# 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 %; 51–200: 15 %; 201–1 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
|
||
|
||
### Vercel (recommended)
|
||
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)
|
||
```bash
|
||
npm run build
|
||
npm start # port 3000 by default
|
||
```
|
||
|
||
Use nginx/Caddy as a reverse proxy.
|
||
|
||
### PM2
|
||
```bash
|
||
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 | |