96 lines
3.1 KiB
Vue
96 lines
3.1 KiB
Vue
<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;
|
||
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> |