Consistently use apiJson for fetches, with timeout and proper error handling (less code duplication).

This commit is contained in:
Leo Vasanko
2025-12-03 13:00:24 -06:00
parent ceb99de738
commit 4306323c44
9 changed files with 173 additions and 194 deletions
+2 -4
View File
@@ -101,7 +101,7 @@ import { useAuthStore } from '@/stores/auth'
import { adminUiPath, makeUiHref } from '@/utils/settings'
import passkey from '@/utils/passkey'
import { goBack } from '@/utils/helpers'
import { apiFetch } from '@/utils/api'
import { apiJson } from '@/utils/api'
const authStore = useAuthStore()
const updateInterval = ref(null)
@@ -174,9 +174,7 @@ const saveName = async () => {
if (!name) { authStore.showMessage('Name cannot be empty', 'error'); return }
try {
saving.value = true
const res = await apiFetch('/auth/api/user/display-name', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ display_name: name }) })
const data = await res.json()
if (!res.ok || data.detail) throw new Error(data.detail || 'Update failed')
await apiJson('/auth/api/user/display-name', { method: 'PUT', body: { display_name: name } })
showNameDialog.value = false
await authStore.loadUserInfo()
authStore.showMessage('Name updated successfully!', 'success', 3000)
@@ -59,7 +59,7 @@ import { ref, onMounted, watch, computed, nextTick } from 'vue'
import QRCode from 'qrcode/lib/browser'
import { formatDate } from '@/utils/helpers'
import { useAuthStore } from '@/stores/auth'
import { apiFetch } from '@/utils/api'
import { apiJson, getUserFriendlyErrorMessage, shouldShowErrorToast } from '@/utils/api'
const authStore = useAuthStore()
@@ -87,9 +87,7 @@ const expirationMessage = computed(() => {
async function fetchLink() {
try {
const res = await apiFetch(props.endpoint, { method: 'POST' })
const data = await res.json()
if (data.detail) throw new Error(data.detail)
const data = await apiJson(props.endpoint, { method: 'POST' })
url.value = data.url
expires.value = data.expires
emit('generated', { url: data.url, expires: data.expires })
@@ -98,6 +96,9 @@ async function fetchLink() {
if (props.autoCopy) copy()
} catch (e) {
console.error('Failed to create link', e)
if (shouldShowErrorToast(e)) {
authStore.showMessage(getUserFriendlyErrorMessage(e), 'error', 4000)
}
// Close the dialog on any error (auth cancelled, network error, etc.)
emit('close')
}
+12 -15
View File
@@ -44,6 +44,7 @@
import { computed, onMounted, reactive, ref } from 'vue'
import passkey from '@/utils/passkey'
import { getSettings } from '@/utils/settings'
import { apiJson, getUserFriendlyErrorMessage } from '@/utils/api'
const props = defineProps({
mode: {
@@ -120,13 +121,7 @@ async function fetchSettings() {
async function fetchUserInfo() {
try {
const res = await fetch('/auth/api/user-info', { method: 'POST' })
if (!res.ok) {
userInfo.value = null
currentView.value = 'login'
return
}
userInfo.value = await res.json()
userInfo.value = await apiJson('/auth/api/user-info', { method: 'POST' })
// Determine view based on authentication status
if (isAuthenticated.value && props.mode !== 'reauth') {
currentView.value = 'forbidden'
@@ -136,6 +131,11 @@ async function fetchUserInfo() {
}
} catch (error) {
console.error('Failed to load user info', error)
// For 401/403 just go to login, for other errors show message
if (error.status !== 401 && error.status !== 403) {
showMessage(getUserFriendlyErrorMessage(error), 'error', 4000)
}
userInfo.value = null
currentView.value = 'login'
}
}
@@ -168,12 +168,14 @@ async function logoutUser() {
if (loading.value) return
loading.value = true
try {
await fetch('/auth/api/logout', { method: 'POST' })
await apiJson('/auth/api/logout', { method: 'POST' })
userInfo.value = null
// Switch to login view after logout
currentView.value = 'login'
showMessage('Logged out. You can sign in with a different account.', 'info', 3000)
} catch (_) { /* ignore */ }
} catch (error) {
showMessage(getUserFriendlyErrorMessage(error), 'error', 4000)
}
finally { loading.value = false }
emit('logout')
}
@@ -185,16 +187,11 @@ function openProfile() {
}
async function setSessionCookie(sessionToken) {
const response = await fetch('/auth/api/set-session', {
return await apiJson('/auth/api/set-session', {
method: 'POST', headers: { Authorization: `Bearer ${sessionToken}` }
})
const payload = await safeParseJson(response)
if (!response.ok || payload?.detail) throw new Error(payload?.detail || 'Session could not be established.')
return payload
}
async function safeParseJson(response) { try { return await response.json() } catch (_) { return null } }
onMounted(async () => {
await fetchSettings()
await fetchUserInfo()