feat: 添加用户设置功能,支持修改昵称和邮箱,重构相关路由和组件
This commit is contained in:
@@ -1,191 +0,0 @@
|
||||
<script lang='ts' setup>
|
||||
import type { UpdateUserProfileBody, UserProfileData } from "@/api/types";
|
||||
import { alertController, toastController } from "@ionic/vue";
|
||||
import { arrowBackOutline } from "ionicons/icons";
|
||||
import { client } from "@/api";
|
||||
import { GenderEnum } from "@/api/enum";
|
||||
import { authClient } from "@/auth";
|
||||
|
||||
const router = useRouter();
|
||||
const userProfile = ref<UserProfileData | null>(null);
|
||||
const birthday = computed(() => useDateFormat(userProfile?.value?.birthday || "", "YYYY/MM/DD"));
|
||||
|
||||
async function getUserProfile() {
|
||||
const { data } = await client.api.user.profile.get();
|
||||
if (data) {
|
||||
userProfile.value = data.userProfile;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateProfile(updates: UpdateUserProfileBody) {
|
||||
const { data } = await client.api.user.profile.put(updates);
|
||||
|
||||
if (data) {
|
||||
userProfile.value = data;
|
||||
const toast = await toastController.create({
|
||||
message: "Profile updated successfully",
|
||||
duration: 2000,
|
||||
position: "bottom",
|
||||
color: "success",
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
|
||||
function handleBack() {
|
||||
router.back();
|
||||
}
|
||||
|
||||
async function handleEditField(field: keyof UpdateUserProfileBody, label: string) {
|
||||
if (!userProfile.value)
|
||||
return;
|
||||
|
||||
const currentValue = userProfile.value[field as keyof UserProfileData];
|
||||
|
||||
const alert = await alertController.create({
|
||||
header: `Edit ${label}`,
|
||||
inputs: [
|
||||
{
|
||||
name: "value",
|
||||
type: "text",
|
||||
placeholder: `Enter your ${label.toLowerCase()}`,
|
||||
value: currentValue?.toString() || "",
|
||||
},
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
text: "Cancel",
|
||||
role: "cancel",
|
||||
},
|
||||
{
|
||||
text: "Save",
|
||||
handler: async (data) => {
|
||||
if (data.value !== undefined) {
|
||||
await updateProfile({ [field]: data.value } as UpdateUserProfileBody);
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
}
|
||||
|
||||
async function onUpdateSelect(value: UpdateUserProfileBody["gender"]) {
|
||||
await updateProfile({ gender: value } as UpdateUserProfileBody);
|
||||
}
|
||||
async function onChangeDateTime(event: CustomEvent) {
|
||||
const selectedDate = useDateFormat(event.detail.value, "YYYY-MM-DD");
|
||||
await updateProfile({ birthday: selectedDate.value } as UpdateUserProfileBody);
|
||||
}
|
||||
|
||||
async function handleSignOut() {
|
||||
const alert = await alertController.create({
|
||||
header: "Sign Out",
|
||||
message: "Are you sure you want to sign out?",
|
||||
buttons: [
|
||||
{
|
||||
text: "Cancel",
|
||||
role: "cancel",
|
||||
},
|
||||
{
|
||||
text: "Sign Out",
|
||||
role: "destructive",
|
||||
handler: async () => {
|
||||
authClient.signOut();
|
||||
router.replace("/layout/riwa");
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await alert.present();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getUserProfile();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ion-page>
|
||||
<ion-header>
|
||||
<ion-toolbar class="ui-toolbar">
|
||||
<ion-buttons slot="start">
|
||||
<ion-button @click="handleBack">
|
||||
<ion-icon slot="icon-only" :icon="arrowBackOutline" />
|
||||
</ion-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Settings</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content :fullscreen="true">
|
||||
<div class="flex flex-col items-center justify-center py-10">
|
||||
<div class="relative">
|
||||
<ui-avatar class="size-25" />
|
||||
</div>
|
||||
<div class="mt-4 text-lg font-semibold">
|
||||
{{ userProfile?.nickname || 'User Name' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Info List -->
|
||||
<ion-list class="mt-5">
|
||||
<ion-item button @click="handleEditField('nickname', 'Nickname')">
|
||||
<ion-label>
|
||||
<p class="text-xs text-text-400">
|
||||
Full Name
|
||||
</p>
|
||||
<h2 class="mt-1">
|
||||
{{ userProfile?.nickname || 'Not set' }}
|
||||
</h2>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<ion-item button>
|
||||
<ion-select interface="action-sheet" toggle-icon="" label-placement="floating" :model-value="userProfile?.gender" label="Gender" placeholder="Select Gender" @update:model-value="onUpdateSelect">
|
||||
<ion-select-option v-for="item in GenderEnum" :key="item" :value="item">
|
||||
{{ item }}
|
||||
</ion-select-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
|
||||
<ion-item button>
|
||||
<ion-datetime-button datetime="datetime" color="primary">
|
||||
<div slot="date-target">
|
||||
{{ birthday }}
|
||||
</div>
|
||||
</ion-datetime-button>
|
||||
<ion-modal :keep-contents-mounted="true">
|
||||
<ion-datetime
|
||||
id="datetime"
|
||||
class="ui-datetime"
|
||||
done-text="Done"
|
||||
presentation="date"
|
||||
:value="userProfile?.birthday"
|
||||
:show-default-buttons="true"
|
||||
@ion-change="onChangeDateTime"
|
||||
/>
|
||||
</ion-modal>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="px-5 mt-10">
|
||||
<ion-button expand="block" color="tertiary" @click="handleSignOut">
|
||||
Sign Out
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-content>
|
||||
</ion-page>
|
||||
</template>
|
||||
|
||||
<style lang='css' scoped>
|
||||
ion-avatar {
|
||||
--border-radius: 50%;
|
||||
}
|
||||
ion-item {
|
||||
--min-height: 60px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user