import { useQuery, useInfiniteQuery, QueryClient, useMutation, } from "@tanstack/react-query"; import { useAuthToken } from "../hooks/use-root-data"; import { MessageList } from "../../src/api/types/models"; import { createChatApi } from "~/utils/api-client-factory"; /** * Custom hook to get the list of user's threads */ export function useGetUserThreads() { const token = useAuthToken(); return useQuery({ queryKey: ["getUserThreads"], queryFn: async () => { if (!token) { throw new Error("Authentication token is required"); } const chatApi = createChatApi(token); return await chatApi.apiChatV1ThreadsList(); }, enabled: !!token, retry: 1, retryDelay: 3000, refetchOnWindowFocus: false, refetchInterval: 20 * 1000, // 30 seconds refetch }); } /** * List a STORE's inbox (owner + staff), scoped to the store's own threads. * Distinct from useGetUserThreads(), which returns the user's personal buyer chats. */ export function useGetStoreThreads(storeId?: string) { const token = useAuthToken(); return useQuery({ queryKey: ["getStoreThreads", storeId], queryFn: async () => { if (!token) { throw new Error("Authentication token is required"); } const chatApi = createChatApi(token); return await chatApi.apiChatV1ThreadsListList({ storeId }); }, enabled: !!token && !!storeId, retry: 1, retryDelay: 3000, refetchOnWindowFocus: false, refetchInterval: 20 * 1000, }); } /** * Server-side function to get thread details */ export async function getThreadDetails(token: string, threadId: string) { if (!token) { throw new Error("Authentication token is required"); } const chatApi = createChatApi(token); return await chatApi.apiChatV1ThreadsRead({ threadId }); } /** * Custom hook to get thread details by ID */ export function useGetThreadDetails(threadId: string) { const token = useAuthToken(); return useQuery({ queryKey: ["getThreadDetails", threadId], queryFn: async () => { if (!token) { throw new Error("Authentication token is required"); } const chatApi = createChatApi(token); return await chatApi.apiChatV1ThreadsRead({ threadId }); }, enabled: !!token && !!threadId, retry: 1, retryDelay: 3000, refetchOnWindowFocus: false, }); } export const deleteMessageFromCache = ( queryClient: QueryClient, threadId: string, messageId: string ) => { queryClient.setQueryData( ["getThreadMessages", threadId], ( oldData: | { pages: Array<{ results: MessageList[]; nextCursor: string | null; }>; pageParams: Array; } | undefined ) => { if (!oldData) return oldData; return { ...oldData, pages: oldData.pages.map((page) => { return { ...page, results: page.results.filter((message) => message.id !== messageId), }; }), }; } ); }; export const setMessagesCache = ( queryClient: QueryClient, threadId: string, data: MessageList ) => { queryClient.setQueryData( ["getThreadMessages", threadId], ( oldData: | { pages: Array<{ results: MessageList[]; nextCursor: string | null; }>; pageParams: Array; } | undefined ) => { if (!oldData) return oldData; return { ...oldData, pages: oldData.pages.map((page, index: number) => { if (index === 0) { return { ...page, results: [data, ...page.results], }; } return page; }), }; } ); }; /** * Custom hook to get thread messages with infinite scrolling */ export function useGetThreadMessages(threadId: string) { const token = useAuthToken(); return useInfiniteQuery({ queryKey: ["getThreadMessages", threadId], queryFn: async ({ pageParam }) => { if (!token) { throw new Error("Authentication token is required"); } const chatApi = createChatApi(token); // Using cursor-based pagination const response = await chatApi.apiChatV1ThreadsMessagesList({ threadId, cursor: pageParam ? String(pageParam) : undefined, }); // Check if response has next cursor let nextCursor; if (response.next) { const nextUrlParts = response.next.split("?cursor="); nextCursor = nextUrlParts.length > 1 ? nextUrlParts[1] : null; } else { nextCursor = null; } const messages = response.results || []; // Get the ID of the last message to use as next cursor return { results: messages, nextCursor, }; }, initialPageParam: undefined as string | undefined, getNextPageParam: (lastPage) => { return lastPage.nextCursor || undefined; }, enabled: !!token && !!threadId, refetchOnWindowFocus: false, }); } /** * Custom hook to create a new chat thread */ export function useCreateChatThread() { const token = useAuthToken(); return useMutation({ mutationFn: async ( input: string | { participantId: string; productId?: string } ) => { if (!token) { throw new Error("Authentication token and user ID are required"); } // Back-compat: callers may pass a bare participantId string. const { participantId, productId } = typeof input === "string" ? { participantId: input, productId: undefined } : input; try { const chatApi = createChatApi(token); return await chatApi.apiChatV1ThreadsCreateCreate({ data: { participantId, ...(productId ? { productId } : {}), }, }); } catch (error) { console.error("Error creating chat thread:", error); throw error; } }, }); }