Refactor app architecture and clean local artifacts
This commit is contained in:
+10
-133
@@ -1,137 +1,14 @@
|
||||
import type {
|
||||
AdminDashboardResponse,
|
||||
AdminSeasonDetailResponse,
|
||||
AdminSeasonListItem,
|
||||
AuthSession,
|
||||
CreateClipPayload,
|
||||
CreateNominationPayload,
|
||||
CreateVotePayload,
|
||||
LoginPayload,
|
||||
OverviewResponse,
|
||||
SeasonCategoriesResponse,
|
||||
UpdateSeasonPayload,
|
||||
ApproveNominationPayload,
|
||||
UpsertCandidatePayload,
|
||||
UpsertCategoryPayload,
|
||||
WinnerArchiveResponse,
|
||||
} from '../types/awards'
|
||||
|
||||
const API_URL = import.meta.env.VITE_API_URL ?? 'http://127.0.0.1:5084'
|
||||
const AUTH_TOKEN_KEY = 'vtsa-session-token'
|
||||
|
||||
function getAuthToken() {
|
||||
if (typeof window === 'undefined') return null
|
||||
return window.localStorage.getItem(AUTH_TOKEN_KEY)
|
||||
}
|
||||
|
||||
async function getJson<T>(path: string): Promise<T> {
|
||||
const token = getAuthToken()
|
||||
const response = await fetch(`${API_URL}${path}`, {
|
||||
headers: token
|
||||
? {
|
||||
Authorization: `Bearer ${token}`,
|
||||
}
|
||||
: undefined,
|
||||
}).catch(() => {
|
||||
throw new Error(`API nicht erreichbar (${API_URL}). Bitte Backend starten.`)
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error(`API request failed for ${path}`)
|
||||
}
|
||||
return response.json() as Promise<T>
|
||||
}
|
||||
|
||||
async function sendDelete<TResponse>(path: string): Promise<TResponse> {
|
||||
const token = getAuthToken()
|
||||
const response = await fetch(`${API_URL}${path}`, {
|
||||
method: 'DELETE',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
|
||||
}).catch(() => {
|
||||
throw new Error(`API nicht erreichbar (${API_URL}). Bitte Backend starten.`)
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text()
|
||||
throw new Error(error || `API request failed for ${path}`)
|
||||
}
|
||||
|
||||
return response.json() as Promise<TResponse>
|
||||
}
|
||||
|
||||
async function sendJson<TResponse>(path: string, method: 'POST' | 'PUT', body: unknown): Promise<TResponse> {
|
||||
const token = getAuthToken()
|
||||
const response = await fetch(`${API_URL}${path}`, {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
}).catch(() => {
|
||||
throw new Error(`API nicht erreichbar (${API_URL}). Bitte Backend starten.`)
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text()
|
||||
throw new Error(error || `API request failed for ${path}`)
|
||||
}
|
||||
|
||||
return response.json() as Promise<TResponse>
|
||||
}
|
||||
import { adminApi } from './api/adminApi'
|
||||
import { authApi } from './api/authApi'
|
||||
import { publicApi } from './api/publicApi'
|
||||
import { systemApi } from './api/systemApi'
|
||||
|
||||
export const api = {
|
||||
getOverview: () => getJson<OverviewResponse>('/api/public/overview'),
|
||||
getSeasonCategories: (year: number) =>
|
||||
getJson<SeasonCategoriesResponse>(`/api/public/seasons/${year}/categories`),
|
||||
getWinnerArchive: (year: number) =>
|
||||
getJson<WinnerArchiveResponse>(`/api/public/seasons/${year}/winners`),
|
||||
getAdminDashboard: () => getJson<AdminDashboardResponse>('/api/admin/dashboard'),
|
||||
getAdminSeasons: () => getJson<AdminSeasonListItem[]>('/api/admin/seasons'),
|
||||
getAdminSeasonDetail: (seasonId: number) =>
|
||||
getJson<AdminSeasonDetailResponse>(`/api/admin/seasons/${seasonId}`),
|
||||
getSession: () => getJson<AuthSession>('/api/auth/session'),
|
||||
login: (payload: LoginPayload) => sendJson<AuthSession>('/api/auth/dev-login', 'POST', payload),
|
||||
logout: () => sendJson<{ loggedOut: boolean }>('/api/auth/logout', 'POST', {}),
|
||||
submitNomination: (payload: CreateNominationPayload) =>
|
||||
sendJson<{ saved: number; category: string }>('/api/public/nominations', 'POST', payload),
|
||||
submitVote: (payload: CreateVotePayload) =>
|
||||
sendJson<{ ballotId: number; entries: number }>('/api/public/votes', 'POST', payload),
|
||||
submitClip: (payload: CreateClipPayload) =>
|
||||
sendJson<{ saved: boolean; clipId: number }>('/api/public/clips', 'POST', payload),
|
||||
updateAdminSeason: (seasonId: number, payload: UpdateSeasonPayload) =>
|
||||
sendJson<{ saved: boolean; seasonId: number }>(`/api/admin/seasons/${seasonId}`, 'PUT', payload),
|
||||
createAdminCategory: (seasonId: number, payload: UpsertCategoryPayload) =>
|
||||
sendJson<{ saved: boolean; categoryId: number }>(`/api/admin/seasons/${seasonId}/categories`, 'POST', payload),
|
||||
updateAdminCategory: (categoryId: number, payload: UpsertCategoryPayload) =>
|
||||
sendJson<{ saved: boolean; categoryId: number }>(`/api/admin/categories/${categoryId}`, 'PUT', payload),
|
||||
createAdminCandidate: (seasonId: number, payload: UpsertCandidatePayload) =>
|
||||
sendJson<{ saved: boolean; candidateId: number }>(`/api/admin/seasons/${seasonId}/candidates`, 'POST', payload),
|
||||
updateAdminCandidate: (candidateId: number, payload: UpsertCandidatePayload) =>
|
||||
sendJson<{ saved: boolean; candidateId: number }>(`/api/admin/candidates/${candidateId}`, 'PUT', payload),
|
||||
deleteAdminCandidate: (candidateId: number) =>
|
||||
sendDelete<{ deleted: boolean; candidateId: number }>(`/api/admin/candidates/${candidateId}`),
|
||||
deleteAdminCategory: (categoryId: number) =>
|
||||
sendDelete<{ deleted: boolean; categoryId: number }>(`/api/admin/categories/${categoryId}`),
|
||||
deleteAdminClip: (clipId: number) =>
|
||||
sendDelete<{ deleted: boolean; clipId: number }>(`/api/admin/clips/${clipId}`),
|
||||
approveAdminNomination: (nominationId: number, payload: ApproveNominationPayload) =>
|
||||
sendJson<{ saved: boolean; nominationId: number; candidateId: number; created: boolean }>(
|
||||
`/api/admin/nominations/${nominationId}/approve`,
|
||||
'POST',
|
||||
payload,
|
||||
),
|
||||
rejectAdminNomination: (nominationId: number) =>
|
||||
sendJson<{ saved: boolean; nominationId: number; rejected: boolean }>(
|
||||
`/api/admin/nominations/${nominationId}/reject`,
|
||||
'POST',
|
||||
{},
|
||||
),
|
||||
resolveRiskFlag: (riskFlagId: number, status = 'resolved') =>
|
||||
sendJson<{ saved: boolean; riskFlagId: number; status: string }>(
|
||||
`/api/admin/risk-flags/${riskFlagId}/resolve`,
|
||||
'POST',
|
||||
{ status },
|
||||
),
|
||||
...publicApi,
|
||||
...authApi,
|
||||
...adminApi,
|
||||
...systemApi,
|
||||
}
|
||||
|
||||
export { AUTH_TOKEN_KEY }
|
||||
export { AUTH_TOKEN_KEY } from './http'
|
||||
export { ApiRequestError } from './http'
|
||||
|
||||
Reference in New Issue
Block a user