Files
Alfred/src/web/shared/hooks/use-materials.ts

147 lines
5.8 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type {
CreateMaterialRequest,
Material,
MaterialListResponse,
MaterialResponse,
MaterialStatus,
} from "../../../shared/api";
import { handleResponse, handleVoidResponse } from "../utils/api";
import { createConsoleLogger } from "../utils/logger";
const MATERIALS_KEY = ["materials"] as const;
const logger = createConsoleLogger();
export function createMaterial(args: { body: CreateMaterialRequest; projectId: string }): Promise<Material> {
const response = fetch(`/api/projects/${args.projectId}/materials`, {
body: JSON.stringify(args.body),
headers: { "Content-Type": "application/json" },
method: "POST",
});
return response.then((r) => handleResponse(r, (data) => (data as MaterialResponse).material));
}
export function approveMaterial(args: { materialId: string; projectId: string }): Promise<Material> {
const response = fetch(`/api/projects/${args.projectId}/materials/${args.materialId}/approve`, { method: "POST" });
return response.then((r) => handleResponse(r, (data) => (data as MaterialResponse).material));
}
export function deleteMaterial(args: { materialId: string; projectId: string }): Promise<void> {
const response = fetch(`/api/projects/${args.projectId}/materials/${args.materialId}`, { method: "DELETE" });
return response.then(handleVoidResponse);
}
export function discardMaterial(args: { materialId: string; projectId: string }): Promise<Material> {
const response = fetch(`/api/projects/${args.projectId}/materials/${args.materialId}/discard`, { method: "POST" });
return response.then((r) => handleResponse(r, (data) => (data as MaterialResponse).material));
}
export function retryMaterial(args: { materialId: string; projectId: string }): Promise<Material> {
const response = fetch(`/api/projects/${args.projectId}/materials/${args.materialId}/retry`, { method: "POST" });
return response.then((r) => handleResponse(r, (data) => (data as MaterialResponse).material));
}
export async function fetchMaterial(args: { materialId: string; projectId: string }): Promise<Material> {
const response = await fetch(`/api/projects/${args.projectId}/materials/${args.materialId}`);
return handleResponse(response, (data) => (data as MaterialResponse).material);
}
export function fetchMaterials(
projectId: string,
params?: { page?: number; pageSize?: number; status?: MaterialStatus },
): Promise<MaterialListResponse> {
const searchParams = new URLSearchParams();
if (params?.page) searchParams.set("page", String(params.page));
if (params?.pageSize) searchParams.set("pageSize", String(params.pageSize));
if (params?.status) searchParams.set("status", params.status);
const qs = searchParams.toString();
const url = `/api/projects/${projectId}/materials${qs ? `?${qs}` : ""}`;
const response = fetch(url);
return response.then((r) => {
if (!r.ok) {
return r.json().then((body: null | { error?: string }) => {
throw new Error(body?.error ?? `HTTP ${r.status}`);
});
}
return r.json() as Promise<MaterialListResponse>;
});
}
export function useCreateMaterial(projectId: string) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: createMaterial,
onSuccess: (data) => {
logger.info("素材创建成功", { materialId: data.id, projectId });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "list", projectId] });
},
});
}
export function useApproveMaterial(projectId: string) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: approveMaterial,
onSuccess: (data) => {
logger.info("素材通过成功", { materialId: data.id, projectId });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "list", projectId] });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "detail", projectId, data.id] });
},
});
}
export function useDeleteMaterial(projectId: string) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: deleteMaterial,
onSuccess: (_data, variables) => {
logger.info("素材删除成功", { materialId: variables.materialId, projectId });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "list", projectId] });
},
});
}
export function useDiscardMaterial(projectId: string) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: discardMaterial,
onSuccess: (data) => {
logger.info("素材放弃成功", { materialId: data.id, projectId });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "list", projectId] });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "detail", projectId, data.id] });
},
});
}
export function useRetryMaterial(projectId: string) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: retryMaterial,
onSuccess: (data) => {
logger.info("素材重试成功", { materialId: data.id, projectId });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "list", projectId] });
void queryClient.invalidateQueries({ queryKey: [...MATERIALS_KEY, "detail", projectId, data.id] });
},
});
}
export function useMaterial(args: { materialId: null | string; projectId: string }) {
return useQuery({
enabled: !!args.materialId,
queryFn: () => fetchMaterial({ materialId: args.materialId!, projectId: args.projectId }),
queryKey: [...MATERIALS_KEY, "detail", args.projectId, args.materialId],
});
}
export function useMaterialList(
projectId: string,
params?: { page?: number; pageSize?: number; status?: MaterialStatus },
) {
return useQuery({
queryFn: () => fetchMaterials(projectId, params),
queryKey: [...MATERIALS_KEY, "list", projectId, params],
});
}