- 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.
214 lines
6.1 KiB
JavaScript
214 lines
6.1 KiB
JavaScript
import Date from "./date";
|
||
import ServiceSelect from "./service";
|
||
import ResourceSelect from "./resource";
|
||
import LocationSelect from "./location/LocationSelect";
|
||
|
||
// Components
|
||
import Content from "./Content";
|
||
import Layout from "@/components/layout";
|
||
import Paying from "@/components/appointment/paying";
|
||
import Detail from "@/components/appointment/detail";
|
||
import FailedPay from "@/components/appointment/failedPay";
|
||
import SuccessPay from "@/components/appointment/successPay";
|
||
import LogInPage from "@/components/register/LogInPage";
|
||
import VerificationPage from "@/components/register/verificationPage";
|
||
import LayoutRegister from "@/components/register/LayoutRegister";
|
||
|
||
function Container({
|
||
step,
|
||
data,
|
||
doctor,
|
||
setData,
|
||
setStep,
|
||
prevData,
|
||
matchedCity,
|
||
isForAnother,
|
||
setIsForAnother,
|
||
disabledDates,
|
||
// Login states
|
||
num,
|
||
setNum,
|
||
uuid,
|
||
setUuid,
|
||
isSendMsg,
|
||
setIsSendMsg,
|
||
// Appointment slot states
|
||
selectedSlot,
|
||
setSelectedSlot,
|
||
selectedDate,
|
||
setSelectedDate,
|
||
appointmentId,
|
||
setAppointmentId,
|
||
appointmentExpiresAt,
|
||
setAppointmentExpiresAt,
|
||
// Service-based booking
|
||
bookingMode,
|
||
bookingServices,
|
||
selectedServiceUuids,
|
||
setSelectedServiceUuids,
|
||
// Booking location (مطب شخصی / کلینیک)
|
||
bookingLocations,
|
||
selectedLocation,
|
||
locationConfirmed,
|
||
changeLocation,
|
||
reopenLocationChoice,
|
||
onDateChange,
|
||
selectedClosedOnDate,
|
||
// نوبتدهی منبعمحور (دستگاه / اتاق / یونیت)
|
||
resources = [],
|
||
selectedResource = null,
|
||
resourceStepNeeded = false,
|
||
changeResource,
|
||
reopenResourceChoice,
|
||
}) {
|
||
const serviceMode = bookingMode === "service";
|
||
const multiLocation = bookingLocations.length > 1;
|
||
const resourceUuid = selectedResource?.uuid ?? null;
|
||
|
||
// محیطِ رزرو از خودِ منبع خوانده میشود وقتی منبعی انتخاب شده: پزشکِ بدون برنامهٔ
|
||
// هفتگی هیچ محلی ندارد که `clinic_uuid` از آن بیاید، ولی دستگاهش محیطش را میداند.
|
||
const clinicUuid = selectedResource
|
||
? selectedResource.clinic_uuid ?? null
|
||
: selectedLocation?.clinic_uuid ?? null;
|
||
|
||
// «محل ندارد» دیگر به معنی «نوبتدهی ندارد» نیست: منبع تقویم خودش را دارد، پس پزشکی
|
||
// که برنامهٔ هفتگی ندارد ولی دستگاهش قابل رزرو است باید به مرحلهٔ منبع برسد.
|
||
const noBookingAtAll = bookingLocations.length === 0 && resources.length === 0;
|
||
|
||
let dateStep;
|
||
if (noBookingAtAll) {
|
||
dateStep = (
|
||
<p className="w-full max-w-[520px] mx-auto py-[40px] text-center text-[14px] text-[#7A7A7A]">
|
||
نوبتدهی آنلاین برای این پزشک فعال نیست.
|
||
</p>
|
||
);
|
||
} else if (multiLocation && !locationConfirmed) {
|
||
dateStep = (
|
||
<LocationSelect
|
||
locations={bookingLocations}
|
||
selected={selectedLocation}
|
||
onSelect={changeLocation}
|
||
/>
|
||
);
|
||
} else if (resourceStepNeeded) {
|
||
dateStep = (
|
||
<ResourceSelect
|
||
resources={resources}
|
||
selected={selectedResource}
|
||
onSelect={changeResource}
|
||
allowDoctorOption={bookingLocations.length > 0}
|
||
/>
|
||
);
|
||
} else if (serviceMode && selectedServiceUuids.length === 0) {
|
||
dateStep = (
|
||
<ServiceSelect
|
||
services={bookingServices}
|
||
onContinue={(uuids) => setSelectedServiceUuids(uuids)}
|
||
/>
|
||
);
|
||
} else {
|
||
dateStep = (
|
||
<Date
|
||
doctor={doctor}
|
||
setStep={setStep}
|
||
disabledDates={disabledDates}
|
||
setSelectedSlot={setSelectedSlot}
|
||
setSelectedDate={setSelectedDate}
|
||
serviceMode={serviceMode}
|
||
selectedServiceUuids={selectedServiceUuids}
|
||
onChangeService={() => setSelectedServiceUuids([])}
|
||
selectedLocation={selectedLocation}
|
||
clinicUuid={clinicUuid}
|
||
resourceUuid={resourceUuid}
|
||
onChangeLocation={multiLocation ? reopenLocationChoice : null}
|
||
onChangeResource={resources.length > 0 ? reopenResourceChoice : null}
|
||
onDateChange={onDateChange}
|
||
closedOnDate={selectedClosedOnDate}
|
||
/>
|
||
);
|
||
}
|
||
|
||
|
||
const elements = [
|
||
dateStep,
|
||
<LogInPage
|
||
num={num}
|
||
setNum={setNum}
|
||
setUuid={setUuid}
|
||
setStep={setStep}
|
||
setIsSendMsg={setIsSendMsg}
|
||
matchedCity={matchedCity}
|
||
/>,
|
||
<VerificationPage
|
||
num={num}
|
||
uuid={uuid}
|
||
setStep={setStep}
|
||
setUuid={setUuid}
|
||
isSendMsg={isSendMsg}
|
||
setIsSendMsg={setIsSendMsg}
|
||
link={false}
|
||
/>,
|
||
<Detail
|
||
data={data}
|
||
setStep={setStep}
|
||
setData={setData}
|
||
prevData={prevData}
|
||
isForAnother={isForAnother}
|
||
setIsForAnother={setIsForAnother}
|
||
doctor={doctor}
|
||
selectedSlot={selectedSlot}
|
||
selectedDate={selectedDate}
|
||
setAppointmentId={setAppointmentId}
|
||
setAppointmentExpiresAt={setAppointmentExpiresAt}
|
||
selectedServiceUuids={selectedServiceUuids}
|
||
clinicUuid={clinicUuid}
|
||
resourceUuid={resourceUuid}
|
||
/>,
|
||
<Paying
|
||
setStep={setStep}
|
||
appointmentId={appointmentId}
|
||
expiresAt={appointmentExpiresAt}
|
||
doctor={doctor}
|
||
data={data}
|
||
isForAnother={isForAnother}
|
||
selectedSlot={selectedSlot}
|
||
selectedDate={selectedDate}
|
||
/>,
|
||
<SuccessPay setStep={setStep} />,
|
||
<FailedPay setStep={setStep} />,
|
||
];
|
||
|
||
return (
|
||
<>
|
||
{step === 1 || step === 2 ? (
|
||
<LayoutRegister matchedCity={matchedCity}>
|
||
{elements[step]}
|
||
</LayoutRegister>
|
||
) : (
|
||
<Layout
|
||
title="رزرو"
|
||
name="booking"
|
||
disableFooter={step > 4}
|
||
matchedCity={matchedCity}
|
||
paddingBottom="pb-[80px]"
|
||
>
|
||
<Content
|
||
disableSide={step === 5 || step === 6}
|
||
isFirst={step === 0}
|
||
setStep={setStep}
|
||
doctor={doctor}
|
||
step={step}
|
||
selectedSlot={selectedSlot}
|
||
selectedDate={selectedDate}
|
||
selectedLocation={selectedLocation}
|
||
>
|
||
{elements[step]}
|
||
</Content>
|
||
</Layout>
|
||
)}
|
||
</>
|
||
);
|
||
}
|
||
|
||
export default Container;
|