- EventRegistrationForm/WatcherForm/PerformerForm: remove session/login nudge/SuccessScreen; both roles redirect to /login?signup=1&email=<email>&next=/account after submit - SuccessScreen.tsx deleted (no longer used) - account.tsx: add 'Betaal nu' CTA via checkoutMutation (shown when watcher + paymentStatus pending) - DB schema: add paymentReminderSentAt column to registration table - Migration: 0008_payment_reminder_sent_at.sql - email.ts: update registrationConfirmationHtml / sendConfirmationEmail with signupUrl param; add sendPaymentReminderEmail and sendPaymentConfirmationEmail functions - routers/index.ts: wire payment reminder into runSendReminders() — queries watchers with paymentStatus pending, paymentReminderSentAt IS NULL, createdAt <= now-3days - mollie.ts webhook: call sendPaymentConfirmationEmail after marking registration paid
108 lines
2.7 KiB
TypeScript
108 lines
2.7 KiB
TypeScript
import confetti from "canvas-confetti";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { CountdownBanner } from "@/components/homepage/CountdownBanner";
|
|
import { PerformerForm } from "@/components/registration/PerformerForm";
|
|
import { TypeSelector } from "@/components/registration/TypeSelector";
|
|
import { WatcherForm } from "@/components/registration/WatcherForm";
|
|
import { useRegistrationOpen } from "@/lib/useRegistrationOpen";
|
|
|
|
function fireConfetti() {
|
|
const colors = ["#d82560", "#52979b", "#d09035", "#214e51", "#ffffff"];
|
|
|
|
confetti({
|
|
particleCount: 120,
|
|
spread: 80,
|
|
origin: { x: 0.3, y: 0.6 },
|
|
colors,
|
|
});
|
|
setTimeout(() => {
|
|
confetti({
|
|
particleCount: 120,
|
|
spread: 80,
|
|
origin: { x: 0.7, y: 0.6 },
|
|
colors,
|
|
});
|
|
}, 200);
|
|
setTimeout(() => {
|
|
confetti({
|
|
particleCount: 80,
|
|
spread: 100,
|
|
origin: { x: 0.5, y: 0.5 },
|
|
colors,
|
|
});
|
|
}, 400);
|
|
}
|
|
|
|
type RegistrationType = "performer" | "watcher";
|
|
|
|
function redirectToSignup(email: string) {
|
|
const params = new URLSearchParams({
|
|
signup: "1",
|
|
email,
|
|
next: "/account",
|
|
});
|
|
window.location.href = `/login?${params.toString()}`;
|
|
}
|
|
|
|
export default function EventRegistrationForm() {
|
|
const { isOpen } = useRegistrationOpen();
|
|
const confettiFired = useRef(false);
|
|
|
|
useEffect(() => {
|
|
if (isOpen && !confettiFired.current) {
|
|
confettiFired.current = true;
|
|
fireConfetti();
|
|
}
|
|
}, [isOpen]);
|
|
|
|
const [selectedType, setSelectedType] = useState<RegistrationType | null>(
|
|
null,
|
|
);
|
|
|
|
if (!isOpen) {
|
|
return (
|
|
<section
|
|
id="registration"
|
|
className="relative z-30 w-full bg-[#214e51]/96 px-6 py-16 md:px-12"
|
|
>
|
|
<div className="mx-auto w-full max-w-6xl">
|
|
<CountdownBanner />
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<section
|
|
id="registration"
|
|
className="relative z-30 w-full bg-[#214e51]/96 px-6 py-16 md:px-12"
|
|
>
|
|
<div className="mx-auto w-full max-w-6xl">
|
|
<h2 className="mb-2 font-['Intro',sans-serif] text-3xl text-white md:text-4xl">
|
|
Schrijf je nu in!
|
|
</h2>
|
|
<p className="mb-2 max-w-3xl text-lg text-white/80 md:text-xl">
|
|
De Kunstenkamp jaarwerking organiseert een Open Mic
|
|
</p>
|
|
<p className="mb-8 max-w-3xl text-lg text-white/80 md:text-xl">
|
|
Doe je mee of kom je kijken? Kies je rol en vul het formulier in.
|
|
</p>
|
|
|
|
{!selectedType && <TypeSelector onSelect={setSelectedType} />}
|
|
{selectedType === "performer" && (
|
|
<PerformerForm
|
|
onBack={() => setSelectedType(null)}
|
|
onSuccess={(_token, email, _name) => redirectToSignup(email)}
|
|
/>
|
|
)}
|
|
{selectedType === "watcher" && (
|
|
<WatcherForm
|
|
onBack={() => setSelectedType(null)}
|
|
onSuccess={(_token, email, _name) => redirectToSignup(email)}
|
|
/>
|
|
)}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|