mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 11:08:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			143 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <script setup>
 | |
| import { ref, computed, onBeforeUnmount } from 'vue';
 | |
| import { useI18n } from 'vue-i18n';
 | |
| import { useRoute } from 'vue-router';
 | |
| import { useEmitter } from 'dashboard/composables/emitter';
 | |
| import { BUS_EVENTS } from 'shared/constants/busEvents';
 | |
| import {
 | |
|   isAConversationRoute,
 | |
|   isAInboxViewRoute,
 | |
|   isNotificationRoute,
 | |
| } from 'dashboard/helper/routeHelpers';
 | |
| import { useEventListener } from '@vueuse/core';
 | |
| 
 | |
| import Button from 'dashboard/components-next/button/Button.vue';
 | |
| 
 | |
| const { t } = useI18n();
 | |
| const route = useRoute();
 | |
| 
 | |
| const RECONNECTED_BANNER_TIMEOUT = 2000;
 | |
| 
 | |
| const showNotification = ref(!navigator.onLine);
 | |
| const isDisconnected = ref(false);
 | |
| const isReconnecting = ref(false);
 | |
| const isReconnected = ref(false);
 | |
| let reconnectTimeout = null;
 | |
| 
 | |
| const bannerText = computed(() => {
 | |
|   if (isReconnecting.value) return t('NETWORK.NOTIFICATION.RECONNECTING');
 | |
|   if (isReconnected.value) return t('NETWORK.NOTIFICATION.RECONNECT_SUCCESS');
 | |
|   return t('NETWORK.NOTIFICATION.OFFLINE');
 | |
| });
 | |
| 
 | |
| const iconName = computed(() => (isReconnected.value ? 'wifi' : 'wifi-off'));
 | |
| const canRefresh = computed(
 | |
|   () => !isReconnecting.value && !isReconnected.value
 | |
| );
 | |
| 
 | |
| const refreshPage = () => {
 | |
|   window.location.reload();
 | |
| };
 | |
| 
 | |
| const closeNotification = () => {
 | |
|   showNotification.value = false;
 | |
|   isReconnected.value = false;
 | |
|   clearTimeout(reconnectTimeout);
 | |
| };
 | |
| 
 | |
| const isInAnyOfTheRoutes = routeName => {
 | |
|   return (
 | |
|     isAConversationRoute(routeName, true) ||
 | |
|     isAInboxViewRoute(routeName, true) ||
 | |
|     isNotificationRoute(routeName, true)
 | |
|   );
 | |
| };
 | |
| 
 | |
| const updateWebsocketStatus = () => {
 | |
|   isDisconnected.value = true;
 | |
|   showNotification.value = true;
 | |
| };
 | |
| 
 | |
| const handleReconnectionCompleted = () => {
 | |
|   isDisconnected.value = false;
 | |
|   isReconnecting.value = false;
 | |
|   isReconnected.value = true;
 | |
|   showNotification.value = true;
 | |
|   reconnectTimeout = setTimeout(closeNotification, RECONNECTED_BANNER_TIMEOUT);
 | |
| };
 | |
| 
 | |
| const handleReconnecting = () => {
 | |
|   if (isInAnyOfTheRoutes(route.name)) {
 | |
|     isReconnecting.value = true;
 | |
|     isReconnected.value = false;
 | |
|     showNotification.value = true;
 | |
|   } else {
 | |
|     handleReconnectionCompleted();
 | |
|   }
 | |
| };
 | |
| 
 | |
| const updateOnlineStatus = event => {
 | |
|   // Case: Websocket is not disconnected
 | |
|   // If the app goes offline, show the notification
 | |
|   // If the app goes online, close the notification
 | |
| 
 | |
|   // Case: Websocket is disconnected
 | |
|   // If the app goes offline, show the notification
 | |
|   // If the app goes online but the websocket is disconnected, don't close the notification
 | |
|   // If the app goes online and the websocket is not disconnected, close the notification
 | |
| 
 | |
|   if (event.type === 'offline') {
 | |
|     showNotification.value = true;
 | |
|   } else if (event.type === 'online' && !isDisconnected.value) {
 | |
|     handleReconnectionCompleted();
 | |
|   }
 | |
| };
 | |
| 
 | |
| useEventListener('online', updateOnlineStatus);
 | |
| useEventListener('offline', updateOnlineStatus);
 | |
| useEmitter(BUS_EVENTS.WEBSOCKET_DISCONNECT, updateWebsocketStatus);
 | |
| useEmitter(
 | |
|   BUS_EVENTS.WEBSOCKET_RECONNECT_COMPLETED,
 | |
|   handleReconnectionCompleted
 | |
| );
 | |
| useEmitter(BUS_EVENTS.WEBSOCKET_RECONNECT, handleReconnecting);
 | |
| 
 | |
| onBeforeUnmount(() => {
 | |
|   clearTimeout(reconnectTimeout);
 | |
| });
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <transition name="network-notification-fade" tag="div">
 | |
|     <div v-show="showNotification" class="fixed z-50 top-2 left-2 group">
 | |
|       <div
 | |
|         class="relative flex items-center justify-between w-full px-2 py-1 bg-n-amber-4 dark:bg-n-amber-8 rounded-lg shadow-lg"
 | |
|       >
 | |
|         <fluent-icon :icon="iconName" class="text-n-amber-12" size="18" />
 | |
|         <span class="px-2 text-xs font-medium tracking-wide text-n-amber-12">
 | |
|           {{ bannerText }}
 | |
|         </span>
 | |
|         <Button
 | |
|           v-if="canRefresh"
 | |
|           ghost
 | |
|           sm
 | |
|           amber
 | |
|           icon="i-lucide-refresh-ccw"
 | |
|           :title="$t('NETWORK.BUTTON.REFRESH')"
 | |
|           class="!text-n-amber-12 dark:!text-n-amber-9"
 | |
|           @click="refreshPage"
 | |
|         />
 | |
| 
 | |
|         <Button
 | |
|           ghost
 | |
|           sm
 | |
|           amber
 | |
|           icon="i-lucide-x"
 | |
|           class="!text-n-amber-12 dark:!text-n-amber-9"
 | |
|           @click="closeNotification"
 | |
|         />
 | |
|       </div>
 | |
|     </div>
 | |
|   </transition>
 | |
| </template>
 | 
