darkwatch/client/src/api.ts

114 lines
3.1 KiB
TypeScript

import type {
Campaign,
Character,
Gear,
Talent,
GameItem,
GameTalent,
RollResult,
} from "./types";
const BASE = "/api";
async function request<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
headers: { "Content-Type": "application/json" },
...options,
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: res.statusText }));
throw new Error(err.error || res.statusText);
}
if (res.status === 204) return undefined as T;
return res.json();
}
// Campaigns
export const getCampaigns = () => request<Campaign[]>("/campaigns");
export const createCampaign = (name: string) =>
request<Campaign>("/campaigns", {
method: "POST",
body: JSON.stringify({ name }),
});
export const deleteCampaign = (id: number) =>
request<void>(`/campaigns/${id}`, { method: "DELETE" });
// Characters
export const getCharacters = (campaignId: number) =>
request<Character[]>(`/campaigns/${campaignId}/characters`);
export const createCharacter = (
campaignId: number,
data: { name: string; class?: string; ancestry?: string; hp_max?: number },
) =>
request<Character>(`/campaigns/${campaignId}/characters`, {
method: "POST",
body: JSON.stringify(data),
});
export const updateCharacter = (id: number, data: Partial<Character>) =>
request<Character>(`/characters/${id}`, {
method: "PATCH",
body: JSON.stringify(data),
});
export const deleteCharacter = (id: number) =>
request<void>(`/characters/${id}`, { method: "DELETE" });
// Stats
export const updateStat = (
characterId: number,
statName: string,
value: number,
) =>
request<{ characterId: number; statName: string; value: number }>(
`/characters/${characterId}/stats/${statName}`,
{ method: "PATCH", body: JSON.stringify({ value }) },
);
// Gear
export const addGear = (
characterId: number,
data: {
name: string;
type?: string;
slot_count?: number;
properties?: Record<string, unknown>;
effects?: Record<string, unknown>;
game_item_id?: number | null;
},
) =>
request<Gear>(`/characters/${characterId}/gear`, {
method: "POST",
body: JSON.stringify(data),
});
export const removeGear = (characterId: number, gearId: number) =>
request<void>(`/characters/${characterId}/gear/${gearId}`, {
method: "DELETE",
});
// Talents
export const addTalent = (
characterId: number,
data: {
name: string;
description?: string;
effect?: Record<string, unknown>;
game_talent_id?: number | null;
},
) =>
request<Talent>(`/characters/${characterId}/talents`, {
method: "POST",
body: JSON.stringify(data),
});
export const removeTalent = (characterId: number, talentId: number) =>
request<void>(`/characters/${characterId}/talents/${talentId}`, {
method: "DELETE",
});
// Game Items
export const getGameItems = () => request<GameItem[]>("/game-items");
// Game Talents
export const getGameTalents = () => request<GameTalent[]>("/game-talents");
// Rolls
export const getRolls = (campaignId: number) =>
request<RollResult[]>(`/campaigns/${campaignId}/rolls`);