added roles to member card

This commit is contained in:
2025-12-18 17:39:44 -05:00
parent a699c20f9b
commit f124e41630
5 changed files with 81 additions and 27 deletions

View File

@@ -1,4 +1,4 @@
import { memberSettings, Member, MemberLight } from "@shared/types/member";
import { memberSettings, Member, MemberLight, MemberCardDetails } from "@shared/types/member";
// @ts-ignore
const addr = import.meta.env.VITE_APIHOST;
@@ -71,7 +71,7 @@ export async function getLightMembers(ids: number[]): Promise<MemberLight[]> {
return response.json();
}
export async function getFullMembers(ids: number[]): Promise<Member[]> {
export async function getFullMembers(ids: number[]): Promise<MemberCardDetails[]> {
if (ids.length === 0) return [];

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import { useMemberDirectory } from '@/stores/memberDirectory';
import { ref, onMounted, computed } from 'vue';
import { Member, type MemberLight } from '@shared/types/member'
import { Member, MemberCardDetails, type MemberLight } from '@shared/types/member'
import Popover from '../ui/popover/Popover.vue';
import PopoverTrigger from '../ui/popover/PopoverTrigger.vue';
import PopoverContent from '../ui/popover/PopoverContent.vue';
@@ -21,7 +21,7 @@ const props = defineProps({
// Local state
const memberLight = ref<MemberLight | null>(null);
const memberFull = ref<Member | null>(null)
const memberFull = ref<MemberCardDetails | null>(null)
const loadingFull = ref(false)
const membersStore = useMemberDirectory();
@@ -63,7 +63,7 @@ const hasFullInfo = computed(() => {
if (!memberFull.value) return false
// check if any field has a value
const { rank, unit, status } = memberFull.value
const { rank, unit, status } = memberFull.value.member
return !!(rank || unit || status)
})
@@ -90,7 +90,7 @@ function formatDate(date: Date): string {
{{ displayName }}
</p>
</PopoverTrigger>
<PopoverContent class="w-72 p-0 overflow-hidden">
<PopoverContent class="w-80 p-0 overflow-hidden">
<!-- Loading -->
<div v-if="loadingFull" class="p-4 text-sm text-muted-foreground mx-auto flex justify-center my-5">
<Spinner></Spinner>
@@ -114,26 +114,33 @@ function formatDate(date: Date): string {
<div class="p-4 space-y-3 text-sm">
<!-- Full info -->
<template v-if="hasFullInfo">
<div v-if="memberFull.loa_until"
<div v-if="memberFull.member.loa_until"
class=" rounded-md text-center bg-yellow-500/10 px-2 py-1 text-xs text-yellow-600">
On Leave of Absence until {{ formatDate(memberFull.loa_until) }}
On Leave of Absence until {{ formatDate(memberFull.member.loa_until) }}
</div>
<div v-if="memberFull.rank" class="flex justify-between">
<div v-if="memberFull.member.rank" class="flex justify-between">
<span class="text-muted-foreground">Rank</span>
<span class="font-medium">{{ memberFull.rank }}</span>
<span class="font-medium">{{ memberFull.member.rank }}</span>
</div>
<div v-if="memberFull.unit" class="flex justify-between">
<div v-if="memberFull.member.unit" class="flex justify-between">
<span class="text-muted-foreground">Unit</span>
<span class="font-medium">{{ memberFull.unit }}</span>
<span class="font-medium">{{ memberFull.member.unit }}</span>
</div>
<div v-if="memberFull.status" class="flex justify-between">
<div v-if="memberFull.member.status" class="flex justify-between">
<span class="text-muted-foreground">Status</span>
<span class="font-medium">{{ memberFull.status }}</span>
<span class="font-medium">{{ memberFull.member.status }}</span>
</div>
<div class="flex gap-2 flex-wrap mt-6">
<div v-for="role in memberFull.roles" class="border rounded-full px-3 text-nowrap">
{{ role.name }}
</div>
</div>
</template>
<!-- No info fallback -->

View File

@@ -1,5 +1,5 @@
import { defineStore } from "pinia"
import type { MemberLight, Member } from "@shared/types/member"
import type { MemberLight, Member, MemberCardDetails } from "@shared/types/member"
import { getLightMembers, getFullMembers } from "@/api/member"
import { reactive, ref } from "vue"
import { resolve } from "path"
@@ -7,7 +7,7 @@ import { rejects } from "assert"
export const useMemberDirectory = defineStore('memberDirectory', () => {
const light = reactive<Record<number, MemberLight>>({});
const full = reactive<Record<number, Member>>({})
const full = reactive<Record<number, MemberCardDetails>>({})
function getLight(id: number): Promise<MemberLight> {
if (light[id]) return Promise.resolve(light[id]);
@@ -24,7 +24,7 @@ export const useMemberDirectory = defineStore('memberDirectory', () => {
})
}
function getFull(id: number): Promise<Member> {
function getFull(id: number): Promise<MemberCardDetails> {
if (full[id]) return Promise.resolve(full[id])
if (!fullWaiters.has(id)) {
@@ -34,7 +34,7 @@ export const useMemberDirectory = defineStore('memberDirectory', () => {
scheduleBatch()
return new Promise<Member>((resolve, reject) => {
return new Promise<MemberCardDetails>((resolve, reject) => {
fullWaiters.get(id)!.push({ resolve, reject })
})
}
@@ -50,7 +50,7 @@ export const useMemberDirectory = defineStore('memberDirectory', () => {
// promises
const lightWaiters = new Map<number, Array<{ resolve: (m: MemberLight) => void; reject: (e: any) => void }>>()
const fullWaiters = new Map<number, Array<{ resolve: (m: Member) => void; reject: (e: any) => void }>>()
const fullWaiters = new Map<number, Array<{ resolve: (m: MemberCardDetails) => void; reject: (e: any) => void }>>()
let batchTimer: ReturnType<typeof setTimeout> | null = null;
@@ -105,12 +105,13 @@ export const useMemberDirectory = defineStore('memberDirectory', () => {
try {
const res = await getFullMembers(ids);
for (const m of res) {
full[m.member_id] = m;
console.log(m)
full[m.member.member_id] = m;
const waiters = fullWaiters.get(m.member_id);
const waiters = fullWaiters.get(m.member.member_id);
if (waiters) {
for (const w of waiters) w.resolve(m)
fullWaiters.delete(m.member_id);
fullWaiters.delete(m.member.member_id);
}
}