fix: show loading spinner when switching between contact threads
Clear old timeline items immediately on thread switch and display a centered loader until the new conversation loads, instead of showing stale messages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -259,6 +259,7 @@ const {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
const {
|
const {
|
||||||
clientTimelineItems,
|
clientTimelineItems,
|
||||||
|
timelineLoading,
|
||||||
timelineContactId,
|
timelineContactId,
|
||||||
timelineLimit,
|
timelineLimit,
|
||||||
loadClientTimeline,
|
loadClientTimeline,
|
||||||
@@ -1624,6 +1625,12 @@ onBeforeUnmount(() => {
|
|||||||
|
|
||||||
<div v-else-if="selectedCommThread" class="relative flex h-full min-h-0 flex-col">
|
<div v-else-if="selectedCommThread" class="relative flex h-full min-h-0 flex-col">
|
||||||
<div class="comm-thread-surface min-h-0 flex-1 space-y-2 overflow-y-auto px-3 pb-2">
|
<div class="comm-thread-surface min-h-0 flex-1 space-y-2 overflow-y-auto px-3 pb-2">
|
||||||
|
<!-- Loading spinner while timeline is fetching -->
|
||||||
|
<div v-if="timelineLoading && clientTimelineItems.length === 0" class="flex h-full items-center justify-center">
|
||||||
|
<span class="loading loading-spinner loading-md text-primary" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
<button
|
<button
|
||||||
class="sticky top-0 z-10 -mx-3 mb-2 flex w-[calc(100%+1.5rem)] items-center gap-2 border-b border-base-300 bg-base-100/80 px-3 py-2 text-left backdrop-blur-sm transition hover:bg-base-100"
|
class="sticky top-0 z-10 -mx-3 mb-2 flex w-[calc(100%+1.5rem)] items-center gap-2 border-b border-base-300 bg-base-100/80 px-3 py-2 text-left backdrop-blur-sm transition hover:bg-base-100"
|
||||||
@click="commPinnedOnly = !commPinnedOnly"
|
@click="commPinnedOnly = !commPinnedOnly"
|
||||||
@@ -1900,6 +1907,7 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -30,9 +30,13 @@ export function useTimeline(opts: { apolloAuthReady: ComputedRef<boolean> }) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const clientTimelineItems = ref<ClientTimelineItem[]>([]);
|
const clientTimelineItems = ref<ClientTimelineItem[]>([]);
|
||||||
|
const timelineLoading = ref(false);
|
||||||
|
|
||||||
watch(() => timelineResult.value?.getClientTimeline, (v) => {
|
watch(() => timelineResult.value?.getClientTimeline, (v) => {
|
||||||
if (v) clientTimelineItems.value = v as ClientTimelineItem[];
|
if (v) {
|
||||||
|
clientTimelineItems.value = v as ClientTimelineItem[];
|
||||||
|
timelineLoading.value = false;
|
||||||
|
}
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|
||||||
async function loadClientTimeline(contactId: string, limit = 500) {
|
async function loadClientTimeline(contactId: string, limit = 500) {
|
||||||
@@ -40,18 +44,28 @@ export function useTimeline(opts: { apolloAuthReady: ComputedRef<boolean> }) {
|
|||||||
if (!normalizedContactId) {
|
if (!normalizedContactId) {
|
||||||
clientTimelineItems.value = [];
|
clientTimelineItems.value = [];
|
||||||
timelineContactId.value = "";
|
timelineContactId.value = "";
|
||||||
|
timelineLoading.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear old data immediately and show loader
|
||||||
|
clientTimelineItems.value = [];
|
||||||
|
timelineLoading.value = true;
|
||||||
|
|
||||||
timelineContactId.value = normalizedContactId;
|
timelineContactId.value = normalizedContactId;
|
||||||
timelineLimit.value = limit;
|
timelineLimit.value = limit;
|
||||||
await refetchTimeline();
|
try {
|
||||||
|
await refetchTimeline();
|
||||||
|
} finally {
|
||||||
|
timelineLoading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshSelectedClientTimeline(selectedCommThreadId: string) {
|
async function refreshSelectedClientTimeline(selectedCommThreadId: string) {
|
||||||
const contactId = String(selectedCommThreadId ?? "").trim();
|
const contactId = String(selectedCommThreadId ?? "").trim();
|
||||||
if (!contactId) {
|
if (!contactId) {
|
||||||
clientTimelineItems.value = [];
|
clientTimelineItems.value = [];
|
||||||
|
timelineLoading.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await loadClientTimeline(contactId);
|
await loadClientTimeline(contactId);
|
||||||
@@ -59,6 +73,7 @@ export function useTimeline(opts: { apolloAuthReady: ComputedRef<boolean> }) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
clientTimelineItems,
|
clientTimelineItems,
|
||||||
|
timelineLoading,
|
||||||
timelineContactId,
|
timelineContactId,
|
||||||
timelineLimit,
|
timelineLimit,
|
||||||
loadClientTimeline,
|
loadClientTimeline,
|
||||||
|
|||||||
Reference in New Issue
Block a user