5 Commits

6 changed files with 70 additions and 27 deletions

View File

@@ -56,9 +56,13 @@ router.get("/me", async (req: Request, res: Response) => {
//get my LOA history
router.get("/history", async (req: Request, res: Response) => {
const user = req.user.id;
try {
const result = await getUserLOA(user);
const user = req.user.id;
const page = Number(req.query.page) || undefined;
const pageSize = Number(req.query.pageSize) || undefined;
const result = await getUserLOA(user, page, pageSize);
res.status(200).json(result)
} catch (error) {
console.error(error);

View File

@@ -36,7 +36,10 @@ export async function getAllLOA(page = 1, pageSize = 10): Promise<PagedData<LOAR
return output;
}
export async function getUserLOA(userId: number): Promise<LOARequest[]> {
export async function getUserLOA(userId: number, page = 1, pageSize = 10): Promise<PagedData<LOARequest>> {
const offset = (page - 1) * pageSize;
const result: LOARequest[] = await pool.query(`
SELECT loa.*, members.name, t.name AS type_name
FROM leave_of_absences AS loa
@@ -53,8 +56,12 @@ export async function getUserLOA(userId: number): Promise<LOARequest[]> {
WHEN loa.closed IS NOT NULL THEN 4
END,
loa.start_date DESC
`, [userId])
return result;
LIMIT ? OFFSET ?;`, [userId, pageSize, offset])
let loaCount = Number((await pool.query(`SELECT COUNT(*) as count FROM leave_of_absences WHERE member_id = ?;`, [userId]))[0].count);
let pageCount = loaCount / pageSize;
let output: PagedData<LOARequest> = { data: result, pagination: { page: page, pageSize: pageSize, total: loaCount, totalPages: pageCount } }
return output;
}
export async function getUserActiveLOA(userId: number): Promise<LOARequest[]> {

View File

@@ -30,10 +30,10 @@ const environment = import.meta.env.VITE_ENVIRONMENT;
<p>This is a development build of the application. Some features will be unavailable or unstable.</p>
</AlertDescription>
</Alert>
<Alert v-if="userStore.user?.LOAData?.[0]" class="m-2 mx-auto w-5xl" variant="info">
<Alert v-if="userStore.user?.LOAs?.[0]" class="m-2 mx-auto w-5xl" variant="info">
<AlertDescription class="flex flex-row items-center text-nowrap gap-5 mx-auto">
<p>You are on LOA until <strong>{{ formatDate(userStore.user?.LOAData?.[0].end_date) }}</strong></p>
<Button variant="secondary" @click="async () => { await cancelLOA(userStore.user?.LOAData?.[0].id); userStore.loadUser(); }">End
<p>You are on LOA until <strong>{{ formatDate(userStore.user?.LOAs?.[0].extended_till || userStore.user?.LOAs?.[0].end_date) }}</strong></p>
<Button variant="secondary" @click="async () => { await cancelLOA(userStore.user.LOAs?.[0].id); userStore.loadUser(); }">End
LOA</Button>
</AlertDescription>
</Alert>

View File

@@ -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");
}
}
@@ -85,8 +85,18 @@ export async function getAllLOAs(page?: number, pageSize?: number): Promise<Page
});
}
export function getMyLOAs(): Promise<LOARequest[]> {
return fetch(`${addr}/loa/history`, {
export function getMyLOAs(page?: number, pageSize?: number): Promise<PagedData<LOARequest>> {
const params = new URLSearchParams();
if (page !== undefined) {
params.set("page", page.toString());
}
if (pageSize !== undefined) {
params.set("pageSize", pageSize.toString());
}
return fetch(`${addr}/loa/history?${params}`, {
method: "GET",
credentials: 'include',
headers: {

View File

@@ -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
})
</script>
<template>
@@ -158,12 +174,13 @@ const maxEndDate = computed(() => {
:display-value="(id) => {
const m = members.find(mem => mem.member_id === id)
return m ? m.displayName || m.member_name : ''
}" />
}" @input="memberFilter = $event.target.value" />
</ComboboxAnchor>
<ComboboxList class="*:w-64">
<ComboboxEmpty class="text-muted-foreground w-full">No results</ComboboxEmpty>
<ComboboxGroup>
<template v-for="member in members" :key="member.member_id">
<div class="max-h-80 overflow-y-scroll scrollbar-themed min-w-3xs">
<template v-for="member in filteredMembers" :key="member.member_id">
<ComboboxItem :value="member.member_id"
class="data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative cursor-pointer select-none px-2 py-1.5 w-full">
{{ member.displayName || member.member_name }}
@@ -173,6 +190,7 @@ const maxEndDate = computed(() => {
</ComboboxItemIndicator>
</ComboboxItem>
</template>
</div>
</ComboboxGroup>
</ComboboxList>
</Combobox>
@@ -286,8 +304,10 @@ const maxEndDate = computed(() => {
</h2>
<p class="max-w-md text-muted-foreground">
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 on behalf of another member.' :
`Your Leave
of Absence request has been submitted successfully.
It will take effect on your selected start date.` }}
</p>

View File

@@ -59,7 +59,9 @@ async function loadLOAs() {
LOAList.value = result.data;
pageData.value = result.pagination;
} else {
LOAList.value = await getMyLOAs();
let result = await getMyLOAs(pageNum.value, pageSize.value);
LOAList.value = result.data;
pageData.value = result.pagination;
}
}