diff --git a/client/src/interfaces/timeslot.ts b/client/src/interfaces/timeslot.ts index eee7ded..9d0007f 100644 --- a/client/src/interfaces/timeslot.ts +++ b/client/src/interfaces/timeslot.ts @@ -1,4 +1,11 @@ export interface Timeslot { startDate: Date endDate: Date +} + +export interface WeeklyTimeslot { + id: number + day_of_week: number + start_time: string + end_time: string } \ No newline at end of file diff --git a/client/src/router/index.ts b/client/src/router/index.ts index 464495e..cfd06ec 100644 --- a/client/src/router/index.ts +++ b/client/src/router/index.ts @@ -24,6 +24,14 @@ const router = createRouter({ // this generates a separate chunk (About.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import('../views/Register.vue') + }, + { + path: '/trainer/schedule', + name: 'TrainerSchedule', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => import('../views/trainer/Schedule.vue') } ] }) diff --git a/client/src/views/trainer/Schedule.vue b/client/src/views/trainer/Schedule.vue new file mode 100644 index 0000000..f0e9970 --- /dev/null +++ b/client/src/views/trainer/Schedule.vue @@ -0,0 +1,201 @@ + + + + + \ No newline at end of file diff --git a/server/src/interfaces/timeslot.ts b/server/src/interfaces/timeslot.ts index caded19..f4c08fa 100644 --- a/server/src/interfaces/timeslot.ts +++ b/server/src/interfaces/timeslot.ts @@ -4,6 +4,7 @@ export interface Timeslot { } export interface WeeklyTimeslot { + id: number day_of_week: number start_time: string end_time: string diff --git a/server/src/routes/index.ts b/server/src/routes/index.ts index 4e95b48..488600d 100644 --- a/server/src/routes/index.ts +++ b/server/src/routes/index.ts @@ -5,7 +5,7 @@ const router: Router = express.Router(); import login from "./login" import register from "./register" import center from "./center"; -import trainer from "./trainer"; +import trainer from "./trainer/index"; import timeslot from "./timeslot"; import order from "./order"; diff --git a/server/src/routes/timeslot.ts b/server/src/routes/timeslot.ts index 9b17ab4..bd93ce6 100644 --- a/server/src/routes/timeslot.ts +++ b/server/src/routes/timeslot.ts @@ -80,6 +80,7 @@ router.get("/timeslot", async (req: Request, res: Response) => { 'center_name',centers.name ) as trainer, json_agg(json_build_object( + 'id',weekly_timeslots.id, 'day_of_week',day_of_week, 'start_time',start_time, 'end_time',end_time) diff --git a/server/src/routes/trainer/index.ts b/server/src/routes/trainer/index.ts new file mode 100644 index 0000000..0cc6904 --- /dev/null +++ b/server/src/routes/trainer/index.ts @@ -0,0 +1,10 @@ +import express, { Express, Router } from "express"; + +const router: Router = express.Router(); +import trainer from "./trainer"; +import weeklyTimeslot from "./weeklyTimeslot"; + +router.use(weeklyTimeslot); +router.use(trainer); + +export default router; \ No newline at end of file diff --git a/server/src/routes/trainer.ts b/server/src/routes/trainer/trainer.ts similarity index 95% rename from server/src/routes/trainer.ts rename to server/src/routes/trainer/trainer.ts index c795219..13de3e3 100644 --- a/server/src/routes/trainer.ts +++ b/server/src/routes/trainer/trainer.ts @@ -1,12 +1,12 @@ import express, { Router, Request, Response } from "express"; import Joi from "joi" -import { client } from "../db"; +import { client } from "../../db"; import { DatabaseError } from "pg"; -import Trainer from "../interfaces/trainer"; -import { AdminAuth } from "../middlewares/auth"; -import { trainerExists } from "../middlewares/trainer"; -import { idSchema } from "../schemas"; +import Trainer from "../../interfaces/trainer"; +import { AdminAuth } from "../../middlewares/auth"; +import { trainerExists } from "../../middlewares/trainer"; +import { idSchema } from "../../schemas"; const router: Router = express.Router(); diff --git a/server/src/routes/trainer/weeklyTimeslot.ts b/server/src/routes/trainer/weeklyTimeslot.ts new file mode 100644 index 0000000..eb27769 --- /dev/null +++ b/server/src/routes/trainer/weeklyTimeslot.ts @@ -0,0 +1,109 @@ +import express, { Router, Response } from "express"; +import Joi from "joi" + +import { client } from "../../db"; +import { DatabaseError } from "pg"; +import { TrainerAuth } from "../../middlewares/auth"; +import { timeSchema } from "../../schemas"; +import { AuthedRequest } from "../../interfaces/auth"; +import { WeeklyTimeslot } from "../../interfaces/timeslot"; + +const router: Router = express.Router(); + +async function getTrainerIdFromUserId(userId: number | undefined): Promise { + const trainerLookupResult = await client.query(` + SELECT id FROM trainers + WHERE user_id = $1; + `, [ + userId + ]); + return trainerLookupResult.rows[0]?.id; +} + +router.get("/trainer/timeslot", TrainerAuth, async (req: AuthedRequest, res: Response) => { + try { + const trainerId: number | undefined = await getTrainerIdFromUserId(req.user?.userId); + if (trainerId === undefined) + return res.sendStatus(403); + + const databaseResult = await client.query(` + SELECT id, day_of_week, start_time, end_time FROM weekly_timeslots + WHERE trainer_id = $1; + `, [ + trainerId + ]); + + const timeslots: WeeklyTimeslot[] = databaseResult.rows; + + return res.status(200).send(timeslots); + } catch (error: DatabaseError | Error | any) { + console.error(error); + return res.sendStatus(500); + } +}) + +const weeklyTimeslotSchema = Joi.object({ + day_of_week: Joi.number().integer().min(1).max(7).required(), + start_time: timeSchema.required(), + end_time: timeSchema.required() +}); + +router.post("/trainer/timeslot", TrainerAuth, async (req: AuthedRequest, res: Response) => { + try { + const trainerId: number | undefined = await getTrainerIdFromUserId(req.user?.userId); + if (trainerId === undefined) + return res.sendStatus(403); + + const validation = weeklyTimeslotSchema.validate(req.body, { abortEarly: false }); + if (validation.error !== undefined) { + return res.status(400).send(validation.error.details); + } + + const weeklyTimeslot: WeeklyTimeslot = validation.value; + + const databaseResult = await client.query(` + INSERT INTO weekly_timeslots (trainer_id, day_of_week, start_time, end_time) + VALUES ($1, $2, $3, $4) + RETURNING *; + `, [ + trainerId, + weeklyTimeslot.day_of_week, + weeklyTimeslot.start_time, + weeklyTimeslot.end_time + ]); + + const timeslots: WeeklyTimeslot = databaseResult.rows[0]; + + return res.status(200).send(timeslots); + } catch (error: DatabaseError | Error | any) { + console.error(error); + return res.sendStatus(500); + } +}) + +router.delete("/trainer/timeslot/:id", TrainerAuth, async (req: AuthedRequest, res: Response) => { + try { + const trainerId: number | undefined = await getTrainerIdFromUserId(req.user?.userId); + if (trainerId === undefined) + return res.sendStatus(403); + + const databaseResult = await client.query(` + DELETE FROM weekly_timeslots + WHERE trainer_id = $1 + AND id = $2; + `, [ + trainerId, + req.params.id + ]); + + if (databaseResult.rowCount < 1) + return res.sendStatus(404); + + return res.sendStatus(204); + } catch (error: DatabaseError | Error | any) { + console.error(error); + return res.sendStatus(500); + } +}) + +export default router; \ No newline at end of file