diff --git a/src/app/admin/bookings/page.tsx b/src/app/admin/bookings/page.tsx index 6e5f5d3..8ac709c 100644 --- a/src/app/admin/bookings/page.tsx +++ b/src/app/admin/bookings/page.tsx @@ -4,6 +4,7 @@ import { useState, useEffect, useMemo, useCallback, useRef } from "react"; import { createPortal } from "react-dom"; import { Phone, Instagram, Send, ChevronDown, ChevronRight, Bell, CheckCircle2, XCircle, Clock, Star, Calendar, DoorOpen, X, Plus } from "lucide-react"; import { adminFetch } from "@/lib/csrf"; +import { MS_PER_DAY } from "@/lib/constants"; import { type BookingStatus, type BookingFilter, type SearchResult, BOOKING_STATUSES, SHORT_DAYS, fmtDate } from "./types"; import { LoadingSpinner, ContactLinks, BookingCard, StatusBadge, StatusActions, DeleteBtn } from "./BookingComponents"; import { GenericBookingsList } from "./GenericBookingsList"; @@ -40,6 +41,8 @@ function ConfirmModal({ open, bookingName, groupInfo, + existingDate, + existingGroup, allClasses, onConfirm, onClose, @@ -47,6 +50,8 @@ function ConfirmModal({ open: boolean; bookingName: string; groupInfo?: string; + existingDate?: string; + existingGroup?: string; allClasses: ScheduleClassInfo[]; onConfirm: (data: { group: string; date: string; comment?: string }) => void; onClose: () => void; @@ -59,10 +64,12 @@ function ConfirmModal({ useEffect(() => { if (!open) return; - setDate(""); setComment(""); - // Try to match groupInfo against schedule to pre-fill - if (groupInfo && allClasses.length > 0) { - const info = groupInfo.toLowerCase(); + const tomorrow = new Date(Date.now() + MS_PER_DAY).toISOString().split("T")[0]; + setDate(existingDate && existingDate.length === 10 ? existingDate : tomorrow); setComment(""); + // Try to match groupInfo or existingGroup against schedule to pre-fill + const matchText = existingGroup || groupInfo; + if (matchText && allClasses.length > 0) { + const info = matchText.toLowerCase(); // Score each class against groupInfo, pick best match let bestMatch: ScheduleClassInfo | null = null; let bestScore = 0; @@ -86,7 +93,7 @@ function ConfirmModal({ } } setHall(""); setTrainer(""); setGroup(""); - }, [open, groupInfo, allClasses]); + }, [open, groupInfo, existingDate, existingGroup, allClasses]); // Cascading options const halls = useMemo(() => [...new Set(allClasses.map((c) => c.hall))], [allClasses]); @@ -132,7 +139,8 @@ function ConfirmModal({ useEffect(() => { if (!open) initRef.current = false; }, [open]); // #11: Keyboard submit - const canSubmit = group && date; + const today = open ? new Date().toISOString().split("T")[0] : ""; + const canSubmit = group && date && date.length === 10 && date >= today; const handleSubmit = useCallback(() => { if (canSubmit) { const groupLabel = groups.find((g) => g.value === group)?.label || group; @@ -152,7 +160,6 @@ function ConfirmModal({ if (!open) return null; - const today = new Date().toISOString().split("T")[0]; const selectClass = "w-full rounded-lg border border-white/[0.08] bg-white/[0.04] px-3 py-2 text-sm text-white outline-none focus:border-gold/40 [color-scheme:dark] disabled:opacity-30 disabled:cursor-not-allowed"; return createPortal( @@ -194,10 +201,14 @@ function ConfirmModal({ type="date" value={date} min={today} + max={new Date(Date.now() + MS_PER_DAY * 365).toISOString().split("T")[0]} disabled={!group} onChange={(e) => setDate(e.target.value)} - className={selectClass} + className={`${selectClass} ${date && (date < today || date.length !== 10) ? "!border-red-500/50" : ""}`} /> + {date && (date < today || date.length !== 10) && ( +
{date < today ? "Дата не может быть в прошлом" : "Неверный формат даты"}
+ )}