feat: add favorites state and buttons
This commit is contained in:
98
src/favorites/api.ts
Normal file
98
src/favorites/api.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { apiBase, type Resource } from "../api";
|
||||
|
||||
export type FavoriteSort = "favorited_at" | "published_at" | "hot";
|
||||
|
||||
export type FavoriteItem = {
|
||||
favoritedAt: string;
|
||||
resource: Resource;
|
||||
};
|
||||
|
||||
export type FavoriteListResponse = {
|
||||
items: FavoriteItem[];
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
};
|
||||
|
||||
export type FavoriteIdsResponse = {
|
||||
ids: string[];
|
||||
};
|
||||
|
||||
export type FavoriteMutationResponse = {
|
||||
ok: boolean;
|
||||
resourceId: string;
|
||||
favorited: boolean;
|
||||
favoritedAt?: string;
|
||||
favoriteCount: number;
|
||||
};
|
||||
|
||||
function authHeaders(token: string): HeadersInit {
|
||||
return { Authorization: `Bearer ${token}` };
|
||||
}
|
||||
|
||||
async function parseJSON<T>(res: Response): Promise<T> {
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
return res.json() as Promise<T>;
|
||||
}
|
||||
|
||||
export async function listFavorites(
|
||||
token: string,
|
||||
params: {
|
||||
sort?: FavoriteSort;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
category?: string;
|
||||
q?: string;
|
||||
includeUnavailable?: boolean;
|
||||
lang?: string;
|
||||
} = {},
|
||||
): Promise<FavoriteListResponse> {
|
||||
const sp = new URLSearchParams();
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value === undefined || value === "") return;
|
||||
sp.set(key, String(value));
|
||||
});
|
||||
const suffix = sp.toString() ? `?${sp}` : "";
|
||||
const res = await fetch(`${apiBase}/api/me/favorites${suffix}`, {
|
||||
headers: authHeaders(token),
|
||||
});
|
||||
return parseJSON<FavoriteListResponse>(res);
|
||||
}
|
||||
|
||||
export async function getFavoriteIds(
|
||||
token: string,
|
||||
resourceIds: string[],
|
||||
): Promise<string[]> {
|
||||
if (resourceIds.length === 0) return [];
|
||||
const uniqueIds = [...new Set(resourceIds)].slice(0, 100);
|
||||
const res = await fetch(
|
||||
`${apiBase}/api/me/favorites/ids?resourceIds=${encodeURIComponent(
|
||||
uniqueIds.join(","),
|
||||
)}`,
|
||||
{ headers: authHeaders(token) },
|
||||
);
|
||||
const data = await parseJSON<FavoriteIdsResponse>(res);
|
||||
return data.ids;
|
||||
}
|
||||
|
||||
export async function addFavorite(
|
||||
token: string,
|
||||
resourceId: string,
|
||||
): Promise<FavoriteMutationResponse> {
|
||||
const res = await fetch(`${apiBase}/api/me/favorites/${resourceId}`, {
|
||||
method: "POST",
|
||||
headers: authHeaders(token),
|
||||
});
|
||||
return parseJSON<FavoriteMutationResponse>(res);
|
||||
}
|
||||
|
||||
export async function removeFavorite(
|
||||
token: string,
|
||||
resourceId: string,
|
||||
): Promise<FavoriteMutationResponse> {
|
||||
const res = await fetch(`${apiBase}/api/me/favorites/${resourceId}`, {
|
||||
method: "DELETE",
|
||||
headers: authHeaders(token),
|
||||
});
|
||||
return parseJSON<FavoriteMutationResponse>(res);
|
||||
}
|
||||
Reference in New Issue
Block a user