Some checks failed
Deploy to Cloudflare Workers / deploy (push) Has been cancelled
214 lines
7.0 KiB
TypeScript
214 lines
7.0 KiB
TypeScript
/** Browser client for Next.js API routes */
|
|
|
|
type ApiResponse<T> = { success: true; data: T } | { success: false; error: string };
|
|
|
|
export async function apiFetch<T>(
|
|
path: string,
|
|
options?: RequestInit
|
|
): Promise<T> {
|
|
const res = await fetch(path, {
|
|
...options,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...options?.headers,
|
|
},
|
|
credentials: "same-origin",
|
|
});
|
|
|
|
let json: ApiResponse<T>;
|
|
try {
|
|
json = await res.json();
|
|
} catch {
|
|
throw new Error(`API ${path} returned invalid JSON (${res.status})`);
|
|
}
|
|
|
|
if (!json.success) {
|
|
throw new Error(json.error || `Request failed (${res.status})`);
|
|
}
|
|
|
|
return json.data;
|
|
}
|
|
|
|
export const api = {
|
|
health: () => apiFetch<{ status: string; supabase: boolean }>("/api/health"),
|
|
|
|
leagues: {
|
|
list: () => apiFetch<unknown[]>("/api/leagues"),
|
|
create: (body: { name: string; description?: string }) =>
|
|
apiFetch<unknown>("/api/leagues", {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
get: (leagueId: string) => apiFetch<unknown>(`/api/leagues/${leagueId}`),
|
|
createCompetition: (
|
|
leagueId: string,
|
|
body: { name: string; tournament_mode: "league" | "cup"; timezone?: string }
|
|
) =>
|
|
apiFetch<unknown>(`/api/leagues/${leagueId}/competitions`, {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
saveRules: (leagueId: string, rules: object) =>
|
|
apiFetch<void>(`/api/leagues/${leagueId}/rules`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ rules }),
|
|
}),
|
|
delete: (leagueId: string) =>
|
|
apiFetch<void>(`/api/leagues/${leagueId}`, { method: "DELETE" }),
|
|
assignMaster: (leagueId: string, email: string) =>
|
|
apiFetch<void>(`/api/leagues/${leagueId}/masters`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ email }),
|
|
}),
|
|
listMasters: (leagueId: string) =>
|
|
apiFetch<unknown[]>(`/api/leagues/${leagueId}/masters`),
|
|
},
|
|
|
|
competitions: {
|
|
get: (id: string) => apiFetch<unknown>(`/api/competitions/${id}`),
|
|
activate: (id: string) =>
|
|
apiFetch<void>(`/api/competitions/${id}/activate`, { method: "POST" }),
|
|
generateFixtures: (id: string) =>
|
|
apiFetch<unknown>(`/api/competitions/${id}/fixtures`, { method: "POST" }),
|
|
standings: (id: string) =>
|
|
apiFetch<unknown[]>(`/api/competitions/${id}/standings`),
|
|
matches: (id: string) =>
|
|
apiFetch<unknown[]>(`/api/competitions/${id}/matches`),
|
|
pendingResults: (id: string) =>
|
|
apiFetch<unknown[]>(`/api/competitions/${id}/pending-results`),
|
|
transfers: (id: string) =>
|
|
apiFetch<unknown[]>(`/api/competitions/${id}/transfers`),
|
|
dashboard: (id: string) =>
|
|
apiFetch<{ results: unknown[]; playerStats: unknown[] }>(
|
|
`/api/competitions/${id}/dashboard`
|
|
),
|
|
listTeams: (id: string) =>
|
|
apiFetch<unknown[]>(`/api/competitions/${id}/teams`),
|
|
createTeam: (
|
|
id: string,
|
|
body: { name: string; nickname?: string; icon?: string }
|
|
) =>
|
|
apiFetch<unknown>(`/api/competitions/${id}/teams`, {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
addRoster: (
|
|
id: string,
|
|
body: { teamId: string; playerId: string }
|
|
) =>
|
|
apiFetch<void>(`/api/competitions/${id}/roster`, {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
transfer: (
|
|
id: string,
|
|
body: { playerId: string; fromTeamId: string; toTeamId: string }
|
|
) =>
|
|
apiFetch<void>(`/api/competitions/${id}/transfers`, {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
},
|
|
|
|
teams: {
|
|
delete: (teamId: string) =>
|
|
apiFetch<void>(`/api/teams/${teamId}`, { method: "DELETE" }),
|
|
update: (teamId: string, body: { home_stadium_name?: string; logo_path?: string; nickname?: string; icon?: string }) =>
|
|
apiFetch<unknown>(`/api/teams/${teamId}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
setAvailability: (
|
|
teamId: string,
|
|
windows: { day_of_week: number; start_time?: string; end_time?: string }[]
|
|
) =>
|
|
apiFetch<void>(`/api/teams/${teamId}/availability`, {
|
|
method: "PUT",
|
|
body: JSON.stringify({ windows }),
|
|
}),
|
|
},
|
|
|
|
players: {
|
|
list: () => apiFetch<unknown[]>("/api/players"),
|
|
create: (body: { display_name: string; external_id?: string }) =>
|
|
apiFetch<unknown>("/api/players", {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
setStatus: (playerId: string, status: "active" | "inactive") =>
|
|
apiFetch<void>(`/api/players/${playerId}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify({ status }),
|
|
}),
|
|
},
|
|
|
|
matches: {
|
|
get: (matchId: string) => apiFetch<unknown>(`/api/matches/${matchId}`),
|
|
proposeSchedule: (matchId: string, scheduledAt: string) =>
|
|
apiFetch<void>(`/api/matches/${matchId}/schedule`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ action: "propose", scheduledAt }),
|
|
}),
|
|
signSchedule: (matchId: string, teamId: string) =>
|
|
apiFetch<void>(`/api/matches/${matchId}/schedule`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ action: "sign", teamId }),
|
|
}),
|
|
submitResult: (
|
|
matchId: string,
|
|
body: { teamId: string; homeScore: number; awayScore: number }
|
|
) =>
|
|
apiFetch<void>(`/api/matches/${matchId}/results`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ action: "submit", ...body }),
|
|
}),
|
|
approveResult: (matchId: string) =>
|
|
apiFetch<void>(`/api/matches/${matchId}/results`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ action: "approve" }),
|
|
}),
|
|
setResult: (
|
|
matchId: string,
|
|
body: { homeScore: number; awayScore: number; note?: string }
|
|
) =>
|
|
apiFetch<void>(`/api/matches/${matchId}/results`, {
|
|
method: "POST",
|
|
body: JSON.stringify({ action: "set", ...body }),
|
|
}),
|
|
},
|
|
|
|
manager: {
|
|
dashboard: () => apiFetch<unknown>("/api/manager/dashboard"),
|
|
competitions: (mode?: "league" | "cup") =>
|
|
apiFetch<unknown[]>(
|
|
`/api/manager/competitions${mode ? `?mode=${mode}` : ""}`
|
|
),
|
|
calendar: (from: string, to: string) =>
|
|
apiFetch<unknown[]>(
|
|
`/api/manager/calendar?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`
|
|
),
|
|
},
|
|
|
|
master: {
|
|
calendar: (from: string, to: string) =>
|
|
apiFetch<unknown[]>(
|
|
`/api/master/calendar?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`
|
|
),
|
|
},
|
|
|
|
issues: {
|
|
list: (asMaster?: boolean) =>
|
|
apiFetch<unknown[]>(`/api/issues${asMaster ? "?as=master" : ""}`),
|
|
create: (body: {
|
|
leagueId: string;
|
|
competitionId?: string;
|
|
subject: string;
|
|
body: string;
|
|
}) =>
|
|
apiFetch<unknown>("/api/issues", {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
}),
|
|
},
|
|
};
|