- Fix getEnrollmentRequests to use listEnrollmentRequests - Fix respondToEnrollmentRequest to use respondToEnrollment
379 lines
14 KiB
TypeScript
379 lines
14 KiB
TypeScript
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<Record<string, string>> {
|
|
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<ClassWithRelations> {
|
|
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<Class> {
|
|
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<Class>): Promise<Class> {
|
|
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<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.delete(`${API_BASE}/database/timetable/classes/${classId}`, { headers });
|
|
},
|
|
|
|
async getMyClasses(): Promise<Class[]> {
|
|
const headers = await getAuthHeaders();
|
|
const response = await axios.get(`${API_BASE}/database/timetable/classes/me/student`, { headers });
|
|
return response.data.classes;
|
|
},
|
|
|
|
async getMyTeachingClasses(): Promise<Class[]> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
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<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.delete(`${API_BASE}/database/timetable/classes/${classId}/students/${studentId}`, { headers });
|
|
},
|
|
|
|
async leaveClass(classId: string): Promise<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.post(`${API_BASE}/database/timetable/classes/${classId}/leave`, {}, { headers });
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Timetable Service
|
|
// ============================================================================
|
|
|
|
export const timetableOnlyService = {
|
|
async listTimetables(filters?: {
|
|
class_id?: string;
|
|
type?: 'ad-hoc' | 'recurring';
|
|
active?: boolean;
|
|
}): Promise<Timetable[]> {
|
|
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<TimetableWithRelations> {
|
|
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<string, unknown>;
|
|
recurrence_rule?: string;
|
|
whiteboard_type?: 'single' | 'multiple';
|
|
}): Promise<Timetable> {
|
|
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<Timetable>): Promise<Timetable> {
|
|
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<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.delete(`${API_BASE}/database/timetable/timetables/${timetableId}`, { headers });
|
|
},
|
|
|
|
async generateLessons(timetableId: string, startDate: string, endDate: string): Promise<void> {
|
|
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<void> {
|
|
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<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.delete(`${API_BASE}/database/timetable/timetables/${timetableId}/teachers/${teacherId}`, { headers });
|
|
},
|
|
|
|
// Lessons from timetable
|
|
async getTimetableLessons(timetableId: string): Promise<TimetableLesson[]> {
|
|
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<Lesson[]> {
|
|
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<LessonWithRelations> {
|
|
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<Lesson> {
|
|
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<Lesson>): Promise<Lesson> {
|
|
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<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.delete(`${API_BASE}/database/timetable/lessons/${lessonId}`, { headers });
|
|
},
|
|
|
|
async startLesson(lessonId: string): Promise<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.post(`${API_BASE}/database/timetable/lessons/${lessonId}/start`, {}, { headers });
|
|
},
|
|
|
|
async endLesson(lessonId: string): Promise<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.post(`${API_BASE}/database/timetable/lessons/${lessonId}/end`, {}, { headers });
|
|
},
|
|
|
|
async cancelLesson(lessonId: string, reason?: string): Promise<void> {
|
|
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<EnrollmentRequest> {
|
|
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<EnrollmentRequestWithProfile[]> {
|
|
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<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.post(
|
|
`${API_BASE}/database/timetable/enrollment-requests/${requestId}/respond`,
|
|
{ status },
|
|
{ headers }
|
|
);
|
|
},
|
|
|
|
async cancelEnrollmentRequest(requestId: string): Promise<void> {
|
|
const headers = await getAuthHeaders();
|
|
await axios.post(`${API_BASE}/database/timetable/enrollment-requests/${requestId}/cancel`, {}, { headers });
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Combined Export
|
|
// ============================================================================
|
|
|
|
export const timetableService = {
|
|
...classService,
|
|
...lessonService,
|
|
...enrollmentService,
|
|
|
|
// Aliases for store compatibility
|
|
getClasses: classService.listClasses,
|
|
getClass: classService.getClass,
|
|
createClass: classService.createClass,
|
|
updateClass: classService.updateClass,
|
|
deleteClass: classService.deleteClass,
|
|
getMyClasses: classService.getMyClasses,
|
|
getMyTeachingClasses: classService.getMyTeachingClasses,
|
|
addTeacherToClass: classService.addTeacher,
|
|
removeTeacherFromClass: classService.removeTeacher,
|
|
addStudentToClass: classService.addStudent,
|
|
removeStudentFromClass: classService.removeStudent,
|
|
|
|
// Timetable aliases
|
|
getTimetables: timetableOnlyService.listTimetables,
|
|
getTimetable: timetableOnlyService.getTimetable,
|
|
createTimetable: timetableOnlyService.createTimetable,
|
|
updateTimetable: timetableOnlyService.updateTimetable,
|
|
deleteTimetable: timetableOnlyService.deleteTimetable,
|
|
getMyTimetables: timetableOnlyService.getMyTimetables,
|
|
getMyTeachingTimetables: timetableOnlyService.getMyTeachingTimetables,
|
|
addTeacherToTimetable: timetableOnlyService.addTeacher,
|
|
removeTeacherFromTimetable: timetableOnlyService.removeTeacher,
|
|
addTimetableLesson: timetableOnlyService.addLesson,
|
|
updateTimetableLesson: timetableOnlyService.updateLesson,
|
|
removeTimetableLesson: timetableOnlyService.removeLesson,
|
|
|
|
// Lesson aliases
|
|
getLessons: lessonService.listLessons,
|
|
getLesson: lessonService.getLesson,
|
|
generateLessons: lessonService.generateLessons,
|
|
cancelLesson: lessonService.cancelLesson,
|
|
getMyLessons: lessonService.getMyLessons,
|
|
getMyTeachingLessons: lessonService.getMyTeachingLessons,
|
|
saveWhiteboard: lessonService.saveWhiteboard,
|
|
getWhiteboard: lessonService.getWhiteboard,
|
|
exportWhiteboard: lessonService.exportWhiteboard,
|
|
|
|
// Enrollment aliases
|
|
getEnrollmentRequests: enrollmentService.listEnrollmentRequests,
|
|
requestEnrollment: enrollmentService.requestEnrollment,
|
|
respondToEnrollmentRequest: enrollmentService.respondToEnrollment,
|
|
cancelEnrollmentRequest: enrollmentService.cancelEnrollmentRequest,
|
|
};
|
|
|
|
export default timetableOnlyService;
|