feat: introduce user profile page with options to edit personal details and change password.

This commit is contained in:
supalerk-ar66 2026-01-26 16:29:37 +07:00
parent 78a26fc2e1
commit 92ff037150
3 changed files with 75 additions and 48 deletions

View file

@ -9,8 +9,7 @@ useHead({
})
const { currentUser, updateUserProfile, changePassword } = useAuth()
// Removed useFormValidation destructuring if not strictly used in template to avoid unused var warnings,
// or keep it if logically needed. Keeping minimalist.
const { t } = useI18n()
const { errors, validate, clearFieldError } = useFormValidation()
const isEditing = ref(false)
@ -48,22 +47,22 @@ const passwordForm = reactive({
confirmPassword: ''
})
const nameRules = [(val: string) => !!val || 'กรุณากรอกข้อมูล']
const nameRules = [(val: string) => !!val || t('common.required')]
const emailRules = [
(val: string) => !!val || 'กรุณากรอกอีเมล',
(val: string) => /.+@.+\..+/.test(val) || ''
(val: string) => !!val || t('common.required'),
(val: string) => /.+@.+\..+/.test(val) || t('common.invalidEmail')
]
const phoneRules = [
(val: string) => !!val || 'กรุณากรอกเบอร์โทรศัพท์',
(val: string) => /^0[0-9]{8,9}$/.test(val) || 'เบอร์โทรศัพท์ไม่ถูกต้อง'
(val: string) => !!val || t('common.required'),
(val: string) => /^0[0-9]{8,9}$/.test(val) || t('common.invalidPhone')
]
const passwordRules = [
(val: string) => !!val || 'กรุณากรอกรหัสผ่าน',
(val: string) => val.length >= 6 || 'รหัสผ่านต้องมีอย่างน้อย 6 ตัวอักษร'
(val: string) => !!val || t('common.required'),
(val: string) => val.length >= 6 || t('common.passwordTooShort')
]
const confirmPasswordRules = [
(val: string) => !!val || 'กรุณายืนยันรหัสผ่าน',
(val: string) => val === passwordForm.newPassword || 'รหัสผ่านใหม่ไม่ตรงกัน'
(val: string) => !!val || t('common.required'),
(val: string) => val === passwordForm.newPassword || t('common.passwordsDoNotMatch')
]
const showCurrentPassword = ref(false)
@ -115,7 +114,7 @@ const handleUpdateProfile = async () => {
if (result?.success) {
// success logic
} else {
alert(result?.error || 'เกิดข้อผิดพลาดในการบันทึกข้อมูลส่วนตัว')
alert(result?.error || t('profile.updateError'))
}
isProfileSaving.value = false
@ -135,12 +134,12 @@ const handleUpdatePassword = async () => {
})
if (result.success) {
alert('เปลี่ยนรหัสผ่านเรียบร้อยแล้ว')
alert(t('profile.passwordSuccess'))
passwordForm.currentPassword = ''
passwordForm.newPassword = ''
passwordForm.confirmPassword = ''
} else {
alert(result.error || 'เปลี่ยนรหัสผ่านไม่สำเร็จ')
alert(result.error || t('profile.passwordError'))
}
isPasswordSaving.value = false
@ -311,10 +310,10 @@ onMounted(() => {
outlined dense rounded
class="premium-q-input"
:rules="emailRules"
hide-bottom-space
disable
hint="ติดต่อผู้ดูแลระบบเพื่อเปลี่ยนอีเมล"
/>
hide-bottom-space
disable
:hint="$t('profile.emailHint')"
/>
</div>
<div>
@ -350,10 +349,10 @@ onMounted(() => {
{{ $t('profile.security') }}
</h2>
<q-form @submit="handleUpdatePassword" class="flex flex-col gap-6">
<div class="text-sm text-slate-500 dark:text-slate-400 mb-2">
เปลยนรหสผานเพอความปลอดภยของบญช กรณาตงรหสผานทคาดเดายาก
</div>
<q-form @submit="handleUpdatePassword" class="flex flex-col gap-6">
<div class="text-sm text-slate-500 dark:text-slate-400 mb-2">
{{ $t('profile.securityDesc') }}
</div>
<div class="space-y-4">
<div>
@ -361,11 +360,11 @@ onMounted(() => {
<q-input
v-model="passwordForm.currentPassword"
:type="showCurrentPassword ? 'text' : 'password'"
outlined dense rounded
class="premium-q-input"
placeholder="••••••••"
:rules="[val => !!val || 'กรุณากรอกรหัสผ่านปัจจุบัน']"
>
outlined dense rounded
class="premium-q-input"
placeholder="••••••••"
:rules="[val => !!val || $t('common.required')]"
>
<template v-slot:append>
<q-icon
:name="showCurrentPassword ? 'visibility_off' : 'visibility'"
@ -383,11 +382,11 @@ onMounted(() => {
<q-input
v-model="passwordForm.newPassword"
:type="showNewPassword ? 'text' : 'password'"
outlined dense rounded
class="premium-q-input"
placeholder="อย่างน้อย 6 ตัวอักษร"
:rules="passwordRules"
>
outlined dense rounded
class="premium-q-input"
:placeholder="$t('profile.newPasswordHint')"
:rules="passwordRules"
>
<template v-slot:append>
<q-icon
:name="showNewPassword ? 'visibility_off' : 'visibility'"
@ -403,11 +402,11 @@ onMounted(() => {
<q-input
v-model="passwordForm.confirmPassword"
:type="showConfirmPassword ? 'text' : 'password'"
outlined dense rounded
class="premium-q-input"
placeholder="ยืนยันรหัสผ่านอีกครั้ง"
:rules="confirmPasswordRules"
>
outlined dense rounded
class="premium-q-input"
:placeholder="$t('profile.confirmPasswordHint')"
:rules="confirmPasswordRules"
>
<template v-slot:append>
<q-icon
:name="showConfirmPassword ? 'visibility_off' : 'visibility'"
@ -422,13 +421,13 @@ onMounted(() => {
<div class="pt-2">
<q-btn
type="submit"
unelevated
rounded
class="w-full py-3 font-bold text-base shadow-lg shadow-amber-500/20"
style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: white;"
label="เปลี่ยนรหัสผ่าน"
:loading="isPasswordSaving"
/>
unelevated
rounded
class="w-full py-3 font-bold text-base shadow-lg shadow-amber-500/20"
style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: white;"
:label="$t('profile.changePasswordBtn')"
:loading="isPasswordSaving"
/>
</div>
</q-form>
</div>