import { useQuery, useMutation, useQueryClient, useInfiniteQuery, } from "@tanstack/react-query"; import { useAuthToken } from "../hooks/use-root-data"; import { SellerApplication, InstagramVerification, } from "../../src/api/types/models"; import { toast } from "~/hooks/use-toast"; import { useNavigate } from "react-router-dom"; import { createFollowsManagementApi, createSellerManagementApi, } from "~/utils/api-client-factory"; /** * Custom hook to fetch seller data by sellerId using React Query */ export const useSellerData = (sellerId: string | undefined) => { const token = useAuthToken(); return useQuery({ queryKey: ["seller", sellerId], queryFn: async () => { if (!sellerId) throw new Error("Seller ID is required"); const sellerApi = createSellerManagementApi(token); return await sellerApi.sellerRead({ username: sellerId }); }, enabled: !!sellerId, // Only run the query if sellerId exists }); }; /** * Custom hook to check if the current user is following a seller */ export const useSellerFollowStatus = (sellerId: string | undefined) => { const token = useAuthToken(); return useQuery({ queryKey: ["sellerFollowStatus", sellerId], queryFn: async () => { if (!sellerId) throw new Error("Seller ID is required"); if (!token) throw new Error("Authentication required"); try { const followsApi = createFollowsManagementApi(token); const response = await followsApi.apiEngagementV1FollowsCheckRead({ sellerId, }); return response?.following; } catch (error) { return false; // If error is thrown, user is not following the seller } }, enabled: !!sellerId && !!token, // Only run the query if sellerId and token exist }); }; /** * Custom hook to follow a seller */ export const useSellerFollow = () => { const token = useAuthToken(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ sellerId }: { sellerId: string }) => { if (!token) throw new Error("Authentication required"); const followsApi = createFollowsManagementApi(token); await followsApi.apiEngagementV1FollowsCreate({ data: { followingId: sellerId }, }); return { success: true }; }, onSuccess: (_, variables) => { // Invalidate and refetch follow status after mutation queryClient.invalidateQueries({ queryKey: ["sellerFollowStatus", variables.sellerId], }); queryClient.invalidateQueries({ queryKey: ["getFollowedSellersService"], }); }, }); }; /** * Custom hook to unfollow a seller */ export const useSellerUnfollow = () => { const token = useAuthToken(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async ({ sellerId }: { sellerId: string }) => { if (!token) throw new Error("Authentication required"); const followsApi = createFollowsManagementApi(token); await followsApi.apiEngagementV1FollowsDelete({ sellerId }); return { success: true }; }, onSuccess: (_, variables) => { // Invalidate and refetch follow status after mutation queryClient.invalidateQueries({ queryKey: ["sellerFollowStatus", variables.sellerId], }); queryClient.invalidateQueries({ queryKey: ["getFollowedSellersService"], }); }, }); }; export const useGetSellerProducts = ( sellerId: string, options?: { q?: string; priceMin?: number; priceMax?: number; ordering?: string; } ) => { const token = useAuthToken(); return useInfiniteQuery({ queryKey: ["sellerProducts", sellerId, options], queryFn: async ({ pageParam = 1 }) => { const sellerApi = createSellerManagementApi(token); return await sellerApi.sellerProductList({ username: sellerId, page: pageParam, q: options?.q, priceMin: options?.priceMin, priceMax: options?.priceMax, ordering: options?.ordering, }); }, getNextPageParam: (lastPage) => { if (!lastPage.next) return undefined; // Extract page number from the next URL const url = new URL(lastPage.next); const page = url.searchParams.get("page"); return page ? parseInt(page, 10) : undefined; }, initialPageParam: 1, enabled: !!sellerId, // Public storefront: prices/discounts must reflect the seller's latest // edits. Always treat as stale and revalidate on mount/refocus so the // store list can't keep showing a pre-edit price (the detail page is SSR // and already fresh, which caused the list-vs-detail mismatch). staleTime: 0, refetchOnMount: true, refetchOnWindowFocus: true, }); }; /** * Custom hook to fetch seller categories */ export const useSellerCategories = () => { return useQuery({ queryKey: ["sellerCategories"], queryFn: async () => { const sellerApi = createSellerManagementApi(); return await sellerApi.apiSellerV1CategoriesList(); }, }); }; /** * Custom hook to fetch state and city data */ export const useStateCityData = () => { return useQuery({ queryKey: ["stateCityData"], queryFn: async () => { const sellerApi = createSellerManagementApi(); return await sellerApi.apiSellerV1StateCityList(); }, }); }; /** * Custom hook to create seller application */ export const useCreateSellerApplication = () => { const token = useAuthToken(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async (data: SellerApplication) => { if (!token) throw new Error("Authentication required"); const sellerApi = createSellerManagementApi(token); return await sellerApi.apiSellerV1ApplyCreate({ data }); }, onSuccess: () => { // Invalidate profile query to refresh sellerUsername queryClient.invalidateQueries({ queryKey: ["getProfile"] }); }, }); }; /** * Custom hook to apply Instagram verification */ export const useInstagramVerification = () => { const token = useAuthToken(); const queryClient = useQueryClient(); return useMutation({ mutationFn: async ( data: InstagramVerification ): Promise => { if (!token) throw new Error("Authentication required"); const sellerApi = createSellerManagementApi(token); return await sellerApi.apiSellerV1InstapplyCreate({ data }); }, onSuccess: (data: InstagramVerification) => { if (data?.isVerified) { toast({ title: "احراز اکانت اینستاگرام با موفقیت انجام شد", description: "اکانت اینستاگرام شما با موفقیت احراز شد", }); // Invalidate seller data after successful verification queryClient.invalidateQueries({ queryKey: ["seller"], }); } else { toast({ title: "احراز اکانت اینستاگرام با موفقیت انجام نشد", description: "لطفا مجددا تلاش کنید", variant: "destructive", }); } }, onError: () => { toast({ title: "احراز اکانت اینستاگرام با موفقیت انجام نشد", description: "لطفا مجددا تلاش کنید", variant: "destructive", }); }, }); }; /** * Custom hook to update seller information */ export const useSellerUpdate = () => { const token = useAuthToken(); const queryClient = useQueryClient(); const navigate = useNavigate(); return useMutation({ mutationFn: async ({ username, data, }: { username: string; data: { storeName: string; storeDescription?: string | null; storeLogo?: string | null; instagramId?: string | null; }; }) => { if (!token) throw new Error("Authentication required"); const sellerApi = createSellerManagementApi(token); return await sellerApi.sellerPartialUpdate({ username, data }); }, onSuccess: (_, variables) => { toast({ title: "اطلاعات فروشگاه با موفقیت به‌روزرسانی شد", description: "تغییرات شما ذخیره شد", }); // Invalidate seller data after successful update queryClient.invalidateQueries({ queryKey: ["seller", variables.username], }); navigate(`/store/${variables.username}`); }, onError: () => { toast({ title: "خطا در به‌روزرسانی اطلاعات", description: "لطفا مجددا تلاش کنید", variant: "destructive", }); }, }); };