mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-04 04:57:51 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<script setup>
 | 
						|
import { ref, computed, onMounted } from 'vue';
 | 
						|
import { useAlert } from 'dashboard/composables';
 | 
						|
import { useStore } from 'dashboard/composables/store';
 | 
						|
import Copilot from 'dashboard/components-next/copilot/Copilot.vue';
 | 
						|
import { useMapGetter } from 'dashboard/composables/store';
 | 
						|
import { useUISettings } from 'dashboard/composables/useUISettings';
 | 
						|
import { useConfig } from 'dashboard/composables/useConfig';
 | 
						|
import { useWindowSize } from '@vueuse/core';
 | 
						|
import { vOnClickOutside } from '@vueuse/components';
 | 
						|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
 | 
						|
import wootConstants from 'dashboard/constants/globals';
 | 
						|
 | 
						|
defineProps({
 | 
						|
  conversationInboxType: {
 | 
						|
    type: String,
 | 
						|
    default: '',
 | 
						|
  },
 | 
						|
});
 | 
						|
 | 
						|
const store = useStore();
 | 
						|
const { uiSettings, updateUISettings } = useUISettings();
 | 
						|
const { isEnterprise } = useConfig();
 | 
						|
const { width: windowWidth } = useWindowSize();
 | 
						|
 | 
						|
const currentUser = useMapGetter('getCurrentUser');
 | 
						|
const assistants = useMapGetter('captainAssistants/getRecords');
 | 
						|
const uiFlags = useMapGetter('captainAssistants/getUIFlags');
 | 
						|
const inboxAssistant = useMapGetter('getCopilotAssistant');
 | 
						|
const currentChat = useMapGetter('getSelectedChat');
 | 
						|
 | 
						|
const isSmallScreen = computed(
 | 
						|
  () => windowWidth.value < wootConstants.SMALL_SCREEN_BREAKPOINT
 | 
						|
);
 | 
						|
 | 
						|
const selectedCopilotThreadId = ref(null);
 | 
						|
const messages = computed(() =>
 | 
						|
  store.getters['copilotMessages/getMessagesByThreadId'](
 | 
						|
    selectedCopilotThreadId.value
 | 
						|
  )
 | 
						|
);
 | 
						|
 | 
						|
const currentAccountId = useMapGetter('getCurrentAccountId');
 | 
						|
const isFeatureEnabledonAccount = useMapGetter(
 | 
						|
  'accounts/isFeatureEnabledonAccount'
 | 
						|
);
 | 
						|
 | 
						|
const selectedAssistantId = ref(null);
 | 
						|
 | 
						|
const activeAssistant = computed(() => {
 | 
						|
  const preferredId = uiSettings.value.preferred_captain_assistant_id;
 | 
						|
 | 
						|
  // If the user has selected a specific assistant, it takes first preference for Copilot.
 | 
						|
  if (preferredId) {
 | 
						|
    const preferredAssistant = assistants.value.find(a => a.id === preferredId);
 | 
						|
    // Return the preferred assistant if found, otherwise continue to next cases
 | 
						|
    if (preferredAssistant) return preferredAssistant;
 | 
						|
  }
 | 
						|
 | 
						|
  // If the above is not available, the assistant connected to the inbox takes preference.
 | 
						|
  if (inboxAssistant.value) {
 | 
						|
    const inboxMatchedAssistant = assistants.value.find(
 | 
						|
      a => a.id === inboxAssistant.value.id
 | 
						|
    );
 | 
						|
    if (inboxMatchedAssistant) return inboxMatchedAssistant;
 | 
						|
  }
 | 
						|
  // If neither of the above is available, the first assistant in the account takes preference.
 | 
						|
  return assistants.value[0];
 | 
						|
});
 | 
						|
 | 
						|
const closeCopilotPanel = () => {
 | 
						|
  if (isSmallScreen.value && uiSettings.value?.is_copilot_panel_open) {
 | 
						|
    updateUISettings({
 | 
						|
      is_contact_sidebar_open: false,
 | 
						|
      is_copilot_panel_open: false,
 | 
						|
    });
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
const setAssistant = async assistant => {
 | 
						|
  selectedAssistantId.value = assistant.id;
 | 
						|
  await updateUISettings({
 | 
						|
    preferred_captain_assistant_id: assistant.id,
 | 
						|
  });
 | 
						|
};
 | 
						|
 | 
						|
const shouldShowCopilotPanel = computed(() => {
 | 
						|
  if (!isEnterprise) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
  const isCaptainEnabled = isFeatureEnabledonAccount.value(
 | 
						|
    currentAccountId.value,
 | 
						|
    FEATURE_FLAGS.CAPTAIN
 | 
						|
  );
 | 
						|
  const { is_copilot_panel_open: isCopilotPanelOpen } = uiSettings.value;
 | 
						|
  return isCaptainEnabled && isCopilotPanelOpen && !uiFlags.value.fetchingList;
 | 
						|
});
 | 
						|
 | 
						|
const handleReset = () => {
 | 
						|
  selectedCopilotThreadId.value = null;
 | 
						|
};
 | 
						|
 | 
						|
const sendMessage = async message => {
 | 
						|
  try {
 | 
						|
    if (selectedCopilotThreadId.value) {
 | 
						|
      await store.dispatch('copilotMessages/create', {
 | 
						|
        assistant_id: activeAssistant.value.id,
 | 
						|
        conversation_id: currentChat.value?.id,
 | 
						|
        threadId: selectedCopilotThreadId.value,
 | 
						|
        message,
 | 
						|
      });
 | 
						|
    } else {
 | 
						|
      const response = await store.dispatch('copilotThreads/create', {
 | 
						|
        assistant_id: activeAssistant.value.id,
 | 
						|
        conversation_id: currentChat.value?.id,
 | 
						|
        message,
 | 
						|
      });
 | 
						|
      selectedCopilotThreadId.value = response.id;
 | 
						|
    }
 | 
						|
  } catch (error) {
 | 
						|
    useAlert(error.message);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
onMounted(() => {
 | 
						|
  if (isEnterprise) {
 | 
						|
    store.dispatch('captainAssistants/get');
 | 
						|
  }
 | 
						|
});
 | 
						|
</script>
 | 
						|
 | 
						|
<template>
 | 
						|
  <div
 | 
						|
    v-if="shouldShowCopilotPanel"
 | 
						|
    v-on-click-outside="() => closeCopilotPanel()"
 | 
						|
    class="bg-n-background h-full overflow-hidden flex-col fixed top-0 ltr:right-0 rtl:left-0 z-40 w-full max-w-sm transition-transform duration-300 ease-in-out md:static md:w-[320px] md:min-w-[320px] ltr:border-l rtl:border-r border-n-weak 2xl:min-w-[360px] 2xl:w-[360px] shadow-lg md:shadow-none"
 | 
						|
    :class="[
 | 
						|
      {
 | 
						|
        'md:flex': shouldShowCopilotPanel,
 | 
						|
        'md:hidden': !shouldShowCopilotPanel,
 | 
						|
      },
 | 
						|
    ]"
 | 
						|
  >
 | 
						|
    <Copilot
 | 
						|
      :messages="messages"
 | 
						|
      :support-agent="currentUser"
 | 
						|
      :conversation-inbox-type="conversationInboxType"
 | 
						|
      :assistants="assistants"
 | 
						|
      :active-assistant="activeAssistant"
 | 
						|
      @set-assistant="setAssistant"
 | 
						|
      @send-message="sendMessage"
 | 
						|
      @reset="handleReset"
 | 
						|
    />
 | 
						|
  </div>
 | 
						|
  <template v-else />
 | 
						|
</template>
 |