feat: Implement resource-based appointment booking flow

- Updated DoctorPage component to accept bookingResources prop for appointment list.
- Added serviceQuery function to serialize service item UUIDs for API requests.
- Introduced new API endpoints for fetching booking resources and resource slots.
- Enhanced tests for new resource-based booking functionality, including resource selection and service availability.
- Created ResourceSelect component for selecting appointment types, including doctor and resource options.
- Updated appointment submission logic to include resource_uuid in payload when applicable.
- Ensured UI reflects changes in booking flow without disrupting existing doctor-centric experience.
This commit is contained in:
hamed
2026-08-09 10:45:52 +03:30
parent 1668ef8890
commit 54bebbd41a
23 changed files with 1094 additions and 32 deletions
+16 -6
View File
@@ -21,7 +21,7 @@ function gregorianMonthsOf(jalaliMonth) {
});
}
function DatePicker({ setDate, clinicUuid = null }) {
function DatePicker({ setDate, clinicUuid = null, resourceUuid = null, selectedServiceUuids = [] }) {
const params = useParams();
const doctorUuid = params?.doctorId;
@@ -36,15 +36,20 @@ function DatePicker({ setDate, clinicUuid = null }) {
// هر محل، روزهای غیرفعال و وضعیت نوبت‌دهی آنلاین خودش را دارد؛ کش ماه‌ها باید
// با تعویض محل دور ریخته شود وگرنه تقویم محل قبلی باقی می‌ماند.
//
// منبع هم همین‌طور: تقویم هر دستگاه مالِ خودش است، و مدتِ سرویس‌های انتخاب‌شده
// تعیین می‌کند کدام روز جا دارد — پس تغییر هرکدام یعنی کشِ باطل.
const serviceKey = selectedServiceUuids.join(",");
useEffect(() => {
loadedMonths.current = new Set();
setDisabledSet(new Set());
setOnlineEnabled(true);
setAutoSelected(false);
}, [clinicUuid]);
}, [clinicUuid, resourceUuid, serviceKey]);
useEffect(() => {
if (!doctorUuid) return;
if (!doctorUuid && !resourceUuid) return;
const targets = [
...gregorianMonthsOf(baseMonth),
@@ -55,8 +60,13 @@ function DatePicker({ setDate, clinicUuid = null }) {
targets.forEach(({ year, month }) => {
loadedMonths.current.add(`${year}-${month}`);
request
.getMonthAvailability(doctorUuid, year, month, clinicUuid)
// منبع پرچمِ `online_booking_enabled` ندارد — آن روی برنامهٔ هفتگیِ پزشک است.
// نبودِ فیلد یعنی «روشن»، و شرطِ پایین‌تر فقط با `false` صریح واکنش نشان می‌دهد.
const req = resourceUuid
? request.getResourceMonthAvailability(resourceUuid, year, month, selectedServiceUuids)
: request.getMonthAvailability(doctorUuid, year, month, clinicUuid);
req
.then((res) => {
const data = res?.data ?? {};
if (data.online_booking_enabled === false) setOnlineEnabled(false);
@@ -73,7 +83,7 @@ function DatePicker({ setDate, clinicUuid = null }) {
loadedMonths.current.delete(`${year}-${month}`);
});
});
}, [doctorUuid, baseMonth, clinicUuid]);
}, [doctorUuid, baseMonth, clinicUuid, resourceUuid, serviceKey]);
const isDisabled = (date) => {
const day = moment(date).startOf("day");