diff --git a/api/src/routes/loa.ts b/api/src/routes/loa.ts index 65cbf4a..45d48cc 100644 --- a/api/src/routes/loa.ts +++ b/api/src/routes/loa.ts @@ -3,7 +3,7 @@ const router = express.Router(); import { Request, Response } from 'express'; import pool from '../db'; -import { closeLOA, createNewLOA, getAllLOA, getLOAbyID, getLoaTypes, getUserLOA } from '../services/loaService'; +import { closeLOA, createNewLOA, getAllLOA, getLOAbyID, getLoaTypes, getUserLOA, setLOAExtension } from '../services/loaService'; import { LOARequest } from '@app/shared/types/loa'; //member posts LOA @@ -104,10 +104,15 @@ router.post('/adminCancel/:id', async (req: Request, res: Response) => { // TODO: Enforce admin only router.post('/extend/:id', async (req: Request, res: Response) => { - const extendTo = req.body; - console.log(extendTo); - try { + const to: Date = req.body.to; + if (!to) { + res.status(400).send("Extension length is required"); + } + + try { + await setLOAExtension(Number(req.params.id), to); + res.sendStatus(200); } catch (error) { console.error(error) res.status(500).json(error); @@ -123,8 +128,7 @@ router.get('/policy', async (req: Request, res: Response) => { if (output.ok) { const out = await output.json(); - console.log(out); - res.status(200).json(out); + res.status(200).json(out.markdown); } else { console.log("BAD"); res.sendStatus(500); diff --git a/api/src/routes/members.js b/api/src/routes/members.js index c93f249..3196569 100644 --- a/api/src/routes/members.js +++ b/api/src/routes/members.js @@ -2,6 +2,7 @@ const express = require('express'); const router = express.Router(); import pool from '../db'; +import { getUserActiveLOA } from '../services/loaService'; import { getUserData } from '../services/memberService'; import { getUserRoles } from '../services/rolesService'; @@ -40,12 +41,13 @@ router.get('/me', async (req, res) => { try { const { id, name, state } = await getUserData(req.user.id); - const LOAData = await pool.query( - `SELECT * - FROM leave_of_absences - WHERE member_id = ? - AND deleted = 0 - AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;`, req.user.id); + // const LOAData = await pool.query( + // `SELECT * + // FROM leave_of_absences + // WHERE member_id = ? + // AND deleted = 0 + // AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;`, req.user.id); + const LOAData = await getUserActiveLOA(req.user.id); const roleData = await getUserRoles(req.user.id); diff --git a/api/src/services/loaService.ts b/api/src/services/loaService.ts index 129f5e2..1446724 100644 --- a/api/src/services/loaService.ts +++ b/api/src/services/loaService.ts @@ -6,13 +6,28 @@ export async function getLoaTypes(): Promise { return await pool.query('SELECT * FROM leave_of_absences_types;'); } -export async function getAllLOA(): Promise { - let res: LOARequest[] = await pool.query( - `SELECT loa.*, members.name, t.name AS type_name - FROM leave_of_absences AS loa - LEFT JOIN members ON loa.member_id = members.id - LEFT JOIN leave_of_absences_types AS t ON loa.type_id = t.id; - `) as LOARequest[]; +export async function getAllLOA(page = 1, pageSize = 20): Promise { + const offset = (page - 1) * pageSize; + + const sql = ` + SELECT loa.*, members.name, t.name AS type_name + FROM leave_of_absences AS loa + LEFT JOIN members ON loa.member_id = members.id + LEFT JOIN leave_of_absences_types AS t ON loa.type_id = t.id + ORDER BY + CASE + WHEN loa.closed IS NULL + AND NOW() > COALESCE(loa.extended_till, loa.end_date) THEN 1 + WHEN loa.closed IS NULL + AND NOW() BETWEEN loa.start_date AND COALESCE(loa.extended_till, loa.end_date) THEN 2 + WHEN loa.closed IS NULL AND NOW() < loa.start_date THEN 3 + WHEN loa.closed IS NOT NULL THEN 4 + END, + loa.start_date DESC + LIMIT ? OFFSET ?; + `; + + let res: LOARequest[] = await pool.query(sql, [pageSize, offset]) as LOARequest[]; return res; } @@ -21,6 +36,16 @@ export async function getUserLOA(userId: number): Promise { return result; } +export async function getUserActiveLOA(userId: number): Promise { + const sql = `SELECT * + FROM leave_of_absences + WHERE member_id = ? + AND closed IS NULL + AND UTC_TIMESTAMP() BETWEEN start_date AND end_date;` + const LOAData = await pool.query(sql, [userId]); + return LOAData; +} + export async function createNewLOA(data: LOARequest) { const sql = `INSERT INTO leave_of_absences (member_id, filed_date, start_date, end_date, type_id, reason) @@ -41,12 +66,17 @@ export async function closeLOA(id: number, closer: number) { export async function getLOAbyID(id: number): Promise { let res = await pool.query(`SELECT * FROM leave_of_absences WHERE id = ?`, [id]); - if (res.length != 1) + console.log(res); + if (res.length == 1) throw new Error(`LOA with id ${id} not found`); return res[0]; } export async function setLOAExtension(id: number, extendTo: Date) { - - + let res = await pool.query(`UPDATE leave_of_absences + SET extended_till = ? + WHERE leave_of_absences.id = ? `, [toDateTime(extendTo), id]); + if (res.affectedRows != 1) + throw new Error(`Could not extend LOA`); + return res[0]; } \ No newline at end of file diff --git a/ui/src/App.vue b/ui/src/App.vue index a656c08..8289a75 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -5,6 +5,7 @@ import { useUserStore } from './stores/user'; import Alert from './components/ui/alert/Alert.vue'; import AlertDescription from './components/ui/alert/AlertDescription.vue'; import Navbar from './components/Navigation/Navbar.vue'; +import { cancelLOA } from './api/loa'; const userStore = useUserStore(); @@ -29,10 +30,11 @@ const environment = import.meta.env.VITE_ENVIRONMENT;

This is a development build of the application. Some features will be unavailable or unstable.

- + -

You are on LOA until {{ formatDate(userStore.user?.loa?.[0].end_date) }}

- +

You are on LOA until {{ formatDate(userStore.user?.LOAData?.[0].end_date) }}

+
diff --git a/ui/src/api/loa.ts b/ui/src/api/loa.ts index 80417d9..fc85bb3 100644 --- a/ui/src/api/loa.ts +++ b/ui/src/api/loa.ts @@ -90,7 +90,6 @@ export async function getLoaTypes(): Promise { }; export async function getLoaPolicy(): Promise { - //@ts-ignore const res = await fetch(`${addr}/loa/policy`, { method: "GET", credentials: 'include', @@ -106,3 +105,34 @@ export async function getLoaPolicy(): Promise { return null; } } + +export async function cancelLOA(id: number, admin: boolean = false) { + let route = admin ? 'adminCancel' : 'cancel'; + const res = await fetch(`${addr}/loa/${route}/${id}`, { + method: "POST", + credentials: 'include', + }); + + if (res.ok) { + return + } else { + throw new Error("Could not cancel LOA"); + } +} + +export async function extendLOA(id: number, to: Date) { + const res = await fetch(`${addr}/loa/extend/${id}`, { + method: "POST", + credentials: 'include', + body: JSON.stringify({ to }), + headers: { + "Content-Type": "application/json", + } + }); + + if (res.ok) { + return + } else { + throw new Error("Could not extend LOA"); + } +} \ No newline at end of file diff --git a/ui/src/components/loa/loaForm.vue b/ui/src/components/loa/loaForm.vue index 1ae6063..4e157bb 100644 --- a/ui/src/components/loa/loaForm.vue +++ b/ui/src/components/loa/loaForm.vue @@ -177,7 +177,7 @@ const maxEndDate = computed(() => { Type