import { useMutation, useQuery, useInfiniteQuery, QueryClient } from '@tanstack/react-query'; import { api, API_URL } from '../api'; import { useAnonymousId } from '@/context/AnonymousIdContext'; import type { EmotionTag, Post, PostSummary, PostContentType } from '@/types'; // A wrapper to inject the anonymous ID header const callApi = (method: 'get' | 'post' | 'delete', url: string, anonymousId: string, data?: any): Promise<{ data: T }> => { const headers = { 'X-Anonymous-User-ID': anonymousId }; if (method === 'post' || method === 'delete') { return api[method](url, data, { headers }); } return api.get(url, { headers }); } export const useApi = () => { const { anonymousId } = useAnonymousId(); // Stream const useGetPosts = (emotion?: EmotionTag) => { return useInfiniteQuery( ['posts', emotion], async ({ pageParam: cursor }) => { if (!anonymousId) throw new Error('Anonymous ID not available'); let url = '/api/posts?'; if (emotion) url += `emotion=${emotion}&`; if (cursor) url += `cursor=${cursor}`; const res = await callApi<{posts: Post[], nextCursor: string | null}>('get', url, anonymousId); return res.data; }, { getNextPageParam: (lastPage) => lastPage.nextCursor, enabled: !!anonymousId, } ); }; // Create const useCreatePost = (queryClient: QueryClient) => { return useMutation( ({ contentType, contentData, emotionTag }: { contentType: PostContentType, contentData: string, emotionTag: EmotionTag }) => { if (!anonymousId) throw new Error('Anonymous ID not available'); return callApi('post', '/api/posts', anonymousId, { contentType, contentData, emotionTag }); }, { onSuccess: () => { queryClient.invalidateQueries(['my-posts']); queryClient.invalidateQueries(['posts']); }, } ); }; const useUploadFile = () => { return useMutation( (file: File) => { if (!anonymousId) throw new Error('Anonymous ID not available'); const formData = new FormData(); formData.append('file', file); return callApi<{url: string}>('post', '/api/upload', anonymousId, formData); }, ); } // My Dissolves const useGetMyPosts = () => { return useQuery( ['my-posts'], () => { if (!anonymousId) throw new Error('Anonymous ID not available'); return callApi<{posts: Post[]}>('get', '/api/posts/me', anonymousId).then(res => res.data); }, { enabled: !!anonymousId } ); }; const useGetSummaries = () => { return useQuery( ['summaries'], () => { if (!anonymousId) throw new Error('Anonymous ID not available'); return callApi<{summaries: PostSummary[]}>('get', '/api/posts/summaries', anonymousId).then(res => res.data); }, { enabled: !!anonymousId } ); }; const useClearSummaries = (queryClient: QueryClient) => { return useMutation( (summaryIds: string[]) => { if (!anonymousId) throw new Error('Anonymous ID not available'); return callApi('post', '/api/posts/summaries/clear', anonymousId, { summaryIds }); }, { onSuccess: () => { queryClient.invalidateQueries(['summaries']); }, } ); }; // Interactions const useHoldPost = (queryClient: QueryClient) => { return useMutation( (postId: string) => { if (!anonymousId) throw new Error('Anonymous ID not available'); return callApi('post', `/api/posts/${postId}/hold`, anonymousId); }, { onSuccess: (_data, postId) => { queryClient.setQueryData(['held-posts', postId], true); } } ); }; const useReportPost = () => { return useMutation( ({ postId, reason }: { postId: string, reason: string }) => { if (!anonymousId) throw new Error('Anonymous ID not available'); return callApi('post', `/api/posts/${postId}/report`, anonymousId, { reason }); }, ); }; const useIsPostHeld = (postId: string) => { const {data} = useQuery(['held-posts', postId], () => false, { staleTime: Infinity, cacheTime: Infinity }); return data; } const getMediaUrl = (path: string) => { if (path.startsWith('/api/media/')) { return `${API_URL}${path}` } return path; } return { useGetPosts, useCreatePost, useUploadFile, useGetMyPosts, useGetSummaries, useClearSummaries, useHoldPost, useReportPost, useIsPostHeld, getMediaUrl }; };