frontend/app/lib/api.ts
2025-07-29 17:55:32 +02:00

209 lines
4.5 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { DateTime, Duration } from "luxon";
const BASE_URL = import.meta.env.VITE_API_URL;
const makePostRequest = async (
url: string,
body: object,
error = "Une erreur est survenue",
method = "POST"
) => {
const response = await fetch(BASE_URL + url, {
method,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(body),
credentials: "include", // Include cookies for authentication
});
const data = await response.json();
if (!response.ok) throw new Error(data.error || error);
return data?.data || data;
};
// TODO: Use swr or react-query for caching and revalidation
// TODO: Cache all to localStorage or IndexedDB for offline support
const makeRequest = async (url: string, error = "Une erreur est survenue") => {
const response = await fetch(BASE_URL + url, { credentials: "include" });
const data = await response.json();
if (!response.ok) throw new Error(data.error || error);
return data?.data || data;
};
/**
* === AUTH API ===
*/
export const requestLogin = async (email: string, token: string) => {
return makePostRequest(
"/auth/request",
{ email, token },
"Échec de la demande de connexion"
);
};
export const verifyOtp = async ({
otpCode,
email,
}: {
otpCode: string;
email: string;
}) => {
return makePostRequest(
"/auth/verify",
{ email, code: otpCode },
"Code de vérification invalide"
);
};
export const getClasses = async () => {
try {
const res = await fetch("/classes.json");
return res.json();
} catch (error) {
console.error("Error fetching classes:", error);
return [];
}
};
export const registerUser = async (
firstName: string,
lastName: string,
className: string,
token: string
) => {
return makePostRequest(
"/auth/register",
{ firstName, lastName, className, token },
"Échec de l'inscription"
);
};
/**
* === COLLES API ===
*/
export const getColles = async (startDate: DateTime) => {
return makeRequest(
`/colles?startDate=${startDate.toISODate()}`,
"Échec de la récupération des colles"
);
};
export interface Colle {
id: number;
date: string; // ISO date string
subject: {
id: number;
name: string;
};
examiner: {
id: number;
name: string;
};
room: {
id: number;
name: string;
};
student: User;
grade?: number; // Nullable grade
bjsecret?: string; // Optional field
bjid?: string; // Optional field
content?: string; // Optional field
comment?: string; // Optional field
attachments?: string[]; // Optional field, array of attachment URLs
}
interface CollePayload {
classColles: Colle[];
studentColles: Colle[];
favoriteColles: Colle[];
}
export const useColles = (startDate: DateTime) => {
// Check if the start date is the current week
// This is used to determine if the data is "actual" or not
const isActual = DateTime.now()
.startOf("week")
.equals(startDate.startOf("week"));
const options = isActual
? {
refetchOnWindowFocus: true,
refetchOnReconnect: true,
staleTime: 0,
gcTime: 0,
}
: {
staleTime: Duration.fromObject({
minutes: 5, // 5 minutes
}).toMillis(),
gcTime: Duration.fromObject({
days: 3, // 3 days
}).toMillis(),
};
const { data, ...props } = useQuery({
queryKey: ["colles", startDate.toISODate()],
queryFn: () => getColles(startDate),
...options,
});
const mergedData = Object.assign(
{
classColles: [],
studentColles: [],
favoriteColles: [],
},
data || {}
) as CollePayload;
return {
...mergedData,
...props
}
};
/**
* === USER API ===
*/
const fetchUser = async () => {
return makeRequest(
"/users/@me",
"Échec de la récupération des informations utilisateur"
);
};
const defaultUser = {
id: 0,
firstName: "",
lastName: "",
fullName: "",
email: "",
className: "",
};
export type User = typeof defaultUser;
export const useUser = () => {
const { data, ...props } = useQuery({
queryKey: ["user"],
queryFn: fetchUser,
staleTime: Duration.fromObject({
minutes: 5, // 5 minutes
}).toMillis(),
gcTime: Duration.fromObject({
days: 3, // 3 days
}).toMillis(),
});
return {
user: (data ? Object.assign(defaultUser, data) : defaultUser) as User,
...props,
};
};
export const logout = async () => {
// TODO: POST
// TODO: Invalidate user query (cache)
};