139 lines
4.5 KiB
TypeScript
139 lines
4.5 KiB
TypeScript
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 = <T,>(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]<T>(url, data, { headers });
|
|
}
|
|
return api.get<T>(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 };
|
|
};
|