diff --git a/frontend/src/stores/user.ts b/frontend/src/stores/user.ts index 4891370..9fa6369 100644 --- a/frontend/src/stores/user.ts +++ b/frontend/src/stores/user.ts @@ -7,7 +7,8 @@ import { ref, computed } from 'vue' import { defineStore } from 'pinia' -import { config } from '@/config' +import { apiClient } from '@/api/client' +import { ApiError } from '@/api/types' import { useAuthStore } from './auth' export interface LinkedAccount { @@ -38,14 +39,28 @@ export const useUserStore = defineStore('user', () => { const hasStarterDeck = computed(() => profile.value?.hasStarterDeck ?? false) const linkedAccounts = computed(() => profile.value?.linkedAccounts ?? []) + /** API response type for user profile */ + interface UserProfileResponse { + id: string + display_name: string + avatar_url: string | null + has_starter_deck: boolean + created_at: string + linked_accounts?: Array<{ + provider: string + provider_user_id: string + email: string | null + linked_at: string + }> + } + /** * Fetch the current user's profile from the API. */ async function fetchProfile(): Promise { const auth = useAuthStore() - const token = await auth.getValidToken() - if (!token) { + if (!auth.isAuthenticated) { error.value = 'Not authenticated' return false } @@ -54,25 +69,16 @@ export const useUserStore = defineStore('user', () => { error.value = null try { - const response = await fetch(`${config.apiBaseUrl}/api/users/me`, { - headers: { - 'Authorization': `Bearer ${token}`, - }, - }) + const data = await apiClient.get('/api/users/me') - if (!response.ok) { - throw new Error('Failed to fetch profile') - } - - const data = await response.json() profile.value = { id: data.id, displayName: data.display_name, avatarUrl: data.avatar_url, hasStarterDeck: data.has_starter_deck, createdAt: data.created_at, - linkedAccounts: data.linked_accounts?.map((acc: Record) => ({ - provider: acc.provider, + linkedAccounts: data.linked_accounts?.map((acc) => ({ + provider: acc.provider as 'google' | 'discord', providerUserId: acc.provider_user_id, email: acc.email, linkedAt: acc.linked_at, @@ -89,7 +95,11 @@ export const useUserStore = defineStore('user', () => { return true } catch (e) { - error.value = e instanceof Error ? e.message : 'Failed to fetch profile' + if (e instanceof ApiError) { + error.value = e.detail || e.message + } else { + error.value = e instanceof Error ? e.message : 'Failed to fetch profile' + } return false } finally { isLoading.value = false @@ -101,9 +111,8 @@ export const useUserStore = defineStore('user', () => { */ async function updateDisplayName(newName: string): Promise { const auth = useAuthStore() - const token = await auth.getValidToken() - if (!token) { + if (!auth.isAuthenticated) { error.value = 'Not authenticated' return false } @@ -112,24 +121,17 @@ export const useUserStore = defineStore('user', () => { error.value = null try { - const response = await fetch(`${config.apiBaseUrl}/api/users/me`, { - method: 'PATCH', - headers: { - 'Authorization': `Bearer ${token}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ display_name: newName }), - }) - - if (!response.ok) { - throw new Error('Failed to update profile') - } + await apiClient.patch('/api/users/me', { display_name: newName }) // Refetch to get updated data await fetchProfile() return true } catch (e) { - error.value = e instanceof Error ? e.message : 'Failed to update profile' + if (e instanceof ApiError) { + error.value = e.detail || e.message + } else { + error.value = e instanceof Error ? e.message : 'Failed to update profile' + } return false } finally { isLoading.value = false