From e9cce2571a1685c8a40d78a7a48c09ac83b15c98 Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 11:11:14 -0500 Subject: [PATCH 01/33] fixed router redirect for homepage join button --- ui/src/pages/Homepage.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/pages/Homepage.vue b/ui/src/pages/Homepage.vue index ec8a114..172fdbb 100644 --- a/ui/src/pages/Homepage.vue +++ b/ui/src/pages/Homepage.vue @@ -8,7 +8,7 @@ const router = useRouter() const user = useUserStore(); function goToApplication() { - router.push('/apply') // change to your form route + router.push('/join') // change to your form route } From 5f038208910a3a1949ccef9eca1a5667c287da62 Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 11:49:14 -0500 Subject: [PATCH 02/33] added first pass of homepage --- api/src/index.ts | 2 ++ api/src/routes/docs.ts | 24 ++++++++++++++++++++++++ ui/src/api/docs.ts | 18 ++++++++++++++++++ ui/src/pages/Homepage.vue | 15 +++++++++++++-- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 api/src/routes/docs.ts create mode 100644 ui/src/api/docs.ts diff --git a/api/src/index.ts b/api/src/index.ts index 7230a30..701d49c 100644 --- a/api/src/index.ts +++ b/api/src/index.ts @@ -64,6 +64,7 @@ import { authRouter } from './routes/auth'; import { roles, memberRoles } from './routes/roles'; import { courseRouter, eventRouter } from './routes/course'; import { calendarRouter } from './routes/calendar'; +import { docsRouter } from './routes/docs'; app.use('/application', applicationRouter); app.use('/ranks', ranks); @@ -77,6 +78,7 @@ app.use('/memberRoles', memberRoles) app.use('/course', courseRouter) app.use('/courseEvent', eventRouter) app.use('/calendar', calendarRouter) +app.use('/docs', docsRouter) app.use('/', authRouter) app.get('/ping', (req, res) => { diff --git a/api/src/routes/docs.ts b/api/src/routes/docs.ts new file mode 100644 index 0000000..13ada87 --- /dev/null +++ b/api/src/routes/docs.ts @@ -0,0 +1,24 @@ +const express = require('express'); +const router = express.Router(); + +import { Request, Response } from 'express'; +import { requireLogin } from '../middleware/auth'; + +router.get('/welcome', [requireLogin], async (req: Request, res: Response) => { + const output = await fetch(`${process.env.DOC_HOST}/api/pages/717`, { + headers: { + Authorization: `Token ${process.env.DOC_TOKEN_ID}:${process.env.DOC_TOKEN_SECRET}`, + } + }) + + if (output.ok) { + const out = await output.json(); + res.status(200).json(out.html); + } else { + console.error("Failed to fetch LOA policy from bookstack"); + res.sendStatus(500); + } +}) + + +export const docsRouter = router; \ No newline at end of file diff --git a/ui/src/api/docs.ts b/ui/src/api/docs.ts new file mode 100644 index 0000000..24c31c8 --- /dev/null +++ b/ui/src/api/docs.ts @@ -0,0 +1,18 @@ +// @ts-ignore +const addr = import.meta.env.VITE_APIHOST; + +export async function getWelcomeMessage(): Promise { + const res = await fetch(`${addr}/docs/welcome`, { + method: "GET", + credentials: 'include', + }); + if (res.ok) { + const out = res.json(); + if (!out) { + return null; + } + return out; + } else { + return null; + } +} \ No newline at end of file diff --git a/ui/src/pages/Homepage.vue b/ui/src/pages/Homepage.vue index 172fdbb..f339311 100644 --- a/ui/src/pages/Homepage.vue +++ b/ui/src/pages/Homepage.vue @@ -1,6 +1,8 @@ From d01881f0afb5bf60f3c09bf22db0d113cab12ccb Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 18:28:04 -0500 Subject: [PATCH 03/33] fixed bug that caused the latest application to be hidden --- api/src/services/applicationService.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/src/services/applicationService.ts b/api/src/services/applicationService.ts index 5692b4c..d0f2c95 100644 --- a/api/src/services/applicationService.ts +++ b/api/src/services/applicationService.ts @@ -32,6 +32,8 @@ export async function getApplicationByID(appID: number): Promise } export async function getApplicationList(page: number = 1, pageSize: number = 25): Promise { + const offset = (page - 1) * pageSize; + const sql = `SELECT member.name AS member_name, app.id, @@ -44,7 +46,7 @@ export async function getApplicationList(page: number = 1, pageSize: number = 25 ORDER BY app.submitted_at DESC LIMIT ? OFFSET ?;` - const rows: ApplicationListRow[] = await pool.query(sql, [pageSize, page]); + const rows: ApplicationListRow[] = await pool.query(sql, [pageSize, offset]); return rows; } From 9196a86570f75c095b748476cee00e4898b48f6c Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 19:00:27 -0500 Subject: [PATCH 04/33] fixed error preventing LOA form from providing user feedback on submit when used from admin panel --- ui/src/api/loa.ts | 4 ++-- ui/src/components/loa/loaForm.vue | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/api/loa.ts b/ui/src/api/loa.ts index bd8802f..9d03071 100644 --- a/ui/src/api/loa.ts +++ b/ui/src/api/loa.ts @@ -31,9 +31,9 @@ export async function adminSubmitLOA(request: LOARequest): Promise<{ id?: number }); if (res.ok) { - return res.json(); + return } else { - return { error: "Failed to submit LOA" }; + throw new Error("Failed to submit LOA"); } } diff --git a/ui/src/components/loa/loaForm.vue b/ui/src/components/loa/loaForm.vue index 44dd7a9..a85fa07 100644 --- a/ui/src/components/loa/loaForm.vue +++ b/ui/src/components/loa/loaForm.vue @@ -286,8 +286,8 @@ const maxEndDate = computed(() => {

- Your Leave of Absence request has been submitted successfully. - It will take effect on your selected start date. + {{ adminMode ? 'You have successfully submitted a Leave of Absence for a member.' : `Your Leave of Absence request has been submitted successfully. + It will take effect on your selected start date.` }}

From eca4a75a6ea24fcb6e293c431e83590c9632cfa9 Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 19:00:38 -0500 Subject: [PATCH 05/33] updated admin LOA wording --- ui/src/components/loa/loaForm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/components/loa/loaForm.vue b/ui/src/components/loa/loaForm.vue index a85fa07..a86fa96 100644 --- a/ui/src/components/loa/loaForm.vue +++ b/ui/src/components/loa/loaForm.vue @@ -286,7 +286,7 @@ const maxEndDate = computed(() => {

- {{ adminMode ? 'You have successfully submitted a Leave of Absence for a member.' : `Your Leave of Absence request has been submitted successfully. + {{ adminMode ? 'You have successfully submitted a Leave of Absence on behalf of another member.' : `Your Leave of Absence request has been submitted successfully. It will take effect on your selected start date.` }}

From 5f6c17361b20d7a81d05a563e59206dccfafe8a6 Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 19:02:32 -0500 Subject: [PATCH 06/33] Fixed active LOA banner not appearing after client state rework --- ui/src/App.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/App.vue b/ui/src/App.vue index 8289a75..28a0fbc 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -30,10 +30,10 @@ 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?.LOAData?.[0].end_date) }}

-
From 5e1351d03311a3972fea13f02c31a56cd01d9eec Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Tue, 16 Dec 2025 19:07:42 -0500 Subject: [PATCH 07/33] Fixed performance issue with member search on LOA form --- ui/src/components/loa/loaForm.vue | 46 ++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/ui/src/components/loa/loaForm.vue b/ui/src/components/loa/loaForm.vue index a86fa96..8bea146 100644 --- a/ui/src/components/loa/loaForm.vue +++ b/ui/src/components/loa/loaForm.vue @@ -134,6 +134,22 @@ const maxEndDate = computed(() => { return null; } }) + +const memberFilter = ref(''); + +const filteredMembers = computed(() => { + const q = memberFilter?.value?.toLowerCase() ?? "" + const results: Member[] = [] + + for (const m of members.value ?? []) { + if (!q || (m.displayName || m.member_name).toLowerCase().includes(q)) { + results.push(m) + if (results.length >= 50) break + } + } + + return results +})