feat(web): add profile management
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -211,6 +211,64 @@ export function useDngAuth() {
|
||||
return user
|
||||
}
|
||||
|
||||
async function updateUserMetadata(data: Record<string, unknown>) {
|
||||
const token = await accessToken()
|
||||
const user = normalizeUser(await $fetch<DngAuthUser>(`${config.public.supabaseUrl}/auth/v1/user`, {
|
||||
method: 'PUT',
|
||||
headers: authHeaders(token),
|
||||
body: { data },
|
||||
}))
|
||||
if (session.value) persist({ ...session.value, user })
|
||||
return user
|
||||
}
|
||||
|
||||
async function avatarStorageRequest(path: string, options: RequestInit) {
|
||||
const token = await accessToken()
|
||||
const baseUrl = String(config.public.supabaseUrl).replace(/\/$/, '')
|
||||
const response = await fetch(`${baseUrl}/storage/v1/${path}`, {
|
||||
...options,
|
||||
headers: {
|
||||
apikey: config.public.supabaseAnonKey,
|
||||
Authorization: `Bearer ${token}`,
|
||||
...options.headers,
|
||||
},
|
||||
})
|
||||
if (!response.ok) {
|
||||
const payload = await response.json().catch(() => null) as { message?: string; error?: string } | null
|
||||
throw new Error(payload?.message || payload?.error || `Profile picture request failed (${response.status}).`)
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadAvatar(file: File) {
|
||||
if (!['image/jpeg', 'image/png', 'image/webp'].includes(file.type)) {
|
||||
throw new Error('Choose a JPG, PNG, or WebP image.')
|
||||
}
|
||||
if (file.size > 2 * 1024 * 1024) throw new Error('Profile pictures must be 2 MB or smaller.')
|
||||
await restore()
|
||||
if (!session.value) throw new Error('Sign in to update your profile picture.')
|
||||
const path = `${session.value.user.id}/avatar`
|
||||
const body = new FormData()
|
||||
body.append('cacheControl', '3600')
|
||||
body.append('', file)
|
||||
await avatarStorageRequest(`object/profile-avatars/${path}`, {
|
||||
method: 'POST',
|
||||
headers: { 'x-upsert': 'true' },
|
||||
body,
|
||||
})
|
||||
return path
|
||||
}
|
||||
|
||||
async function removeAvatar() {
|
||||
await restore()
|
||||
if (!session.value) throw new Error('Sign in to update your profile picture.')
|
||||
const path = `${session.value.user.id}/avatar`
|
||||
await avatarStorageRequest('object/profile-avatars', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ prefixes: [path] }),
|
||||
})
|
||||
}
|
||||
|
||||
async function accessToken() {
|
||||
await restore()
|
||||
if (!session.value) throw new Error('Enter the alpha to continue.')
|
||||
@@ -238,5 +296,20 @@ export function useDngAuth() {
|
||||
hydrated.value = true
|
||||
}
|
||||
|
||||
return { session, hydrated, restore, refresh, signUp, signIn, requestPasswordReset, updatePassword, accessToken, signOut, invalidate }
|
||||
return {
|
||||
session,
|
||||
hydrated,
|
||||
restore,
|
||||
refresh,
|
||||
signUp,
|
||||
signIn,
|
||||
requestPasswordReset,
|
||||
updatePassword,
|
||||
updateUserMetadata,
|
||||
uploadAvatar,
|
||||
removeAvatar,
|
||||
accessToken,
|
||||
signOut,
|
||||
invalidate,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user