Initial commit – TimeMaster Zeiterfassung & HR-Tool
Stand: agent-06 (Audit-Log), agent-05 (Krankmeldung), agent-07 Phase 1 (Personalnummer), Busylight-Pull-Integration, TOTP/2FA, Abwesenheiten, Zeiterfassung, Kiosk-Grundgerüst. Migrations 0001–0023 deployed auf 192.168.1.137 + .164. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
const BASE_URL = '/api/v1'
|
||||
|
||||
async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
|
||||
const token = localStorage.getItem('access_token')
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...(options.headers as Record<string, string>),
|
||||
}
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`
|
||||
|
||||
const res = await fetch(`${BASE_URL}${path}`, { ...options, headers })
|
||||
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ detail: res.statusText }))
|
||||
const msg = typeof err.detail === 'string'
|
||||
? err.detail
|
||||
: Array.isArray(err.detail)
|
||||
? err.detail.map((e: { msg: string }) => e.msg).join(', ')
|
||||
: res.statusText
|
||||
throw new Error(msg)
|
||||
}
|
||||
|
||||
if (res.status === 204) return undefined as T
|
||||
return res.json()
|
||||
}
|
||||
|
||||
async function requestForm<T>(path: string, form: FormData): Promise<T> {
|
||||
const token = localStorage.getItem('access_token')
|
||||
const headers: Record<string, string> = {}
|
||||
if (token) headers['Authorization'] = `Bearer ${token}`
|
||||
// No Content-Type header – browser sets multipart boundary automatically
|
||||
const res = await fetch(`${BASE_URL}${path}`, { method: 'POST', body: form, headers })
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ detail: res.statusText }))
|
||||
const msg = typeof err.detail === 'string'
|
||||
? err.detail
|
||||
: Array.isArray(err.detail)
|
||||
? err.detail.map((e: { msg: string }) => e.msg).join(', ')
|
||||
: res.statusText
|
||||
throw new Error(msg)
|
||||
}
|
||||
if (res.status === 204) return undefined as T
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export const api = {
|
||||
get: <T>(path: string) => request<T>(path),
|
||||
post: <T>(path: string, body: unknown) => request<T>(path, { method: 'POST', body: JSON.stringify(body) }),
|
||||
patch: <T>(path: string, body: unknown) => request<T>(path, { method: 'PATCH', body: JSON.stringify(body) }),
|
||||
del: <T>(path: string) => request<T>(path, { method: 'DELETE' }),
|
||||
postForm: <T>(path: string, form: FormData) => requestForm<T>(path, form),
|
||||
}
|
||||
Reference in New Issue
Block a user