Fix time slot picker bugs for past dates

Fixed issues:
- Added isAvailable parameter to handleSlotClick to prevent clicks on unavailable slots
- Added validation to prevent selecting past dates in date picker
- Added validation in handlePreviousDay to block navigating to past dates
- Added warning message when trying to view past dates
- Prevents the "slot is not defined" error when clicking disabled slots

Now the modal properly:
- Blocks selecting dates before today
- Shows clear error messages for past dates
- Prevents clicks on unavailable time slots
- Handles edge cases like passed sessions being rescheduled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-31 18:11:41 +07:00
parent c6b45378f3
commit 86b59c756f

View File

@@ -120,6 +120,10 @@ export function TimeSlotPickerModal({
// Date navigation handlers // Date navigation handlers
const handlePreviousDay = () => { const handlePreviousDay = () => {
const newDate = addDays(currentDate, -1); const newDate = addDays(currentDate, -1);
// Prevent going to past dates
if (isPast(newDate) && !isToday(newDate)) {
return;
}
setCurrentDate(newDate); setCurrentDate(newDate);
}; };
@@ -131,6 +135,10 @@ export function TimeSlotPickerModal({
const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newDate = parse(e.target.value, 'yyyy-MM-dd', new Date()); const newDate = parse(e.target.value, 'yyyy-MM-dd', new Date());
if (!isNaN(newDate.getTime())) { if (!isNaN(newDate.getTime())) {
// Prevent selecting past dates
if (isPast(newDate) && !isToday(newDate)) {
return;
}
setCurrentDate(newDate); setCurrentDate(newDate);
} }
}; };
@@ -208,8 +216,9 @@ export function TimeSlotPickerModal({
const totalBlocks = getSlotsInRange().length; const totalBlocks = getSlotsInRange().length;
const totalDuration = totalBlocks * (settings?.consulting_block_duration_minutes || 30); const totalDuration = totalBlocks * (settings?.consulting_block_duration_minutes || 30);
const handleSlotClick = (slotStart: string) => { const handleSlotClick = (slotStart: string, isAvailable: boolean) => {
if (!slot.available) return; // Prevent clicking on unavailable slots
if (!isAvailable) return;
// No selection yet → Set as pending // No selection yet → Set as pending
if (!selectedRange.start) { if (!selectedRange.start) {
@@ -327,7 +336,13 @@ export function TimeSlotPickerModal({
</div> </div>
{/* Info */} {/* Info */}
{isToday(currentDate) && timeSlots.length === 0 ? ( {isPast(currentDate) && !isToday(currentDate) ? (
<div className="bg-destructive/10 border-2 border-destructive/20 p-4 rounded-lg text-center">
<p className="text-sm text-destructive font-medium">
Tidak dapat memilih tanggal yang sudah lewat. Silakan pilih tanggal hari ini atau tanggal yang akan datang.
</p>
</div>
) : isToday(currentDate) && timeSlots.length === 0 ? (
<div className="bg-amber-50 dark:bg-amber-950 border-2 border-amber-200 dark:border-amber-800 p-4 rounded-lg text-center"> <div className="bg-amber-50 dark:bg-amber-950 border-2 border-amber-200 dark:border-amber-800 p-4 rounded-lg text-center">
<p className="text-sm text-amber-900 dark:text-amber-100"> <p className="text-sm text-amber-900 dark:text-amber-100">
Tidak ada slot tersedia untuk sisa hari ini. Silakan pilih tanggal lain. Tidak ada slot tersedia untuk sisa hari ini. Silakan pilih tanggal lain.
@@ -367,7 +382,7 @@ export function TimeSlotPickerModal({
!slot.available ? 'opacity-30 cursor-not-allowed' : '' !slot.available ? 'opacity-30 cursor-not-allowed' : ''
}`} }`}
disabled={!slot.available} disabled={!slot.available}
onClick={() => handleSlotClick(slot.start)} onClick={() => handleSlotClick(slot.start, slot.available)}
> >
{slot.start} {slot.start}
</Button> </Button>