146 lines
5.1 KiB
JavaScript
146 lines
5.1 KiB
JavaScript
"use client";
|
||
|
||
import { useEffect, useRef, useState } from "react";
|
||
import { useParams } from "next/navigation";
|
||
import moment from "moment-jalaali";
|
||
import "moment-timezone";
|
||
import { dateToTimestamp } from "@/helper";
|
||
import { request } from "@/services/response";
|
||
import InlineJalaliMonth from "@/components/common/InlineJalaliMonth";
|
||
|
||
function gregorianMonthsOf(jalaliMonth) {
|
||
const first = moment(jalaliMonth).startOf("jMonth");
|
||
const last = moment(jalaliMonth).endOf("jMonth");
|
||
const keys = new Set();
|
||
for (const d of [first, last]) {
|
||
keys.add(`${d.year()}-${d.month() + 1}`);
|
||
}
|
||
return [...keys].map((k) => {
|
||
const [year, month] = k.split("-").map(Number);
|
||
return { year, month };
|
||
});
|
||
}
|
||
|
||
function DatePicker({ setDate, clinicUuid = null }) {
|
||
const params = useParams();
|
||
const doctorUuid = params?.doctorId;
|
||
|
||
const [baseMonth, setBaseMonth] = useState(moment().tz("Asia/Tehran"));
|
||
const [selectedDate, setSelectedDate] = useState(null);
|
||
const [autoSelected, setAutoSelected] = useState(false);
|
||
const [disabledSet, setDisabledSet] = useState(() => new Set());
|
||
const [onlineEnabled, setOnlineEnabled] = useState(true);
|
||
const loadedMonths = useRef(new Set());
|
||
|
||
const secondMonth = moment(baseMonth).add(1, "jMonth");
|
||
|
||
// هر محل، روزهای غیرفعال و وضعیت نوبتدهی آنلاین خودش را دارد؛ کش ماهها باید
|
||
// با تعویض محل دور ریخته شود وگرنه تقویم محل قبلی باقی میماند.
|
||
useEffect(() => {
|
||
loadedMonths.current = new Set();
|
||
setDisabledSet(new Set());
|
||
setOnlineEnabled(true);
|
||
setAutoSelected(false);
|
||
}, [clinicUuid]);
|
||
|
||
useEffect(() => {
|
||
if (!doctorUuid) return;
|
||
|
||
const targets = [
|
||
...gregorianMonthsOf(baseMonth),
|
||
...gregorianMonthsOf(secondMonth),
|
||
].filter(({ year, month }) => !loadedMonths.current.has(`${year}-${month}`));
|
||
|
||
if (targets.length === 0) return;
|
||
|
||
targets.forEach(({ year, month }) => {
|
||
loadedMonths.current.add(`${year}-${month}`);
|
||
request
|
||
.getMonthAvailability(doctorUuid, year, month, clinicUuid)
|
||
.then((res) => {
|
||
const data = res?.data ?? {};
|
||
if (data.online_booking_enabled === false) setOnlineEnabled(false);
|
||
const dates = Array.isArray(data.disabled_dates) ? data.disabled_dates : [];
|
||
if (dates.length) {
|
||
setDisabledSet((prev) => {
|
||
const next = new Set(prev);
|
||
dates.forEach((d) => next.add(d));
|
||
return next;
|
||
});
|
||
}
|
||
})
|
||
.catch(() => {
|
||
loadedMonths.current.delete(`${year}-${month}`);
|
||
});
|
||
});
|
||
}, [doctorUuid, baseMonth, clinicUuid]);
|
||
|
||
const isDisabled = (date) => {
|
||
const day = moment(date).startOf("day");
|
||
if (day.isBefore(moment().startOf("day"))) return true;
|
||
return disabledSet.has(day.format("YYYY-MM-DD"));
|
||
};
|
||
|
||
const selectDay = (date) => {
|
||
if (isDisabled(date)) return;
|
||
setSelectedDate(date);
|
||
setDate(dateToTimestamp(date));
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (autoSelected) return;
|
||
|
||
const today = moment().tz("Asia/Tehran");
|
||
for (let i = 0; i <= 60; i++) {
|
||
const candidate = today.clone().add(i, "days");
|
||
if (!isDisabled(candidate)) {
|
||
setSelectedDate(candidate);
|
||
setBaseMonth(candidate.clone());
|
||
setDate(candidate.clone().startOf("day").unix());
|
||
setAutoSelected(true);
|
||
break;
|
||
}
|
||
}
|
||
}, [disabledSet, autoSelected, setDate]);
|
||
|
||
if (!onlineEnabled) {
|
||
return (
|
||
<div className="w-full py-[40px] text-center text-[#525252] text-[14px] md:text-[16px] font-medium">
|
||
نوبتدهی آنلاین این پزشک در حال حاضر غیرفعال است.
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div dir="rtl" className="datePickerApt flex items-start justify-evenly gap-[24px] w-full">
|
||
<div className="w-full lg:w-1/2">
|
||
<InlineJalaliMonth
|
||
displayDate={baseMonth}
|
||
selectedDate={selectedDate}
|
||
onSelectDay={selectDay}
|
||
isDisabled={isDisabled}
|
||
// وقتی تقویم ماه بعد در کنار این نمایش داده میشود (md و xl) دکمهٔ «بعد»
|
||
// این تقویم پنهان میماند تا دوتا نشود؛ در موبایل و lg که تنها همین تقویم
|
||
// دیده میشود، دکمهٔ «بعد» فعال است تا کاربر بتواند به ماه بعد برود.
|
||
nextBtnClass="md:invisible lg:visible xl:invisible"
|
||
onPrev={() => setBaseMonth(moment(baseMonth).subtract(1, "jMonth"))}
|
||
onNext={() => setBaseMonth(moment(baseMonth).add(1, "jMonth"))}
|
||
/>
|
||
</div>
|
||
<div className="hidden md:block lg:hidden xl:block w-1/2">
|
||
<InlineJalaliMonth
|
||
displayDate={secondMonth}
|
||
selectedDate={selectedDate}
|
||
onSelectDay={selectDay}
|
||
isDisabled={isDisabled}
|
||
showPrev={false}
|
||
onNext={() => setBaseMonth(moment(baseMonth).add(1, "jMonth"))}
|
||
onPrev={() => setBaseMonth(moment(baseMonth).subtract(1, "jMonth"))}
|
||
/>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default DatePicker;
|