implemented expandable LOA details

This commit is contained in:
2025-12-15 19:06:07 -05:00
parent 8aaaea5ed0
commit 2a0d7c2ff2

View File

@@ -15,7 +15,7 @@ import {
DropdownMenuItem, DropdownMenuItem,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu" } from "@/components/ui/dropdown-menu"
import { Ellipsis } from "lucide-vue-next"; import { ChevronDown, ChevronUp, Ellipsis, X } from "lucide-vue-next";
import { cancelLOA, extendLOA, getAllLOAs, getMyLOAs } from "@/api/loa"; import { cancelLOA, extendLOA, getAllLOAs, getMyLOAs } from "@/api/loa";
import { onMounted, ref, computed } from "vue"; import { onMounted, ref, computed } from "vue";
import { LOARequest } from "@shared/types/loa"; import { LOARequest } from "@shared/types/loa";
@@ -104,6 +104,9 @@ async function commitExtend() {
isExtending.value = false; isExtending.value = false;
await loadLOAs(); await loadLOAs();
} }
const expanded = ref<number | null>(null);
const hoverID = ref<number | null>(null);
</script> </script>
<template> <template>
@@ -139,51 +142,91 @@ async function commitExtend() {
<TableHead>Type</TableHead> <TableHead>Type</TableHead>
<TableHead>Start</TableHead> <TableHead>Start</TableHead>
<TableHead>End</TableHead> <TableHead>End</TableHead>
<TableHead class="w-[500px]">Reason</TableHead> <!-- <TableHead class="w-[500px]">Reason</TableHead> -->
<TableHead>Posted on</TableHead> <TableHead>Posted on</TableHead>
<TableHead>Status</TableHead> <TableHead>Status</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<TableRow v-for="post in LOAList" :key="post.id" class="hover:bg-muted/50"> <template v-for="post in LOAList" :key="post.id">
<TableCell class="font-medium"> <TableRow class="hover:bg-muted/50 cursor-pointer" @click="expanded = post.id"
<MemberCard :member-id="post.member_id"></MemberCard> @mouseenter="hoverID = post.id" @mouseleave="hoverID = null" :class="{
</TableCell> 'border-b-0': expanded === post.id,
<TableCell>{{ post.type_name }}</TableCell> 'bg-muted/50': hoverID === post.id
<TableCell>{{ formatDate(post.start_date) }}</TableCell> }">
<TableCell>{{ post.extended_till ? formatDate(post.extended_till) : formatDate(post.end_date) }} <TableCell class="font-medium">
</TableCell> <MemberCard :member-id="post.member_id"></MemberCard>
<TableCell>{{ post.reason }}</TableCell> </TableCell>
<TableCell>{{ formatDate(post.filed_date) }}</TableCell> <TableCell>{{ post.type_name }}</TableCell>
<TableCell> <TableCell>{{ formatDate(post.start_date) }}</TableCell>
<Badge v-if="loaStatus(post) === 'Upcoming'" class="bg-blue-400">Upcoming</Badge> <TableCell>{{ post.extended_till ? formatDate(post.extended_till) :
<Badge v-else-if="loaStatus(post) === 'Active'" class="bg-green-500">Active</Badge> formatDate(post.end_date) }}
<Badge v-else-if="loaStatus(post) === 'Overdue'" class="bg-yellow-400">Overdue</Badge> </TableCell>
<Badge v-else class="bg-gray-400">Ended</Badge> <!-- <TableCell>{{ post.reason }}</TableCell> -->
</TableCell> <TableCell>{{ formatDate(post.filed_date) }}</TableCell>
<TableCell @click.stop="" class="text-right"> <TableCell>
<DropdownMenu> <Badge v-if="loaStatus(post) === 'Upcoming'" class="bg-blue-400">Upcoming</Badge>
<DropdownMenuTrigger class="cursor-pointer"> <Badge v-else-if="loaStatus(post) === 'Active'" class="bg-green-500">Active</Badge>
<Ellipsis></Ellipsis> <Badge v-else-if="loaStatus(post) === 'Overdue'" class="bg-yellow-400">Overdue</Badge>
</DropdownMenuTrigger> <Badge v-else class="bg-gray-400">Ended</Badge>
<DropdownMenuContent> </TableCell>
<DropdownMenuItem v-if="!post.closed && props.adminMode" <TableCell @click.stop="" class="text-right">
@click="isExtending = true; targetLOA = post"> <DropdownMenu>
Extend <DropdownMenuTrigger class="cursor-pointer">
</DropdownMenuItem> <Button variant="ghost">
<DropdownMenuItem v-if="!post.closed" :variant="'destructive'" <Ellipsis class="size-6"></Ellipsis>
@click="cancelAndReload(post.id)">{{ loaStatus(post) === 'Upcoming' ? 'Cancel' : </Button>
'End' }} </DropdownMenuTrigger>
</DropdownMenuItem> <DropdownMenuContent>
<!-- Fallback: no actions available --> <DropdownMenuItem v-if="!post.closed && props.adminMode"
<p v-if="post.closed || (!props.adminMode && post.closed)" @click="isExtending = true; targetLOA = post">
class="p-2 text-center text-sm"> Extend
No actions </DropdownMenuItem>
</p> <DropdownMenuItem v-if="!post.closed" :variant="'destructive'"
</DropdownMenuContent> @click="cancelAndReload(post.id)">{{ loaStatus(post) === 'Upcoming' ?
</DropdownMenu> 'Cancel' :
</TableCell> 'End' }}
</TableRow> </DropdownMenuItem>
<!-- Fallback: no actions available -->
<p v-if="post.closed || (!props.adminMode && post.closed)"
class="p-2 text-center text-sm">
No actions
</p>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
<TableCell>
<Button v-if="expanded === post.id" @click.stop="expanded = null" variant="ghost">
<ChevronUp class="size-6" />
</Button>
<Button v-else @click.stop="expanded = post.id" variant="ghost">
<ChevronDown class="size-6" />
</Button>
</TableCell>
</TableRow>
<TableRow v-if="expanded === post.id" @mouseenter="hoverID = post.id"
@mouseleave="hoverID = null" :class="{ 'bg-muted/50 border-t-0': hoverID === post.id }">
<TableCell :colspan="8" class="p-0">
<div class="w-full p-3 mb-6 space-y-3">
<div class="flex justify-between items-start gap-4">
<div class="flex-1">
<!-- Title -->
<p class="text-md font-semibold text-foreground">
Reason
</p>
<!-- Content -->
<p
class="mt-1 text-md whitespace-pre-wrap leading-relaxed text-muted-foreground">
{{ post.reason }}
</p>
</div>
</div>
</div>
</TableCell>
</TableRow>
</template>
</TableBody> </TableBody>
</Table> </Table>
</div> </div>