diff --git a/public/favicon.ico b/public/favicon.ico index df36fcf..da8b5c6 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/src/api/auth.ts b/src/api/auth.ts index 8f6d030..d95d73b 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -1,15 +1,7 @@ import type { LoginPayload, RefreshPayload, TokenPair } from '@/types/auth' +import { API_BASE_URL, extractErrorMessage } from '@/api/http' -export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? '/api/v1' - -async function extractErrorMessage(response: Response, fallback: string): Promise { - try { - const errorData = await response.json() - return errorData.message || errorData.error || fallback - } catch { - return response.statusText || fallback - } -} +export { API_BASE_URL } async function postJson( path: string, diff --git a/src/api/client.ts b/src/api/client.ts index d7ed06a..26c2204 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -1,6 +1,8 @@ import { useAuthStore } from '@/stores/auth' -import { API_BASE_URL } from '@/api/auth' import router from '@/router' +import { API_BASE_URL, extractErrorMessage } from '@/api/http' + +export { API_BASE_URL, extractErrorMessage } let refreshPromise: Promise | null = null @@ -94,6 +96,10 @@ export const apiClient = { method: 'PUT', body: body ? JSON.stringify(body) : undefined, }), - delete: (endpoint: string, options?: FetchOptions) => - fetchWithAuth(endpoint, { ...options, method: 'DELETE' }), + delete: (endpoint: string, body?: unknown, options?: FetchOptions) => + fetchWithAuth(endpoint, { + ...options, + method: 'DELETE', + body: body ? JSON.stringify(body) : undefined, + }), } diff --git a/src/api/http.ts b/src/api/http.ts new file mode 100644 index 0000000..bdf7a0d --- /dev/null +++ b/src/api/http.ts @@ -0,0 +1,10 @@ +export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? '/api/v1' + +export async function extractErrorMessage(response: Response, fallback: string): Promise { + try { + const errorData = await response.json() + return errorData.message || errorData.error || fallback + } catch { + return response.statusText || fallback + } +} diff --git a/src/api/lists.ts b/src/api/lists.ts index 740f82c..e673a85 100644 --- a/src/api/lists.ts +++ b/src/api/lists.ts @@ -1,4 +1,5 @@ import { apiClient } from '@/api/client' +import { extractErrorMessage } from '@/api/http' import type { List, ListItem, @@ -10,15 +11,6 @@ import type { RemoveUserFromListPayload, } from '@/types/list' -async function extractErrorMessage(response: Response, fallback: string): Promise { - try { - const errorData = await response.json() - return errorData.message || errorData.error || fallback - } catch { - return response.statusText || fallback - } -} - export async function getListsApi(): Promise { const response = await apiClient.get('/lists') if (!response.ok) { @@ -76,9 +68,7 @@ export async function addUserToListApi(payload: AddUserToListPayload): Promise { - const response = await apiClient.delete('/lists/user', { - body: JSON.stringify(payload), - }) + const response = await apiClient.delete('/lists/user', payload) if (!response.ok) { throw new Error(await extractErrorMessage(response, 'Failed to remove user from list')) } diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue index b2a4bfd..6bc720b 100644 --- a/src/components/AppHeader.vue +++ b/src/components/AppHeader.vue @@ -29,6 +29,7 @@ async function handleLogout() { {{ listsStore.pendingCount }} pending + ⚠ sync error @@ -85,6 +86,11 @@ async function handleLogout() { background-color: var(--c-text-soft); } +.sync-error { + color: var(--c-danger); + cursor: help; +} + .logout { background: none; border: 1px solid var(--c-border); diff --git a/src/components/DeleteListModal.vue b/src/components/DeleteListModal.vue index 1be0dac..c32d652 100644 --- a/src/components/DeleteListModal.vue +++ b/src/components/DeleteListModal.vue @@ -1,29 +1,17 @@