Files
nobat724_front/app/component/date/dateTime/index.js
T
hamed 54bebbd41a 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.
2026-08-09 10:45:52 +03:30

127 lines
4.0 KiB
JavaScript

"use client";
import { useEffect, useState } from "react";
import moment from "moment-jalaali";
import Hours from "./hours";
import Tabs from "../../Tabs";
import { request } from "@/services/response";
import SendAppo from "./SendAppo";
import { adaptSlots, adaptServiceSlots, hasAvailable } from "@/lib/appointmentSlots";
function DateTime({
date,
doctor,
setStep,
setSelectedSlot,
setSelectedDate,
serviceMode = false,
selectedServiceUuids = [],
clinicUuid = null,
resourceUuid = null,
selectedLocation = null,
}) {
const [value, setValue] = useState(0);
const [hour, setHour] = useState();
const [appo, setAppo] = useState("تاریخ مورد نظرتان را انتخاب کنید.");
const sessions = Array.isArray(appo) ? appo : [];
const listTab = sessions.map((s) => s.label);
const currentSlots = sessions[value]?.slots ?? [];
const handleChange = (event, newValue) => {
setHour();
setValue(newValue);
};
// آدرس از محل انتخاب‌شده می‌آید، نه از doctor.address: در محیط کلینیک ممکن است
// آدرس اصلاً در فهرست آدرس‌های شخصی پزشک نباشد.
const locationAddress =
selectedLocation?.address ??
(hour?.location_id
? doctor?.address?.find((a) => String(a.id) === String(hour.location_id))?.address ?? null
: null);
useEffect(() => {
if (!date || !doctor?.uuid) return;
if (serviceMode && selectedServiceUuids.length === 0) return;
setAppo("loading");
setHour();
const dateStr = moment.unix(date).format("YYYY-MM-DD");
// منبع تقویم خودش را دارد، پس زمان‌هایش از اندپوینت خودش می‌آید نه از برنامهٔ
// هفتگی پزشک. شکل پاسخ همان `start_times` است، پس adapter مشترک می‌ماند.
const req = resourceUuid
? request
.getResourceSlots(resourceUuid, dateStr, selectedServiceUuids)
.then(adaptServiceSlots)
: serviceMode
? request
.getServiceSlots(doctor.uuid, dateStr, selectedServiceUuids, clinicUuid)
.then(adaptServiceSlots)
: request.getAppointmentSlots(doctor.uuid, dateStr, clinicUuid).then(adaptSlots);
req
.then((parsed) => {
if (!parsed.length) {
setAppo("در حال حاضر، نوبتی برای این روز موجود نمی‌باشد.");
setValue(0);
return;
}
setAppo(parsed);
const firstAvailable = parsed.findIndex((s) => hasAvailable(s.slots));
setValue(firstAvailable >= 0 ? firstAvailable : 0);
})
.catch(() => {
setAppo("در حال حاضر، نوبتی برای این روز موجود نمی‌باشد.");
setValue(0);
});
}, [date, doctor?.uuid, serviceMode, selectedServiceUuids, clinicUuid, resourceUuid]);
return (
<div className="w-full">
{sessions.length > 1 && (
<Tabs
isSm={sessions.length === 2}
style={{
".MuiTabs-indicator": {
height: "4px",
borderRadius: "8px",
background: "#F17732",
},
"& .MuiTabs-flexContainer": {
borderBottom: "2px solid #EFEFEF",
marginBottom: "1px",
},
"& .mui-11pdt05-MuiButtonBase-root-MuiTab-root.Mui-selected": {
color: "#F17732 !important",
},
"& .MuiButtonBase-root.Mui-selected": {
color: "#F17732 !important",
},
}}
value={value}
listTab={listTab}
handleChange={handleChange}
/>
)}
<Hours
appo={appo}
slots={currentSlots}
hour={hour}
setHour={setHour}
locationAddress={locationAddress}
/>
<SendAppo
hour={hour}
setStep={setStep}
setSelectedSlot={setSelectedSlot}
date={date}
setSelectedDate={setSelectedDate}
/>
</div>
);
}
export default DateTime;