fix: Add error toasts and optimistic messages to chat session hook
Errors from sendChatMessage were silently swallowed. Now shows toast on failure and immediately renders the user's message optimistically.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { trpc } from '@/lib/trpc';
|
||||
import { useLiveUpdates } from './useLiveUpdates';
|
||||
|
||||
@@ -46,10 +47,13 @@ export function useChatSession(
|
||||
): UseChatSessionResult {
|
||||
const utils = trpc.useUtils();
|
||||
|
||||
// Optimistic messages shown before server confirms
|
||||
const [optimisticMessages, setOptimisticMessages] = useState<ChatMessage[]>([]);
|
||||
|
||||
// Live updates for chat + agent events
|
||||
useLiveUpdates([
|
||||
{ prefix: 'chat:', invalidate: ['getChatSession'] },
|
||||
{ prefix: 'agent:', invalidate: ['getChatSession'] },
|
||||
{ prefix: 'agent:', invalidate: ['getChatSession', 'getAgent'] },
|
||||
{ prefix: 'changeset:', invalidate: ['getChatSession'] },
|
||||
]);
|
||||
|
||||
@@ -59,7 +63,14 @@ export function useChatSession(
|
||||
{ enabled: !!targetId },
|
||||
);
|
||||
const session = (sessionQuery.data as ChatSession | null) ?? null;
|
||||
const messages = session?.messages ?? [];
|
||||
const serverMessages = session?.messages ?? [];
|
||||
|
||||
// Merge: show server messages, plus any optimistic ones not yet confirmed
|
||||
const serverMsgIds = new Set(serverMessages.map(m => m.id));
|
||||
const messages = [
|
||||
...serverMessages,
|
||||
...optimisticMessages.filter(m => !serverMsgIds.has(m.id)),
|
||||
];
|
||||
|
||||
// Query agent status if session has an agent
|
||||
const agentQuery = trpc.getAgent.useQuery(
|
||||
@@ -86,6 +97,13 @@ export function useChatSession(
|
||||
const sendMutation = trpc.sendChatMessage.useMutation({
|
||||
onSuccess: () => {
|
||||
void utils.getChatSession.invalidate({ targetType, targetId });
|
||||
// Clear optimistic messages once server confirms
|
||||
setOptimisticMessages([]);
|
||||
},
|
||||
onError: (err) => {
|
||||
toast.error(`Chat failed: ${err.message}`);
|
||||
// Remove optimistic messages on error
|
||||
setOptimisticMessages([]);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -94,6 +112,9 @@ export function useChatSession(
|
||||
onSuccess: () => {
|
||||
void utils.getChatSession.invalidate({ targetType, targetId });
|
||||
},
|
||||
onError: (err) => {
|
||||
toast.error(`Failed to close chat: ${err.message}`);
|
||||
},
|
||||
});
|
||||
|
||||
const sendMutateRef = useRef(sendMutation.mutate);
|
||||
@@ -105,6 +126,17 @@ export function useChatSession(
|
||||
|
||||
const sendMessage = useCallback(
|
||||
(message: string) => {
|
||||
// Add optimistic user message immediately
|
||||
const optimistic: ChatMessage = {
|
||||
id: `opt-${Date.now()}`,
|
||||
chatSessionId: '',
|
||||
role: 'user',
|
||||
content: message,
|
||||
changeSetId: null,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
setOptimisticMessages(prev => [...prev, optimistic]);
|
||||
|
||||
sendMutateRef.current({
|
||||
targetType,
|
||||
targetId,
|
||||
|
||||
Reference in New Issue
Block a user