102 lines
2.6 KiB
TypeScript
102 lines
2.6 KiB
TypeScript
|
|
export interface Meme {
|
||
|
|
id: string;
|
||
|
|
title: string;
|
||
|
|
description: string | null;
|
||
|
|
file_path: string;
|
||
|
|
file_name: string;
|
||
|
|
file_size: number;
|
||
|
|
mime_type: string;
|
||
|
|
width: number;
|
||
|
|
height: number;
|
||
|
|
parent_id: string | null;
|
||
|
|
created_at: string;
|
||
|
|
tags: string[];
|
||
|
|
children?: Meme[];
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface Tag {
|
||
|
|
id: number;
|
||
|
|
name: string;
|
||
|
|
meme_count: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface MemesResponse {
|
||
|
|
memes: Meme[];
|
||
|
|
total: number;
|
||
|
|
page: number;
|
||
|
|
limit: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface ListParams {
|
||
|
|
tag?: string;
|
||
|
|
q?: string;
|
||
|
|
page?: number;
|
||
|
|
limit?: number;
|
||
|
|
parent_only?: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function apiFetch<T>(url: string, init?: RequestInit): Promise<T> {
|
||
|
|
const res = await fetch(url, init);
|
||
|
|
if (!res.ok) {
|
||
|
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
||
|
|
throw new Error(err.error ?? res.statusText);
|
||
|
|
}
|
||
|
|
return res.json() as Promise<T>;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const api = {
|
||
|
|
memes: {
|
||
|
|
list(params: ListParams = {}): Promise<MemesResponse> {
|
||
|
|
const qs = new URLSearchParams();
|
||
|
|
if (params.tag) qs.set('tag', params.tag);
|
||
|
|
if (params.q) qs.set('q', params.q);
|
||
|
|
if (params.page) qs.set('page', String(params.page));
|
||
|
|
if (params.limit) qs.set('limit', String(params.limit));
|
||
|
|
if (params.parent_only !== undefined) qs.set('parent_only', String(params.parent_only));
|
||
|
|
return apiFetch<MemesResponse>(`/api/memes?${qs}`);
|
||
|
|
},
|
||
|
|
|
||
|
|
get(id: string): Promise<Meme & { children: Meme[] }> {
|
||
|
|
return apiFetch(`/api/memes/${id}`);
|
||
|
|
},
|
||
|
|
|
||
|
|
upload(formData: FormData): Promise<Meme> {
|
||
|
|
return apiFetch('/api/memes', { method: 'POST', body: formData });
|
||
|
|
},
|
||
|
|
|
||
|
|
update(id: string, body: { title?: string; description?: string; tags?: string[] }): Promise<Meme> {
|
||
|
|
return apiFetch(`/api/memes/${id}`, {
|
||
|
|
method: 'PUT',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify(body),
|
||
|
|
});
|
||
|
|
},
|
||
|
|
|
||
|
|
delete(id: string): Promise<{ ok: boolean }> {
|
||
|
|
return apiFetch(`/api/memes/${id}`, { method: 'DELETE' });
|
||
|
|
},
|
||
|
|
|
||
|
|
rescale(id: string, body: { width?: number; height?: number; quality?: number; label?: string }): Promise<Meme> {
|
||
|
|
return apiFetch(`/api/memes/${id}/rescale`, {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify(body),
|
||
|
|
});
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
tags: {
|
||
|
|
list(): Promise<Tag[]> {
|
||
|
|
return apiFetch('/api/tags');
|
||
|
|
},
|
||
|
|
|
||
|
|
delete(id: number): Promise<{ ok: boolean }> {
|
||
|
|
return apiFetch(`/api/tags/${id}`, { method: 'DELETE' });
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
imageUrl(filePath: string): string {
|
||
|
|
return `/images/${filePath}`;
|
||
|
|
},
|
||
|
|
};
|