## Description Fixes #12868 This PR fixes a Vue 3 reactivity bug that causes the widget to display "We are away at the moment" on initial page load, even when agents are online and the API correctly returns their availability. ## Problem The widget welcome screen shows "We are away" on first render, only updating to show correct agent status after navigating to the conversation view and back. This misleads visitors into thinking no agents are available. **Reproduction:** Open website with widget in fresh incognito window, click bubble immediately → shows "away" despite agents being online. ## Root Cause Vue 3 reactivity chain breaks in the `useAvailability` composable: **Before (broken):** ```javascript // AvailabilityContainer.vue const { isOnline } = useAvailability(props.agents); // Passes VALUE // useAvailability.js const availableAgents = toRef(agents); // Creates ref from VALUE, doesn't track changes ``` When the API responds and updates the Vuex store, the parent component's computed `props.agents` updates correctly, but the composable's `toRef()` doesn't know about the change because it was created from a static value, not a reactive source. ## Solution **After (fixed):** ```javascript // AvailabilityContainer.vue const { isOnline } = useAvailability(toRef(props, 'agents')); // Passes REACTIVE REF // useAvailability.js const availableAgents = computed(() => unref(agents)); // Unwraps ref and tracks changes ``` Now when `props.agents` updates after the API response, the `computed()` re-evaluates and all downstream reactive properties (`hasOnlineAgents`, `isOnline`) update correctly. ## Testing - ✅ Initial page load shows correct agent status immediately - ✅ Status changes via WebSocket update correctly - ✅ No configuration changes or workarounds needed - ✅ Tested with network monitoring (Puppeteer) confirming API returns correct data ## Files Changed 1. `app/javascript/widget/components/Availability/AvailabilityContainer.vue` - Pass `toRef(props, 'agents')` instead of `props.agents` 2. `app/javascript/widget/composables/useAvailability.js` - Use `computed(() => unref(agents))` instead of `toRef(agents)` - Added explanatory comments ## Related Issues - #5918 - Similar symptoms, closed with workaround (business hours toggle) rather than fixing root cause - #5763 - Different issue (mobile app presence) This is a genuine Vue 3 reactivity bug affecting all widgets, independent of business hours configuration. Co-authored-by: rcoenen <rcoenen@users.noreply.github.com> Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
90 lines
2.4 KiB
Vue
90 lines
2.4 KiB
Vue
<script setup>
|
|
import { computed, toRef } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useMapGetter } from 'dashboard/composables/store.js';
|
|
import GroupedAvatars from 'widget/components/GroupedAvatars.vue';
|
|
import AvailabilityText from './AvailabilityText.vue';
|
|
import { useAvailability } from 'widget/composables/useAvailability';
|
|
|
|
const props = defineProps({
|
|
agents: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
showHeader: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
showAvatars: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
textClasses: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
});
|
|
|
|
const { t } = useI18n();
|
|
|
|
const availableMessage = useMapGetter('appConfig/getAvailableMessage');
|
|
const unavailableMessage = useMapGetter('appConfig/getUnavailableMessage');
|
|
|
|
// Pass toRef(props, 'agents') instead of props.agents to maintain reactivity
|
|
// when the parent component's agents prop updates (e.g., after API response)
|
|
const {
|
|
currentTime,
|
|
hasOnlineAgents,
|
|
isOnline,
|
|
inboxConfig,
|
|
isInWorkingHours,
|
|
} = useAvailability(toRef(props, 'agents'));
|
|
|
|
const workingHours = computed(() => inboxConfig.value.workingHours || []);
|
|
const workingHoursEnabled = computed(
|
|
() => inboxConfig.value.workingHoursEnabled || false
|
|
);
|
|
const utcOffset = computed(
|
|
() => inboxConfig.value.utcOffset || inboxConfig.value.timezone || 'UTC'
|
|
);
|
|
const replyTime = computed(
|
|
() => inboxConfig.value.replyTime || 'in_a_few_minutes'
|
|
);
|
|
|
|
// If online or in working hours
|
|
const isAvailable = computed(
|
|
() => isOnline.value || (workingHoursEnabled.value && isInWorkingHours.value)
|
|
);
|
|
|
|
const headerText = computed(() =>
|
|
isAvailable.value
|
|
? availableMessage.value || t('TEAM_AVAILABILITY.ONLINE')
|
|
: unavailableMessage.value || t('TEAM_AVAILABILITY.OFFLINE')
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex items-center justify-between gap-2">
|
|
<div class="flex flex-col gap-1">
|
|
<div v-if="showHeader" class="font-medium text-n-slate-12">
|
|
{{ headerText }}
|
|
</div>
|
|
|
|
<AvailabilityText
|
|
:time="currentTime"
|
|
:utc-offset="utcOffset"
|
|
:working-hours="workingHours"
|
|
:working-hours-enabled="workingHoursEnabled"
|
|
:has-online-agents="hasOnlineAgents"
|
|
:reply-time="replyTime"
|
|
:is-online="isOnline"
|
|
:is-in-working-hours="isInWorkingHours"
|
|
:class="textClasses"
|
|
class="text-n-slate-11"
|
|
/>
|
|
</div>
|
|
|
|
<GroupedAvatars v-if="showAvatars && isOnline" :users="agents" />
|
|
</div>
|
|
</template>
|