The backend already returns is_available:false for past slots, but a slot can lapse after the list is loaded. Disable any slot whose start (unix seconds) is before now in the time grid, so a just-passed slot can't be clicked. The grid disabling makes a SendAppo-level guard redundant — a past slot can no longer be selected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.2 KiB
تأیید و سختسازی غیرفعالبودن اسلاتهای گذشته در صفحهی نوبت
پروژه
nobat724_front — سایت عمومی. بعد از پرامپت backend اجرا شود.
Cross-repo: وابسته به اصلاح
is_availableدر backend:clinicpro/.claude/prompt/mark-past-slots-unavailable.mdبعد از آن، اسلاتهای گذشتهی روز جاری از API باis_available: falseمیآیند و UI خودکار آنها را خاکستری میکند. این پرامپت آن را تأیید و یک گارد سبک سمت کلاینت اضافه میکند.
زمینه
گرید ساعت (List.js) از قبل دکمه را با disabled={!item.is_available} غیرفعال و خاکستری میکند. پس وقتی backend اسلات گذشته را is_available: false بدهد، بدون تغییر فرانت خاکستری میشود. تنها ریسک باقیمانده: کاربر صفحه را ساعت ۹:۵۹ باز کرده، اسلات ۱۰:۰۰ آن لحظه is_available: true بوده و در state مانده؛ ساعت ۱۰:۰۱ همان آبجکت قدیمی هنوز کلیکپذیر است چون داده دوباره fetch نشده. backend موقع ثبت رد میکند (۴۲۲)، ولی بهتر است UI هم همان لحظه جلوی کلیک را بگیرد.
مشکل / هدف
۱. تأیید کن گرید ساعت is_available را درست رعایت میکند (انتظار: نیازی به تغییر نیست).
۲. یک گارد سبک سمت کلاینت اضافه کن: اسلاتی که start (Unix ثانیه) آن از «اکنون» گذشته، حتی اگر is_available: true آمده باشد، در UI غیرفعال شود.
فایلهای مرتبط
| فایل | نقش |
|---|---|
app/component/date/dateTime/hours/List.js |
گرید ساعت؛ disabled={!item.is_available} |
lib/appointmentSlots.js |
adapter اسلاتها (sessions[] → morning/evening) — اسلاتها start/is_available دارند |
app/component/date/dateTime/SendAppo.js |
دکمهی «تایید نوبت»؛ disabled={!hour} |
وضعیت فعلی (کد واقعی)
hours/List.js
<Button
onClick={() => setHour(item)}
disabled={!item.is_available}
...
>
...
<p className={`... ${item.is_available ? "text-[#525252]" : "text-[#D7D7D7]"} ...`}>
{item.start_time}
</p>
</Button>
آبجکت اسلات (از adaptSlots / API)
{ start: 1781933400, end: 1781934600, start_time: "09:00", end_time: "09:20", location_id: 2581, is_available: true }
وظایف
۱. گارد زمان گذشته در گرید ساعت
در List.js یک محاسبهی کوچک اضافه کن که اسلات گذشته را غیرقابلانتخاب کند (مبنا: item.start بر حسب ثانیه):
const isPast = (item) => item?.start && item.start * 1000 < Date.now();
const isSelectable = (item) => item.is_available && !isPast(item);
سپس در دکمه disabled={!isSelectable(item)} و در کلاس متن isSelectable(item) ? ... : ... را جایگزین item.is_available کن.
startثانیه است؛Date.now()میلیثانیه — پسstart * 1000.
۲. (اختیاری) عدم انتخاب اسلات گذشته در SendAppo
اگر منطقی بود، در SendAppo هم قبل از setSelectedSlot(hour) مطمئن شو hour.start * 1000 >= Date.now()؛ در غیر این صورت اجازه نده مرحله جلو برود. (اگر گارد گرید کافی است و کاربر اصلاً نمیتواند اسلات گذشته را انتخاب کند، این مرحله را رد کن و در گزارش ذکر کن.)
۳. تأیید رفتار end-to-end
- با
date=<امروز>و یک ساعت که چند اسلات اول روز گذشتهاند، تأیید کن اسلاتهای گذشته خاکستری و غیرقابلکلیکاند و اسلاتهای آینده فعال.
نکات مهم
- بدون تایمر/رندر مکرر اضافه نکن مگر لازم باشد؛ یک محاسبه در زمان رندر کافی است (هر بار state تغییر کند یا کامپوننت رندر شود ارزیابی میشود). نیازی به
setIntervalبرای بهروزرسانی هر ثانیه نیست مگر کاربر بخواهد. - منبع اصلی همچنان backend است: این گارد فقط لبهی «اسلاتی که همین حالا گذشت» را میگیرد. اگر backend درست
is_available:falseبدهد، این گارد در عمل کماثر ولی بیضرر و درست است. - تایمزون:
startاز API بر حسب Unix ثانیه (UTC مبنا) است؛Date.now()هم Unix میلیثانیه است — مقایسه درست است بدون تبدیل تایمزون. - RTL/Jalali/multi-domain را خراب نکن؛ منطق
morning/eveningو adapter دستنخورده بماند. - تست:
npm run buildو سپس بررسی دستی روی صفحهی نوبت پزشک تست. سپس commit با پیام توصیفی.