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 { trpc } from '@/lib/trpc';
|
||||||
import { useLiveUpdates } from './useLiveUpdates';
|
import { useLiveUpdates } from './useLiveUpdates';
|
||||||
|
|
||||||
@@ -46,10 +47,13 @@ export function useChatSession(
|
|||||||
): UseChatSessionResult {
|
): UseChatSessionResult {
|
||||||
const utils = trpc.useUtils();
|
const utils = trpc.useUtils();
|
||||||
|
|
||||||
|
// Optimistic messages shown before server confirms
|
||||||
|
const [optimisticMessages, setOptimisticMessages] = useState<ChatMessage[]>([]);
|
||||||
|
|
||||||
// Live updates for chat + agent events
|
// Live updates for chat + agent events
|
||||||
useLiveUpdates([
|
useLiveUpdates([
|
||||||
{ prefix: 'chat:', invalidate: ['getChatSession'] },
|
{ prefix: 'chat:', invalidate: ['getChatSession'] },
|
||||||
{ prefix: 'agent:', invalidate: ['getChatSession'] },
|
{ prefix: 'agent:', invalidate: ['getChatSession', 'getAgent'] },
|
||||||
{ prefix: 'changeset:', invalidate: ['getChatSession'] },
|
{ prefix: 'changeset:', invalidate: ['getChatSession'] },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -59,7 +63,14 @@ export function useChatSession(
|
|||||||
{ enabled: !!targetId },
|
{ enabled: !!targetId },
|
||||||
);
|
);
|
||||||
const session = (sessionQuery.data as ChatSession | null) ?? null;
|
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
|
// Query agent status if session has an agent
|
||||||
const agentQuery = trpc.getAgent.useQuery(
|
const agentQuery = trpc.getAgent.useQuery(
|
||||||
@@ -86,6 +97,13 @@ export function useChatSession(
|
|||||||
const sendMutation = trpc.sendChatMessage.useMutation({
|
const sendMutation = trpc.sendChatMessage.useMutation({
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
void utils.getChatSession.invalidate({ targetType, targetId });
|
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: () => {
|
onSuccess: () => {
|
||||||
void utils.getChatSession.invalidate({ targetType, targetId });
|
void utils.getChatSession.invalidate({ targetType, targetId });
|
||||||
},
|
},
|
||||||
|
onError: (err) => {
|
||||||
|
toast.error(`Failed to close chat: ${err.message}`);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const sendMutateRef = useRef(sendMutation.mutate);
|
const sendMutateRef = useRef(sendMutation.mutate);
|
||||||
@@ -105,6 +126,17 @@ export function useChatSession(
|
|||||||
|
|
||||||
const sendMessage = useCallback(
|
const sendMessage = useCallback(
|
||||||
(message: string) => {
|
(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({
|
sendMutateRef.current({
|
||||||
targetType,
|
targetType,
|
||||||
targetId,
|
targetId,
|
||||||
|
|||||||
Reference in New Issue
Block a user