feat: introduce user profile page with options to edit personal details and change password.
This commit is contained in:
parent
78a26fc2e1
commit
92ff037150
3 changed files with 75 additions and 48 deletions
|
|
@ -100,7 +100,16 @@
|
||||||
"security": "Security",
|
"security": "Security",
|
||||||
"currentPassword": "Current Password",
|
"currentPassword": "Current Password",
|
||||||
"newPassword": "New Password",
|
"newPassword": "New Password",
|
||||||
"confirmNewPassword": "Confirm New Password"
|
"confirmNewPassword": "Confirm New Password",
|
||||||
|
"securityDesc": "Update your password for better account security. Please choose a strong password.",
|
||||||
|
"newPasswordHint": "At least 6 characters",
|
||||||
|
"confirmPasswordHint": "Confirm your password again",
|
||||||
|
"changePasswordBtn": "Change Password",
|
||||||
|
"emailHint": "Contact admin to change email",
|
||||||
|
"updateSuccess": "Profile updated successfully",
|
||||||
|
"updateError": "Failed to update profile",
|
||||||
|
"passwordSuccess": "Password changed successfully",
|
||||||
|
"passwordError": "Failed to change password"
|
||||||
},
|
},
|
||||||
"userMenu": {
|
"userMenu": {
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
|
|
@ -128,6 +137,11 @@
|
||||||
"newBadge": "New",
|
"newBadge": "New",
|
||||||
"popularBadge": "Popular",
|
"popularBadge": "Popular",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"cancel": "Cancel"
|
"cancel": "Cancel",
|
||||||
|
"required": "This field is required",
|
||||||
|
"invalidEmail": "Invalid email address",
|
||||||
|
"invalidPhone": "Invalid phone number",
|
||||||
|
"passwordTooShort": "At least 6 characters",
|
||||||
|
"passwordsDoNotMatch": "Passwords do not match"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,16 @@
|
||||||
"security": "ความปลอดภัย",
|
"security": "ความปลอดภัย",
|
||||||
"currentPassword": "รหัสผ่านปัจจุบัน",
|
"currentPassword": "รหัสผ่านปัจจุบัน",
|
||||||
"newPassword": "รหัสผ่านใหม่",
|
"newPassword": "รหัสผ่านใหม่",
|
||||||
"confirmNewPassword": "ยืนยันรหัสผ่านใหม่"
|
"confirmNewPassword": "ยืนยันรหัสผ่านใหม่",
|
||||||
|
"securityDesc": "เปลี่ยนรหัสผ่านเพื่อความปลอดภัยของบัญชี กรุณาตั้งรหัสผ่านที่คาดเดายาก",
|
||||||
|
"newPasswordHint": "อย่างน้อย 6 ตัวอักษร",
|
||||||
|
"confirmPasswordHint": "ยืนยันรหัสผ่านอีกครั้ง",
|
||||||
|
"changePasswordBtn": "เปลี่ยนรหัสผ่าน",
|
||||||
|
"emailHint": "ติดต่อผู้ดูแลระบบเพื่อเปลี่ยนอีเมล",
|
||||||
|
"updateSuccess": "บันทึกข้อมูลส่วนตัวเรียบร้อยแล้ว",
|
||||||
|
"updateError": "เกิดข้อผิดพลาดในการบันทึกข้อมูลส่วนตัว",
|
||||||
|
"passwordSuccess": "เปลี่ยนรหัสผ่านเรียบร้อยแล้ว",
|
||||||
|
"passwordError": "เปลี่ยนรหัสผ่านไม่สำเร็จ"
|
||||||
},
|
},
|
||||||
"userMenu": {
|
"userMenu": {
|
||||||
"home": "หน้าหลัก",
|
"home": "หน้าหลัก",
|
||||||
|
|
@ -128,6 +137,11 @@
|
||||||
"newBadge": "ใหม่",
|
"newBadge": "ใหม่",
|
||||||
"popularBadge": "ยอดนิยม",
|
"popularBadge": "ยอดนิยม",
|
||||||
"save": "บันทึก",
|
"save": "บันทึก",
|
||||||
"cancel": "ยกเลิก"
|
"cancel": "ยกเลิก",
|
||||||
|
"required": "กรุณากรอกข้อมูล",
|
||||||
|
"invalidEmail": "อีเมลไม่ถูกต้อง",
|
||||||
|
"invalidPhone": "เบอร์โทรศัพท์ไม่ถูกต้อง",
|
||||||
|
"passwordTooShort": "รหัสผ่านต้องมีอย่างน้อย 6 ตัวอักษร",
|
||||||
|
"passwordsDoNotMatch": "รหัสผ่านใหม่ไม่ตรงกัน"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,7 @@ useHead({
|
||||||
})
|
})
|
||||||
|
|
||||||
const { currentUser, updateUserProfile, changePassword } = useAuth()
|
const { currentUser, updateUserProfile, changePassword } = useAuth()
|
||||||
// Removed useFormValidation destructuring if not strictly used in template to avoid unused var warnings,
|
const { t } = useI18n()
|
||||||
// or keep it if logically needed. Keeping minimalist.
|
|
||||||
const { errors, validate, clearFieldError } = useFormValidation()
|
const { errors, validate, clearFieldError } = useFormValidation()
|
||||||
|
|
||||||
const isEditing = ref(false)
|
const isEditing = ref(false)
|
||||||
|
|
@ -48,22 +47,22 @@ const passwordForm = reactive({
|
||||||
confirmPassword: ''
|
confirmPassword: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const nameRules = [(val: string) => !!val || 'กรุณากรอกข้อมูล']
|
const nameRules = [(val: string) => !!val || t('common.required')]
|
||||||
const emailRules = [
|
const emailRules = [
|
||||||
(val: string) => !!val || 'กรุณากรอกอีเมล',
|
(val: string) => !!val || t('common.required'),
|
||||||
(val: string) => /.+@.+\..+/.test(val) || 'อีเมลไม่ถูกต้อง'
|
(val: string) => /.+@.+\..+/.test(val) || t('common.invalidEmail')
|
||||||
]
|
]
|
||||||
const phoneRules = [
|
const phoneRules = [
|
||||||
(val: string) => !!val || 'กรุณากรอกเบอร์โทรศัพท์',
|
(val: string) => !!val || t('common.required'),
|
||||||
(val: string) => /^0[0-9]{8,9}$/.test(val) || 'เบอร์โทรศัพท์ไม่ถูกต้อง'
|
(val: string) => /^0[0-9]{8,9}$/.test(val) || t('common.invalidPhone')
|
||||||
]
|
]
|
||||||
const passwordRules = [
|
const passwordRules = [
|
||||||
(val: string) => !!val || 'กรุณากรอกรหัสผ่าน',
|
(val: string) => !!val || t('common.required'),
|
||||||
(val: string) => val.length >= 6 || 'รหัสผ่านต้องมีอย่างน้อย 6 ตัวอักษร'
|
(val: string) => val.length >= 6 || t('common.passwordTooShort')
|
||||||
]
|
]
|
||||||
const confirmPasswordRules = [
|
const confirmPasswordRules = [
|
||||||
(val: string) => !!val || 'กรุณายืนยันรหัสผ่าน',
|
(val: string) => !!val || t('common.required'),
|
||||||
(val: string) => val === passwordForm.newPassword || 'รหัสผ่านใหม่ไม่ตรงกัน'
|
(val: string) => val === passwordForm.newPassword || t('common.passwordsDoNotMatch')
|
||||||
]
|
]
|
||||||
|
|
||||||
const showCurrentPassword = ref(false)
|
const showCurrentPassword = ref(false)
|
||||||
|
|
@ -115,7 +114,7 @@ const handleUpdateProfile = async () => {
|
||||||
if (result?.success) {
|
if (result?.success) {
|
||||||
// success logic
|
// success logic
|
||||||
} else {
|
} else {
|
||||||
alert(result?.error || 'เกิดข้อผิดพลาดในการบันทึกข้อมูลส่วนตัว')
|
alert(result?.error || t('profile.updateError'))
|
||||||
}
|
}
|
||||||
|
|
||||||
isProfileSaving.value = false
|
isProfileSaving.value = false
|
||||||
|
|
@ -135,12 +134,12 @@ const handleUpdatePassword = async () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
alert('เปลี่ยนรหัสผ่านเรียบร้อยแล้ว')
|
alert(t('profile.passwordSuccess'))
|
||||||
passwordForm.currentPassword = ''
|
passwordForm.currentPassword = ''
|
||||||
passwordForm.newPassword = ''
|
passwordForm.newPassword = ''
|
||||||
passwordForm.confirmPassword = ''
|
passwordForm.confirmPassword = ''
|
||||||
} else {
|
} else {
|
||||||
alert(result.error || 'เปลี่ยนรหัสผ่านไม่สำเร็จ')
|
alert(result.error || t('profile.passwordError'))
|
||||||
}
|
}
|
||||||
|
|
||||||
isPasswordSaving.value = false
|
isPasswordSaving.value = false
|
||||||
|
|
@ -311,10 +310,10 @@ onMounted(() => {
|
||||||
outlined dense rounded
|
outlined dense rounded
|
||||||
class="premium-q-input"
|
class="premium-q-input"
|
||||||
:rules="emailRules"
|
:rules="emailRules"
|
||||||
hide-bottom-space
|
hide-bottom-space
|
||||||
disable
|
disable
|
||||||
hint="ติดต่อผู้ดูแลระบบเพื่อเปลี่ยนอีเมล"
|
:hint="$t('profile.emailHint')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -350,10 +349,10 @@ onMounted(() => {
|
||||||
{{ $t('profile.security') }}
|
{{ $t('profile.security') }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<q-form @submit="handleUpdatePassword" class="flex flex-col gap-6">
|
<q-form @submit="handleUpdatePassword" class="flex flex-col gap-6">
|
||||||
<div class="text-sm text-slate-500 dark:text-slate-400 mb-2">
|
<div class="text-sm text-slate-500 dark:text-slate-400 mb-2">
|
||||||
เปลี่ยนรหัสผ่านเพื่อความปลอดภัยของบัญชี กรุณาตั้งรหัสผ่านที่คาดเดายาก
|
{{ $t('profile.securityDesc') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -361,11 +360,11 @@ onMounted(() => {
|
||||||
<q-input
|
<q-input
|
||||||
v-model="passwordForm.currentPassword"
|
v-model="passwordForm.currentPassword"
|
||||||
:type="showCurrentPassword ? 'text' : 'password'"
|
:type="showCurrentPassword ? 'text' : 'password'"
|
||||||
outlined dense rounded
|
outlined dense rounded
|
||||||
class="premium-q-input"
|
class="premium-q-input"
|
||||||
placeholder="••••••••"
|
placeholder="••••••••"
|
||||||
:rules="[val => !!val || 'กรุณากรอกรหัสผ่านปัจจุบัน']"
|
:rules="[val => !!val || $t('common.required')]"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon
|
<q-icon
|
||||||
:name="showCurrentPassword ? 'visibility_off' : 'visibility'"
|
:name="showCurrentPassword ? 'visibility_off' : 'visibility'"
|
||||||
|
|
@ -383,11 +382,11 @@ onMounted(() => {
|
||||||
<q-input
|
<q-input
|
||||||
v-model="passwordForm.newPassword"
|
v-model="passwordForm.newPassword"
|
||||||
:type="showNewPassword ? 'text' : 'password'"
|
:type="showNewPassword ? 'text' : 'password'"
|
||||||
outlined dense rounded
|
outlined dense rounded
|
||||||
class="premium-q-input"
|
class="premium-q-input"
|
||||||
placeholder="อย่างน้อย 6 ตัวอักษร"
|
:placeholder="$t('profile.newPasswordHint')"
|
||||||
:rules="passwordRules"
|
:rules="passwordRules"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon
|
<q-icon
|
||||||
:name="showNewPassword ? 'visibility_off' : 'visibility'"
|
:name="showNewPassword ? 'visibility_off' : 'visibility'"
|
||||||
|
|
@ -403,11 +402,11 @@ onMounted(() => {
|
||||||
<q-input
|
<q-input
|
||||||
v-model="passwordForm.confirmPassword"
|
v-model="passwordForm.confirmPassword"
|
||||||
:type="showConfirmPassword ? 'text' : 'password'"
|
:type="showConfirmPassword ? 'text' : 'password'"
|
||||||
outlined dense rounded
|
outlined dense rounded
|
||||||
class="premium-q-input"
|
class="premium-q-input"
|
||||||
placeholder="ยืนยันรหัสผ่านอีกครั้ง"
|
:placeholder="$t('profile.confirmPasswordHint')"
|
||||||
:rules="confirmPasswordRules"
|
:rules="confirmPasswordRules"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon
|
<q-icon
|
||||||
:name="showConfirmPassword ? 'visibility_off' : 'visibility'"
|
:name="showConfirmPassword ? 'visibility_off' : 'visibility'"
|
||||||
|
|
@ -422,13 +421,13 @@ onMounted(() => {
|
||||||
<div class="pt-2">
|
<div class="pt-2">
|
||||||
<q-btn
|
<q-btn
|
||||||
type="submit"
|
type="submit"
|
||||||
unelevated
|
unelevated
|
||||||
rounded
|
rounded
|
||||||
class="w-full py-3 font-bold text-base shadow-lg shadow-amber-500/20"
|
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;"
|
style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); color: white;"
|
||||||
label="เปลี่ยนรหัสผ่าน"
|
:label="$t('profile.changePasswordBtn')"
|
||||||
:loading="isPasswordSaving"
|
:loading="isPasswordSaving"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</q-form>
|
</q-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue