feat: implement useUrlState hook for managing URL-based state in admin pages
- Refactor multiple admin pages (BlogsPage, ClinicsPage, DoctorsPage, etc.) to utilize the new useUrlState hook for managing pagination, search, and filter states via URL. - Ensure that the state persists in the URL, allowing users to return to the same state when navigating back from detail pages. - Update relevant components to handle state changes appropriately and maintain clean URLs by removing default values. - Add SlotPicker component for selecting appointment slots based on availability. - Create tests for useUrlState to validate its functionality and ensure correct behavior when interacting with the URL. - Update API documentation to reflect changes in appointment creation and slot selection processes.
This commit is contained in:
@@ -39,11 +39,38 @@ const toEpoch = (isoDate: string, time: string) => tehranWallClockToUnix(isoDate
|
||||
*/
|
||||
export async function findRecordUuid(mobile: string): Promise<string | null> {
|
||||
const res: any = await api.get(
|
||||
`/api/v1/patient?search=${encodeURIComponent(mobile)}&limit=1`,
|
||||
`/api/v1/patients?search=${encodeURIComponent(mobile)}&limit=1`,
|
||||
);
|
||||
return res?.data?.[0]?.uuid ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* پروندهٔ بیمارِ یک نوبت — اگر هنوز ساخته نشده باشد، از روی خودِ نوبت ساخته میشود.
|
||||
* «ثبت سرویس» روی نوبتی که صاحبش هنوز پرونده ندارد نباید بنبست باشد؛ ساخت پرونده
|
||||
* روی سرور idempotent است و پروندهٔ موجود را برمیگرداند.
|
||||
*/
|
||||
export async function ensureRecordUuid(appointment: {
|
||||
patient_mobile?: string | null;
|
||||
patient_name?: string | null;
|
||||
patient_national_code?: string | null;
|
||||
}): Promise<string | null> {
|
||||
const mobile = (appointment.patient_mobile ?? "").trim();
|
||||
if (mobile === "") return null;
|
||||
|
||||
const found = await findRecordUuid(mobile);
|
||||
if (found) return found;
|
||||
|
||||
const res: any = await api.post("/api/v1/patient", {
|
||||
mobile,
|
||||
name: (appointment.patient_name ?? "").trim(),
|
||||
...(appointment.patient_national_code
|
||||
? { national_code: appointment.patient_national_code }
|
||||
: {}),
|
||||
});
|
||||
|
||||
return res?.data?.uuid ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* «شارژ کیف پول» accent link (appointment create/edit forms) — deep-links the
|
||||
* patient's wallet tab, where the manual top-up modal lives.
|
||||
@@ -120,14 +147,14 @@ export default function AppointmentActionsMenu({
|
||||
const goToServiceRegistration = async () => {
|
||||
setOpen(false);
|
||||
try {
|
||||
const recordUuid = await findRecordUuid(appointment.patient_mobile);
|
||||
const recordUuid = await ensureRecordUuid(appointment);
|
||||
if (!recordUuid) {
|
||||
toast.error("پروندهای برای این بیمار یافت نشد");
|
||||
toast.error("این نوبت شماره تماس ندارد؛ ابتدا نوبت را ویرایش کنید");
|
||||
return;
|
||||
}
|
||||
navigate(`/admin/patients/${recordUuid}/session/new`);
|
||||
} catch {
|
||||
toast.error("خطا در یافتن پرونده بیمار");
|
||||
} catch (e: any) {
|
||||
toast.error(e?.message || "خطا در یافتن پرونده بیمار");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -672,7 +699,7 @@ export function ReplaceAppointmentModal({
|
||||
queryKey: ["replace-patients", patientSearch],
|
||||
queryFn: () =>
|
||||
api.get(
|
||||
`/api/v1/patient?search=${encodeURIComponent(patientSearch)}&limit=10`,
|
||||
`/api/v1/patients?search=${encodeURIComponent(patientSearch)}&limit=10`,
|
||||
),
|
||||
enabled: patientSearch.trim().length >= 2,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user