65 lines
2 KiB
TypeScript
65 lines
2 KiB
TypeScript
import type { Recipe, RecipeInput, RecipeSummary } from "../types/recipe";
|
|
|
|
const BASE = "/api";
|
|
|
|
async function request<T>(path: string, options?: RequestInit): Promise<T> {
|
|
const isFormData = options?.body instanceof FormData;
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
...options,
|
|
headers: {
|
|
...(isFormData ? {} : { "Content-Type": "application/json" }),
|
|
...options?.headers,
|
|
},
|
|
});
|
|
if (!res.ok) {
|
|
let detail = "";
|
|
try {
|
|
const data = await res.json();
|
|
detail = data.detail ?? JSON.stringify(data);
|
|
} catch {
|
|
detail = await res.text();
|
|
}
|
|
throw new Error(detail || `Request failed: ${res.status}`);
|
|
}
|
|
if (res.status === 204) return undefined as T;
|
|
return res.json() as Promise<T>;
|
|
}
|
|
|
|
export function listRecipes(search?: string): Promise<RecipeSummary[]> {
|
|
const query = search ? `?search=${encodeURIComponent(search)}` : "";
|
|
return request(`/recipes${query}`);
|
|
}
|
|
|
|
export function getRecipe(id: number): Promise<Recipe> {
|
|
return request(`/recipes/${id}`);
|
|
}
|
|
|
|
export function createRecipe(payload: RecipeInput): Promise<Recipe> {
|
|
return request(`/recipes`, { method: "POST", body: JSON.stringify(payload) });
|
|
}
|
|
|
|
export function updateRecipe(id: number, payload: RecipeInput): Promise<Recipe> {
|
|
return request(`/recipes/${id}`, { method: "PUT", body: JSON.stringify(payload) });
|
|
}
|
|
|
|
export function deleteRecipe(id: number): Promise<void> {
|
|
return request(`/recipes/${id}`, { method: "DELETE" });
|
|
}
|
|
|
|
export function uploadRecipeImage(id: number, file: File): Promise<Recipe> {
|
|
const form = new FormData();
|
|
form.append("file", file);
|
|
return request(`/recipes/${id}/image`, { method: "POST", body: form });
|
|
}
|
|
|
|
export function deleteRecipeImage(id: number): Promise<Recipe> {
|
|
return request(`/recipes/${id}/image`, { method: "DELETE" });
|
|
}
|
|
|
|
export function pdfDownloadUrl(id: number): string {
|
|
return `${BASE}/recipes/${id}/pdf`;
|
|
}
|
|
|
|
export function uploadedImageUrl(filename: string): string {
|
|
return `/uploads/${filename}`;
|
|
}
|