165 lines
4.2 KiB
TypeScript
165 lines
4.2 KiB
TypeScript
import { useState } from "react";
|
|
|
|
interface GiftSelectorProps {
|
|
value: number;
|
|
onChange: (cents: number) => void;
|
|
id?: string;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
const PRESET_AMOUNTS = [
|
|
{ label: "€5", cents: 500 },
|
|
{ label: "€10", cents: 1000 },
|
|
{ label: "€25", cents: 2500 },
|
|
{ label: "€50", cents: 5000 },
|
|
];
|
|
|
|
export function GiftSelector({
|
|
value,
|
|
onChange,
|
|
id,
|
|
disabled,
|
|
}: GiftSelectorProps) {
|
|
const [customInput, setCustomInput] = useState("");
|
|
const [isCustom, setIsCustom] = useState(false);
|
|
|
|
// Check if current value matches a preset
|
|
const isPresetSelected = PRESET_AMOUNTS.some((p) => p.cents === value);
|
|
const showCustomInput = isCustom || (!isPresetSelected && value > 0);
|
|
|
|
const handlePresetClick = (cents: number) => {
|
|
onChange(cents);
|
|
setIsCustom(false);
|
|
setCustomInput("");
|
|
};
|
|
|
|
const handleCustomInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const input = e.target.value.replace(/[^0-9,]/g, "");
|
|
setCustomInput(input);
|
|
|
|
// Parse euros to cents
|
|
if (input) {
|
|
const normalized = input.replace(",", ".");
|
|
const euros = Number.parseFloat(normalized);
|
|
if (!Number.isNaN(euros) && euros >= 0) {
|
|
onChange(Math.round(euros * 100));
|
|
}
|
|
} else {
|
|
onChange(0);
|
|
}
|
|
};
|
|
|
|
const handleCustomClick = () => {
|
|
setIsCustom(true);
|
|
if (value > 0 && !isPresetSelected) {
|
|
// Keep existing custom value
|
|
setCustomInput((value / 100).toFixed(2).replace(".", ","));
|
|
} else {
|
|
setCustomInput("");
|
|
onChange(0);
|
|
}
|
|
};
|
|
|
|
const handleSkip = () => {
|
|
onChange(0);
|
|
setIsCustom(false);
|
|
setCustomInput("");
|
|
};
|
|
|
|
// When disabled, show read-only view
|
|
if (disabled) {
|
|
return (
|
|
<div id={id} className="space-y-4">
|
|
<p className="mb-3 text-sm text-white/60">
|
|
Deelname is gratis, maar een vrijwillige gift wordt zeer gewaardeerd.
|
|
</p>
|
|
{value > 0 ? (
|
|
<div className="rounded border border-pink-400/30 bg-pink-400/10 px-4 py-3">
|
|
<p className="font-medium text-pink-300">
|
|
€{(value / 100).toFixed(2).replace(".", ",")}
|
|
</p>
|
|
<p className="mt-1 text-pink-300/60 text-xs">
|
|
Gift is verwerkt en kan niet meer worden aangepast
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<p className="text-sm text-white/40">Geen gift toegevoegd</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div id={id} className="space-y-4">
|
|
<p className="mb-3 text-sm text-white/60">
|
|
Deelname is gratis, maar een vrijwillige gift wordt zeer gewaardeerd.
|
|
</p>
|
|
|
|
{/* Preset amounts */}
|
|
<div className="flex flex-wrap gap-2">
|
|
{PRESET_AMOUNTS.map((preset) => (
|
|
<button
|
|
key={preset.cents}
|
|
type="button"
|
|
onClick={() => handlePresetClick(preset.cents)}
|
|
className={`rounded px-4 py-2 font-semibold text-sm transition-all ${
|
|
value === preset.cents
|
|
? "bg-white text-[#214e51]"
|
|
: "border border-white/30 bg-white/5 text-white hover:bg-white/10"
|
|
}`}
|
|
>
|
|
{preset.label}
|
|
</button>
|
|
))}
|
|
<button
|
|
type="button"
|
|
onClick={handleCustomClick}
|
|
className={`rounded px-4 py-2 font-semibold text-sm transition-all ${
|
|
showCustomInput && !isPresetSelected
|
|
? "bg-white text-[#214e51]"
|
|
: "border border-white/30 bg-white/5 text-white hover:bg-white/10"
|
|
}`}
|
|
>
|
|
Anders
|
|
</button>
|
|
</div>
|
|
|
|
{/* Custom amount input */}
|
|
{showCustomInput && (
|
|
<div className="mt-3 flex items-center gap-2">
|
|
<span className="text-lg text-white">€</span>
|
|
<input
|
|
type="text"
|
|
inputMode="decimal"
|
|
placeholder="0,00"
|
|
value={customInput}
|
|
onChange={handleCustomInputChange}
|
|
className="w-24 rounded border border-white/30 bg-white/10 px-3 py-2 text-lg text-white placeholder:text-white/40 focus:border-white/50 focus:outline-none"
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{/* Skip option */}
|
|
{value > 0 && (
|
|
<button
|
|
type="button"
|
|
onClick={handleSkip}
|
|
className="text-sm text-white/50 underline underline-offset-2 hover:text-white/70"
|
|
>
|
|
Liever geen gift
|
|
</button>
|
|
)}
|
|
|
|
{/* Selected amount display */}
|
|
{value > 0 && (
|
|
<p className="text-sm text-white/80">
|
|
Geselecteerd:{" "}
|
|
<span className="font-semibold text-white">
|
|
€{(value / 100).toFixed(2).replace(".", ",")}
|
|
</span>
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|