import { useMemo, useState, useEffect } from 'react'; import { format, startOfMonth, endOfMonth, addMonths, subMonths } from 'date-fns'; import useSWR, { mutate } from 'swr'; import { getCalendarLessons, getMentorStudents, getMentorSubjects, createCalendarLesson, updateCalendarLesson, deleteCalendarLesson, } from 'src/utils/dashboard-api'; import { getGroups } from 'src/utils/groups-api'; import { useAuthContext } from 'src/auth/hooks'; // ---------------------------------------------------------------------- const STUDENTS_ENDPOINT = '/manage/clients/?page=1&page_size=200'; const SUBJECTS_ENDPOINT = '/schedule/subjects/'; const GROUPS_ENDPOINT = '/groups/'; const swrOptions = { revalidateIfStale: true, revalidateOnFocus: false, revalidateOnReconnect: true, }; // Ключ кэша для календаря (по месяцу) function calendarKey(date = new Date()) { const start = format(startOfMonth(subMonths(date, 1)), 'yyyy-MM-dd'); const end = format(endOfMonth(addMonths(date, 1)), 'yyyy-MM-dd'); return ['calendar', start, end]; } // ---------------------------------------------------------------------- export function useGetEvents(currentDate) { const date = currentDate || new Date(); const start = format(startOfMonth(subMonths(date, 1)), 'yyyy-MM-dd'); const end = format(endOfMonth(addMonths(date, 1)), 'yyyy-MM-dd'); const { user } = useAuthContext(); const getChildId = () => { if (user?.role !== 'parent') return null; try { const s = localStorage.getItem('selected_child'); return s ? (JSON.parse(s)?.id || null) : null; } catch { return null; } }; const [childId, setChildId] = useState(getChildId); useEffect(() => { if (user?.role !== 'parent') return undefined; const handler = () => setChildId(getChildId()); window.addEventListener('child-changed', handler); return () => window.removeEventListener('child-changed', handler); // eslint-disable-next-line react-hooks/exhaustive-deps }, [user?.role]); const { data: response, isLoading, error, isValidating } = useSWR( ['calendar', start, end, childId], ([, s, e, cid]) => getCalendarLessons(s, e, cid ? { child_id: cid } : undefined), swrOptions ); const memoizedValue = useMemo(() => { const lessonsArray = response?.data?.lessons || response?.lessons || []; const events = lessonsArray.map((lesson) => { const start = lesson.start_time || lesson.start; const end = lesson.end_time || lesson.end || start; const startTimeStr = start ? new Date(start).toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit', hourCycle: 'h23', }) : ''; const subject = lesson.subject_name || lesson.subject || 'Урок'; const participant = lesson.group_name ? `Группа: ${lesson.group_name}` : (lesson.client_name || ''); const displayTitle = `${startTimeStr} ${subject}${participant ? ` - ${participant}` : ''}`; const status = String(lesson.status || 'scheduled').toLowerCase(); let eventColor = '#7635dc'; if (status === 'completed') eventColor = '#00ab55'; else if (status === 'cancelled') eventColor = '#ff4842'; else if (status === 'in_progress') eventColor = '#1890ff'; return { id: String(lesson.id), title: displayTitle, start, end, allDay: false, color: eventColor, backgroundColor: eventColor, borderColor: eventColor, textColor: '#FFFFFF', extendedProps: { ...lesson, status, student: lesson.client_name || '', mentor: lesson.mentor_name || '', group: lesson.group || null, group_name: lesson.group_name || '', }, }; }); return { events, eventsLoading: isLoading, eventsError: error, eventsValidating: isValidating, eventsEmpty: !isLoading && !events.length, }; }, [response, error, isLoading, isValidating]); return memoizedValue; } // ---------------------------------------------------------------------- export function useGetStudents() { const { data: response, isLoading, error } = useSWR( STUDENTS_ENDPOINT, getMentorStudents, swrOptions ); return useMemo(() => { const rawData = response?.data?.results || response?.results || response || []; return { students: Array.isArray(rawData) ? rawData : [], studentsLoading: isLoading, studentsError: error, }; }, [response, isLoading, error]); } export function useGetSubjects() { const { data: response, isLoading, error } = useSWR( SUBJECTS_ENDPOINT, getMentorSubjects, swrOptions ); return useMemo(() => { const rawData = response?.data || response?.results || response || []; return { subjects: Array.isArray(rawData) ? rawData : [], subjectsLoading: isLoading, subjectsError: error, }; }, [response, isLoading, error]); } export function useGetGroups() { const { data, isLoading, error } = useSWR(GROUPS_ENDPOINT, getGroups, swrOptions); return useMemo(() => ({ groups: Array.isArray(data) ? data : [], groupsLoading: isLoading, groupsError: error, }), [data, isLoading, error]); } // ---------------------------------------------------------------------- function revalidateCalendar() { mutate((key) => Array.isArray(key) && key[0] === 'calendar', undefined, { revalidate: true }); } export async function createEvent(eventData) { const isGroup = !!eventData.group; const payload = { title: eventData.title || 'Занятие', description: eventData.description || '', start_time: eventData.start_time, duration: eventData.duration || 60, price: eventData.price, is_recurring: eventData.is_recurring || false, ...(eventData.subject && { subject_id: Number(eventData.subject) }), ...(isGroup ? { group: eventData.group } : { client: String(eventData.client) }), }; const res = await createCalendarLesson(payload); revalidateCalendar(); return res; } export async function updateEvent(eventData, currentDate) { const { id, ...data } = eventData; const updatePayload = {}; if (data.start_time) updatePayload.start_time = data.start_time; if (data.duration) updatePayload.duration = data.duration; if (data.price != null) updatePayload.price = data.price; if (data.description != null) updatePayload.description = data.description; if (data.status) updatePayload.status = data.status; const res = await updateCalendarLesson(String(id), updatePayload); revalidateCalendar(); return res; } export async function deleteEvent(eventId, deleteAllFuture = false) { await deleteCalendarLesson(String(eventId), deleteAllFuture); revalidateCalendar(); }