- Add ui/src/api/chat.ts with chatApi (7 methods: list/create/get/update/delete conversations + list/post messages) - Add ui/src/hooks/useChatConversations.ts with useInfiniteQuery + placeholderData + CRUD mutations - Add ui/src/hooks/useChatMessages.ts with useInfiniteQuery + sendMutation + flattened/reversed messages array - Fix [Rule 3 - Blocking]: export ChatConversation, ChatMessage, ChatConversationListResponse, ChatMessageListResponse from packages/shared/src/index.ts (types existed in types/chat.ts but were not re-exported at package root)
33 lines
1.5 KiB
TypeScript
33 lines
1.5 KiB
TypeScript
import { useInfiniteQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { chatApi } from "../api/chat";
|
|
import type { ChatMessage, ChatMessageListResponse } from "@paperclipai/shared";
|
|
|
|
export function useChatMessages(conversationId: string | null) {
|
|
const queryClient = useQueryClient();
|
|
|
|
const query = useInfiniteQuery({
|
|
queryKey: ["chat", "messages", conversationId],
|
|
queryFn: ({ pageParam }) =>
|
|
chatApi.listMessages(conversationId!, { cursor: pageParam as string | undefined }),
|
|
initialPageParam: undefined as string | undefined,
|
|
getNextPageParam: (lastPage: ChatMessageListResponse) =>
|
|
lastPage.hasMore ? lastPage.items.at(-1)?.createdAt : undefined,
|
|
enabled: !!conversationId,
|
|
});
|
|
|
|
const sendMutation = useMutation({
|
|
mutationFn: (data: { content: string }) =>
|
|
chatApi.postMessage(conversationId!, { role: "user", content: data.content }),
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({ queryKey: ["chat", "messages", conversationId] });
|
|
// Also invalidate conversations to update lastMessagePreview and sort order
|
|
queryClient.invalidateQueries({ queryKey: ["chat", "conversations"] });
|
|
},
|
|
});
|
|
|
|
// Flatten pages into a single sorted array (oldest first for display)
|
|
// Messages come from API in desc(createdAt) order -- reversing gives chronological order
|
|
const messages: ChatMessage[] = query.data?.pages.flatMap((p) => p.items).reverse() ?? [];
|
|
|
|
return { ...query, messages, sendMutation };
|
|
}
|