Files
nobat724_front/.claude/prompt/verify-past-slots-disabled.md
T
hamedandClaude Opus 4.8 e820cc88ee fix(appointment): client guard for slots that pass while page is open
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>
2026-06-15 16:51:30 +03:30

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 با پیام توصیفی.