import { useMutation, useQuery, useQueryClient, useInfiniteQuery, } from "@tanstack/react-query"; import { useAuthToken } from "../hooks/use-root-data"; import { FullProductCreate, FullProductUpdate, ProductDetail, ProductOwnershipCheck, ProductAttributeValue, SellerProductListItem, VariantStockUpdateRequest, VariantStockUpdateResponse, ProductBasePriceUpdateRequest, ProductBasePriceUpdateResponse, VariantPriceUpdateRequest, VariantPriceUpdateResponse, PaginatedSimilarProduct, } from "../../src/api/types"; import { useToast } from "../hooks/use-toast"; import { createProductManagementApi, createApiApi, } from "~/utils/api-client-factory"; /** * Custom hook to fetch all attribute values */ export const useAttributeValues = () => { const token = useAuthToken(); return useQuery({ queryKey: ["attributeValues"], queryFn: async (): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1AttributevalueList(); }, enabled: !!token, }); }; /** * Custom hook to fetch color attributes */ export const useColorAttributes = () => { const { data: attributeValues, isLoading, error } = useAttributeValues(); return { data: attributeValues?.filter( (attr) => attr.attributeName?.toLowerCase() === "color" ) || [], isLoading, error, }; }; /** * Custom hook to fetch size attributes */ export const useSizeAttributes = () => { const { data: attributeValues, isLoading, error } = useAttributeValues(); return { data: attributeValues?.filter( (attr) => attr.attributeName?.toLowerCase() === "size" ) || [], isLoading, error, }; }; /** * Custom hook to create a full product with attributes and variants */ export const useCreateFullProduct = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async ( productData: FullProductCreate ): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1ProductsFullCreateCreate({ data: productData, }); }, onSuccess: () => { toast({ title: "موفق", description: "محصول با موفقیت ایجاد شد", variant: "default", }); // Invalidate relevant queries queryClient.invalidateQueries({ queryKey: ["products"] }); queryClient.invalidateQueries({ queryKey: ["sellerProducts"] }); }, onError: (error: Error) => { console.error("Product creation failed:", error); toast({ title: "خطا", description: "خطا در ایجاد محصول. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to fetch seller categories */ export const useProductCategories = () => { const token = useAuthToken(); return useQuery({ queryKey: ["sellerCategories"], queryFn: async () => { const productApi = createProductManagementApi(token); return await productApi.apiProductV1CategoriesList(); }, }); }; /** * Custom hook to fetch a is-owner product */ export const useIsOwnerProduct = (productId: string) => { const token = useAuthToken(); return useQuery({ queryKey: ["is-owner-product", productId], queryFn: async (): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1ProductsIsOwnerList({ id: productId, }); }, enabled: !!token && !!productId, }); }; /** * Custom hook to fetch a single product details */ export const useProductDetails = (productId: string) => { const token = useAuthToken(); return useQuery({ queryKey: ["product", productId], queryFn: async (): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1ProductsRead({ id: productId }); }, enabled: !!token && !!productId, }); }; /** * Custom hook to delete a product */ export const useDeleteProduct = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async (productId: string): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1ProductsDelete({ id: productId }); }, onSuccess: () => { toast({ title: "موفق", description: "محصول با موفقیت حذف شد", variant: "default", }); // Invalidate relevant queries queryClient.invalidateQueries({ queryKey: ["products"] }); queryClient.invalidateQueries({ queryKey: ["sellerProducts"] }); }, onError: (error: Error) => { console.error("Product deletion failed:", error); toast({ title: "خطا", description: "خطا در حذف محصول. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to update a product */ export const useUpdateProduct = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async ({ productId, productData, }: { productId: string; productData: FullProductUpdate; }): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1ProductsPartialUpdate({ id: productId, data: productData, }); }, onSuccess: (data, variables) => { toast({ title: "موفق", description: "محصول با موفقیت به‌روزرسانی شد", variant: "default", }); // Invalidate relevant queries queryClient.invalidateQueries({ queryKey: ["product", variables.productId], }); queryClient.invalidateQueries({ queryKey: ["products"] }); queryClient.invalidateQueries({ queryKey: ["sellerProducts"] }); }, onError: (error: Error) => { console.error("Product update failed:", error); toast({ title: "خطا", description: "خطا در به‌روزرسانی محصول. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to toggle product active status */ export const useToggleProductStatus = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async ({ productId, isActive, }: { productId: string; isActive: boolean; }): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); return await productApi.apiProductV1ProductsActivatePartialUpdate({ data: { id: productId, isActive }, }); }, onSuccess: (data, variables) => { toast({ title: "موفق", description: variables.isActive ? "محصول با موفقیت فعال شد" : "محصول با موفقیت غیرفعال شد", variant: "default", }); // Invalidate relevant queries queryClient.invalidateQueries({ queryKey: ["product", variables.productId], }); queryClient.invalidateQueries({ queryKey: ["products"] }); queryClient.invalidateQueries({ queryKey: ["sellerProducts"] }); }, onError: (error: Error) => { console.error("Product status toggle failed:", error); toast({ title: "خطا", description: "خطا در تغییر وضعیت محصول. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to fetch seller products list using apiProductV1SellerProductsList */ export const useGetSellerProductsList = () => { const token = useAuthToken(); const productApi = createProductManagementApi(token); return useQuery({ queryKey: ["sellerProductsList"], queryFn: async (): Promise => { if (!token) throw new Error("Authentication required"); return await productApi.apiProductV1SellerProductsList(); }, enabled: !!token, staleTime: 30 * 60 * 1000, // 30 seconds - balance between freshness and performance }); }; /** * Custom hook to update product variant stock */ export const useUpdateVariantStock = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async ({ variantId, stock, }: { variantId: string; stock: number; }): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); const data: VariantStockUpdateRequest = { variantId, stock, }; return await productApi.apiProductV1ProductsVariantsStockPartialUpdate({ data, }); }, onSuccess: (data) => { toast({ title: "موفق", description: "موجودی با موفقیت به‌روزرسانی شد", variant: "default", }); // Invalidate relevant queries to refresh the data queryClient.invalidateQueries({ queryKey: ["sellerProductsList"] }); queryClient.invalidateQueries({ queryKey: ["products"] }); if (data.product) { queryClient.invalidateQueries({ queryKey: ["product", data.product] }); } }, onError: (error: Error) => { console.error("Variant stock update failed:", error); toast({ title: "خطا", description: "خطا در به‌روزرسانی موجودی. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to update a product's base price (quick edit). */ export const useUpdateProductBasePrice = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async ({ productId, basePrice, }: { productId: string; basePrice: string; }): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); const data: ProductBasePriceUpdateRequest = { productId, basePrice, }; return await productApi.apiProductV1ProductsBasePricePartialUpdate({ data, }); }, onSuccess: (data) => { toast({ title: "موفق", description: "قیمت با موفقیت به‌روزرسانی شد", variant: "default", }); queryClient.invalidateQueries({ queryKey: ["sellerProductsList"] }); queryClient.invalidateQueries({ queryKey: ["products"] }); if (data.id) { queryClient.invalidateQueries({ queryKey: ["product", data.id] }); } }, onError: (error: Error) => { console.error("Base price update failed:", error); toast({ title: "خطا", description: "خطا در به‌روزرسانی قیمت. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to update a single variant's price override (quick edit). * Pass `price: null` to clear the override and inherit the base price. */ export const useUpdateVariantPrice = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const { toast } = useToast(); return useMutation({ mutationFn: async ({ variantId, price, }: { variantId: string; price: string | null; }): Promise => { if (!token) throw new Error("Authentication required"); const productApi = createProductManagementApi(token); const data: VariantPriceUpdateRequest = { variantId, price, }; return await productApi.apiProductV1ProductsVariantsPricePartialUpdate({ data, }); }, onSuccess: (data) => { toast({ title: "موفق", description: "قیمت با موفقیت به‌روزرسانی شد", variant: "default", }); queryClient.invalidateQueries({ queryKey: ["sellerProductsList"] }); queryClient.invalidateQueries({ queryKey: ["products"] }); if (data.product) { queryClient.invalidateQueries({ queryKey: ["product", data.product] }); } }, onError: (error: Error) => { console.error("Variant price update failed:", error); toast({ title: "خطا", description: "خطا در به‌روزرسانی قیمت. لطفاً دوباره تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to fetch similar products for a given product ID */ export const useSimilarProducts = ( productId: string, pageSize: number = 12 ) => { const apiApi = createApiApi(); return useQuery({ queryKey: ["similarProducts", productId, pageSize], queryFn: async () => { if (!productId) throw new Error("Product ID is required"); return await apiApi.apiProductV1ProductsSimilarList({ id: productId, pageSize, }); }, enabled: !!productId, }); }; /** * Custom hook for infinite similar products loading using cursor-based pagination */ export const useSimilarProductsInfinite = ( productId: string, pageSize: number = 20 ) => { const apiApi = createApiApi(); return useInfiniteQuery({ queryKey: ["similarProductsInfinite", productId, pageSize], queryFn: async ({ pageParam }): Promise => { if (!productId) throw new Error("Product ID is required"); // If pageParam is a full URL, extract the cursor let cursor: string | undefined = undefined; if (typeof pageParam === "string" && pageParam.includes("cursor=")) { const url = new URL(pageParam); const cursorParam = url.searchParams.get("cursor"); if (cursorParam) cursor = cursorParam; } else if (typeof pageParam === "string") { cursor = pageParam; } return await apiApi.apiProductV1ProductsSimilarList({ id: productId, cursor, pageSize, }); }, getNextPageParam: (lastPage) => { return lastPage.next || undefined; }, initialPageParam: undefined, enabled: !!productId, }); };