Files
nobat724_front/app/component/date/datePicker/index.js
T

146 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"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;