import axios from 'axios'; import { supabase } from '../supabaseClient'; import { Class, ClassWithRelations, ClassFilters, Timetable, TimetableWithRelations, TimetableLesson, Lesson, LessonWithRelations, EnrollmentRequest, EnrollmentRequestWithProfile, } from '../types/timetable.types'; // API base URL const API_BASE = import.meta.env.VITE_API_URL || 'http://localhost:8000'; // ============================================================================ // Helper: Get auth headers // ============================================================================ async function getAuthHeaders(): Promise> { const { data: { session } } = await supabase.auth.getSession(); if (!session?.access_token) { throw new Error('No authentication token available'); } return { Authorization: `Bearer ${session.access_token}`, }; } // ============================================================================ // Class Service // ============================================================================ export const classService = { async listClasses(filters?: ClassFilters): Promise<{ classes: Class[]; total: number }> { const headers = await getAuthHeaders(); const params = new URLSearchParams(); if (filters?.subject) params.append('subject', filters.subject); if (filters?.school_year) params.append('school_year', filters.school_year); if (filters?.academic_term) params.append('academic_term', filters.academic_term); if (filters?.search) params.append('search', filters.search); if (filters?.skip !== undefined) params.append('skip', filters.skip.toString()); if (filters?.limit !== undefined) params.append('limit', filters.limit.toString()); const response = await axios.get(`${API_BASE}/database/timetable/classes?${params}`, { headers }); return response.data; }, async getClass(classId: string): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/classes/${classId}`, { headers }); return response.data; }, async createClass(data: { name: string; subject: string; school_year: string; academic_term: string; description?: string; }): Promise { const headers = await getAuthHeaders(); const response = await axios.post(`${API_BASE}/database/timetable/classes`, data, { headers }); return response.data; }, async updateClass(classId: string, data: Partial): Promise { const headers = await getAuthHeaders(); const response = await axios.patch(`${API_BASE}/database/timetable/classes/${classId}`, data, { headers }); return response.data; }, async deleteClass(classId: string): Promise { const headers = await getAuthHeaders(); await axios.delete(`${API_BASE}/database/timetable/classes/${classId}`, { headers }); }, async getMyClasses(): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/classes/me/student`, { headers }); return response.data.classes; }, async getMyTeachingClasses(): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/classes/me/teacher`, { headers }); return response.data.classes; }, // Teacher management async addTeacher(classId: string, teacherId: string, isPrimary: boolean = false): Promise { const headers = await getAuthHeaders(); await axios.post( `${API_BASE}/database/timetable/classes/${classId}/teachers`, { teacher_id: teacherId, is_primary: isPrimary }, { headers } ); }, async removeTeacher(classId: string, teacherId: string): Promise { const headers = await getAuthHeaders(); await axios.delete(`${API_BASE}/database/timetable/classes/${classId}/teachers/${teacherId}`, { headers }); }, // Student management async addStudent(classId: string, studentId: string): Promise { const headers = await getAuthHeaders(); await axios.post( `${API_BASE}/database/timetable/classes/${classId}/students`, { student_id: studentId }, { headers } ); }, async removeStudent(classId: string, studentId: string): Promise { const headers = await getAuthHeaders(); await axios.delete(`${API_BASE}/database/timetable/classes/${classId}/students/${studentId}`, { headers }); }, async leaveClass(classId: string): Promise { const headers = await getAuthHeaders(); await axios.post(`${API_BASE}/database/timetable/classes/${classId}/leave`, {}, { headers }); }, }; // ============================================================================ // Timetable Service // ============================================================================ export const timetableService = { async listTimetables(filters?: { class_id?: string; type?: 'ad-hoc' | 'recurring'; active?: boolean; }): Promise { const headers = await getAuthHeaders(); const params = new URLSearchParams(); if (filters?.class_id) params.append('class_id', filters.class_id); if (filters?.type) params.append('type', filters.type); if (filters?.active !== undefined) params.append('active', filters.active.toString()); const response = await axios.get(`${API_BASE}/database/timetable/timetables?${params}`, { headers }); return response.data.timetables; }, async getTimetable(timetableId: string): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/timetables/${timetableId}`, { headers }); return response.data; }, async createTimetable(data: { class_id: string; name: string; type: 'ad-hoc' | 'recurring'; start_date: string; end_date?: string; recurrence_pattern?: Record; recurrence_rule?: string; whiteboard_type?: 'single' | 'multiple'; }): Promise { const headers = await getAuthHeaders(); const response = await axios.post(`${API_BASE}/database/timetable/timetables`, data, { headers }); return response.data; }, async updateTimetable(timetableId: string, data: Partial): Promise { const headers = await getAuthHeaders(); const response = await axios.patch(`${API_BASE}/database/timetable/timetables/${timetableId}`, data, { headers }); return response.data; }, async deleteTimetable(timetableId: string): Promise { const headers = await getAuthHeaders(); await axios.delete(`${API_BASE}/database/timetable/timetables/${timetableId}`, { headers }); }, async generateLessons(timetableId: string, startDate: string, endDate: string): Promise { const headers = await getAuthHeaders(); await axios.post( `${API_BASE}/database/timetable/timetables/${timetableId}/generate-lessons`, { start_date: startDate, end_date: endDate }, { headers } ); }, // Timetable Teachers async addTimetableTeacher(timetableId: string, teacherId: string): Promise { const headers = await getAuthHeaders(); await axios.post( `${API_BASE}/database/timetable/timetables/${timetableId}/teachers`, { teacher_id: teacherId }, { headers } ); }, async removeTimetableTeacher(timetableId: string, teacherId: string): Promise { const headers = await getAuthHeaders(); await axios.delete(`${API_BASE}/database/timetable/timetables/${timetableId}/teachers/${teacherId}`, { headers }); }, // Lessons from timetable async getTimetableLessons(timetableId: string): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/timetables/${timetableId}/lessons`, { headers }); return response.data.lessons; }, }; // ============================================================================ // Lesson Service // ============================================================================ export const lessonService = { async listLessons(filters?: { timetable_id?: string; start_date?: string; end_date?: string; status?: 'scheduled' | 'in-progress' | 'completed' | 'cancelled'; }): Promise { const headers = await getAuthHeaders(); const params = new URLSearchParams(); if (filters?.timetable_id) params.append('timetable_id', filters.timetable_id); if (filters?.start_date) params.append('start_date', filters.start_date); if (filters?.end_date) params.append('end_date', filters.end_date); if (filters?.status) params.append('status', filters.status); const response = await axios.get(`${API_BASE}/database/timetable/lessons?${params}`, { headers }); return response.data.lessons; }, async getLesson(lessonId: string): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/lessons/${lessonId}`, { headers }); return response.data; }, async createLesson(data: { timetable_id: string; scheduled_start: string; scheduled_end: string; teacher_id?: string; title?: string; description?: string; }): Promise { const headers = await getAuthHeaders(); const response = await axios.post(`${API_BASE}/database/timetable/lessons`, data, { headers }); return response.data; }, async updateLesson(lessonId: string, data: Partial): Promise { const headers = await getAuthHeaders(); const response = await axios.patch(`${API_BASE}/database/timetable/lessons/${lessonId}`, data, { headers }); return response.data; }, async deleteLesson(lessonId: string): Promise { const headers = await getAuthHeaders(); await axios.delete(`${API_BASE}/database/timetable/lessons/${lessonId}`, { headers }); }, async startLesson(lessonId: string): Promise { const headers = await getAuthHeaders(); await axios.post(`${API_BASE}/database/timetable/lessons/${lessonId}/start`, {}, { headers }); }, async endLesson(lessonId: string): Promise { const headers = await getAuthHeaders(); await axios.post(`${API_BASE}/database/timetable/lessons/${lessonId}/end`, {}, { headers }); }, async cancelLesson(lessonId: string, reason?: string): Promise { const headers = await getAuthHeaders(); await axios.post( `${API_BASE}/database/timetable/lessons/${lessonId}/cancel`, { reason }, { headers } ); }, }; // ============================================================================ // Enrollment Request Service // ============================================================================ export const enrollmentService = { async requestEnrollment(classId: string, message?: string): Promise { const headers = await getAuthHeaders(); const response = await axios.post( `${API_BASE}/database/timetable/classes/${classId}/enroll`, { message }, { headers } ); return response.data; }, async listEnrollmentRequests(classId: string): Promise { const headers = await getAuthHeaders(); const response = await axios.get(`${API_BASE}/database/timetable/classes/${classId}/enrollment-requests`, { headers }); return response.data.requests; }, async respondToEnrollment(requestId: string, status: 'approved' | 'rejected'): Promise { const headers = await getAuthHeaders(); await axios.post( `${API_BASE}/database/timetable/enrollment-requests/${requestId}/respond`, { status }, { headers } ); }, async cancelEnrollmentRequest(requestId: string): Promise { const headers = await getAuthHeaders(); await axios.post(`${API_BASE}/database/timetable/enrollment-requests/${requestId}/cancel`, {}, { headers }); }, }; // ============================================================================ // Combined Export // ============================================================================ export const timetableService = { ...classService, ...timetableService, ...lessonService, ...enrollmentService, }; export default timetableService;