feat: Add user profile management page including personal info editing, avatar upload, and password change.

This commit is contained in:
supalerk-ar66 2026-01-28 14:44:41 +07:00
parent cf12ef965e
commit 70d2dfa4c7
4 changed files with 185 additions and 31 deletions

View file

@ -255,30 +255,84 @@ export const useAuth = () => {
const uploadAvatar = async (file: File) => {
if (!token.value) return { success: false, error: 'ไม่พบ Token การใช้งาน' }
const formData = new FormData()
formData.append('file', file)
// optional: validate เบื้องต้น
const allowed = ['image/jpeg', 'image/png', ]
if (!allowed.includes(file.type)) {
return { success: false, error: 'รองรับเฉพาะไฟล์ jpg/png/' }
}
const maxMB = 5
if (file.size > maxMB * 1024 * 1024) {
return { success: false, error: `ไฟล์ต้องไม่เกิน ${maxMB}MB` }
}
try {
const data = await $fetch<{ code: number; message: string; data: { avatar_url: string; id: number } }>(`${API_BASE_URL}/user/upload-avatar`, {
const formData = new FormData()
formData.append('file', file) // ✅ field = file
interface AvatarResponse {
code: number
message: string
data: {
id: number
avatar_url: string
}
}
const doUpload = async () => {
return await $fetch<AvatarResponse>(`${API_BASE_URL}/user/upload-avatar`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token.value}`
accept: 'application/json',
Authorization: `Bearer ${token.value}`
},
body: formData
})
// อัปเดตข้อมูล User ใน Local State เมื่ออัปโหลดสำเร็จ
if (data.data.avatar_url && user.value && user.value.profile) {
user.value.profile.avatar_url = data.data.avatar_url
} else {
// หากไม่มีข้อมูลใน cache ให้ดึงใหม่
await fetchUserProfile(true)
}
try {
let response: AvatarResponse
try {
response = await doUpload()
} catch (err: any) {
// ✅ ถ้า 401 ให้ refresh แล้วลองใหม่ 1 ครั้ง
if (err?.statusCode === 401) {
const refreshed = await refreshAccessToken()
if (!refreshed) {
logout()
return { success: false, error: 'Token หมดอายุ กรุณาเข้าสู่ระบบใหม่' }
}
response = await doUpload()
} else {
throw err
}
}
return { success: true, data: data.data }
const newUrl = response?.data?.avatar_url
// ✅ สำคัญ: re-assign ทั้งก้อน เพื่อให้ cookie/reactivity อัปเดตชัวร์
if (newUrl && user.value) {
user.value = {
...user.value,
profile: {
...(user.value.profile ?? {
prefix: { th: '', en: '' },
first_name: '',
last_name: '',
phone: null,
avatar_url: null
}),
avatar_url: newUrl
}
}
}
// ✅ ถ้าต้องการ sync ให้ตรง server 100% ค่อย force refresh (optional)
await fetchUserProfile(true)
return { success: true, data: response.data }
} catch (err: any) {
console.error('Upload avatar failed:', err)
return { success: false, error: err.data?.message || 'อัปโหลดรูปภาพไม่สำเร็จ' }
return { success: false, error: err.data?.message || err.message || 'อัปโหลดรูปภาพไม่สำเร็จ' }
}
}