homeio
PublicForked from doctor-io/homeio
useStoreSources.ts
"use client";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type {
StoreCatalogSource,
StoreCatalogSourceCreateRequest,
StoreCatalogSourceUpdateRequest,
} from "@/lib/shared/contracts/apps";
import { queryKeys } from "@/lib/shared/query-keys";
type StoreSourcesResponse = {
data: StoreCatalogSource[];
};
type StoreSourceResponse = {
data: StoreCatalogSource;
};
async function fetchStoreSources() {
const response = await fetch("/api/v1/store/sources", {
cache: "no-store",
});
if (!response.ok) {
throw new Error(`Failed to fetch store sources (${response.status})`);
}
const json = (await response.json()) as StoreSourcesResponse;
return json.data;
}
async function createStoreSource(payload: StoreCatalogSourceCreateRequest) {
const response = await fetch("/api/v1/store/sources", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const json = (await response.json().catch(() => ({}))) as { error?: string };
throw new Error(json.error ?? `Failed to add store source (${response.status})`);
}
const json = (await response.json()) as StoreSourceResponse;
return json.data;
}
async function updateStoreSource(input: {
sourceId: string;
payload: StoreCatalogSourceUpdateRequest;
}) {
const response = await fetch(`/api/v1/store/sources/${encodeURIComponent(input.sourceId)}`, {
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(input.payload),
});
if (!response.ok) {
const json = (await response.json().catch(() => ({}))) as { error?: string };
throw new Error(json.error ?? `Failed to update store source (${response.status})`);
}
const json = (await response.json()) as StoreSourceResponse;
return json.data;
}
async function refreshStoreSource(sourceId: string) {
const response = await fetch(
`/api/v1/store/sources/${encodeURIComponent(sourceId)}/refresh`,
{
method: "POST",
},
);
if (!response.ok) {
const json = (await response.json().catch(() => ({}))) as { error?: string };
throw new Error(json.error ?? `Failed to refresh store source (${response.status})`);
}
const json = (await response.json()) as StoreSourceResponse;
return json.data;
}
async function deleteStoreSource(sourceId: string) {
const response = await fetch(`/api/v1/store/sources/${encodeURIComponent(sourceId)}`, {
method: "DELETE",
});
if (!response.ok) {
const json = (await response.json().catch(() => ({}))) as { error?: string };
throw new Error(json.error ?? `Failed to remove store source (${response.status})`);
}
const json = (await response.json()) as StoreSourceResponse;
return json.data;
}
export function useStoreSources() {
return useQuery({
queryKey: queryKeys.storeSources,
queryFn: fetchStoreSources,
staleTime: 60_000,
refetchOnMount: false,
refetchOnReconnect: false,
refetchOnWindowFocus: false,
placeholderData: (previousData) => previousData,
});
}
export function useStoreSourceActions() {
const queryClient = useQueryClient();
function invalidateStoreState() {
void queryClient.invalidateQueries({ queryKey: queryKeys.storeSources });
void queryClient.invalidateQueries({ queryKey: queryKeys.storeCatalog });
}
const addSource = useMutation({
mutationFn: createStoreSource,
onSuccess: invalidateStoreState,
});
const updateSource = useMutation({
mutationFn: updateStoreSource,
onSuccess: invalidateStoreState,
});
const refreshSource = useMutation({
mutationFn: refreshStoreSource,
onSuccess: invalidateStoreState,
});
const removeSource = useMutation({
mutationFn: deleteStoreSource,
onSuccess: invalidateStoreState,
});
return {
addSource,
updateSource,
refreshSource,
removeSource,
};
}