"use client"; import { useEffect, useMemo, useState } from "react"; import { Bell, CalendarDays, ChevronLeft, ChevronRight, Download, Filter, Plus, Search, Settings, X } from "@/components/shared/ui-icons"; import type { UserRole } from "@/config/homeAppsConfig"; import { formatJalaliDate, formatJalaliDateTime, toPersianDigits } from "@/lib/persianFormat"; import type { CalendarConnectedItemType, CalendarEvent, CalendarEventStatus, CalendarEventType, CalendarSettings, CalendarViewMode } from "@/types/calendar"; import { calendarEventTypeDefinitions } from "@/services/mock/calendar/calendarMockData"; import { createEvent as storeCreateEvent, getEventById as storeGetEventById, getEvents, getSelectedDate, getSelectedView, getSettings, saveEvents, saveSelectedDate, saveSelectedView, saveSettings } from "@/services/calendar/calendarStorageService"; import { MacToggle } from "@/components/mac/MacToggle"; import { PersianDatePicker, PersianDateTimePicker, PersianTimePicker } from "./PersianDatePicker"; import { AccessibleDialog } from "@/components/shared/AccessibleDialog"; import { WindowSplitView } from "@/components/shared/WindowSplitView"; type CalendarRouteMode = "main" | "day" | "my" | "team" | "organization" | "system" | "events" | "create" | "detail" | "edit" | "attendance" | "participants" | "reminders" | "audit" | "reports" | "settings"; const weekDaysFa = ["شنبه", "یکشنبه", "دوشنبه", "سه‌شنبه", "چهارشنبه", "پنجشنبه", "جمعه"]; const viewLabels: Record = { day: "روزانه", week: "هفتگی", month: "ماهانه", list: "لیستی", timeline: "تایم‌لاین", today: "امروز", upcoming: "رویدادهای آینده", overdue: "رویدادهای عقب‌افتاده" }; const statusLabels: Record = { draft: "پیش‌نویس", published: "منتشرشده", scheduled: "زمان‌بندی‌شده", live: "در حال برگزاری", completed: "برگزارشده", cancelled: "لغوشده", overdue: "عقب‌افتاده", needs_attention: "نیازمند توجه" }; const roleLabels: Record = { super_admin: "مدیر کل سامانه", org_admin: "مدیر آموزش سازمان", manager: "مدیر واحد", employee: "کارکنان" }; export function EducationalCalendarPage({ role = "org_admin", mode = "main", eventId = "ev-2", initialDate, onToast }: { role?: UserRole; mode?: CalendarRouteMode; eventId?: string; initialDate?: string; onToast?: (message: string, tone?: "success" | "error") => void }) { const [view, setViewState] = useState(mode === "day" ? "day" : "month"); const [anchorDate, setAnchorDateState] = useState(() => dateFromYmd(initialDate ?? "2026-06-22")); const [events, setEvents] = useState([]); const [selectedEvent, setSelectedEvent] = useState(null); const [query, setQuery] = useState(""); const [createOpen, setCreateOpen] = useState(mode === "create"); const [settingsOpen, setSettingsOpen] = useState(mode === "settings"); const [prefillDate, setPrefillDate] = useState(toYmd(anchorDate)); const [toast, setToast] = useState(""); useEffect(() => { const savedView = mode === "day" ? "day" : getSelectedView(); const savedDate = initialDate ?? getSelectedDate(); setViewState(savedView); setAnchorDateState(dateFromYmd(savedDate)); setEvents(applyRoleScope(getEvents(), role, mode)); if (["detail", "edit"].includes(mode)) setSelectedEvent(storeGetEventById(eventId) ?? null); }, [eventId, initialDate, mode, role]); const showToast = (message: string) => { setToast(message); onToast?.(message, "success"); window.setTimeout(() => setToast(""), 2400); }; const setView = (next: CalendarViewMode) => { setViewState(next); saveSelectedView(next); }; const setAnchorDate = (date: Date) => { setAnchorDateState(date); saveSelectedDate(toYmd(date)); }; const visibleEvents = useMemo(() => { const cleanQuery = query.trim(); return events.filter((event) => { if (!cleanQuery) return true; return [event.title, event.description, event.instructorFa, event.organizationFa, event.connectedItem?.title].filter(Boolean).join(" ").includes(cleanQuery); }); }, [events, query]); const persistEvents = (next: CalendarEvent[]) => { setEvents(applyRoleScope(saveEvents(next), role, mode)); }; const createNewEvent = (payload: Partial) => { const created = storeCreateEvent(payload); const next = getEvents(); setEvents(applyRoleScope(next, role, mode)); setSelectedEvent(created); setCreateOpen(false); showToast("رویداد ایجاد شد"); }; if (mode === "create") { return ( window.history.back()} onCreate={createNewEvent} /> {toast && } ); } if (mode === "settings") { return ( { saveSettings(settings); showToast("تنظیمات ذخیره شد"); }} /> ); } if (mode === "detail") { const event = selectedEvent ?? storeGetEventById(eventId); return {event ? undefined} /> : }; } return ( setAnchorDate(new Date())} onNavigate={(direction) => setAnchorDate(addByView(anchorDate, view, direction))} onCreate={() => { setPrefillDate(toYmd(anchorDate)); setCreateOpen(true); }} onSettings={() => setSettingsOpen(true)} />
{view === "month" && ( isSameDay(event.startAt, anchorDate))} onCreate={() => { setPrefillDate(toYmd(anchorDate)); setCreateOpen(true); }} onSelectEvent={setSelectedEvent} />} initialSidebarWidth={280} > { setAnchorDate(date); setPrefillDate(toYmd(date)); }} onQuickCreate={(date) => { setPrefillDate(toYmd(date)); setCreateOpen(true); }} onSelectEvent={setSelectedEvent} onEventsChange={persistEvents} /> )} {view === "week" && } {view === "day" && isSameDay(event.startAt, anchorDate))} selectedDate={anchorDate} onCreate={() => { setPrefillDate(toYmd(anchorDate)); setCreateOpen(true); }} onSelectEvent={setSelectedEvent} />} {view === "list" && } {view === "timeline" && } {view === "today" && isSameDay(event.startAt, new Date()))} selectedDate={new Date()} onCreate={() => { setPrefillDate(toYmd(new Date())); setCreateOpen(true); }} onSelectEvent={setSelectedEvent} />} {view === "upcoming" && } {view === "overdue" && }
{createOpen && setCreateOpen(false)} onCreate={createNewEvent} />} {settingsOpen && setSettingsOpen(false)} onSaved={(settings) => { saveSettings(settings); setSettingsOpen(false); showToast("تنظیمات ذخیره شد"); }} />} {selectedEvent && setSelectedEvent(null)} />} {toast && }
); } export function CalendarShell({ children }: { children: React.ReactNode }) { return
تقویم آموزشی
{children}
; } export function CalendarToolbar({ role, mode, anchorDate, view, query, onQuery, onView, onToday, onNavigate, onCreate, onSettings }: { role: UserRole; mode: CalendarRouteMode; anchorDate: Date; view: CalendarViewMode; query: string; onQuery: (value: string) => void; onView: (value: CalendarViewMode) => void; onToday: () => void; onNavigate: (direction: -1 | 1) => void; onCreate: () => void; onSettings: () => void }) { const title = mode === "my" ? "تقویم من" : mode === "team" ? "تقویم تیم" : mode === "organization" ? "تقویم سازمان" : mode === "system" ? "تقویم کل سامانه" : "تقویم آموزشی"; return (

{new Intl.DateTimeFormat("fa-IR", { month: "long", year: "numeric" }).format(anchorDate)}

{title}، {roleLabels[role]}
{role !== "employee" && }
); } export function CalendarViewSwitcher({ view, onView }: { view: CalendarViewMode; onView: (view: CalendarViewMode) => void }) { return
{(["day", "week", "month", "list", "timeline"] as CalendarViewMode[]).map((item) => )}
; } export function CalendarMonthView({ events, anchorDate, selectedDate, onSelectDay, onQuickCreate, onSelectEvent, onEventsChange }: { events: CalendarEvent[]; anchorDate: Date; selectedDate: Date; onSelectDay: (date: Date) => void; onQuickCreate: (date: Date) => void; onSelectEvent: (event: CalendarEvent) => void; onEventsChange: (events: CalendarEvent[]) => void }) { const days = buildMonthDays(anchorDate); const [dragId, setDragId] = useState(null); return (
{weekDaysFa.map((day) =>
{day.slice(0, 1)}
)}
{days.map((day) => { const dayEvents = events.filter((event) => isSameDay(event.startAt, day.date)); const today = isSameDay(day.date, new Date()); const holiday = day.date.getDay() === 5; return (
onSelectDay(day.date)} onKeyDown={(event) => event.key === "Enter" && onSelectDay(day.date)} onDragOver={(event) => event.preventDefault()} onDrop={(dropEvent) => { dropEvent.stopPropagation(); if (!dragId) return; const next = getEvents().map((item) => item.id === dragId ? moveEventToDay(item, day.date) : item); onEventsChange(next); setDragId(null); }} aria-label={`${day.currentMonth ? "" : "خارج از ماه، "}${holiday ? "تعطیل، " : ""}${dayEvents.length} رویداد`} className={`group flex min-h-0 flex-col overflow-hidden rounded-[14px] border border-[var(--color-border)] p-2 text-right outline-none transition hover:bg-[var(--color-selected)] focus:ring-2 focus:ring-[var(--color-focus-ring)] ${day.currentMonth ? "bg-[var(--color-card)]" : "bg-[var(--color-bg-soft)] text-[var(--color-text-muted)] opacity-55"} ${holiday ? "border-t-rose-400/70" : ""} ${isSameDay(day.date, selectedDate) ? "border-emerald-500 bg-emerald-500/10 ring-1 ring-inset ring-emerald-500" : ""}`} >
{toPersianDigits(day.date.getDate())}
{dayEvents.slice(0, 2).map((event) => ( { clickEvent.stopPropagation(); onSelectEvent(event); }} onDragStart={(dragEvent) => { dragEvent.stopPropagation(); setDragId(event.id); }} /> ))} {dayEvents.length > 2 && }
); })}
); } function CalendarSelectedDayPanel({ date, events, onCreate, onSelectEvent }: { date: Date; events: CalendarEvent[]; onCreate: () => void; onSelectEvent: (event: CalendarEvent) => void }) { return ( ); } export function CalendarDayView({ events, selectedDate, onCreate, onSelectEvent }: { events: CalendarEvent[]; selectedDate: Date; onCreate: () => void; onSelectEvent: (event: CalendarEvent) => void }) { return (

{formatJalaliDate(selectedDate)}

{events.length ? `${toPersianDigits(events.length)} رویداد` : "رویدادی برای این روز وجود ندارد"}

{events.length ?
{events.map((event) => { clickEvent.stopPropagation(); onSelectEvent(event); }} />)}
: }
); } export function CalendarWeekView({ events, anchorDate, onSelectEvent }: { events: CalendarEvent[]; anchorDate: Date; onSelectEvent: (event: CalendarEvent) => void }) { const week = buildWeekDays(anchorDate); return
{week.map((day) =>

{formatJalaliDate(day)}

{events.filter((event) => isSameDay(event.startAt, day)).map((event) => { clickEvent.stopPropagation(); onSelectEvent(event); }} />)}
)}
; } export function CalendarListView({ events, onSelectEvent }: { events: CalendarEvent[]; onSelectEvent: (event: CalendarEvent) => void }) { if (!events.length) return ; return
{events.map((event) => { clickEvent.stopPropagation(); onSelectEvent(event); }} />)}
; } export function CalendarTimelineView({ events, onSelectEvent }: { events: CalendarEvent[]; onSelectEvent: (event: CalendarEvent) => void }) { return
{events.map((event) => )}
; } export function CalendarEventCard({ event, compact, detailed, className = "", onClick, onDragStart }: { event: CalendarEvent; compact?: boolean; detailed?: boolean; className?: string; onClick?: (event: React.MouseEvent) => void; onDragStart?: (event: React.DragEvent) => void }) { const type = getType(event.type); return (
keyboardEvent.key === "Enter" && onClick?.(keyboardEvent as unknown as React.MouseEvent)} onClick={onClick} className={`group rounded-2xl border border-white/25 bg-white/45 text-right shadow-sm outline-none transition hover:-translate-y-0.5 hover:bg-white/65 focus:ring-2 focus:ring-sky-400/50 dark:bg-white/10 dark:hover:bg-white/15 ${compact ? "p-2 text-xs" : "p-3"} ${className}`}>

{event.title}

{!compact &&

{type.labelFa} · {statusLabels[event.status]}

} {detailed &&

{formatJalaliDateTime(event.startAt)} · {event.instructorFa ?? "مدرس ثبت نشده"} · {toPersianDigits(event.participantsCount)} نفر

}
); } export function CalendarEventDetail({ event, role, onClose }: { event: CalendarEvent; role: UserRole; onClose: () => void }) { useEffect(() => { const handler = (keyboardEvent: KeyboardEvent) => keyboardEvent.key === "Escape" && onClose(); window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [onClose]); const type = getType(event.type); const canEdit = role === "super_admin" || role === "org_admin" || (role === "manager" && event.type === "team_session"); return (

{type.labelFa}

{event.title}

{formatJalaliDateTime(event.startAt)} تا {formatJalaliDateTime(event.endAt)}

{event.description || "توضیحی برای این رویداد ثبت نشده است."}

{event.attendanceEnabled && }
{canEdit && }
); } export function CalendarEventActions({ event }: { event: CalendarEvent }) { const action = getEventPrimaryAction(event); const clickable = Boolean(action.href) && !action.disabled; return (

اقدام رویداد

{action.description &&

{action.description}

}
); } export function CalendarEventCreateSheet({ role, initialDate, onClose, onCreate }: { role: UserRole; initialDate: string; onClose: () => void; onCreate: (payload: Partial) => void }) { return ; } export function CalendarEventCreateForm({ role, initialDate, onCancel, onCreate }: { role: UserRole; initialDate: string; onCancel: () => void; onCreate: (payload: Partial) => void }) { const [title, setTitle] = useState(""); const [type, setType] = useState("online_class"); const [description, setDescription] = useState(""); const [startDate, setStartDate] = useState(initialDate); const [startTime, setStartTime] = useState("09:00"); const [endDate, setEndDate] = useState(initialDate); const [endTime, setEndTime] = useState("10:00"); const [connectedType, setConnectedType] = useState("none"); const [onlineLink, setOnlineLink] = useState(""); const [recordingLink, setRecordingLink] = useState(""); const [audience, setAudience] = useState("کارکنان"); const [reminder, setReminder] = useState("۶۰"); const [status, setStatus] = useState("scheduled"); const [warnings, setWarnings] = useState([]); const [step, setStep] = useState(0); useEffect(() => { setStartDate(initialDate); setEndDate(initialDate); }, [initialDate]); const validate = (targetStep = step) => { const nextWarnings: string[] = []; if (targetStep === 0 && !title.trim()) nextWarnings.push("عنوان رویداد الزامی است."); if (targetStep === 1 && !startDate) nextWarnings.push("تاریخ شروع الزامی است."); if (targetStep === 1 && !startTime) nextWarnings.push("ساعت شروع الزامی است."); const startAt = toIsoFromParts(startDate, startTime); const endAt = toIsoFromParts(endDate || startDate, endTime || startTime); if (targetStep === 1 && new Date(endAt) < new Date(startAt)) nextWarnings.push("تاریخ پایان نباید قبل از تاریخ شروع باشد."); if (targetStep === 2 && type === "online_class" && !onlineLink.trim()) nextWarnings.push("برای کلاس آنلاین، لینک ورود یا لینک جلسه را وارد کنید."); setWarnings(nextWarnings); return { valid: nextWarnings.length === 0, startAt, endAt }; }; const submit = (event: React.FormEvent) => { event.preventDefault(); if (step < 3) { const result = validate(step); if (result.valid) { setWarnings([]); setStep((value) => value + 1); } return; } const first = validate(0); const timing = validate(1); const connection = validate(2); if (!first.valid || !timing.valid || !connection.valid) return; const definition = getType(type); onCreate({ title: title.trim(), description, type, status, startAt: timing.startAt, endAt: timing.endAt, allDay: false, color: definition.color, connectedItem: { type: connectedType as CalendarConnectedItemType, title: connectedType === "none" ? "هیچ‌کدام" : connectionLabel(connectedType) }, onlineLink: onlineLink || undefined, recordingLink: recordingLink || undefined, roleTargets: role === "manager" ? ["employee"] : ["manager", "employee"], organizationFa: audience, participantsCount: 1, reminders: [{ id: `rem-${Date.now()}`, titleFa: `${toPersianDigits(reminder)} دقیقه قبل`, minutesBefore: Number(reminder), channels: ["in_app"], state: "pending", recipientsCount: 1 }], attendanceEnabled: type === "online_class" || type === "webinar" || type === "in_person_class" }); }; return (
{["مشخصات", "زمان", "دسترسی", "مرور"].map((label, index) =>
{toPersianDigits(index + 1)}. {label}. {label}
)}
{!!warnings.length &&
{warnings.map((warning) =>

{warning}

)}
}
{step === 0 &&