frontend: Owner management
This commit is contained in:
parent
9df2ee08d2
commit
994ba0bc01
8 changed files with 293 additions and 27 deletions
59
frontend/app/composables/useAPI.ts
Normal file
59
frontend/app/composables/useAPI.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
export function useApi() {
|
||||
const config = useRuntimeConfig()
|
||||
const { token, logout } = useAuth()
|
||||
|
||||
async function apiFetch<T>(url: string, options: any = {}) {
|
||||
try {
|
||||
return await $fetch<T>(url, {
|
||||
baseURL: config.public.apiBase,
|
||||
headers: {
|
||||
...(options.headers || {}),
|
||||
...(token.value ? { Authorization: `Bearer ${token.value}` } : {})
|
||||
},
|
||||
...options
|
||||
})
|
||||
} catch (error: any) {
|
||||
// Netzwerkfehler oder Server nicht erreichbar
|
||||
if (!error.response) {
|
||||
console.error("API unreachable:", error)
|
||||
throw new Error("Der Server ist nicht erreichbar.")
|
||||
}
|
||||
|
||||
const status = error.response.status
|
||||
const data = error.response._data
|
||||
|
||||
// 401 → Token ungültig oder abgelaufen
|
||||
if (status === 401) {
|
||||
console.warn("API returned 401 — logging out")
|
||||
logout()
|
||||
throw new Error("Deine Sitzung ist abgelaufen. Bitte erneut einloggen.")
|
||||
}
|
||||
|
||||
// 403 → keine Berechtigung
|
||||
if (status === 403) {
|
||||
throw new Error("Du hast keine Berechtigung für diese Aktion.")
|
||||
}
|
||||
|
||||
// 400 → Validierungsfehler
|
||||
if (status === 400) {
|
||||
throw new Error(data?.detail || "Ungültige Eingabe.")
|
||||
}
|
||||
|
||||
// 404 → nicht gefunden
|
||||
if (status === 404) {
|
||||
throw new Error("Die angeforderte Ressource wurde nicht gefunden.")
|
||||
}
|
||||
|
||||
// 500 → Serverfehler
|
||||
if (status >= 500) {
|
||||
console.error("Server error:", data)
|
||||
throw new Error("Interner Serverfehler. Bitte später erneut versuchen.")
|
||||
}
|
||||
|
||||
// Fallback
|
||||
throw new Error(data?.detail || "Unbekannter Fehler.")
|
||||
}
|
||||
}
|
||||
|
||||
return { apiFetch }
|
||||
}
|
||||
|
|
@ -1,15 +1,46 @@
|
|||
function decodeJwt(token: string) {
|
||||
try {
|
||||
const payload = token.split(".")[1]
|
||||
const decoded = JSON.parse(atob(payload))
|
||||
return decoded
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
export function useAuth() {
|
||||
const token = useState("token", () => null)
|
||||
const token = useState<string | null>("token", () => null)
|
||||
|
||||
function setToken(t: string) {
|
||||
token.value = t
|
||||
localStorage.setItem("token", t)
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem("token", t)
|
||||
}
|
||||
}
|
||||
|
||||
function loadToken() {
|
||||
token.value = localStorage.getItem("token")
|
||||
if (typeof window !== "undefined") {
|
||||
const stored = localStorage.getItem("token")
|
||||
if (!stored) return
|
||||
|
||||
const payload = decodeJwt(stored)
|
||||
if( !payload || !payload.exp || payload.exp * 1000 < Date.now()) {
|
||||
console.info("Token expired - removing it from storage")
|
||||
localStorage.removeItem("token")
|
||||
token.value = null
|
||||
}
|
||||
token.value = stored
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return { token, setToken, loadToken }
|
||||
}
|
||||
function logout() {
|
||||
token.value = null
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.removeItem("token")
|
||||
}
|
||||
}
|
||||
|
||||
return { token, setToken, loadToken, logout }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue