Simplify registration flow: mandatory signup redirect, payment emails, payment reminder cron

- 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
This commit is contained in:
2026-03-11 11:08:03 +01:00
parent e59a588a9d
commit 17c6315dad
10 changed files with 399 additions and 523 deletions

View File

@@ -22,24 +22,13 @@ interface PerformerErrors {
interface Props {
onBack: () => void;
onSuccess: (token: string, email: string, name: string) => void;
prefillFirstName?: string;
prefillLastName?: string;
prefillEmail?: string;
isLoggedIn?: boolean;
}
export function PerformerForm({
onBack,
onSuccess,
prefillFirstName = "",
prefillLastName = "",
prefillEmail = "",
isLoggedIn = false,
}: Props) {
export function PerformerForm({ onBack, onSuccess }: Props) {
const [data, setData] = useState({
firstName: prefillFirstName,
lastName: prefillLastName,
email: prefillEmail,
firstName: "",
lastName: "",
email: "",
phone: "",
artForm: "",
experience: "",
@@ -265,15 +254,14 @@ export function PerformerForm({
id="p-email"
name="email"
value={data.email}
onChange={isLoggedIn ? undefined : handleChange}
onBlur={isLoggedIn ? undefined : handleBlur}
readOnly={isLoggedIn}
onChange={handleChange}
onBlur={handleBlur}
placeholder="jouw@email.be"
autoComplete="email"
inputMode="email"
aria-required="true"
aria-invalid={touched.email && !!errors.email}
className={`${inputCls(!!touched.email && !!errors.email)}${isLoggedIn ? "cursor-not-allowed opacity-60" : ""}`}
className={inputCls(!!touched.email && !!errors.email)}
/>
{touched.email && errors.email && (
<span className="text-red-300 text-sm" role="alert">