fix: optimistic message send — no full timeline reload
Instead of calling openCommunicationThread() after sending (which triggered a full timeline refetch, destroyed audio waveforms, and caused the chat to jump), we now: - Optimistically append the sent message to clientTimelineItems - Scroll to bottom smoothly - Refresh contacts sidebar for lastMessageText preview - Auto-scroll only fires on thread switch (empty→loaded), not on every timeline update, preserving audio waveform DOM elements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -844,17 +844,17 @@ async function sendCommMessage() {
|
||||
const text = commDraft.value.trim();
|
||||
if (!text || commSending.value || !selectedCommThread.value) return;
|
||||
commSending.value = true;
|
||||
const contactId = selectedCommThreadId.value;
|
||||
const contactName = selectedCommThread.value.contact;
|
||||
try {
|
||||
const channel = commSendChannel.value;
|
||||
if (!channel) return;
|
||||
const { useMutation } = await import("@vue/apollo-composable");
|
||||
const { CreateCommunicationMutationDocument, CommunicationsQueryDocument, ContactInboxesQueryDocument } = await import("~~/graphql/generated");
|
||||
const { mutate: doCreateCommunication } = useMutation(CreateCommunicationMutationDocument, {
|
||||
refetchQueries: [{ query: CommunicationsQueryDocument }, { query: ContactInboxesQueryDocument }],
|
||||
});
|
||||
await doCreateCommunication({
|
||||
const { CreateCommunicationMutationDocument } = await import("~~/graphql/generated");
|
||||
const { mutate: doCreateCommunication } = useMutation(CreateCommunicationMutationDocument);
|
||||
const result = await doCreateCommunication({
|
||||
input: {
|
||||
contact: selectedCommThread.value.contact,
|
||||
contact: contactName,
|
||||
channel,
|
||||
kind: "message",
|
||||
direction: "out",
|
||||
@@ -862,7 +862,36 @@ async function sendCommMessage() {
|
||||
},
|
||||
});
|
||||
commDraft.value = "";
|
||||
openCommunicationThread(selectedCommThread.value.contact);
|
||||
|
||||
// Optimistically append the sent message to timeline (no full reload)
|
||||
const newId = result?.data?.createCommunication?.id ?? `temp-${Date.now()}`;
|
||||
const now = new Date().toISOString();
|
||||
clientTimelineItems.value = [
|
||||
...clientTimelineItems.value,
|
||||
{
|
||||
id: newId,
|
||||
contactId,
|
||||
contentType: "message",
|
||||
contentId: newId,
|
||||
datetime: now,
|
||||
message: {
|
||||
id: newId,
|
||||
at: now,
|
||||
contact: contactName,
|
||||
contactInboxId: "",
|
||||
sourceExternalId: "",
|
||||
sourceTitle: "",
|
||||
channel: channel as CommItem["channel"],
|
||||
kind: "message",
|
||||
direction: "out",
|
||||
text,
|
||||
},
|
||||
},
|
||||
];
|
||||
scrollCommThreadToBottom();
|
||||
|
||||
// Refresh sidebar preview (lastMessageText) — lightweight
|
||||
void refetchContacts();
|
||||
} finally {
|
||||
commSending.value = false;
|
||||
}
|
||||
@@ -1145,9 +1174,9 @@ function scrollCommThreadToBottom() {
|
||||
});
|
||||
}
|
||||
|
||||
// Scroll to bottom whenever timeline items change (thread switch or new message)
|
||||
watch(clientTimelineItems, (items) => {
|
||||
if (items.length) scrollCommThreadToBottom();
|
||||
// Scroll to bottom when a new thread loads (items go from [] → [items])
|
||||
watch(clientTimelineItems, (items, oldItems) => {
|
||||
if (items.length && (!oldItems || oldItems.length === 0)) scrollCommThreadToBottom();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user