From 52364d717c559be58828d9da872dde58225a8f8d Mon Sep 17 00:00:00 2001 From: Gabriellvl Date: Fri, 21 Mar 2025 23:23:33 +0100 Subject: [PATCH] feat: teacher en student frontend controllers --- backend/src/routes/router.ts | 2 + frontend/config.ts | 1 + frontend/src/controllers/base-controller.ts | 72 +++++++++++++++++++ frontend/src/controllers/controllers.ts | 16 +++++ .../src/controllers/student-controller.ts | 44 ++++++++++++ .../src/controllers/teacher-controller.ts | 37 ++++++++++ 6 files changed, 172 insertions(+) create mode 100644 frontend/config.ts create mode 100644 frontend/src/controllers/base-controller.ts create mode 100644 frontend/src/controllers/controllers.ts create mode 100644 frontend/src/controllers/student-controller.ts create mode 100644 frontend/src/controllers/teacher-controller.ts diff --git a/backend/src/routes/router.ts b/backend/src/routes/router.ts index 639857a7..e05f9909 100644 --- a/backend/src/routes/router.ts +++ b/backend/src/routes/router.ts @@ -1,5 +1,6 @@ import { Response, Router } from 'express'; import studentRouter from './students.js'; +import teacherRouter from './teachers.js'; import groupRouter from './groups.js'; import assignmentRouter from './assignments.js'; import submissionRouter from './submissions.js'; @@ -22,6 +23,7 @@ router.get('/', (_, res: Response) => { }); router.use('/student', studentRouter /* #swagger.tags = ['Student'] */); +router.use('/teacher', teacherRouter /* #swagger.tags = ['Teacher'] */); router.use('/group', groupRouter /* #swagger.tags = ['Group'] */); router.use('/assignment', assignmentRouter /* #swagger.tags = ['Assignment'] */); router.use('/submission', submissionRouter /* #swagger.tags = ['Submission'] */); diff --git a/frontend/config.ts b/frontend/config.ts new file mode 100644 index 00000000..656687fd --- /dev/null +++ b/frontend/config.ts @@ -0,0 +1 @@ +export const API_BASE = "http://localhost:3000/api"; diff --git a/frontend/src/controllers/base-controller.ts b/frontend/src/controllers/base-controller.ts new file mode 100644 index 00000000..8005a32e --- /dev/null +++ b/frontend/src/controllers/base-controller.ts @@ -0,0 +1,72 @@ +import {API_BASE} from "../../config.ts"; + +export class BaseController { + protected baseUrl: string; + + constructor(basePath: string) { + this.baseUrl = `${API_BASE}/${basePath}`; + } + + protected async get(path: string, queryParams?: Record): Promise { + let url = `${this.baseUrl}${path}`; + if (queryParams) { + const query = new URLSearchParams(); + Object.entries(queryParams).forEach(([key, value]) => { + if (value !== undefined && value !== null) query.append(key, value.toString()); + }); + url += `?${query.toString()}`; + } + + const res = await fetch(url); + if (!res.ok) { + const errorData = await res.json().catch(() => ({})); + throw new Error(errorData?.error || `Error ${res.status}: ${res.statusText}`); + } + + return res.json(); + } + + protected async post(path: string, body: unknown): Promise { + const res = await fetch(`${this.baseUrl}${path}`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + const errorData = await res.json().catch(() => ({})); + throw new Error(errorData?.error || `Error ${res.status}: ${res.statusText}`); + } + + return res.json(); + } + + protected async delete(path: string): Promise { + const res = await fetch(`${this.baseUrl}${path}`, { + method: "DELETE", + }); + + if (!res.ok) { + const errorData = await res.json().catch(() => ({})); + throw new Error(errorData?.error || `Error ${res.status}: ${res.statusText}`); + } + + return res.json(); + } + + protected async put(path: string, body: unknown): Promise { + const res = await fetch(`${this.baseUrl}${path}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); + + if (!res.ok) { + const errorData = await res.json().catch(() => ({})); + throw new Error(errorData?.error || `Error ${res.status}: ${res.statusText}`); + } + + return res.json(); + } + +} diff --git a/frontend/src/controllers/controllers.ts b/frontend/src/controllers/controllers.ts new file mode 100644 index 00000000..61bb09d6 --- /dev/null +++ b/frontend/src/controllers/controllers.ts @@ -0,0 +1,16 @@ +import {StudentController} from "@/controllers/student-controller.ts"; +import {TeacherController} from "@/controllers/teacher-controller.ts"; + +export function controllerGetter(Factory: new () => T): () => T { + let instance: T | undefined; + + return (): T => { + if (!instance) { + instance = new Factory(); + } + return instance; + }; +} + +export const getStudentController = controllerGetter(StudentController); +export const getTeacherController = controllerGetter(TeacherController); diff --git a/frontend/src/controllers/student-controller.ts b/frontend/src/controllers/student-controller.ts new file mode 100644 index 00000000..e74bd74c --- /dev/null +++ b/frontend/src/controllers/student-controller.ts @@ -0,0 +1,44 @@ +import {BaseController} from "@/controllers/base-controller.ts"; + +export class StudentController extends BaseController { + constructor() { + super("students"); + } + + getAll(full = true) { + return this.get<{ students: any[] }>("/", { full }); + } + + getByUsername(username: string) { + return this.get(`/${username}`); + } + + createStudent(data: any) { + return this.post("/", data); + } + + deleteStudent(username: string) { + return this.delete(`/${username}`); + } + + getClasses(username: string, full = true) { + return this.get<{ classes: any[] }>(`/${username}/classes`, { full }); + } + + getAssignments(username: string, full = true) { + return this.get<{ assignments: any[] }>(`/${username}/assignments`, { full }); + } + + getGroups(username: string, full = true) { + return this.get<{ groups: any[] }>(`/${username}/groups`, { full }); + } + + getSubmissions(username: string) { + return this.get<{ submissions: any[] }>(`/${username}/submissions`); + } + + getQuestions(username: string, full = true) { + return this.get<{ questions: any[] }>(`/${username}/questions`, { full }); + } + +} diff --git a/frontend/src/controllers/teacher-controller.ts b/frontend/src/controllers/teacher-controller.ts new file mode 100644 index 00000000..d3273ac1 --- /dev/null +++ b/frontend/src/controllers/teacher-controller.ts @@ -0,0 +1,37 @@ +import {BaseController} from "@/controllers/base-controller.ts"; + +export class TeacherController extends BaseController { + constructor() { + super("teachers"); + } + + getAll(full = false) { + return this.get<{ teachers: any[] }>("/", { full }); + } + + getByUsername(username: string) { + return this.get(`/${username}`); + } + + createTeacher(data: any) { + return this.post("/", data); + } + + deleteTeacher(username: string) { + return this.delete(`/${username}`); + } + + getClasses(username: string, full = false) { + return this.get(`/${username}/classes`, { full }); + } + + getStudents(username: string, full = false) { + return this.get<{ students: any[] }>(`/${username}/students`, { full }); + } + + getQuestions(username: string, full = false) { + return this.get<{ questions: any[] }>(`/${username}/questions`, { full }); + } + + // getInvitations(id: string) {return this.get<{ invitations: string[] }>(`/${id}/invitations`);} +}