# نمایش روزهای تعطیل/غیرقابل‌انتخاب روی تقویم صفحه‌ی نوبت + احترام به بازه‌ی رزرو

## پروژه

`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 خالی

```js
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

```js
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 موجود

```js
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)
```

```json
{
  "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 ورودی شمسی می‌خواهد یا میلادی** — اگر میلادی است، ماه شمسیِ نمایش‌داده‌شده را باید به بازه‌ی میلادی تبدیل و برای ماه(های) میلادی متناظر صدا بزنی. interceptor `services/api.js` یک‌بار پاسخ را باز می‌کند → داده در `res.data`.

## وظایف

اجرای مرحله‌به‌مرحله؛ بعد از هر قابلیت `npm run build` و سپس commit جدا.

### ۱. افزودن `getMonthAvailability` به `services/response.js`

```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` یک state `disabledTimestamps` نگه‌دار و با `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 بگیر (یا prop `disabledDates` را با 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 با پیام توصیفی.
