Files
hope-events/frontend/src/app/register/[eventId]/page.tsx
T
joshuaandClaude Sonnet 5 f0f8d4c242 Fix early-bird price blending and mislabeling; add contact-only events
- Early-bird pricing: RegistrationOption now tracks each purchase as a
  separate price tranche instead of overwriting a single price/quantity
  on repeat purchases, so buying more tickets after a tier expires no
  longer re-prices tickets already bought at the old price. Stock-limit
  checks, total-due calculation, and the Finance report's revenue-by-
  option are all tranche-aware; pages that showed one blended price per
  line now render/total each tranche. Viewing a pending/partially-paid
  registration (dashboard, detail page, or an event's registration
  list) now refreshes stale pricing on the spot instead of only at
  payment time.
- Fixed the "(early bird)" dashboard label incorrectly firing on any
  line priced below the base option price (e.g. a plain cheaper
  variant) — it now checks the real applied-tier flag.
- Added contact-only events (e.g. baptism): no registration/payment
  flow, shown on the public site with a "Contact us" popup instead of
  a Register button. Configurable via the admin event wizard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 17:26:35 +02:00

37 lines
1.3 KiB
TypeScript

import { notFound, redirect } from "next/navigation";
import { Navbar } from "@/components/layout/Navbar";
import { Footer } from "@/components/layout/Footer";
import { apiFetch, ApiError } from "@/lib/api";
import RegisterForm from "./RegisterForm";
export const revalidate = 60;
export default async function RegisterPage({ params }: { params: Promise<{ eventId: string }> }) {
const { eventId } = await params;
let event: any;
try {
// Fetched server-side (same pattern as /events/[id]) so the form's content is part of
// the initial HTML instead of showing a loading skeleton after a client-side fetch.
event = await apiFetch<any>(`/api/events/${eventId}`, { nextOptions: { next: { revalidate } } });
} catch (e) {
if (e instanceof ApiError && e.status === 404) notFound();
throw e;
}
// Contact-only events (e.g. baptism) have no registration flow — bounce a stale/direct
// link back to the event detail page, which renders the Contact affordance instead.
if (event.requiresRegistration === false) {
redirect(`/events/${eventId}`);
}
return (
<div className="min-h-screen flex flex-col">
<Navbar />
<main className="flex-1 p-6 max-w-2xl mx-auto w-full">
<RegisterForm event={event} />
</main>
<Footer />
</div>
);
}