Public wrapper for GET /api/v1/appointment-settings/month-availability
/{doctor_uuid}?year=&month= so the calendar can learn which days are
bookable.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.5 KiB
نمایش روزهای تعطیل/غیرقابلانتخاب روی تقویم صفحهی نوبت + احترام به بازهی رزرو
پروژه
nobat724_front — سایت عمومی نوبتدهی. این پرامپت بعد از پرامپت backend اجرا شود.
Cross-repo: این کار به endpoint جدید backend وابسته است:
GET /api/v1/appointment-settings/month-availability/{doctorUuid}?year=&month=که در پرامپتclinicpro/.claude/prompt/doctor-booking-window-and-month-availability.mdساخته میشود. اگر آن endpoint هنوز نیست، متوقف شو و اول backend را اجرا کن.
زمینه
تقویم دوماههی صفحهی نوبت (/appointment/[doctorId]) الان همهی روزهای آینده را قابلانتخاب نشان میدهد، چون در اصلاح قبلی فراخوانی endpoint ناموجود appointment/not-available حذف شد و disabledDates={[]} پاس داده میشود. در نتیجه روزهای تعطیلِ پزشک (مثلاً ۲۷/۰۳/۱۴۰۵ که با date override بسته شده) روی تقویم خاکستری نمیشوند و کاربر میتواند رویشان کلیک کند — بعد فقط لیست اسلات خالی میبیند. همچنین بازهی رزرو (مثلاً «تا ۲ ماه جلوتر») روی تقویم اعمال نمیشود.
مشکل / هدف
تقویم باید روزهای غیرقابلانتخاب را خاکستری و disable کند. این روزها از endpoint month-availability میآیند: تعطیلات، date overrideهای بسته، روزهای بدون شیفت، و روزهای خارج از بازهی رزرو پزشک. چون تقویم دوماهه است، باید برای هر دو ماه نمایشدادهشده داده گرفته شود و با تغییر ماه (navigation) دادهی ماه جدید هم لود شود.
فایلهای مرتبط
| فایل | نقش |
|---|---|
services/response.js |
افزودن getMonthAvailability(doctorUuid, year, month) |
app/appointment/[doctorId]/page.js |
الان disabledDates={[]} میفرستد (سرور-ساید) |
components/appointment/index.js → Container → date/index.js → Time → SelectDatePicker |
زنجیرهی پاسدادن disabledDates |
app/component/date/datePicker/index.js |
تقویم دوماههی client؛ disabledDates آرایهی Unix timestamp است |
components/common/InlineJalaliMonth.js |
رندر یک ماه؛ isDisabled(date) روز را خاکستری/disable میکند |
lib/appointmentSlots.js |
adapter موجود اسلاتها (الگوی adapter جدا) |
وضعیت فعلی (کد واقعی)
app/appointment/[doctorId]/page.js — disabledDates خالی
let doctor = null;
try {
const doctorRes = await axiosInstance.get(`${API_URL}/api/v1/doctor/${doctorId}`);
doctor = doctorRes.data?.data?.data;
} catch (error) {}
return (
<AppointmentPage doctor={doctor} disabledDates={[]} matchedCity={matchedCity} />
);
app/component/date/datePicker/index.js — مصرف disabledDates
function DatePicker({ setDate, disabledDates = [] }) {
const [baseMonth, setBaseMonth] = useState(moment().tz("Asia/Tehran"));
// ...
const isDisabled = (date) => {
const day = moment(date).startOf("day");
if (day.isBefore(moment().startOf("day"))) return true;
return disabledDates.some((ts) => day.isSame(moment.unix(ts).startOf("day")));
};
// auto-select nearest available day از همین isDisabled استفاده میکند
// دو InlineJalaliMonth: baseMonth (راست) + secondMonth = baseMonth+1 (چپ)
}
disabledDatesآرایهی Unix timestamp (ثانیه) است؛isDisabledگذشته را هم میبندد.baseMonthبا فلشهای ناوبری تغییر میکند.
services/response.js — توابع slot موجود
getAppointmentSlots: (doctor_uuid, date) =>
api.get(`api/v1/appointment-slots?doctor_uuid=${doctor_uuid}&date=${date}`, removeTokenHead),
قرارداد endpoint جدید backend (مرجع)
GET /api/v1/appointment-settings/month-availability/{doctorUuid}?year=&month= (PUBLIC)
{
"success": true,
"data": {
"year": 2026,
"month": 6,
"disabled_dates": ["2026-06-16", "2026-06-20"],
"online_booking_enabled": true,
"booking_window": { "value": 2, "unit": "month" }
}
}
disabled_datesفرمتY-m-dمیلادی. قبل از پیادهسازی، با پرامپت backend چک کن که endpoint ورودی شمسی میخواهد یا میلادی — اگر میلادی است، ماه شمسیِ نمایشدادهشده را باید به بازهی میلادی تبدیل و برای ماه(های) میلادی متناظر صدا بزنی. interceptorservices/api.jsیکبار پاسخ را باز میکند → داده درres.data.
وظایف
اجرای مرحلهبهمرحله؛ بعد از هر قابلیت npm run build و سپس commit جدا.
۱. افزودن getMonthAvailability به services/response.js
getMonthAvailability: (doctor_uuid, year, month) =>
api.get(`api/v1/appointment-settings/month-availability/${doctor_uuid}`, {
params: { year, month },
}),
(public — بدون requireAuth؛ از همان الگوی getAppointmentSlots پیروی کن.)
۲. لود دادهی دردسترسبودن در DatePicker و disableکردن روزها
- چون
DatePickerکامپوننت client است وdoctor.uuidدر آن در دسترس نیست (الان فقطsetDate/disabledDatesمیگیرد)، یاdoctorUuidرا بهعنوان prop از زنجیره پاس بده، یا ازuseParams().doctorIdداخلDatePickerبخوان (همان uuid است — الگوی موجودSendAppo). - داخل
DatePickerیک statedisabledTimestampsنگهدار و باuseEffectوابسته بهbaseMonth:- برای ماهِ
baseMonthو ماهِsecondMonth(baseMonth+1)getMonthAvailabilityرا صدا بزن (تبدیل ماه نمایشی به year/month مطابق قرارداد backend). disabled_dates(Y-m-d) را به Unix timestamp (moment(d,"YYYY-MM-DD").startOf("day").unix()) تبدیل و در state بریز.
- برای ماهِ
isDisabledفعلی را نگهدار ولی منبعdisabledDatesرا از این state بگیر (یا propdisabledDatesرا با state داخلی merge کن). گذشته همچنان بسته بماند.- auto-select: منطق انتخاب نزدیکترین روز قابلانتخاب باید بعد از لود
disabledTimestampsاجرا/بازاجرا شود تا روی روز تعطیل auto-select نشود.
۳. هندل ناوبری ماه
- با کلیک فلشها
baseMonthتغییر میکند →useEffectدوباره دادهی دو ماه جدید را میگیرد. مطمئن شو state تجمعی است (ماههای قبلی پاک نشوند یا حداقل ماههای نمایشفعلی پوشش داده شوند) و درخواست تکراری بیمورد نزن (میتوانی ماههای لودشده را cache کنی با یکSet/object key=year-month).
۴. (اختیاری ولی توصیهشده) نمایش وضعیت نوبتدهی خاموش
- اگر
online_booking_enabled === falseدر پاسخ، بهجای تقویم یک پیام «نوبتدهی آنلاین این پزشک غیرفعال است» نشان بده و دکمهی «تایید نوبت» را disable کن. (اگر میخواهی این بخش را جدا کنی، در گزارش ذکر کن.)
نکات مهم
- وابستگی cross-repo: بدون endpoint
month-availabilityاین کار کامل نمیشود. اگر نبود متوقف شو. - شمسی/میلادی: تقویم سایت شمسی است؛ endpoint احتمالاً میلادی میخواهد. تبدیل را با
moment-jalaaliانجام بده و حدس نزن — قرارداد دقیق را از پرامپت/داک backend بگیر. یک ماه شمسی روی دو ماه میلادی میافتد؛ یا برای پوشش کامل، بازهی میلادیِ روزهای نمایشدادهشده را محاسبه کن. - timestampها Unix (ثانیه):
disabledDatesکهisDisabledمیخواند آرایهی Unix ثانیه است؛ تبدیلY-m-d → unixرا باstartOf("day")درAsia/Tehranانجام بده تا با منطق فعلی همخوان شود. - interceptor:
request.*بدنه را یکبار باز میکند →res.data.disabled_dates. - عدم رگرسیون: تقویم دوماهه، ترتیب RTL (خرداد راست، تیر چپ)، فلشها، و انتخاب خودکار نباید بشکنند.
InlineJalaliMonthفقطisDisabledرا مصرف میکند — منطق رنگ خاکستری از قبل هست. - Multi-domain/Jalali/RTL: حفظ شوند.
- تست:
npm run build؛ سپس دستی با پزشک4a0594b1-008b-478a-a593-259b95d8c2ddکه یک date override بسته روی ۲۷/۰۳/۱۴۰۵ دارد — آن روز باید خاکستری و غیرقابلکلیک باشد، و روزهای خارج از بازهی رزرو هم همینطور. سپس commit با پیام توصیفی.