/** * Mobile chat mutations — create session, delete session, mark session read. * * Send-message is NOT a mutation: the chat screen runs a hand-written * optimistic burst (seed messages cache → seed pendingTask cache → flip * activeSession → POST → patch with real task_id) that doesn't map cleanly * onto useMutation. See the chat tab screen for the send path. * * Mirrors the optimistic-update + rollback + onSettled-invalidate pattern * of data/mutations/inbox.ts and web's packages/core/chat/mutations.ts. */ import { useMutation, useQueryClient } from "@tanstack/react-query"; import type { ChatSession } from "@multica/core/types"; import { api } from "@/data/api"; import { useWorkspaceStore } from "@/data/workspace-store"; import { chatKeys } from "@/data/queries/chat"; export function useCreateChatSession() { const qc = useQueryClient(); const wsId = useWorkspaceStore((s) => s.currentWorkspaceId); return useMutation({ mutationFn: (data: { agent_id: string; title?: string }) => api.createChatSession(data), onSettled: () => { // Optimistic prepend isn't done here — the chat screen seeds caches // synchronously around its send burst and uses the returned session // id directly. The invalidate ensures the dropdown picks up the new // row (and any has_unread / title server defaults) without a refetch // race on switch. qc.invalidateQueries({ queryKey: chatKeys.sessions(wsId) }); }, }); } export function useDeleteChatSession() { const qc = useQueryClient(); const wsId = useWorkspaceStore((s) => s.currentWorkspaceId); return useMutation({ mutationFn: (id: string) => api.deleteChatSession(id), onMutate: async (id) => { const key = chatKeys.sessions(wsId); await qc.cancelQueries({ queryKey: key }); const prev = qc.getQueryData(key); qc.setQueryData(key, (old) => old ? old.filter((s) => s.id !== id) : old, ); return { prev, key }; }, onError: (_err, _id, ctx) => { if (ctx?.prev) qc.setQueryData(ctx.key, ctx.prev); }, onSettled: (_data, _err, id) => { qc.invalidateQueries({ queryKey: chatKeys.sessions(wsId) }); // Detail-side caches the screen may still hold for this id. qc.removeQueries({ queryKey: chatKeys.messages(id) }); qc.removeQueries({ queryKey: chatKeys.pendingTask(id) }); }, }); } export function useMarkChatSessionRead() { const qc = useQueryClient(); const wsId = useWorkspaceStore((s) => s.currentWorkspaceId); return useMutation({ mutationFn: (sessionId: string) => api.markChatSessionRead(sessionId), onMutate: async (sessionId) => { const key = chatKeys.sessions(wsId); await qc.cancelQueries({ queryKey: key }); const prev = qc.getQueryData(key); qc.setQueryData(key, (old) => old?.map((s) => s.id === sessionId ? { ...s, has_unread: false } : s, ), ); return { prev, key }; }, onError: (_err, _id, ctx) => { if (ctx?.prev) qc.setQueryData(ctx.key, ctx.prev); }, onSettled: () => { qc.invalidateQueries({ queryKey: chatKeys.sessions(wsId) }); }, }); }