Vitron-Front/app/requestHandler/use-product-hooks.ts
2026-04-29 01:44:16 +03:30

429 lines
12 KiB
TypeScript

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,
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<ProductAttributeValue[]> => {
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<ProductDetail> => {
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<ProductOwnershipCheck> => {
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<ProductDetail> => {
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<void> => {
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<ProductDetail> => {
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<ProductDetail> => {
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<SellerProductListItem[]> => {
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<VariantStockUpdateResponse> => {
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 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<PaginatedSimilarProduct>({
queryKey: ["similarProductsInfinite", productId, pageSize],
queryFn: async ({ pageParam }): Promise<PaginatedSimilarProduct> => {
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,
});
};