uchill/front_minimal/src/actions/calendar.js

213 lines
6.7 KiB
JavaScript

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();
}