Added displayname and member card system
This commit is contained in:
@@ -1 +1,97 @@
|
||||
<template>Hello</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { memberSettings } from '@shared/types/member'
|
||||
import { getMemberSettings, setMemberSettings } from "@/api/member";
|
||||
import Spinner from "@/components/ui/spinner/Spinner.vue";
|
||||
import { useMemberDirectory } from "@/stores/memberDirectory";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const saving = ref(false);
|
||||
const loading = ref(true);
|
||||
const showLoading = ref(false);
|
||||
const form = ref<memberSettings>();
|
||||
|
||||
const memberDictionary = useMemberDirectory()
|
||||
const userStore = useUserStore()
|
||||
|
||||
function saveSettings() {
|
||||
saving.value = true;
|
||||
|
||||
setTimeout(async () => {
|
||||
// Replace with your API save call
|
||||
setMemberSettings(form.value);
|
||||
saving.value = false;
|
||||
console.log(userStore.user.id)
|
||||
memberDictionary.invalidateMember(userStore.user.id)
|
||||
}, 800);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
// Start a brief timer before showing the spinner
|
||||
const timer = setTimeout(() => {
|
||||
showLoading.value = true;
|
||||
}, 200); // 150–250ms is ideal
|
||||
|
||||
form.value = await getMemberSettings();
|
||||
|
||||
clearTimeout(timer);
|
||||
loading.value = false;
|
||||
showLoading.value = false; // ensure spinner hides if it was shown
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="mx-auto max-w-3xl w-full py-10 px-6 space-y-10">
|
||||
<!-- Page Header -->
|
||||
<div>
|
||||
<h1 class="scroll-m-20 text-2xl font-semibold tracking-tight">Profile Settings</h1>
|
||||
<p class="text-muted-foreground mt-1">
|
||||
Manage your account information and display preferences.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Account Info</CardTitle>
|
||||
<CardDescription>Your identity across the platform.</CardDescription>
|
||||
</CardHeader>
|
||||
<Transition name="fade" mode="out-in">
|
||||
|
||||
<CardContent class="space-y-6 min-h-40" v-if="!loading">
|
||||
<!-- Display Name -->
|
||||
<div class="grid gap-2">
|
||||
<Label for="displayName">Display Name</Label>
|
||||
<Input id="displayName" v-model="form.displayName" placeholder="Your display name" />
|
||||
</div>
|
||||
|
||||
</CardContent>
|
||||
<CardContent v-else class="min-h-40 space-y-6 flex items-center">
|
||||
<Spinner v-if="showLoading" class="size-7 flex mx-auto -my-10"></Spinner>
|
||||
</CardContent>
|
||||
</Transition>
|
||||
|
||||
<CardFooter class="flex justify-end">
|
||||
<Button @click="saveSettings" :disabled="saving">
|
||||
{{ saving ? "Saving..." : "Save Changes" }}
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.05s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -21,6 +21,7 @@ import SelectValue from '@/components/ui/select/SelectValue.vue';
|
||||
import SelectContent from '@/components/ui/select/SelectContent.vue';
|
||||
import SelectItem from '@/components/ui/select/SelectItem.vue';
|
||||
import Input from '@/components/ui/input/Input.vue';
|
||||
import MemberCard from '@/components/members/MemberCard.vue';
|
||||
|
||||
enum sidePanelState { view, create, closed };
|
||||
|
||||
@@ -152,9 +153,13 @@ onMounted(async () => {
|
||||
<TableCell class="font-medium">{{ report.course_name.length > 30 ? report.course_shortname :
|
||||
report.course_name }}</TableCell>
|
||||
<TableCell>{{ report.date.split('T')[0] }}</TableCell>
|
||||
<TableCell class="text-right">{{ report.created_by_name === null ? "Unknown User" :
|
||||
<TableCell class="text-right">
|
||||
<MemberCard v-if="report.created_by_name" :member-id="report.created_by"></MemberCard>
|
||||
<span v-else>Unknown User</span>
|
||||
</TableCell>
|
||||
<!-- <TableCell class="text-right">{{ report.created_by_name === null ? "Unknown User" :
|
||||
report.created_by_name
|
||||
}}</TableCell>
|
||||
}}</TableCell> -->
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
@@ -172,11 +177,14 @@ onMounted(async () => {
|
||||
<div class="flex flex-col mb-5 border rounded-lg bg-muted/70 p-2 py-3 px-4">
|
||||
<p class="scroll-m-20 text-xl font-semibold tracking-tight">{{ focusedTrainingReport.course_name }}
|
||||
</p>
|
||||
<div class="flex gap-10">
|
||||
<div class="flex gap-10 items-center">
|
||||
<p class="text-muted-foreground">{{ focusedTrainingReport.event_date.split('T')[0] }}</p>
|
||||
<p class="">Created by {{ focusedTrainingReport.created_by_name === null ? "Unknown User" :
|
||||
<p class="flex gap-2 items-center">Created by:
|
||||
<MemberCard v-if="focusedTrainingReport.created_by"
|
||||
:member-id="focusedTrainingReport.created_by" />
|
||||
<p v-else>{{ focusedTrainingReport.created_by_name === null ? "Unknown User" :
|
||||
focusedTrainingReport.created_by_name
|
||||
}}
|
||||
}}</p>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -191,7 +199,11 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div v-for="person in focusedTrainingTrainers"
|
||||
class="grid grid-cols-4 py-2 items-center border-b last:border-none">
|
||||
<p>{{ person.attendee_name }}</p>
|
||||
<div>
|
||||
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
||||
class="justify-self-start"></MemberCard>
|
||||
<p v-else>{{ person.attendee_name }}</p>
|
||||
</div>
|
||||
<p class="">{{ person.role.name }}</p>
|
||||
<p class="col-span-2 text-right px-2"
|
||||
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
|
||||
@@ -213,7 +225,11 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div v-for="person in focusedTrainingTrainees"
|
||||
class="grid grid-cols-5 py-2 items-center border-b last:border-none">
|
||||
<p>{{ person.attendee_name }}</p>
|
||||
<div>
|
||||
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
||||
class="justify-self-start"></MemberCard>
|
||||
<p v-else>{{ person.attendee_name }}</p>
|
||||
</div>
|
||||
<Checkbox :disabled="!focusedTrainingReport.course.hasQual"
|
||||
:model-value="person.passed_bookwork" class="pointer-events-none ml-5">
|
||||
</Checkbox>
|
||||
@@ -242,7 +258,11 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div v-for="person in focusedNoShows"
|
||||
class="grid grid-cols-5 py-2 items-center border-b last:border-none">
|
||||
<p>{{ person.attendee_name }}</p>
|
||||
<div>
|
||||
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
||||
class="justify-self-start"></MemberCard>
|
||||
<p v-else>{{ person.attendee_name }}</p>
|
||||
</div>
|
||||
<!-- <Checkbox :default-value="person.passed_bookwork ? true : false" class="pointer-events-none">
|
||||
</Checkbox>
|
||||
<Checkbox :default-value="person.passed_qual ? true : false" class="pointer-events-none">
|
||||
|
||||
Reference in New Issue
Block a user