initial commit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-03-23 08:46:51 +01:00
commit 4608494a3f
130 changed files with 40361 additions and 0 deletions

102
src/admin/utils/api.ts Normal file
View File

@@ -0,0 +1,102 @@
let showSessionExpiredAlert = false
let showLogoutAlert = false
let getTokenFn: (() => string | null) | null = null
let refreshFn: (() => Promise<boolean>) | null = null
let refreshPromise: Promise<boolean> | null = null
export const shouldShowSessionExpiredAlert = (): boolean => {
if (showSessionExpiredAlert) {
showSessionExpiredAlert = false
return true
}
return false
}
export const setSessionExpired = (): void => {
showSessionExpiredAlert = true
}
export const shouldShowLogoutAlert = (): boolean => {
if (showLogoutAlert) {
showLogoutAlert = false
return true
}
return false
}
export const setLogoutAlert = (): void => {
showLogoutAlert = true
}
export const setTokenGetter = (fn: () => string | null): void => {
getTokenFn = fn
}
export const setRefreshFn = (fn: () => Promise<boolean>): void => {
refreshFn = fn
}
export const apiFetch = async (url: string, options: RequestInit = {}): Promise<Response> => {
let token: string | null = null
try {
token = getTokenFn ? getTokenFn() : null
} catch {
// token retrieval failed
}
const headers: Record<string, string> = {
...(options.headers as Record<string, string>),
}
if (!headers['Content-Type'] && options.body && !(options.body instanceof FormData)) {
headers['Content-Type'] = 'application/json'
}
if (token) {
headers['Authorization'] = `Bearer ${token}`
}
let response = await fetch(url, {
...options,
headers,
credentials: 'include',
})
if (response.status === 401 && refreshFn) {
try {
if (!refreshPromise) {
refreshPromise = refreshFn().finally(() => {
refreshPromise = null
})
}
const refreshed = await refreshPromise
if (refreshed) {
token = getTokenFn ? getTokenFn() : null
if (token) {
headers['Authorization'] = `Bearer ${token}`
}
response = await fetch(url, {
...options,
headers,
credentials: 'include',
})
} else {
setSessionExpired()
}
} catch {
setSessionExpired()
}
}
return response
}
export const getAccessToken = (): string | null => {
try {
return getTokenFn ? getTokenFn() : null
} catch {
return null
}
}
export default apiFetch