feat:gifts

This commit is contained in:
2026-03-03 16:26:37 +01:00
parent e7b3d7260f
commit b8cefd373d
10 changed files with 416 additions and 22 deletions

View File

@@ -2,6 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { createFileRoute, Link, useParams } from "@tanstack/react-router";
import { useState } from "react";
import { toast } from "sonner";
import { GiftSelector } from "@/components/registration/GiftSelector";
import { GuestList } from "@/components/registration/GuestList";
import {
calculateDrinkCard,
@@ -123,6 +124,7 @@ interface EditFormProps {
extraQuestions: string | null;
guests: string | null;
paymentStatus: string | null;
giftAmount: number | null;
};
onCancel: () => void;
onSaved: () => void;
@@ -147,6 +149,7 @@ function EditForm({ token, initialData, onCancel, onSaved }: EditFormProps) {
const [formGuests, setFormGuests] = useState<GuestEntry[]>(
parseGuests(initialData.guests),
);
const [giftAmount, setGiftAmount] = useState(initialData.giftAmount ?? 0);
const updateMutation = useMutation({
...orpc.updateRegistration.mutationOptions(),
@@ -191,6 +194,7 @@ function EditForm({ token, initialData, onCancel, onSaved }: EditFormProps) {
phone: g.phone.trim() || undefined,
})),
extraQuestions: formData.extraQuestions.trim() || undefined,
giftAmount,
});
}
@@ -407,6 +411,7 @@ function EditForm({ token, initialData, onCancel, onSaved }: EditFormProps) {
)}
</p>
}
isPaid={isPaid}
/>
)}
@@ -426,6 +431,18 @@ function EditForm({ token, initialData, onCancel, onSaved }: EditFormProps) {
/>
</div>
{/* Gift selector */}
<div className="border-white/10 border-t pt-6">
<h3 className="mb-4 font-['Intro',sans-serif] text-white text-xl">
Vrijwillige Gift
</h3>
<GiftSelector
value={giftAmount}
onChange={setGiftAmount}
disabled={isPaid && (initialData.giftAmount ?? 0) > 0}
/>
</div>
<div className="flex flex-wrap items-center gap-4 pt-4">
<button
type="submit"
@@ -568,8 +585,8 @@ function ManageRegistrationPage() {
)}
</div>
{/* Payment status */}
{!isPerformer && (
{/* Payment status - shown for everyone with pending/extra payment or gift */}
{(data.paymentStatus !== "paid" || (data.giftAmount ?? 0) > 0) && (
<div className="mb-6">
{data.paymentStatus === "paid" ? (
<PaidBadge />
@@ -581,6 +598,15 @@ function ManageRegistrationPage() {
</div>
)}
{/* Gift display */}
{(data.giftAmount ?? 0) > 0 && (
<div className="mb-6">
<div className="inline-flex items-center gap-2 rounded-full border border-pink-400/40 bg-pink-400/10 px-4 py-1.5 font-semibold text-pink-300 text-sm">
<span>Vrijwillige gift: {(data.giftAmount ?? 0) / 100}</span>
</div>
</div>
)}
{/* Registration details */}
<div className="space-y-6 rounded-lg border border-white/20 bg-white/5 p-6 md:p-8">
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
@@ -656,20 +682,23 @@ function ManageRegistrationPage() {
{/* Actions */}
<div className="mt-8 flex flex-wrap items-center gap-4">
{!isPerformer &&
(data.paymentStatus === "pending" ||
data.paymentStatus === "extra_payment_pending") && (
{/* Show pay button if there's something to pay (for watchers: drink card, for performers: gift) */}
{(data.paymentStatus === "pending" ||
data.paymentStatus === "extra_payment_pending") &&
(!isPerformer || (data.giftAmount ?? 0) > 0) && (
<button
type="button"
onClick={() => checkoutMutation.mutate({ token })}
disabled={checkoutMutation.isPending}
className={`px-8 py-3 font-['Intro',sans-serif] text-lg transition-all hover:scale-105 disabled:opacity-50 ${data.paymentStatus === "extra_payment_pending" ? "bg-orange-400 text-white hover:bg-orange-300" : "bg-teal-400 text-[#214e51] hover:bg-teal-300"}`}
className={`px-8 py-3 font-['Intro',sans-serif] text-lg transition-all hover:scale-105 disabled:opacity-50 ${data.paymentStatus === "extra_payment_pending" ? "bg-orange-400 text-white hover:bg-orange-300" : isPerformer ? "bg-pink-400 text-white hover:bg-pink-300" : "bg-teal-400 text-[#214e51] hover:bg-teal-300"}`}
>
{checkoutMutation.isPending
? "Laden..."
: data.paymentStatus === "extra_payment_pending"
? `Extra betalen (€${((data.paymentAmount ?? 0) / 100).toFixed(0)})`
: "Nu betalen"}
: isPerformer
? `Gift betalen (€${((data.giftAmount ?? 0) / 100).toFixed(0)})`
: "Nu betalen"}
</button>
)}
<button