import { useEffect, useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useNavigate, useParams, Link } from 'react-router-dom'; import { ChevronRightIcon } from '@heroicons/react/24/outline'; import { toast } from 'sonner'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import PersianDateInput from '../components/ui/PersianDateInput'; import PriceInput from '../components/ui/PriceInput'; import { WalletChargeLink } from '../components/AppointmentActions'; interface Option { uuid: string; name?: string; full_name?: string } interface AppointmentDetail { uuid: string; slot_start: number; slot_end: number; status: string; version: number; note?: string | null; patient_mobile?: string | null; user?: { uuid: string; mobile: string } | null; deposit_required?: boolean; deposit_amount_rials?: number | null; service_section?: Option | null; service_item?: Option | null; staff?: Option | null; } const isoDate = (ts: number) => { const d = new Date(ts * 1000); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; }; const isoTime = (ts: number) => { const d = new Date(ts * 1000); return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`; }; const toEpoch = (date: string, time: string) => Math.floor(new Date(`${date}T${time || '00:00'}`).getTime() / 1000); /** ویرایش نوبت (Figma edit.pdf) — full-page edit of service specs, timing, deposit, status and notes. */ export default function AppointmentEditPage() { const { uuid = '' } = useParams(); const navigate = useNavigate(); const qc = useQueryClient(); const { data, isLoading } = useQuery>({ queryKey: ['appointment-edit', uuid], queryFn: () => api.get(`/api/v1/appointment/${uuid}`), enabled: !!uuid, }); const a = data?.data?.data; const [sectionUuid, setSectionUuid] = useState(''); const [itemUuid, setItemUuid] = useState(''); const [staffUuid, setStaffUuid] = useState(''); const [date, setDate] = useState(''); const [start, setStart] = useState(''); const [end, setEnd] = useState(''); const [depositRequired, setDepositRequired] = useState(false); const [depositRials, setDepositRials] = useState(0); const [status, setStatus] = useState(''); const [note, setNote] = useState(''); // hydrate once the appointment arrives useEffect(() => { if (!a) return; setSectionUuid(a.service_section?.uuid ?? ''); setItemUuid(a.service_item?.uuid ?? ''); setStaffUuid(a.staff?.uuid ?? ''); setDate(isoDate(a.slot_start)); setStart(isoTime(a.slot_start)); setEnd(isoTime(a.slot_end)); setDepositRequired(!!a.deposit_required); setDepositRials(a.deposit_amount_rials ?? 0); setStatus(a.status); setNote(a.note ?? ''); }, [a]); const sectionsQ = useQuery>({ queryKey: ['service-sections'], queryFn: () => api.get('/api/v1/service-sections') }); const itemsQ = useQuery>({ queryKey: ['service-items', sectionUuid], queryFn: () => api.get(`/api/v1/service-items/${sectionUuid}`), enabled: !!sectionUuid, }); const staffQ = useQuery>({ queryKey: ['staff-list'], queryFn: () => api.get('/api/v1/staff') }); const save = useMutation({ mutationFn: () => api.patch(`/api/v1/appointment/${uuid}`, { slot_start: toEpoch(date, start), slot_end: toEpoch(date, end), service_section_uuid: sectionUuid, service_item_uuid: itemUuid, staff_uuid: staffUuid, deposit_required: depositRequired, deposit_amount_rials: depositRequired ? depositRials : null, note, ...(status !== a?.status ? { status } : {}), version: a?.version, }), onSuccess: () => { qc.invalidateQueries({ queryKey: ['appointments'] }); toast.success('نوبت به‌روزرسانی شد'); navigate('/admin/appointments'); }, onError: (e: any) => toast.error(e.message || 'خطا در ذخیره اطلاعات'), }); const label = { fontSize: 12.5, color: 'var(--text-3)' } as const; const sel = { width: '100%', height: 38, borderRadius: 'var(--r-sm)', border: '1px solid var(--border)', background: 'var(--surface)', fontSize: 13, fontFamily: 'inherit', padding: '0 10px' } as const; if (isLoading || !a) return
در حال بارگذاری...
; const statusOptions: [string, string][] = [ ['pending', 'ثبت شده'], ['confirmed', 'قطعی شده'], ['following_up', 'در حال پیگیری'], ['salon', 'سالن'], ['completed', 'ویزیت شده'], ['cancelled_by_doctor', 'لغو شده'], ]; return (
بازگشت
مشخصات سرویس:
زمان نوبت:
setStart(e.target.value)} dir="ltr" />
setEnd(e.target.value)} dir="ltr" />
بیعانه:
{depositRequired && ( <>
)}