import { useState, useEffect, useCallback } from 'react' import { ChevronLeft, ChevronRight, Calendar, Users, X, Check, Loader2 } from 'lucide-react' import { api, type ScheduleEntry } from '../lib/api' import { useAuth } from '../contexts/AuthContext' import type { User } from '../types' import { cn } from '../lib/utils' import { format, startOfWeek, addDays, addWeeks, subWeeks, isToday, parseISO, startOfMonth, endOfMonth, eachDayOfInterval, addMonths, subMonths, getDay, } from 'date-fns' import { ru } from 'date-fns/locale' const ROLE_COLORS: Record = { hotel_admin: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-300', manager: 'bg-brand-100 text-brand-700 dark:bg-brand-900/30 dark:text-brand-300', receptionist: 'bg-sky-100 text-sky-700 dark:bg-sky-900/30 dark:text-sky-300', housekeeper: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300', accountant: 'bg-violet-100 text-violet-700 dark:bg-violet-900/30 dark:text-violet-300', security: 'bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-300', technician: 'bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300', } const ROLE_LABELS: Record = { hotel_admin: 'Сис. администратор', manager: 'Менеджер', receptionist: 'Ресепшн', housekeeper: 'Горничная', accountant: 'Бухгалтер', security: 'Охрана', technician: 'Тех. специалист', } const SHIFT_PRESETS = [ { label: 'Дневная', start: '09:00', end: '21:00' }, { label: 'Ночная', start: '21:00', end: '09:00' }, { label: 'Утро', start: '07:00', end: '15:00' }, { label: 'Вечер', start: '15:00', end: '23:00' }, { label: '8 часов',start: '09:00', end: '17:00' }, ] function getWeekDays(weekStart: Date): Date[] { return Array.from({ length: 7 }, (_, i) => addDays(weekStart, i)) } function fmtDate(d: Date) { return format(d, 'yyyy-MM-dd') } function fmtTime(t: string | null | undefined) { if (!t) return '' return t.slice(0, 5) } /** Returns true if the date is Saturday (6) or Sunday (0) */ function isWeekend(d: Date): boolean { const dow = getDay(d) return dow === 0 || dow === 6 } interface CellEditorProps { userId: string date: string entry: ScheduleEntry | undefined onClose: () => void onSave: (data: { shift_start?: string; shift_end?: string; is_day_off: boolean; notes?: string }) => Promise onDelete: () => Promise } function CellEditor({ date, entry, onClose, onSave, onDelete }: CellEditorProps) { const [isDayOff, setIsDayOff] = useState(entry?.isDayOff ?? false) const [shiftStart, setShiftStart] = useState(fmtTime(entry?.shiftStart) || '09:00') const [shiftEnd, setShiftEnd] = useState(fmtTime(entry?.shiftEnd) || '18:00') const [notes, setNotes] = useState(entry?.notes ?? '') const [saving, setSaving] = useState(false) const applyPreset = (p: typeof SHIFT_PRESETS[0]) => { setShiftStart(p.start) setShiftEnd(p.end) setIsDayOff(false) } const handleSave = async () => { setSaving(true) await onSave({ shift_start: isDayOff ? undefined : shiftStart || undefined, shift_end: isDayOff ? undefined : shiftEnd || undefined, is_day_off: isDayOff, notes: notes || undefined, }) setSaving(false) } const handleDelete = async () => { setSaving(true) await onDelete() setSaving(false) } return (
e.stopPropagation()}>

{format(parseISO(date), 'd MMMM', { locale: ru })}

{/* Day off toggle */}
Выходной день
{!isDayOff && ( <> {/* Presets */}
{SHIFT_PRESETS.map(p => ( ))}
{/* Time inputs */}
setShiftStart(e.target.value)} className="input text-sm w-full" />
setShiftEnd(e.target.value)} className="input text-sm w-full" />
)} {/* Notes */}