- 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.
127 lines
4.0 KiB
JavaScript
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;
|