import type { AuthResponse, UserLogin, UserRegister, User, Subject, SubjectCreate, SubjectUpdate, Grade, GradeCreate, GradeUpdate, ReportPeriod, ReportPeriodCreate, ReportPeriodUpdate, TeacherGrade, TeacherGradeCreate, TeacherGradeUpdate, } from "~/types/api"; const API_BASE_URL = import.meta.env.VITE_API_URL || "http://localhost:8000/api"; class ApiClient { private getHeaders(includeAuth: boolean = false): HeadersInit { const headers: HeadersInit = { "Content-Type": "application/json", }; if (includeAuth) { const token = localStorage.getItem("access_token"); if (token) { headers["Authorization"] = `Bearer ${token}`; } } return headers; } private async handleResponse(response: Response): Promise { if (!response.ok) { const error = await response.json().catch(() => ({ detail: "An error occurred" })); throw new Error(error.detail || `HTTP ${response.status}`); } if (response.status === 204) { return undefined as T; } return response.json(); } // Auth endpoints async register(data: UserRegister): Promise { const response = await fetch(`${API_BASE_URL}/auth/register`, { method: "POST", headers: this.getHeaders(), body: JSON.stringify(data), }); const result = await this.handleResponse(response); localStorage.setItem("access_token", result.access_token); return result; } async login(data: UserLogin): Promise { const response = await fetch(`${API_BASE_URL}/auth/login`, { method: "POST", headers: this.getHeaders(), body: JSON.stringify(data), }); const result = await this.handleResponse(response); localStorage.setItem("access_token", result.access_token); return result; } async getMe(): Promise { const response = await fetch(`${API_BASE_URL}/auth/me`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } logout(): void { localStorage.removeItem("access_token"); } isAuthenticated(): boolean { return !!localStorage.getItem("access_token"); } // Subject endpoints async getSubjects(): Promise { const response = await fetch(`${API_BASE_URL}/subjects`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async getSubject(id: string): Promise { const response = await fetch(`${API_BASE_URL}/subjects/${id}`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async createSubject(data: SubjectCreate): Promise { const response = await fetch(`${API_BASE_URL}/subjects`, { method: "POST", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async updateSubject(id: string, data: SubjectUpdate): Promise { const response = await fetch(`${API_BASE_URL}/subjects/${id}`, { method: "PUT", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async deleteSubject(id: string): Promise { const response = await fetch(`${API_BASE_URL}/subjects/${id}`, { method: "DELETE", headers: this.getHeaders(true), }); return this.handleResponse(response); } // Grade endpoints async getGrades(subjectId?: string): Promise { const url = subjectId ? `${API_BASE_URL}/grades?subject_id=${subjectId}` : `${API_BASE_URL}/grades`; const response = await fetch(url, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async getGrade(id: string): Promise { const response = await fetch(`${API_BASE_URL}/grades/${id}`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async createGrade(data: GradeCreate): Promise { const response = await fetch(`${API_BASE_URL}/grades`, { method: "POST", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async updateGrade(id: string, data: GradeUpdate): Promise { const response = await fetch(`${API_BASE_URL}/grades/${id}`, { method: "PUT", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async deleteGrade(id: string): Promise { const response = await fetch(`${API_BASE_URL}/grades/${id}`, { method: "DELETE", headers: this.getHeaders(true), }); return this.handleResponse(response); } // Report Period endpoints async getPeriods(): Promise { const response = await fetch(`${API_BASE_URL}/periods`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async getPeriod(id: string): Promise { const response = await fetch(`${API_BASE_URL}/periods/${id}`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async createPeriod(data: ReportPeriodCreate): Promise { const response = await fetch(`${API_BASE_URL}/periods`, { method: "POST", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async updatePeriod(id: string, data: ReportPeriodUpdate): Promise { const response = await fetch(`${API_BASE_URL}/periods/${id}`, { method: "PUT", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async deletePeriod(id: string): Promise { const response = await fetch(`${API_BASE_URL}/periods/${id}`, { method: "DELETE", headers: this.getHeaders(true), }); return this.handleResponse(response); } // Teacher Grade endpoints async getTeacherGrades(subjectId?: string, periodId?: string): Promise { const params = new URLSearchParams(); if (subjectId) params.append("subject_id", subjectId); if (periodId) params.append("period_id", periodId); const url = `${API_BASE_URL}/teacher-grades${params.toString() ? `?${params.toString()}` : ""}`; const response = await fetch(url, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async getTeacherGrade(id: string): Promise { const response = await fetch(`${API_BASE_URL}/teacher-grades/${id}`, { headers: this.getHeaders(true), }); return this.handleResponse(response); } async createTeacherGrade(data: TeacherGradeCreate): Promise { const response = await fetch(`${API_BASE_URL}/teacher-grades`, { method: "POST", headers: this.getHeaders(true), body: JSON.stringify(data), }); return this.handleResponse(response); } async deleteTeacherGrade(id: string): Promise { const response = await fetch(`${API_BASE_URL}/teacher-grades/${id}`, { method: "DELETE", headers: this.getHeaders(true), }); return this.handleResponse(response); } // Export endpoints async exportGradesCSV(periodId?: string): Promise { const url = periodId ? `${API_BASE_URL}/export/grades?period_id=${periodId}` : `${API_BASE_URL}/export/grades`; const response = await fetch(url, { headers: this.getHeaders(true), }); if (!response.ok) { throw new Error("Failed to export grades"); } // Create a blob from the response and trigger download const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = downloadUrl; // Extract filename from Content-Disposition header or use default const contentDisposition = response.headers.get("Content-Disposition"); const filename = contentDisposition ? contentDisposition.split("filename=")[1]?.replace(/"/g, "") : "grades_export.csv"; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(downloadUrl); } } export const api = new ApiClient();