TorbatYar/frontend/modules/beauty/components/ReceptionAppointmentRow.tsx
Mortezakoohjani d579d0b142 feat(loyalty): add Loyalty Platform Frontend module
Add frontend/modules/loyalty with types, API client, design system, feature pages and thin App Router routes under app/loyalty/. BFF proxy at app/api/loyalty/. Include loyalty frontend docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 10:50:55 +03:30

83 lines
2.5 KiB
TypeScript

"use client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { beautyBusinessApi, type Appointment } from "@/modules/beauty/services/beauty-business-api";
import { useTenantId } from "@/hooks/useTenantId";
import { Button } from "@/components/ds";
import { AppointmentCard } from "@/modules/beauty/design-system";
type ActionKind = "confirm" | "check-in" | "complete" | "cancel" | "no-show";
export function ReceptionAppointmentRow({
appointment,
staffName,
serviceName,
actions,
queryKey,
}: {
appointment: Appointment;
staffName?: string;
serviceName?: string;
actions: ActionKind[];
queryKey: string[];
}) {
const { tenantId } = useTenantId();
const qc = useQueryClient();
const mutation = useMutation({
mutationFn: (kind: ActionKind) => {
const body = { version: appointment.version };
switch (kind) {
case "confirm":
return beautyBusinessApi.appointments.confirm(tenantId!, appointment.id, body);
case "check-in":
return beautyBusinessApi.appointments.checkIn(tenantId!, appointment.id, body);
case "complete":
return beautyBusinessApi.appointments.complete(tenantId!, appointment.id, body);
case "cancel":
return beautyBusinessApi.appointments.cancel(tenantId!, appointment.id, body);
case "no-show":
return beautyBusinessApi.appointments.noShow(tenantId!, appointment.id, body);
}
},
onSuccess: async () => {
toast.success("انجام شد");
await qc.invalidateQueries({ queryKey });
},
onError: (e: Error) => toast.error(e.message),
});
const labels: Record<ActionKind, string> = {
confirm: "تأیید",
"check-in": "پذیرش",
complete: "تکمیل",
cancel: "لغو",
"no-show": "عدم حضور",
};
return (
<AppointmentCard
appointment={appointment}
staffName={staffName}
serviceName={serviceName}
actions={
<div className="flex flex-wrap gap-1">
{actions.map((a) => (
<Button
key={a}
type="button"
size="sm"
variant={a === "cancel" ? "outline" : "secondary"}
disabled={mutation.isPending}
onClick={() => mutation.mutate(a)}
>
{labels[a]}
</Button>
))}
</div>
}
/>
);
}