Revived the page! He's baaaaack

This commit is contained in:
2026-01-27 10:01:41 -05:00
parent 7c7cbef3f3
commit 67562f56aa
9 changed files with 469 additions and 95 deletions

View File

@@ -102,6 +102,7 @@ import { roles, memberRoles } from './routes/roles';
import { courseRouter, eventRouter } from './routes/course';
import { calendarRouter } from './routes/calendar';
import { docsRouter } from './routes/docs';
import { units } from './routes/units';
app.use('/application', applicationRouter);
app.use('/ranks', ranks);
@@ -115,6 +116,7 @@ app.use('/memberRoles', memberRoles)
app.use('/course', courseRouter)
app.use('/courseEvent', eventRouter)
app.use('/calendar', calendarRouter)
app.use('/units', units)
app.use('/docs', docsRouter)
app.use('/', authRouter)

View File

@@ -5,7 +5,7 @@ import { Request, Response } from 'express';
import pool from '../db';
import { requireLogin, requireMemberState, requireRole } from '../middleware/auth';
import { getUserActiveLOA } from '../services/db/loaService';
import { getAllMembersLite, getMemberSettings, getMembersFull, getMembersLite, getUserData, getUserState, setUserSettings } from '../services/db/memberService';
import { getAllMembersLite, getMemberSettings, getMembersFull, getMembersLite, getUserData, getUserState, setUserSettings, getFilteredMembers } from '../services/db/memberService';
import { getUserRoles } from '../services/db/rolesService';
import { memberSettings, MemberState, myData } from '@app/shared/types/member';
@@ -42,6 +42,27 @@ router.get('/', [requireLogin, requireMemberState(MemberState.Member)], async (r
}
});
router.get('/filtered', [requireLogin, requireMemberState(MemberState.Member)], async (req, res) => {
try {
// Extract Query Parameters
const page = parseInt(req.query.page as string) || 1;
const pageSize = parseInt(req.query.pageSize as string) || 15;
const search = req.query.search as string | undefined;
const status = req.query.status as string | undefined;
const unitId = req.query.unitId as string | undefined;
// Call the service function
const result = await getFilteredMembers(page, pageSize, search, status, unitId);
return res.status(200).json(result);
} catch (error) {
logger.error('app', 'Failed to get filtered users', {
error: error instanceof Error ? error.message : String(error),
});
return res.status(500).json({ error: 'Failed to fetch users' });
}
});
router.get('/me', [requireLogin], async (req: Request, res) => {
if (!req.user) return res.sendStatus(401);

29
api/src/routes/units.ts Normal file
View File

@@ -0,0 +1,29 @@
import express = require('express');
const unitsRouter = express.Router();
import pool from '../db';
import { requireLogin } from '../middleware/auth';
import { logger } from '../services/logging/logger';
import { Unit } from '@app/shared/types/units';
unitsRouter.use(requireLogin);
//get all units
unitsRouter.get('/', async (req, res) => {
try {
const result: Unit[] = await pool.query('SELECT * FROM units WHERE active = 1;');
res.json(result);
} catch (error) {
logger.error(
'app',
'Failed to get all units',
{
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
}
);
res.sendStatus(500);
}
});
export const units = unitsRouter;

View File

@@ -1,9 +1,97 @@
import { Role } from "@app/shared/types/roles";
import pool from "../../db";
import { Member, MemberCardDetails, MemberLight, memberSettings, MemberState } from '@app/shared/types/member'
import { Member, MemberCardDetails, MemberLight, memberSettings, MemberState, PaginatedMembers } from '@app/shared/types/member'
import { logger } from "../logging/logger";
import { memberCache } from "../../routes/auth";
export async function getFilteredMembers(
page: number = 1,
pageSize: number = 15,
search?: string,
status?: string,
unitId?: string
): Promise<PaginatedMembers> {
try {
const offset = (page - 1) * pageSize;
const whereClauses: string[] = [];
const params: any[] = [];
if (status && status !== 'all') {
whereClauses.push(`m.state = ?`);
params.push(status);
}
if (search) {
whereClauses.push(`v.member_name LIKE ?`);
params.push(`%${search}%`);
}
if (unitId && unitId !== 'all') {
whereClauses.push(`v.unit = ?`);
params.push(unitId);
}
const whereClause = whereClauses.length > 0
? ` WHERE ${whereClauses.join(' AND ')}`
: '';
// COUNT QUERY
const countQuery = `SELECT COUNT(*) as total FROM view_member_rank_unit_status_latest v INNER JOIN members m ON v.member_id = m.id ${whereClause}`;
const [countResults]: any[] = await pool.query(countQuery, params);
const total = Number(countResults?.total) || 0;
// DATA QUERY
const dataQuery = `
SELECT
v.*,
CASE
WHEN EXISTS (
SELECT 1 FROM leave_of_absences l
WHERE l.member_id = v.member_id
AND l.deleted = 0
AND UTC_TIMESTAMP() BETWEEN l.start_date AND l.end_date
) THEN 1 ELSE 0
END AS on_loa
FROM view_member_rank_unit_status_latest v
INNER JOIN members m ON v.member_id = m.id
${whereClause} -- Added back correctly
ORDER BY v.member_name ASC
LIMIT ? OFFSET ?
`;
const rows: any[] = await pool.query(dataQuery, [...params, pageSize, offset]);
// Map rows to Member type
const members: Member[] = rows.map(row => ({
member_id: Number(row.member_id),
member_name: row.member_name,
displayName: row.displayName,
rank: row.rank,
rank_date: row.rank_date,
unit: row.unit,
unit_date: row.unit_date,
status: row.status,
status_date: row.status_date,
loa_until: row.loa_until ? new Date(row.loa_until) : undefined,
}));
return {
data: members,
pagination: {
page,
pageSize,
total,
totalPages: Math.ceil(total / pageSize),
},
};
} catch (error) {
logger.error('app', 'Error fetching filtered members', {
error: error instanceof Error ? error.message : String(error),
});
throw error;
}
}
export async function getUserData(userID: number): Promise<Member> {
const sql = `SELECT * FROM view_member_rank_unit_status_latest WHERE member_id = ?`;
const res: Member = await pool.query(sql, [userID]);