From 816a43658b25c208425d5e97dc7b1e74d8feac00 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Tue, 25 Aug 2026 16:51:47 +0200 Subject: [PATCH] fix(call): stop conversation-joined watcher on immediate match - switch to @vueuse library implementation of whenever - immediate + once matches how we use it - whenever stops the watcher on immediate match, resolving the stray watcher issue Assisted-by: ClaudeCode:claude-sonnet-5 Signed-off-by: Maksim Sukharev --- src/App.vue | 2 +- src/composables/useJoinedConversation.ts | 22 +++++++++++----------- src/views/MainView.vue | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/App.vue b/src/App.vue index ff5c05352c9..269d58a41e5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -615,7 +615,7 @@ export default { unwatchJoinedConversation = watchJoinedConversation(targetToken, () => { stopWatchingJoinedConversation() this._joinCallHandler({ token: targetToken }) - }, { immediate: true }) + }) } }, }, diff --git a/src/composables/useJoinedConversation.ts b/src/composables/useJoinedConversation.ts index 109a8c53e25..76975446335 100644 --- a/src/composables/useJoinedConversation.ts +++ b/src/composables/useJoinedConversation.ts @@ -3,10 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ -import type { MaybeRefOrGetter, WatchCallback, WatchOptions, WatchStopHandle } from 'vue' +import type { MaybeRefOrGetter, WatchCallback, WatchStopHandle } from 'vue' -import { createSharedComposable } from '@vueuse/core' -import { onBeforeMount, onBeforeUnmount, readonly, ref, toValue, watch } from 'vue' +import { createSharedComposable, whenever } from '@vueuse/core' +import { onBeforeMount, onBeforeUnmount, readonly, ref, toValue } from 'vue' import { EventBus } from '../services/EventBus.ts' import SessionStorage from '../services/SessionStorage.js' @@ -39,24 +39,24 @@ export const useJoinedConversation = createSharedComposable(useJoinedConversatio /** * Watch for the current joined conversation matching the provided token. + * Fires immediately if already matching, and stops after the first match * * @param token token to match against the joined conversation * @param callback callback triggered when the joined conversation matches the token - * @param options watch options */ export function watchJoinedConversation( token: MaybeRefOrGetter, - callback: WatchCallback, - options?: WatchOptions, + callback: WatchCallback, ): WatchStopHandle { const currentJoinedConversation = useJoinedConversation() - return watch(currentJoinedConversation, (newToken, oldToken, onCleanup) => { + // Getter resolves to the matching token / undefined + // `whenever()` only invokes the callback and stops watching on a truthy value. + return whenever(() => { const targetToken = toValue(token) - if (!targetToken || newToken !== targetToken) { + if (!targetToken || currentJoinedConversation.value !== targetToken) { return } - - callback(newToken, oldToken, onCleanup) - }, options) + return targetToken + }, callback, { immediate: true, once: true }) } diff --git a/src/views/MainView.vue b/src/views/MainView.vue index fb078554328..626c506d37f 100644 --- a/src/views/MainView.vue +++ b/src/views/MainView.vue @@ -126,7 +126,7 @@ function handleDirectCall(routeToken: string) { unwatchJoinedConversation = watchJoinedConversation(routeToken, () => { stopWatchingJoinedConversation() void joinCall(routeToken, { directCall: true }) - }, { immediate: true }) + }) }