The service picker summed duration_minutes itself while the backend already returns total_duration_minutes. Two sources of truth: when the formula changes to solo/additional minutes, the site would keep showing the old number and the patient would see a duration that does not match their appointment. The picker runs before the date step and appointment-service-slots needs a date, so it is called with today. total_duration_minutes does not depend on the date — the backend computes it before touching that day's shifts, so the number is right even when today is closed and start_times comes back empty. The label reads "مدت تقریبی" until the server number arrives, then "مدت کل". A missing field or a failed request falls back to the client sum with a console.warn rather than blanking the step. Staleness is derived from the selection key instead of reset in the effect body, which also clears the set-state-in-effect lint warning. Task: clinicpro/docs/new_feture/taskes/task-00b-nobat724-service-mode/ Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
187 lines
4.8 KiB
JavaScript
187 lines
4.8 KiB
JavaScript
import Date from "./date";
|
||
import ServiceSelect from "./service";
|
||
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,
|
||
}) {
|
||
const serviceMode = bookingMode === "service";
|
||
const clinicUuid = selectedLocation?.clinic_uuid ?? null;
|
||
const multiLocation = bookingLocations.length > 1;
|
||
|
||
let dateStep;
|
||
if (bookingLocations.length === 0) {
|
||
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 (serviceMode && selectedServiceUuids.length === 0) {
|
||
dateStep = (
|
||
<ServiceSelect
|
||
services={bookingServices}
|
||
doctorUuid={doctor?.uuid}
|
||
clinicUuid={clinicUuid}
|
||
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}
|
||
onChangeLocation={multiLocation ? reopenLocationChoice : 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}
|
||
/>,
|
||
<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;
|