Files
NextChair/src/features/staff/components/add-stamp-button.tsx
T
2026-09-05 09:32:05 +01:00

118 lines
3.4 KiB
TypeScript

"use client";
import { Stamp } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState, useTransition } from "react";
import { Button } from "@/components/ui/button";
import { Modal } from "@/components/ui/modal";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils/cn";
import { addLoyaltyStampAction } from "../actions/loyalty-actions";
export function AddStampButton({
customerId,
appointmentId,
className,
size = "sm",
}: {
customerId: string;
appointmentId?: string;
className?: string;
size?: "sm" | "md" | "lg";
}) {
const router = useRouter();
const [open, setOpen] = useState(false);
const [amount, setAmount] = useState("1");
const [reason, setReason] = useState("");
const [error, setError] = useState<string | null>(null);
const [result, setResult] = useState<{ rewardCreated?: boolean } | null>(null);
const [isPending, startTransition] = useTransition();
const close = () => {
const shouldRefresh = !!result;
setOpen(false);
setResult(null);
setError(null);
setAmount("1");
setReason("");
if (shouldRefresh) router.refresh();
};
const submit = () => {
const parsed = Number(amount);
if (!Number.isInteger(parsed) || parsed <= 0) {
setError("Enter a positive number of stamps.");
return;
}
setError(null);
startTransition(async () => {
const res = await addLoyaltyStampAction({
customerId,
amount: parsed,
appointmentId,
reason: reason || undefined,
});
if (!res.success) {
setError(res.error ?? "Couldn't add a stamp.");
return;
}
setResult({ rewardCreated: res.rewardCreated });
});
};
return (
<>
<Button
variant="secondary"
size={size}
className={cn("shrink-0", className)}
onClick={() => setOpen(true)}
>
<Stamp className="h-4 w-4" aria-hidden="true" />
Add Loyalty Stamp
</Button>
<Modal open={open} onClose={close} title={result ? "Stamp Added" : "Add Loyalty Stamp"}>
{result ? (
<div className="space-y-4">
<p role="status" className="text-muted text-sm">
The stamp has been recorded on this customer&apos;s loyalty account.
</p>
{result.rewardCreated && (
<p className="border-accent-loyalty/30 bg-accent-loyalty/10 rounded-lg border p-3 text-xs font-medium">
They&apos;ve now reached the stamp threshold — a reward is available.
</p>
)}
<Button className="w-full" onClick={close}>
Done
</Button>
</div>
) : (
<div className="space-y-4">
<Input
label="Stamps to add"
type="number"
min={1}
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<Input
label="Reason (optional)"
placeholder="e.g. Referral bonus"
value={reason}
onChange={(e) => setReason(e.target.value)}
/>
{error && (
<p role="alert" className="text-danger text-sm font-medium">
{error}
</p>
)}
<Button className="w-full" isLoading={isPending} onClick={submit}>
Add Stamp
</Button>
</div>
)}
</Modal>
</>
);
}