- GlobalItem interface extended with sourceUrl, imageCredit, imageSourceUrl fields - Attribution block below image: Photo credit and source link when present - Product page link (sourceUrl) at bottom of detail page - Image div mb-6 moved to attribution paragraph for consistent spacing
81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { ApiError, apiDelete, apiGet, apiPost } from "../lib/api";
|
|
|
|
interface GlobalItem {
|
|
id: number;
|
|
brand: string;
|
|
model: string;
|
|
category: string | null;
|
|
weightGrams: number | null;
|
|
priceCents: number | null;
|
|
imageUrl: string | null;
|
|
description: string | null;
|
|
sourceUrl: string | null;
|
|
imageCredit: string | null;
|
|
imageSourceUrl: string | null;
|
|
createdAt: string;
|
|
}
|
|
|
|
interface GlobalItemWithOwnerCount extends GlobalItem {
|
|
ownerCount: number;
|
|
}
|
|
|
|
interface ItemGlobalLink {
|
|
id: number;
|
|
itemId: number;
|
|
globalItemId: number;
|
|
}
|
|
|
|
export function useGlobalItems(query?: string, tags?: string[]) {
|
|
const params = new URLSearchParams();
|
|
if (query) params.set("q", query);
|
|
if (tags && tags.length > 0) params.set("tags", tags.join(","));
|
|
const qs = params.toString();
|
|
|
|
return useQuery({
|
|
queryKey: ["global-items", query ?? "", tags ?? []],
|
|
queryFn: () =>
|
|
apiGet<GlobalItem[]>(`/api/global-items${qs ? `?${qs}` : ""}`),
|
|
});
|
|
}
|
|
|
|
export function useGlobalItem(id: number | null) {
|
|
return useQuery({
|
|
queryKey: ["global-items", id],
|
|
queryFn: () => apiGet<GlobalItemWithOwnerCount>(`/api/global-items/${id}`),
|
|
enabled: id != null,
|
|
retry: (count, error) =>
|
|
error instanceof ApiError && error.status === 404 ? false : count < 3,
|
|
});
|
|
}
|
|
|
|
export function useLinkItem() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: ({
|
|
itemId,
|
|
globalItemId,
|
|
}: {
|
|
itemId: number;
|
|
globalItemId: number;
|
|
}) =>
|
|
apiPost<ItemGlobalLink>(`/api/items/${itemId}/link`, { globalItemId }),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["items"] });
|
|
queryClient.invalidateQueries({ queryKey: ["global-items"] });
|
|
},
|
|
});
|
|
}
|
|
|
|
export function useUnlinkItem() {
|
|
const queryClient = useQueryClient();
|
|
return useMutation({
|
|
mutationFn: (itemId: number) =>
|
|
apiDelete<{ success: boolean }>(`/api/items/${itemId}/link`),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["items"] });
|
|
queryClient.invalidateQueries({ queryKey: ["global-items"] });
|
|
},
|
|
});
|
|
}
|