/** * API модуль для расписания занятий */ import apiClient from '@/lib/api-client'; export interface Lesson { id: string; title: string; subject?: string; description?: string; start_time: string; end_time: string; status?: 'scheduled' | 'in_progress' | 'completed' | 'cancelled'; mentor?: { id: string; first_name: string; last_name: string; email: string; }; client?: { id: string; user?: { id: string; first_name: string; last_name: string; email: string; }; }; client_name?: string; mentor_notes?: string; mentor_grade?: number; school_grade?: number; homework_text?: string; price?: number; meeting_url?: string; duration?: number; group?: number; group_name?: string; livekit_room_name?: string; completed_at?: string; } /** Файл урока (для экрана завершения занятия) */ export interface LessonFile { id: string | number; lesson: string | number; file?: string; material?: string | number; source?: 'uploaded' | 'material'; filename: string; file_size?: number; file_size_display?: string; file_url?: string; description?: string; uploaded_by?: number; uploaded_by_name?: string; created_at?: string; } export interface CreateLessonFileData { lesson: string; file?: File; material?: string; filename?: string; description?: string; } /** * Получить список занятий * Для родителя передать child_id (user_id ребёнка). * Для ментора передать client_id (Client.id) — занятия конкретного студента. */ export async function getLessons(params?: { start_date?: string; end_date?: string; status?: string; child_id?: string; client_id?: string; }): Promise<{ results: Lesson[]; count?: number }> { const queryParams = new URLSearchParams(); if (params?.start_date) queryParams.append('start_date', params.start_date); if (params?.end_date) queryParams.append('end_date', params.end_date); if (params?.status) queryParams.append('status', params.status); if (params?.child_id) queryParams.append('child_id', params.child_id); if (params?.client_id) queryParams.append('client_id', params.client_id); const queryString = queryParams.toString(); const url = `/schedule/lessons/${queryString ? `?${queryString}` : ''}`; const response = await apiClient.get(url); if (Array.isArray(response.data)) { return { results: response.data }; } return response.data; } /** Ответ calendar API */ interface CalendarResponse { success: boolean; data: { start_date: string; end_date: string; lessons: Lesson[]; total: number }; } /** * Занятия для календаря (лёгкий endpoint по диапазону дат). * Для родителя передать child_id (user_id ребёнка). */ export async function getLessonsCalendar(params: { start_date: string; end_date: string; status?: string; child_id?: string; }): Promise<{ lessons: Lesson[] }> { const q = new URLSearchParams({ start_date: params.start_date, end_date: params.end_date }); if (params.status) q.append('status', params.status); if (params.child_id) q.append('child_id', params.child_id); // cache: false — после создания/редактирования/удаления занятия интерфейс должен обновиться без перезагрузки const res = await apiClient.get(`/schedule/lessons/calendar/?${q}`, { cache: false }); const lessons = res.data?.data?.lessons; return { lessons: Array.isArray(lessons) ? lessons : [] }; } /** * Получить занятие по ID */ export async function getLesson(id: string): Promise { const response = await apiClient.get(`/schedule/lessons/${id}/`); return response.data; } export interface CreateLessonData { client: string; title?: string; description?: string; start_time: string; duration: number; price?: number; is_recurring?: boolean; subject_id?: number; mentor_subject_id?: number; subject_name?: string; } export interface UpdateLessonData { title?: string; description?: string; start_time?: string; duration?: number; price?: number; } /** * Создать занятие */ export async function createLesson(data: CreateLessonData): Promise { const response = await apiClient.post('/schedule/lessons/', data); return response.data; } /** * Обновить занятие */ export async function updateLesson(id: string, data: UpdateLessonData): Promise { const response = await apiClient.patch(`/schedule/lessons/${id}/`, data); return response.data; } /** * Удалить занятие */ export async function deleteLesson(id: string, deleteAllFuture = false): Promise { await apiClient.delete(`/schedule/lessons/${id}/`, { data: { delete_all_future: deleteAllFuture }, }); } /** Ответ API завершения занятия */ export interface CompleteLessonResponse { success: boolean; message?: string; data?: Lesson; } /** * Завершить занятие / обновить обратную связь. * lessonFileIds — ID файлов урока, которые нужно привязать к ДЗ (только они попадут в «Файлы задания»). */ export async function completeLesson( id: string, notes?: string, mentorGrade?: number, schoolGrade?: number, homeworkText?: string, hasHomeworkFiles?: boolean, lessonFileIds?: number[] ): Promise { const body: Record = { notes: notes ?? '', mentor_grade: mentorGrade, school_grade: schoolGrade, homework_text: homeworkText, has_homework_files: hasHomeworkFiles, }; if (lessonFileIds != null) { body.lesson_file_ids = lessonFileIds; } const response = await apiClient.post(`/schedule/lessons/${id}/complete/`, body); return response.data; } /** * Получить файлы урока (для экрана завершения занятия). */ export async function getLessonFiles(lessonId: string): Promise { const response = await apiClient.get( `/schedule/lesson-files/?lesson=${lessonId}` ); const data = response.data; if (Array.isArray(data)) return data; return (data as { results: LessonFile[] })?.results ?? []; } /** * Создать файл урока (загрузка файла или привязка материала). */ export async function createLessonFile(data: CreateLessonFileData): Promise { const formData = new FormData(); formData.append('lesson', data.lesson); if (data.file) formData.append('file', data.file); if (data.material) formData.append('material', data.material); if (data.filename) formData.append('filename', data.filename); if (data.description) formData.append('description', data.description); const response = await apiClient.post('/schedule/lesson-files/', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }); return response.data; } /** * Удалить файл урока. */ export async function deleteLessonFile(fileId: string): Promise { await apiClient.delete(`/schedule/lesson-files/${fileId}/`); } /** * Прикрепить файл к уроку (для ДЗ при завершении занятия). * Возвращает созданный LessonFile (нужен id для передачи в complete как lesson_file_ids). */ export async function uploadLessonFile(lessonId: number | string, file: File): Promise { const formData = new FormData(); formData.append('lesson', String(lessonId)); formData.append('file', file); const response = await apiClient.post('/schedule/lesson-files/', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }); return response.data; }