mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	feat: Rewrite command bar mixin to a composable (#10015)
Co-authored-by: Shivam Mishra <scm.mymail@gmail.com>
This commit is contained in:
		@@ -13,7 +13,7 @@ import wootConstants from 'dashboard/constants/globals';
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
  CMD_REOPEN_CONVERSATION,
 | 
					  CMD_REOPEN_CONVERSATION,
 | 
				
			||||||
  CMD_RESOLVE_CONVERSATION,
 | 
					  CMD_RESOLVE_CONVERSATION,
 | 
				
			||||||
} from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
 | 
					} from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const store = useStore();
 | 
					const store = useStore();
 | 
				
			||||||
const getters = useStoreGetters();
 | 
					const getters = useStoreGetters();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
 | 
				
			|||||||
import { useAI } from 'dashboard/composables/useAI';
 | 
					import { useAI } from 'dashboard/composables/useAI';
 | 
				
			||||||
import AICTAModal from './AICTAModal.vue';
 | 
					import AICTAModal from './AICTAModal.vue';
 | 
				
			||||||
import AIAssistanceModal from './AIAssistanceModal.vue';
 | 
					import AIAssistanceModal from './AIAssistanceModal.vue';
 | 
				
			||||||
import { CMD_AI_ASSIST } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
 | 
					import { CMD_AI_ASSIST } from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
import AIAssistanceCTAButton from './AIAssistanceCTAButton.vue';
 | 
					import AIAssistanceCTAButton from './AIAssistanceCTAButton.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import {
 | 
				
			|||||||
  CMD_MUTE_CONVERSATION,
 | 
					  CMD_MUTE_CONVERSATION,
 | 
				
			||||||
  CMD_SEND_TRANSCRIPT,
 | 
					  CMD_SEND_TRANSCRIPT,
 | 
				
			||||||
  CMD_UNMUTE_CONVERSATION,
 | 
					  CMD_UNMUTE_CONVERSATION,
 | 
				
			||||||
} from '../../../routes/dashboard/commands/commandBarBusEvents';
 | 
					} from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import {
 | 
				
			|||||||
  CMD_BULK_ACTION_SNOOZE_CONVERSATION,
 | 
					  CMD_BULK_ACTION_SNOOZE_CONVERSATION,
 | 
				
			||||||
  CMD_BULK_ACTION_REOPEN_CONVERSATION,
 | 
					  CMD_BULK_ACTION_REOPEN_CONVERSATION,
 | 
				
			||||||
  CMD_BULK_ACTION_RESOLVE_CONVERSATION,
 | 
					  CMD_BULK_ACTION_RESOLVE_CONVERSATION,
 | 
				
			||||||
} from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
 | 
					} from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import AgentSelector from './AgentSelector.vue';
 | 
					import AgentSelector from './AgentSelector.vue';
 | 
				
			||||||
import UpdateActions from './UpdateActions.vue';
 | 
					import UpdateActions from './UpdateActions.vue';
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								app/javascript/dashboard/composables/commands/spec/fixtures.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								app/javascript/dashboard/composables/commands/spec/fixtures.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
				
			|||||||
 | 
					export const mockAssignableAgents = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 1,
 | 
				
			||||||
 | 
					    account_id: 1,
 | 
				
			||||||
 | 
					    availability_status: 'online',
 | 
				
			||||||
 | 
					    auto_offline: true,
 | 
				
			||||||
 | 
					    confirmed: true,
 | 
				
			||||||
 | 
					    email: 'john@doe.com',
 | 
				
			||||||
 | 
					    available_name: 'John Doe',
 | 
				
			||||||
 | 
					    name: 'John Doe',
 | 
				
			||||||
 | 
					    role: 'administrator',
 | 
				
			||||||
 | 
					    thumbnail: '',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mockCurrentChat = {
 | 
				
			||||||
 | 
					  meta: {
 | 
				
			||||||
 | 
					    sender: {
 | 
				
			||||||
 | 
					      additional_attributes: {},
 | 
				
			||||||
 | 
					      availability_status: 'offline',
 | 
				
			||||||
 | 
					      email: null,
 | 
				
			||||||
 | 
					      id: 212,
 | 
				
			||||||
 | 
					      name: 'Chatwoot',
 | 
				
			||||||
 | 
					      phone_number: null,
 | 
				
			||||||
 | 
					      identifier: null,
 | 
				
			||||||
 | 
					      thumbnail: '',
 | 
				
			||||||
 | 
					      custom_attributes: {},
 | 
				
			||||||
 | 
					      last_activity_at: 1723553344,
 | 
				
			||||||
 | 
					      created_at: 1722588710,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    channel: 'Channel::WebWidget',
 | 
				
			||||||
 | 
					    assignee: {
 | 
				
			||||||
 | 
					      id: 1,
 | 
				
			||||||
 | 
					      account_id: 1,
 | 
				
			||||||
 | 
					      availability_status: 'online',
 | 
				
			||||||
 | 
					      auto_offline: true,
 | 
				
			||||||
 | 
					      confirmed: true,
 | 
				
			||||||
 | 
					      email: 'john@doe.com',
 | 
				
			||||||
 | 
					      available_name: 'John Doe',
 | 
				
			||||||
 | 
					      name: 'John Doe',
 | 
				
			||||||
 | 
					      role: 'administrator',
 | 
				
			||||||
 | 
					      thumbnail: '',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    hmac_verified: false,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  id: 138,
 | 
				
			||||||
 | 
					  messages: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      id: 3348,
 | 
				
			||||||
 | 
					      content: 'Hello, how can I assist you today?',
 | 
				
			||||||
 | 
					      account_id: 1,
 | 
				
			||||||
 | 
					      inbox_id: 1,
 | 
				
			||||||
 | 
					      conversation_id: 138,
 | 
				
			||||||
 | 
					      message_type: 1,
 | 
				
			||||||
 | 
					      created_at: 1724398739,
 | 
				
			||||||
 | 
					      updated_at: '2024-08-23T07:38:59.763Z',
 | 
				
			||||||
 | 
					      private: false,
 | 
				
			||||||
 | 
					      status: 'sent',
 | 
				
			||||||
 | 
					      source_id: null,
 | 
				
			||||||
 | 
					      content_type: 'text',
 | 
				
			||||||
 | 
					      content_attributes: {},
 | 
				
			||||||
 | 
					      sender_type: 'User',
 | 
				
			||||||
 | 
					      sender_id: 1,
 | 
				
			||||||
 | 
					      external_source_ids: {},
 | 
				
			||||||
 | 
					      additional_attributes: {},
 | 
				
			||||||
 | 
					      processed_message_content: 'Hello, how can I assist you today?',
 | 
				
			||||||
 | 
					      sentiment: {},
 | 
				
			||||||
 | 
					      conversation: {
 | 
				
			||||||
 | 
					        assignee_id: 1,
 | 
				
			||||||
 | 
					        unread_count: 0,
 | 
				
			||||||
 | 
					        last_activity_at: 1724398739,
 | 
				
			||||||
 | 
					        contact_inbox: {
 | 
				
			||||||
 | 
					          source_id: '5e57317d-053b-4a72-8292-a25b9f29c401',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      sender: {
 | 
				
			||||||
 | 
					        id: 1,
 | 
				
			||||||
 | 
					        name: 'John Doe',
 | 
				
			||||||
 | 
					        available_name: 'John Doe',
 | 
				
			||||||
 | 
					        avatar_url: '',
 | 
				
			||||||
 | 
					        type: 'user',
 | 
				
			||||||
 | 
					        availability_status: 'online',
 | 
				
			||||||
 | 
					        thumbnail: '',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  account_id: 1,
 | 
				
			||||||
 | 
					  uuid: '69dd6922-2f0c-4317-8796-bbeb3679cead',
 | 
				
			||||||
 | 
					  additional_attributes: {
 | 
				
			||||||
 | 
					    browser: {
 | 
				
			||||||
 | 
					      device_name: 'Unknown',
 | 
				
			||||||
 | 
					      browser_name: 'Chrome',
 | 
				
			||||||
 | 
					      platform_name: 'macOS',
 | 
				
			||||||
 | 
					      browser_version: '127.0.0.0',
 | 
				
			||||||
 | 
					      platform_version: '10.15.7',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    referer: 'http://chatwoot.com/widget_tests?dark_mode=auto',
 | 
				
			||||||
 | 
					    initiated_at: {
 | 
				
			||||||
 | 
					      timestamp: 'Fri Aug 02 2024 15:21:18 GMT+0530 (India Standard Time)',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    browser_language: 'en',
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  agent_last_seen_at: 1724400730,
 | 
				
			||||||
 | 
					  assignee_last_seen_at: 1724400686,
 | 
				
			||||||
 | 
					  can_reply: true,
 | 
				
			||||||
 | 
					  contact_last_seen_at: 1723553351,
 | 
				
			||||||
 | 
					  custom_attributes: {},
 | 
				
			||||||
 | 
					  inbox_id: 1,
 | 
				
			||||||
 | 
					  labels: ['billing'],
 | 
				
			||||||
 | 
					  muted: false,
 | 
				
			||||||
 | 
					  snoozed_until: null,
 | 
				
			||||||
 | 
					  status: 'open',
 | 
				
			||||||
 | 
					  created_at: 1722592278,
 | 
				
			||||||
 | 
					  timestamp: 1724398739,
 | 
				
			||||||
 | 
					  first_reply_created_at: 1722592316,
 | 
				
			||||||
 | 
					  unread_count: 0,
 | 
				
			||||||
 | 
					  last_non_activity_message: {},
 | 
				
			||||||
 | 
					  last_activity_at: 1724398739,
 | 
				
			||||||
 | 
					  priority: null,
 | 
				
			||||||
 | 
					  waiting_since: 0,
 | 
				
			||||||
 | 
					  sla_policy_id: 10,
 | 
				
			||||||
 | 
					  applied_sla: {
 | 
				
			||||||
 | 
					    id: 143,
 | 
				
			||||||
 | 
					    sla_id: 10,
 | 
				
			||||||
 | 
					    sla_status: 'missed',
 | 
				
			||||||
 | 
					    created_at: 1722592279,
 | 
				
			||||||
 | 
					    updated_at: 1722874214,
 | 
				
			||||||
 | 
					    sla_description: '',
 | 
				
			||||||
 | 
					    sla_name: 'Hacker SLA',
 | 
				
			||||||
 | 
					    sla_first_response_time_threshold: 600,
 | 
				
			||||||
 | 
					    sla_next_response_time_threshold: 240,
 | 
				
			||||||
 | 
					    sla_only_during_business_hours: false,
 | 
				
			||||||
 | 
					    sla_resolution_time_threshold: 259200,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  sla_events: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      id: 270,
 | 
				
			||||||
 | 
					      event_type: 'nrt',
 | 
				
			||||||
 | 
					      meta: {
 | 
				
			||||||
 | 
					        message_id: 2743,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      updated_at: 1722592819,
 | 
				
			||||||
 | 
					      created_at: 1722592819,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      id: 275,
 | 
				
			||||||
 | 
					      event_type: 'rt',
 | 
				
			||||||
 | 
					      meta: {},
 | 
				
			||||||
 | 
					      updated_at: 1722852322,
 | 
				
			||||||
 | 
					      created_at: 1722852322,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  allMessagesLoaded: false,
 | 
				
			||||||
 | 
					  dataFetched: true,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mockTeamsList = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 5,
 | 
				
			||||||
 | 
					    name: 'design',
 | 
				
			||||||
 | 
					    description: 'design team',
 | 
				
			||||||
 | 
					    allow_auto_assign: true,
 | 
				
			||||||
 | 
					    account_id: 1,
 | 
				
			||||||
 | 
					    is_member: false,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mockActiveLabels = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 16,
 | 
				
			||||||
 | 
					    title: 'billing',
 | 
				
			||||||
 | 
					    description: '',
 | 
				
			||||||
 | 
					    color: '#D8EA19',
 | 
				
			||||||
 | 
					    show_on_sidebar: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mockInactiveLabels = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 2,
 | 
				
			||||||
 | 
					    title: 'Feature Request',
 | 
				
			||||||
 | 
					    description: '',
 | 
				
			||||||
 | 
					    color: '#D8EA19',
 | 
				
			||||||
 | 
					    show_on_sidebar: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const MOCK_FEATURE_FLAGS = {
 | 
				
			||||||
 | 
					  CRM: 'crm',
 | 
				
			||||||
 | 
					  AGENT_MANAGEMENT: 'agent_management',
 | 
				
			||||||
 | 
					  TEAM_MANAGEMENT: 'team_management',
 | 
				
			||||||
 | 
					  INBOX_MANAGEMENT: 'inbox_management',
 | 
				
			||||||
 | 
					  REPORTS: 'reports',
 | 
				
			||||||
 | 
					  LABELS: 'labels',
 | 
				
			||||||
 | 
					  CANNED_RESPONSES: 'canned_responses',
 | 
				
			||||||
 | 
					  INTEGRATIONS: 'integrations',
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					import { useAppearanceHotKeys } from '../useAppearanceHotKeys';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { LocalStorage } from 'shared/helpers/localStorage';
 | 
				
			||||||
 | 
					import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
 | 
				
			||||||
 | 
					import { setColorTheme } from 'dashboard/helper/themeHelper.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useI18n');
 | 
				
			||||||
 | 
					vi.mock('shared/helpers/localStorage');
 | 
				
			||||||
 | 
					vi.mock('dashboard/helper/themeHelper.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('useAppearanceHotKeys', () => {
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    useI18n.mockReturnValue({
 | 
				
			||||||
 | 
					      t: vi.fn(key => key),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    window.matchMedia = vi.fn().mockReturnValue({ matches: false });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return goToAppearanceHotKeys computed property', () => {
 | 
				
			||||||
 | 
					    const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
 | 
					    expect(goToAppearanceHotKeys.value).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should have the correct number of appearance options', () => {
 | 
				
			||||||
 | 
					    const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
 | 
					    expect(goToAppearanceHotKeys.value.length).toBe(4); // 1 parent + 3 theme options
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should have the correct parent option', () => {
 | 
				
			||||||
 | 
					    const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
 | 
					    const parentOption = goToAppearanceHotKeys.value.find(
 | 
				
			||||||
 | 
					      option => option.id === 'appearance_settings'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(parentOption).toBeDefined();
 | 
				
			||||||
 | 
					    expect(parentOption.children.length).toBe(3);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should have the correct theme options', () => {
 | 
				
			||||||
 | 
					    const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
 | 
					    const themeOptions = goToAppearanceHotKeys.value.filter(
 | 
				
			||||||
 | 
					      option => option.parent === 'appearance_settings'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(themeOptions.length).toBe(3);
 | 
				
			||||||
 | 
					    expect(themeOptions.map(option => option.id)).toEqual([
 | 
				
			||||||
 | 
					      'light',
 | 
				
			||||||
 | 
					      'dark',
 | 
				
			||||||
 | 
					      'auto',
 | 
				
			||||||
 | 
					    ]);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should call setAppearance when a theme option is selected', () => {
 | 
				
			||||||
 | 
					    const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
 | 
					    const lightThemeOption = goToAppearanceHotKeys.value.find(
 | 
				
			||||||
 | 
					      option => option.id === 'light'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    lightThemeOption.handler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(LocalStorage.set).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					      LOCAL_STORAGE_KEYS.COLOR_SCHEME,
 | 
				
			||||||
 | 
					      'light'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(setColorTheme).toHaveBeenCalledWith(false);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should handle system dark mode preference', () => {
 | 
				
			||||||
 | 
					    window.matchMedia = vi.fn().mockReturnValue({ matches: true });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
 | 
					    const autoThemeOption = goToAppearanceHotKeys.value.find(
 | 
				
			||||||
 | 
					      option => option.id === 'auto'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    autoThemeOption.handler();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(LocalStorage.set).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					      LOCAL_STORAGE_KEYS.COLOR_SCHEME,
 | 
				
			||||||
 | 
					      'auto'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(setColorTheme).toHaveBeenCalledWith(true);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					import { useBulkActionsHotKeys } from '../useBulkActionsHotKeys';
 | 
				
			||||||
 | 
					import { useStore, useMapGetter } from 'dashboard/composables/store';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
 | 
					import { emitter } from 'shared/helpers/mitt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/store');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useI18n');
 | 
				
			||||||
 | 
					vi.mock('shared/helpers/mitt');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('useBulkActionsHotKeys', () => {
 | 
				
			||||||
 | 
					  let store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    store = {
 | 
				
			||||||
 | 
					      getters: {
 | 
				
			||||||
 | 
					        'bulkActions/getSelectedConversationIds': [],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useStore.mockReturnValue(store);
 | 
				
			||||||
 | 
					    useMapGetter.mockImplementation(key => ({
 | 
				
			||||||
 | 
					      value: store.getters[key],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useI18n.mockReturnValue({ t: vi.fn(key => key) });
 | 
				
			||||||
 | 
					    emitter.emit = vi.fn();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return bulk actions when conversations are selected', () => {
 | 
				
			||||||
 | 
					    store.getters['bulkActions/getSelectedConversationIds'] = [1, 2, 3];
 | 
				
			||||||
 | 
					    const { bulkActionsHotKeys } = useBulkActionsHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(bulkActionsHotKeys.value.length).toBeGreaterThan(0);
 | 
				
			||||||
 | 
					    expect(bulkActionsHotKeys.value).toContainEqual(
 | 
				
			||||||
 | 
					      expect.objectContaining({
 | 
				
			||||||
 | 
					        id: 'bulk_action_snooze_conversation',
 | 
				
			||||||
 | 
					        title: 'COMMAND_BAR.COMMANDS.SNOOZE_CONVERSATION',
 | 
				
			||||||
 | 
					        section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(bulkActionsHotKeys.value).toContainEqual(
 | 
				
			||||||
 | 
					      expect.objectContaining({
 | 
				
			||||||
 | 
					        id: 'bulk_action_reopen_conversation',
 | 
				
			||||||
 | 
					        title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
 | 
				
			||||||
 | 
					        section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(bulkActionsHotKeys.value).toContainEqual(
 | 
				
			||||||
 | 
					      expect.objectContaining({
 | 
				
			||||||
 | 
					        id: 'bulk_action_resolve_conversation',
 | 
				
			||||||
 | 
					        title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
 | 
				
			||||||
 | 
					        section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should include snooze options in bulk actions', () => {
 | 
				
			||||||
 | 
					    store.getters['bulkActions/getSelectedConversationIds'] = [1, 2, 3];
 | 
				
			||||||
 | 
					    const { bulkActionsHotKeys } = useBulkActionsHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const snoozeAction = bulkActionsHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'bulk_action_snooze_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(snoozeAction).toBeDefined();
 | 
				
			||||||
 | 
					    expect(snoozeAction.children).toEqual(
 | 
				
			||||||
 | 
					      Object.values(wootConstants.SNOOZE_OPTIONS)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should create handlers for reopen and resolve actions', () => {
 | 
				
			||||||
 | 
					    store.getters['bulkActions/getSelectedConversationIds'] = [1, 2, 3];
 | 
				
			||||||
 | 
					    const { bulkActionsHotKeys } = useBulkActionsHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const reopenAction = bulkActionsHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'bulk_action_reopen_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const resolveAction = bulkActionsHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'bulk_action_resolve_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(reopenAction.handler).toBeDefined();
 | 
				
			||||||
 | 
					    expect(resolveAction.handler).toBeDefined();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reopenAction.handler();
 | 
				
			||||||
 | 
					    expect(emitter.emit).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					      'CMD_BULK_ACTION_REOPEN_CONVERSATION'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resolveAction.handler();
 | 
				
			||||||
 | 
					    expect(emitter.emit).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					      'CMD_BULK_ACTION_RESOLVE_CONVERSATION'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return an empty array when no conversations are selected', () => {
 | 
				
			||||||
 | 
					    store.getters['bulkActions/getSelectedConversationIds'] = [];
 | 
				
			||||||
 | 
					    const { bulkActionsHotKeys } = useBulkActionsHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(bulkActionsHotKeys.value).toEqual([]);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,204 @@
 | 
				
			|||||||
 | 
					import { useConversationHotKeys } from '../useConversationHotKeys';
 | 
				
			||||||
 | 
					import { useStore, useMapGetter } from 'dashboard/composables/store';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useRoute } from 'dashboard/composables/route';
 | 
				
			||||||
 | 
					import { useConversationLabels } from 'dashboard/composables/useConversationLabels';
 | 
				
			||||||
 | 
					import { useAI } from 'dashboard/composables/useAI';
 | 
				
			||||||
 | 
					import { useAgentsList } from 'dashboard/composables/useAgentsList';
 | 
				
			||||||
 | 
					import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  mockAssignableAgents,
 | 
				
			||||||
 | 
					  mockCurrentChat,
 | 
				
			||||||
 | 
					  mockTeamsList,
 | 
				
			||||||
 | 
					  mockActiveLabels,
 | 
				
			||||||
 | 
					  mockInactiveLabels,
 | 
				
			||||||
 | 
					} from './fixtures';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/store');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useI18n');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/route');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useConversationLabels');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useAI');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useAgentsList');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('useConversationHotKeys', () => {
 | 
				
			||||||
 | 
					  let store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    store = {
 | 
				
			||||||
 | 
					      dispatch: vi.fn(),
 | 
				
			||||||
 | 
					      getters: {
 | 
				
			||||||
 | 
					        getSelectedChat: mockCurrentChat,
 | 
				
			||||||
 | 
					        'draftMessages/getReplyEditorMode': REPLY_EDITOR_MODES.REPLY,
 | 
				
			||||||
 | 
					        getContextMenuChatId: null,
 | 
				
			||||||
 | 
					        'teams/getTeams': mockTeamsList,
 | 
				
			||||||
 | 
					        'draftMessages/get': vi.fn(),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useStore.mockReturnValue(store);
 | 
				
			||||||
 | 
					    useMapGetter.mockImplementation(key => ({
 | 
				
			||||||
 | 
					      value: store.getters[key],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useI18n.mockReturnValue({ t: vi.fn(key => key) });
 | 
				
			||||||
 | 
					    useRoute.mockReturnValue({ name: 'inbox_conversation' });
 | 
				
			||||||
 | 
					    useConversationLabels.mockReturnValue({
 | 
				
			||||||
 | 
					      activeLabels: { value: mockActiveLabels },
 | 
				
			||||||
 | 
					      inactiveLabels: { value: mockInactiveLabels },
 | 
				
			||||||
 | 
					      addLabelToConversation: vi.fn(),
 | 
				
			||||||
 | 
					      removeLabelFromConversation: vi.fn(),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    useAI.mockReturnValue({ isAIIntegrationEnabled: { value: true } });
 | 
				
			||||||
 | 
					    useAgentsList.mockReturnValue({
 | 
				
			||||||
 | 
					      agentsList: { value: [] },
 | 
				
			||||||
 | 
					      assignableAgents: { value: mockAssignableAgents },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return the correct computed properties', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(conversationHotKeys.value).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should generate conversation hot keys', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    expect(conversationHotKeys.value.length).toBeGreaterThan(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should include AI assist actions when AI integration is enabled', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const aiAssistAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'ai_assist'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(aiAssistAction).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should not include AI assist actions when AI integration is disabled', () => {
 | 
				
			||||||
 | 
					    useAI.mockReturnValue({ isAIIntegrationEnabled: { value: false } });
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const aiAssistAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'ai_assist'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(aiAssistAction).toBeUndefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should dispatch actions when handlers are called', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const assignAgentAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'assign_an_agent'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(assignAgentAction).toBeDefined();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (assignAgentAction && assignAgentAction.children) {
 | 
				
			||||||
 | 
					      const childAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					        action => action.id === assignAgentAction.children[0]
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      if (childAction && childAction.handler) {
 | 
				
			||||||
 | 
					        childAction.handler({ agentInfo: { id: 2 } });
 | 
				
			||||||
 | 
					        expect(store.dispatch).toHaveBeenCalledWith('assignAgent', {
 | 
				
			||||||
 | 
					          conversationId: 1,
 | 
				
			||||||
 | 
					          agentId: 2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return snooze actions when in snooze context', () => {
 | 
				
			||||||
 | 
					    store.getters.getContextMenuChatId = 1;
 | 
				
			||||||
 | 
					    useMapGetter.mockImplementation(key => ({
 | 
				
			||||||
 | 
					      value: store.getters[key],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    useRoute.mockReturnValue({ name: 'inbox_conversation' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const snoozeAction = conversationHotKeys.value.find(action =>
 | 
				
			||||||
 | 
					      action.id.includes('snooze_conversation')
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(snoozeAction).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return the correct label actions when there are active labels', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const addLabelAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'add_a_label_to_the_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const removeLabelAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'remove_a_label_to_the_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(addLabelAction).toBeDefined();
 | 
				
			||||||
 | 
					    expect(removeLabelAction).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return only add label actions when there are no active labels', () => {
 | 
				
			||||||
 | 
					    useConversationLabels.mockReturnValue({
 | 
				
			||||||
 | 
					      activeLabels: { value: [] },
 | 
				
			||||||
 | 
					      inactiveLabels: { value: [{ title: 'inactive_label' }] },
 | 
				
			||||||
 | 
					      addLabelToConversation: vi.fn(),
 | 
				
			||||||
 | 
					      removeLabelFromConversation: vi.fn(),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const addLabelAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'add_a_label_to_the_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const removeLabelAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'remove_a_label_to_the_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(addLabelAction).toBeDefined();
 | 
				
			||||||
 | 
					    expect(removeLabelAction).toBeUndefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return the correct team assignment actions', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const assignTeamAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'assign_a_team'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(assignTeamAction).toBeDefined();
 | 
				
			||||||
 | 
					    expect(assignTeamAction.children.length).toBe(mockTeamsList.length);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return the correct priority assignment actions', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const assignPriorityAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'assign_priority'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(assignPriorityAction).toBeDefined();
 | 
				
			||||||
 | 
					    expect(assignPriorityAction.children.length).toBe(4);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return the correct conversation additional actions', () => {
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const muteAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'mute_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const sendTranscriptAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'send_transcript'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(muteAction).toBeDefined();
 | 
				
			||||||
 | 
					    expect(sendTranscriptAction).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return unmute action when conversation is muted', () => {
 | 
				
			||||||
 | 
					    store.getters.getSelectedChat = { ...mockCurrentChat, muted: true };
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					    const unmuteAction = conversationHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'unmute_conversation'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(unmuteAction).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should not return conversation hot keys when not in conversation or inbox route', () => {
 | 
				
			||||||
 | 
					    useRoute.mockReturnValue({ name: 'some_other_route' });
 | 
				
			||||||
 | 
					    const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(conversationHotKeys.value.length).toBe(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,188 @@
 | 
				
			|||||||
 | 
					import { useGoToCommandHotKeys } from '../useGoToCommandHotKeys';
 | 
				
			||||||
 | 
					import { useStore, useMapGetter } from 'dashboard/composables/store';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useRouter } from 'dashboard/composables/route';
 | 
				
			||||||
 | 
					import { useAdmin } from 'dashboard/composables/useAdmin';
 | 
				
			||||||
 | 
					import { frontendURL } from 'dashboard/helper/URLHelper';
 | 
				
			||||||
 | 
					import { MOCK_FEATURE_FLAGS } from './fixtures';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/store');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useI18n');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/route');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useAdmin');
 | 
				
			||||||
 | 
					vi.mock('dashboard/helper/URLHelper');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const mockRoutes = [
 | 
				
			||||||
 | 
					  { path: 'accounts/:accountId/dashboard', name: 'dashboard' },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/contacts',
 | 
				
			||||||
 | 
					    name: 'contacts',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.CRM,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/settings/agents/list',
 | 
				
			||||||
 | 
					    name: 'agent_settings',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.AGENT_MANAGEMENT,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/settings/teams/list',
 | 
				
			||||||
 | 
					    name: 'team_settings',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.TEAM_MANAGEMENT,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/settings/inboxes/list',
 | 
				
			||||||
 | 
					    name: 'inbox_settings',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.INBOX_MANAGEMENT,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  { path: 'accounts/:accountId/profile/settings', name: 'profile_settings' },
 | 
				
			||||||
 | 
					  { path: 'accounts/:accountId/notifications', name: 'notifications' },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/reports/overview',
 | 
				
			||||||
 | 
					    name: 'reports_overview',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.REPORTS,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/settings/labels/list',
 | 
				
			||||||
 | 
					    name: 'label_settings',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.LABELS,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/settings/canned-response/list',
 | 
				
			||||||
 | 
					    name: 'canned_responses',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.CANNED_RESPONSES,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: 'accounts/:accountId/settings/applications',
 | 
				
			||||||
 | 
					    name: 'applications',
 | 
				
			||||||
 | 
					    featureFlag: MOCK_FEATURE_FLAGS.INTEGRATIONS,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('useGoToCommandHotKeys', () => {
 | 
				
			||||||
 | 
					  let store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    store = {
 | 
				
			||||||
 | 
					      getters: {
 | 
				
			||||||
 | 
					        getCurrentAccountId: 1,
 | 
				
			||||||
 | 
					        'accounts/isFeatureEnabledonAccount': vi.fn().mockReturnValue(true),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useStore.mockReturnValue(store);
 | 
				
			||||||
 | 
					    useMapGetter.mockImplementation(key => ({
 | 
				
			||||||
 | 
					      value: store.getters[key],
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useI18n.mockReturnValue({ t: vi.fn(key => key) });
 | 
				
			||||||
 | 
					    useRouter.mockReturnValue({ push: vi.fn() });
 | 
				
			||||||
 | 
					    useAdmin.mockReturnValue({ isAdmin: { value: true } });
 | 
				
			||||||
 | 
					    frontendURL.mockImplementation(url => url);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return goToCommandHotKeys computed property', () => {
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    expect(goToCommandHotKeys.value).toBeDefined();
 | 
				
			||||||
 | 
					    expect(goToCommandHotKeys.value.length).toBeGreaterThan(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should filter commands based on feature flags', () => {
 | 
				
			||||||
 | 
					    store.getters['accounts/isFeatureEnabledonAccount'] = vi.fn(
 | 
				
			||||||
 | 
					      (accountId, flag) => flag !== MOCK_FEATURE_FLAGS.CRM
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mockRoutes.forEach(route => {
 | 
				
			||||||
 | 
					      const command = goToCommandHotKeys.value.find(cmd =>
 | 
				
			||||||
 | 
					        cmd.id.includes(route.name)
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      if (route.featureFlag === MOCK_FEATURE_FLAGS.CRM) {
 | 
				
			||||||
 | 
					        expect(command).toBeUndefined();
 | 
				
			||||||
 | 
					      } else if (!route.featureFlag) {
 | 
				
			||||||
 | 
					        expect(command).toBeDefined();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should filter commands for non-admin users', () => {
 | 
				
			||||||
 | 
					    useAdmin.mockReturnValue({ isAdmin: { value: false } });
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const adminOnlyCommands = goToCommandHotKeys.value.filter(
 | 
				
			||||||
 | 
					      cmd =>
 | 
				
			||||||
 | 
					        cmd.id.includes('agent_settings') ||
 | 
				
			||||||
 | 
					        cmd.id.includes('team_settings') ||
 | 
				
			||||||
 | 
					        cmd.id.includes('inbox_settings')
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(adminOnlyCommands.length).toBe(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should include commands for both admin and agent roles when user is admin', () => {
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    const adminCommand = goToCommandHotKeys.value.find(cmd =>
 | 
				
			||||||
 | 
					      cmd.id.includes('agent_settings')
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const agentCommand = goToCommandHotKeys.value.find(cmd =>
 | 
				
			||||||
 | 
					      cmd.id.includes('profile_settings')
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(adminCommand).toBeDefined();
 | 
				
			||||||
 | 
					    expect(agentCommand).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should translate section and title for each command', () => {
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    goToCommandHotKeys.value.forEach(command => {
 | 
				
			||||||
 | 
					      expect(useI18n().t).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					        expect.stringContaining('COMMAND_BAR.SECTIONS.')
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      expect(useI18n().t).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					        expect.stringContaining('COMMAND_BAR.COMMANDS.')
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      expect(command.section).toBeDefined();
 | 
				
			||||||
 | 
					      expect(command.title).toBeDefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should call router.push with correct URL when handler is called', () => {
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    goToCommandHotKeys.value.forEach(command => {
 | 
				
			||||||
 | 
					      command.handler();
 | 
				
			||||||
 | 
					      expect(useRouter().push).toHaveBeenCalledWith(expect.any(String));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should use current account ID in the path', () => {
 | 
				
			||||||
 | 
					    store.getters.getCurrentAccountId = 42;
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    goToCommandHotKeys.value.forEach(command => {
 | 
				
			||||||
 | 
					      command.handler();
 | 
				
			||||||
 | 
					      expect(useRouter().push).toHaveBeenCalledWith(
 | 
				
			||||||
 | 
					        expect.stringContaining('42')
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should include icon for each command', () => {
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    goToCommandHotKeys.value.forEach(command => {
 | 
				
			||||||
 | 
					      expect(command.icon).toBeDefined();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return commands for all enabled features', () => {
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    const enabledFeatureCommands = goToCommandHotKeys.value.filter(cmd =>
 | 
				
			||||||
 | 
					      mockRoutes.some(route => route.featureFlag && cmd.id.includes(route.name))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(enabledFeatureCommands.length).toBeGreaterThan(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should not return commands for disabled features', () => {
 | 
				
			||||||
 | 
					    store.getters['accounts/isFeatureEnabledonAccount'] = vi.fn(() => false);
 | 
				
			||||||
 | 
					    const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
 | 
					    const disabledFeatureCommands = goToCommandHotKeys.value.filter(cmd =>
 | 
				
			||||||
 | 
					      mockRoutes.some(route => route.featureFlag && cmd.id.includes(route.name))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(disabledFeatureCommands.length).toBe(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					import { useInboxHotKeys } from '../useInboxHotKeys';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useRoute } from 'dashboard/composables/route';
 | 
				
			||||||
 | 
					import { isAInboxViewRoute } from 'dashboard/helper/routeHelpers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/useI18n');
 | 
				
			||||||
 | 
					vi.mock('dashboard/composables/route');
 | 
				
			||||||
 | 
					vi.mock('dashboard/helper/routeHelpers');
 | 
				
			||||||
 | 
					vi.mock('shared/helpers/mitt');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('useInboxHotKeys', () => {
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    useI18n.mockReturnValue({ t: vi.fn(key => key) });
 | 
				
			||||||
 | 
					    useRoute.mockReturnValue({ name: 'inbox_dashboard' });
 | 
				
			||||||
 | 
					    isAInboxViewRoute.mockReturnValue(true);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return inbox hot keys when on an inbox view route', () => {
 | 
				
			||||||
 | 
					    const { inboxHotKeys } = useInboxHotKeys();
 | 
				
			||||||
 | 
					    expect(inboxHotKeys.value.length).toBeGreaterThan(0);
 | 
				
			||||||
 | 
					    expect(inboxHotKeys.value[0].id).toBe('snooze_notification');
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should return an empty array when not on an inbox view route', () => {
 | 
				
			||||||
 | 
					    isAInboxViewRoute.mockReturnValue(false);
 | 
				
			||||||
 | 
					    const { inboxHotKeys } = useInboxHotKeys();
 | 
				
			||||||
 | 
					    expect(inboxHotKeys.value).toEqual([]);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should have the correct structure for snooze actions', () => {
 | 
				
			||||||
 | 
					    const { inboxHotKeys } = useInboxHotKeys();
 | 
				
			||||||
 | 
					    const snoozeNotificationAction = inboxHotKeys.value.find(
 | 
				
			||||||
 | 
					      action => action.id === 'snooze_notification'
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    expect(snoozeNotificationAction).toBeDefined();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ICON_APPEARANCE,
 | 
				
			||||||
 | 
					  ICON_LIGHT_MODE,
 | 
				
			||||||
 | 
					  ICON_DARK_MODE,
 | 
				
			||||||
 | 
					  ICON_SYSTEM_MODE,
 | 
				
			||||||
 | 
					} from 'dashboard/helper/commandbar/icons';
 | 
				
			||||||
 | 
					import { LocalStorage } from 'shared/helpers/localStorage';
 | 
				
			||||||
 | 
					import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
 | 
				
			||||||
 | 
					import { setColorTheme } from 'dashboard/helper/themeHelper.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getThemeOptions = t => [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'light',
 | 
				
			||||||
 | 
					    label: t('COMMAND_BAR.COMMANDS.LIGHT_MODE'),
 | 
				
			||||||
 | 
					    icon: ICON_LIGHT_MODE,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'dark',
 | 
				
			||||||
 | 
					    label: t('COMMAND_BAR.COMMANDS.DARK_MODE'),
 | 
				
			||||||
 | 
					    icon: ICON_DARK_MODE,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    key: 'auto',
 | 
				
			||||||
 | 
					    label: t('COMMAND_BAR.COMMANDS.SYSTEM_MODE'),
 | 
				
			||||||
 | 
					    icon: ICON_SYSTEM_MODE,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const setAppearance = theme => {
 | 
				
			||||||
 | 
					  LocalStorage.set(LOCAL_STORAGE_KEYS.COLOR_SCHEME, theme);
 | 
				
			||||||
 | 
					  const isOSOnDarkMode = window.matchMedia(
 | 
				
			||||||
 | 
					    '(prefers-color-scheme: dark)'
 | 
				
			||||||
 | 
					  ).matches;
 | 
				
			||||||
 | 
					  setColorTheme(isOSOnDarkMode);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useAppearanceHotKeys() {
 | 
				
			||||||
 | 
					  const { t } = useI18n();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const themeOptions = computed(() => getThemeOptions(t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const goToAppearanceHotKeys = computed(() => {
 | 
				
			||||||
 | 
					    const options = themeOptions.value.map(theme => ({
 | 
				
			||||||
 | 
					      id: theme.key,
 | 
				
			||||||
 | 
					      title: theme.label,
 | 
				
			||||||
 | 
					      parent: 'appearance_settings',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.APPEARANCE'),
 | 
				
			||||||
 | 
					      icon: theme.icon,
 | 
				
			||||||
 | 
					      handler: () => {
 | 
				
			||||||
 | 
					        setAppearance(theme.key);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'appearance_settings',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.CHANGE_APPEARANCE'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.APPEARANCE'),
 | 
				
			||||||
 | 
					        icon: ICON_APPEARANCE,
 | 
				
			||||||
 | 
					        children: options.map(option => option.id),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      ...options,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    goToAppearanceHotKeys,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useMapGetter } from 'dashboard/composables/store';
 | 
				
			||||||
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  CMD_BULK_ACTION_SNOOZE_CONVERSATION,
 | 
				
			||||||
 | 
					  CMD_BULK_ACTION_REOPEN_CONVERSATION,
 | 
				
			||||||
 | 
					  CMD_BULK_ACTION_RESOLVE_CONVERSATION,
 | 
				
			||||||
 | 
					} from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ICON_SNOOZE_CONVERSATION,
 | 
				
			||||||
 | 
					  ICON_REOPEN_CONVERSATION,
 | 
				
			||||||
 | 
					  ICON_RESOLVE_CONVERSATION,
 | 
				
			||||||
 | 
					} from 'dashboard/helper/commandbar/icons';
 | 
				
			||||||
 | 
					import { emitter } from 'shared/helpers/mitt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { createSnoozeHandlers } from 'dashboard/helper/commandbar/actions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createEmitHandler = event => () => emitter.emit(event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const SNOOZE_CONVERSATION_BULK_ACTIONS = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 'bulk_action_snooze_conversation',
 | 
				
			||||||
 | 
					    title: 'COMMAND_BAR.COMMANDS.SNOOZE_CONVERSATION',
 | 
				
			||||||
 | 
					    section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
				
			||||||
 | 
					    icon: ICON_SNOOZE_CONVERSATION,
 | 
				
			||||||
 | 
					    children: Object.values(SNOOZE_OPTIONS),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  ...createSnoozeHandlers(
 | 
				
			||||||
 | 
					    CMD_BULK_ACTION_SNOOZE_CONVERSATION,
 | 
				
			||||||
 | 
					    'bulk_action_snooze_conversation',
 | 
				
			||||||
 | 
					    'COMMAND_BAR.SECTIONS.BULK_ACTIONS'
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RESOLVED_CONVERSATION_BULK_ACTIONS = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 'bulk_action_reopen_conversation',
 | 
				
			||||||
 | 
					    title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
 | 
				
			||||||
 | 
					    section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
				
			||||||
 | 
					    icon: ICON_REOPEN_CONVERSATION,
 | 
				
			||||||
 | 
					    handler: createEmitHandler(CMD_BULK_ACTION_REOPEN_CONVERSATION),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const OPEN_CONVERSATION_BULK_ACTIONS = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    id: 'bulk_action_resolve_conversation',
 | 
				
			||||||
 | 
					    title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
 | 
				
			||||||
 | 
					    section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
				
			||||||
 | 
					    icon: ICON_RESOLVE_CONVERSATION,
 | 
				
			||||||
 | 
					    handler: createEmitHandler(CMD_BULK_ACTION_RESOLVE_CONVERSATION),
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useBulkActionsHotKeys() {
 | 
				
			||||||
 | 
					  const { t } = useI18n();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const selectedConversations = useMapGetter(
 | 
				
			||||||
 | 
					    'bulkActions/getSelectedConversationIds'
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const prepareActions = actions => {
 | 
				
			||||||
 | 
					    return actions.map(action => ({
 | 
				
			||||||
 | 
					      ...action,
 | 
				
			||||||
 | 
					      title: t(action.title),
 | 
				
			||||||
 | 
					      section: t(action.section),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const bulkActionsHotKeys = computed(() => {
 | 
				
			||||||
 | 
					    let actions = [];
 | 
				
			||||||
 | 
					    if (selectedConversations.value.length > 0) {
 | 
				
			||||||
 | 
					      actions = [
 | 
				
			||||||
 | 
					        ...SNOOZE_CONVERSATION_BULK_ACTIONS,
 | 
				
			||||||
 | 
					        ...RESOLVED_CONVERSATION_BULK_ACTIONS,
 | 
				
			||||||
 | 
					        ...OPEN_CONVERSATION_BULK_ACTIONS,
 | 
				
			||||||
 | 
					      ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return prepareActions(actions);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    bulkActionsHotKeys,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,408 @@
 | 
				
			|||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useStore, useMapGetter } from 'dashboard/composables/store';
 | 
				
			||||||
 | 
					import { useRoute } from 'dashboard/composables/route';
 | 
				
			||||||
 | 
					import { emitter } from 'shared/helpers/mitt';
 | 
				
			||||||
 | 
					import { useConversationLabels } from 'dashboard/composables/useConversationLabels';
 | 
				
			||||||
 | 
					import { useAI } from 'dashboard/composables/useAI';
 | 
				
			||||||
 | 
					import { useAgentsList } from 'dashboard/composables/useAgentsList';
 | 
				
			||||||
 | 
					import { CMD_AI_ASSIST } from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
 | 
					import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  ICON_ADD_LABEL,
 | 
				
			||||||
 | 
					  ICON_ASSIGN_AGENT,
 | 
				
			||||||
 | 
					  ICON_ASSIGN_PRIORITY,
 | 
				
			||||||
 | 
					  ICON_ASSIGN_TEAM,
 | 
				
			||||||
 | 
					  ICON_REMOVE_LABEL,
 | 
				
			||||||
 | 
					  ICON_PRIORITY_URGENT,
 | 
				
			||||||
 | 
					  ICON_PRIORITY_HIGH,
 | 
				
			||||||
 | 
					  ICON_PRIORITY_LOW,
 | 
				
			||||||
 | 
					  ICON_PRIORITY_MEDIUM,
 | 
				
			||||||
 | 
					  ICON_PRIORITY_NONE,
 | 
				
			||||||
 | 
					  ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					  ICON_AI_SUMMARY,
 | 
				
			||||||
 | 
					  ICON_AI_SHORTEN,
 | 
				
			||||||
 | 
					  ICON_AI_EXPAND,
 | 
				
			||||||
 | 
					  ICON_AI_GRAMMAR,
 | 
				
			||||||
 | 
					} from 'dashboard/helper/commandbar/icons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  OPEN_CONVERSATION_ACTIONS,
 | 
				
			||||||
 | 
					  SNOOZE_CONVERSATION_ACTIONS,
 | 
				
			||||||
 | 
					  RESOLVED_CONVERSATION_ACTIONS,
 | 
				
			||||||
 | 
					  SEND_TRANSCRIPT_ACTION,
 | 
				
			||||||
 | 
					  UNMUTE_ACTION,
 | 
				
			||||||
 | 
					  MUTE_ACTION,
 | 
				
			||||||
 | 
					} from 'dashboard/helper/commandbar/actions';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  isAConversationRoute,
 | 
				
			||||||
 | 
					  isAInboxViewRoute,
 | 
				
			||||||
 | 
					} from 'dashboard/helper/routeHelpers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const prepareActions = (actions, t) => {
 | 
				
			||||||
 | 
					  return actions.map(action => ({
 | 
				
			||||||
 | 
					    ...action,
 | 
				
			||||||
 | 
					    title: t(action.title),
 | 
				
			||||||
 | 
					    section: t(action.section),
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createPriorityOptions = (t, currentPriority) => {
 | 
				
			||||||
 | 
					  return [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('CONVERSATION.PRIORITY.OPTIONS.NONE'),
 | 
				
			||||||
 | 
					      key: null,
 | 
				
			||||||
 | 
					      icon: ICON_PRIORITY_NONE,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('CONVERSATION.PRIORITY.OPTIONS.URGENT'),
 | 
				
			||||||
 | 
					      key: 'urgent',
 | 
				
			||||||
 | 
					      icon: ICON_PRIORITY_URGENT,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('CONVERSATION.PRIORITY.OPTIONS.HIGH'),
 | 
				
			||||||
 | 
					      key: 'high',
 | 
				
			||||||
 | 
					      icon: ICON_PRIORITY_HIGH,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('CONVERSATION.PRIORITY.OPTIONS.MEDIUM'),
 | 
				
			||||||
 | 
					      key: 'medium',
 | 
				
			||||||
 | 
					      icon: ICON_PRIORITY_MEDIUM,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('CONVERSATION.PRIORITY.OPTIONS.LOW'),
 | 
				
			||||||
 | 
					      key: 'low',
 | 
				
			||||||
 | 
					      icon: ICON_PRIORITY_LOW,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ].filter(item => item.key !== currentPriority);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createNonDraftMessageAIAssistActions = (t, replyMode) => {
 | 
				
			||||||
 | 
					  if (replyMode === REPLY_EDITOR_MODES.REPLY) {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.REPLY_SUGGESTION'),
 | 
				
			||||||
 | 
					        key: 'reply_suggestion',
 | 
				
			||||||
 | 
					        icon: ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.SUMMARIZE'),
 | 
				
			||||||
 | 
					      key: 'summarize',
 | 
				
			||||||
 | 
					      icon: ICON_AI_SUMMARY,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createDraftMessageAIAssistActions = t => {
 | 
				
			||||||
 | 
					  return [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.REPHRASE'),
 | 
				
			||||||
 | 
					      key: 'rephrase',
 | 
				
			||||||
 | 
					      icon: ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.FIX_SPELLING_GRAMMAR'),
 | 
				
			||||||
 | 
					      key: 'fix_spelling_grammar',
 | 
				
			||||||
 | 
					      icon: ICON_AI_GRAMMAR,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.EXPAND'),
 | 
				
			||||||
 | 
					      key: 'expand',
 | 
				
			||||||
 | 
					      icon: ICON_AI_EXPAND,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.SHORTEN'),
 | 
				
			||||||
 | 
					      key: 'shorten',
 | 
				
			||||||
 | 
					      icon: ICON_AI_SHORTEN,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.MAKE_FRIENDLY'),
 | 
				
			||||||
 | 
					      key: 'make_friendly',
 | 
				
			||||||
 | 
					      icon: ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.MAKE_FORMAL'),
 | 
				
			||||||
 | 
					      key: 'make_formal',
 | 
				
			||||||
 | 
					      icon: ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      label: t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.SIMPLIFY'),
 | 
				
			||||||
 | 
					      key: 'simplify',
 | 
				
			||||||
 | 
					      icon: ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useConversationHotKeys() {
 | 
				
			||||||
 | 
					  const { t } = useI18n();
 | 
				
			||||||
 | 
					  const store = useStore();
 | 
				
			||||||
 | 
					  const route = useRoute();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const {
 | 
				
			||||||
 | 
					    activeLabels,
 | 
				
			||||||
 | 
					    inactiveLabels,
 | 
				
			||||||
 | 
					    addLabelToConversation,
 | 
				
			||||||
 | 
					    removeLabelFromConversation,
 | 
				
			||||||
 | 
					  } = useConversationLabels();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { isAIIntegrationEnabled } = useAI();
 | 
				
			||||||
 | 
					  const { agentsList } = useAgentsList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const currentChat = useMapGetter('getSelectedChat');
 | 
				
			||||||
 | 
					  const replyMode = useMapGetter('draftMessages/getReplyEditorMode');
 | 
				
			||||||
 | 
					  const contextMenuChatId = useMapGetter('getContextMenuChatId');
 | 
				
			||||||
 | 
					  const teams = useMapGetter('teams/getTeams');
 | 
				
			||||||
 | 
					  const getDraftMessage = useMapGetter('draftMessages/get');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const conversationId = computed(() => currentChat.value?.id);
 | 
				
			||||||
 | 
					  const draftKey = computed(
 | 
				
			||||||
 | 
					    () => `draft-${conversationId.value}-${replyMode.value}`
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const draftMessage = computed(() => getDraftMessage.value(draftKey.value));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const hasAnAssignedTeam = computed(() => !!currentChat.value?.meta?.team);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const teamsList = computed(() => {
 | 
				
			||||||
 | 
					    if (hasAnAssignedTeam.value) {
 | 
				
			||||||
 | 
					      return [{ id: 0, name: t('TEAMS_SETTINGS.LIST.NONE') }, ...teams.value];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return teams.value;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onChangeAssignee = action => {
 | 
				
			||||||
 | 
					    store.dispatch('assignAgent', {
 | 
				
			||||||
 | 
					      conversationId: currentChat.value.id,
 | 
				
			||||||
 | 
					      agentId: action.agentInfo.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onChangePriority = action => {
 | 
				
			||||||
 | 
					    store.dispatch('assignPriority', {
 | 
				
			||||||
 | 
					      conversationId: currentChat.value.id,
 | 
				
			||||||
 | 
					      priority: action.priority.key,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onChangeTeam = action => {
 | 
				
			||||||
 | 
					    store.dispatch('assignTeam', {
 | 
				
			||||||
 | 
					      conversationId: currentChat.value.id,
 | 
				
			||||||
 | 
					      teamId: action.teamInfo.id,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const statusActions = computed(() => {
 | 
				
			||||||
 | 
					    const isOpen = currentChat.value?.status === wootConstants.STATUS_TYPE.OPEN;
 | 
				
			||||||
 | 
					    const isSnoozed =
 | 
				
			||||||
 | 
					      currentChat.value?.status === wootConstants.STATUS_TYPE.SNOOZED;
 | 
				
			||||||
 | 
					    const isResolved =
 | 
				
			||||||
 | 
					      currentChat.value?.status === wootConstants.STATUS_TYPE.RESOLVED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let actions = [];
 | 
				
			||||||
 | 
					    if (isOpen) {
 | 
				
			||||||
 | 
					      actions = [...OPEN_CONVERSATION_ACTIONS, ...SNOOZE_CONVERSATION_ACTIONS];
 | 
				
			||||||
 | 
					    } else if (isResolved || isSnoozed) {
 | 
				
			||||||
 | 
					      actions = RESOLVED_CONVERSATION_ACTIONS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return prepareActions(actions, t);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const priorityOptions = computed(() =>
 | 
				
			||||||
 | 
					    createPriorityOptions(t, currentChat.value?.priority)
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const assignAgentActions = computed(() => {
 | 
				
			||||||
 | 
					    const agentOptions = agentsList.value.map(agent => ({
 | 
				
			||||||
 | 
					      id: `agent-${agent.id}`,
 | 
				
			||||||
 | 
					      title: agent.name,
 | 
				
			||||||
 | 
					      parent: 'assign_an_agent',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.CHANGE_ASSIGNEE'),
 | 
				
			||||||
 | 
					      agentInfo: agent,
 | 
				
			||||||
 | 
					      icon: ICON_ASSIGN_AGENT,
 | 
				
			||||||
 | 
					      handler: onChangeAssignee,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'assign_an_agent',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.ASSIGN_AN_AGENT'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
				
			||||||
 | 
					        icon: ICON_ASSIGN_AGENT,
 | 
				
			||||||
 | 
					        children: agentOptions.map(option => option.id),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      ...agentOptions,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const assignPriorityActions = computed(() => {
 | 
				
			||||||
 | 
					    const options = priorityOptions.value.map(priority => ({
 | 
				
			||||||
 | 
					      id: `priority-${priority.key}`,
 | 
				
			||||||
 | 
					      title: priority.label,
 | 
				
			||||||
 | 
					      parent: 'assign_priority',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.CHANGE_PRIORITY'),
 | 
				
			||||||
 | 
					      priority: priority,
 | 
				
			||||||
 | 
					      icon: priority.icon,
 | 
				
			||||||
 | 
					      handler: onChangePriority,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'assign_priority',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.ASSIGN_PRIORITY'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
				
			||||||
 | 
					        icon: ICON_ASSIGN_PRIORITY,
 | 
				
			||||||
 | 
					        children: options.map(option => option.id),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      ...options,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const assignTeamActions = computed(() => {
 | 
				
			||||||
 | 
					    const teamOptions = teamsList.value.map(team => ({
 | 
				
			||||||
 | 
					      id: `team-${team.id}`,
 | 
				
			||||||
 | 
					      title: team.name,
 | 
				
			||||||
 | 
					      parent: 'assign_a_team',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.CHANGE_TEAM'),
 | 
				
			||||||
 | 
					      teamInfo: team,
 | 
				
			||||||
 | 
					      icon: ICON_ASSIGN_TEAM,
 | 
				
			||||||
 | 
					      handler: onChangeTeam,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'assign_a_team',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.ASSIGN_A_TEAM'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
				
			||||||
 | 
					        icon: ICON_ASSIGN_TEAM,
 | 
				
			||||||
 | 
					        children: teamOptions.map(option => option.id),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      ...teamOptions,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const addLabelActions = computed(() => {
 | 
				
			||||||
 | 
					    const availableLabels = inactiveLabels.value.map(label => ({
 | 
				
			||||||
 | 
					      id: label.title,
 | 
				
			||||||
 | 
					      title: `#${label.title}`,
 | 
				
			||||||
 | 
					      parent: 'add_a_label_to_the_conversation',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.ADD_LABEL'),
 | 
				
			||||||
 | 
					      icon: ICON_ADD_LABEL,
 | 
				
			||||||
 | 
					      handler: action => addLabelToConversation({ title: action.id }),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      ...availableLabels,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'add_a_label_to_the_conversation',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.ADD_LABELS_TO_CONVERSATION'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
				
			||||||
 | 
					        icon: ICON_ADD_LABEL,
 | 
				
			||||||
 | 
					        children: inactiveLabels.value.map(label => label.title),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const removeLabelActions = computed(() => {
 | 
				
			||||||
 | 
					    const activeLabelsComputed = activeLabels.value.map(label => ({
 | 
				
			||||||
 | 
					      id: label.title,
 | 
				
			||||||
 | 
					      title: `#${label.title}`,
 | 
				
			||||||
 | 
					      parent: 'remove_a_label_to_the_conversation',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.REMOVE_LABEL'),
 | 
				
			||||||
 | 
					      icon: ICON_REMOVE_LABEL,
 | 
				
			||||||
 | 
					      handler: action => removeLabelFromConversation(action.id),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      ...activeLabelsComputed,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'remove_a_label_to_the_conversation',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.REMOVE_LABEL_FROM_CONVERSATION'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
				
			||||||
 | 
					        icon: ICON_REMOVE_LABEL,
 | 
				
			||||||
 | 
					        children: activeLabels.value.map(label => label.title),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const labelActions = computed(() => {
 | 
				
			||||||
 | 
					    if (activeLabels.value.length) {
 | 
				
			||||||
 | 
					      return [...addLabelActions.value, ...removeLabelActions.value];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return addLabelActions.value;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const conversationAdditionalActions = computed(() => {
 | 
				
			||||||
 | 
					    return prepareActions(
 | 
				
			||||||
 | 
					      [
 | 
				
			||||||
 | 
					        currentChat.value.muted ? UNMUTE_ACTION : MUTE_ACTION,
 | 
				
			||||||
 | 
					        SEND_TRANSCRIPT_ACTION,
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      t
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const AIAssistActions = computed(() => {
 | 
				
			||||||
 | 
					    const aiOptions = draftMessage.value
 | 
				
			||||||
 | 
					      ? createDraftMessageAIAssistActions(t)
 | 
				
			||||||
 | 
					      : createNonDraftMessageAIAssistActions(t, replyMode.value);
 | 
				
			||||||
 | 
					    const options = aiOptions.map(item => ({
 | 
				
			||||||
 | 
					      id: `ai-assist-${item.key}`,
 | 
				
			||||||
 | 
					      title: item.label,
 | 
				
			||||||
 | 
					      parent: 'ai_assist',
 | 
				
			||||||
 | 
					      section: t('COMMAND_BAR.SECTIONS.AI_ASSIST'),
 | 
				
			||||||
 | 
					      priority: item,
 | 
				
			||||||
 | 
					      icon: item.icon,
 | 
				
			||||||
 | 
					      handler: () => emitter.emit(CMD_AI_ASSIST, item.key),
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        id: 'ai_assist',
 | 
				
			||||||
 | 
					        title: t('COMMAND_BAR.COMMANDS.AI_ASSIST'),
 | 
				
			||||||
 | 
					        section: t('COMMAND_BAR.SECTIONS.AI_ASSIST'),
 | 
				
			||||||
 | 
					        icon: ICON_AI_ASSIST,
 | 
				
			||||||
 | 
					        children: options.map(option => option.id),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      ...options,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const isConversationOrInboxRoute = computed(() => {
 | 
				
			||||||
 | 
					    return isAConversationRoute(route.name) || isAInboxViewRoute(route.name);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const shouldShowSnoozeOption = computed(() => {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      isAConversationRoute(route.name, true, false) && contextMenuChatId.value
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getDefaultConversationHotKeys = computed(() => {
 | 
				
			||||||
 | 
					    const defaultConversationHotKeys = [
 | 
				
			||||||
 | 
					      ...statusActions.value,
 | 
				
			||||||
 | 
					      ...conversationAdditionalActions.value,
 | 
				
			||||||
 | 
					      ...assignAgentActions.value,
 | 
				
			||||||
 | 
					      ...assignTeamActions.value,
 | 
				
			||||||
 | 
					      ...labelActions.value,
 | 
				
			||||||
 | 
					      ...assignPriorityActions.value,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    if (isAIIntegrationEnabled.value) {
 | 
				
			||||||
 | 
					      return [...defaultConversationHotKeys, ...AIAssistActions.value];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return defaultConversationHotKeys;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const conversationHotKeys = computed(() => {
 | 
				
			||||||
 | 
					    if (shouldShowSnoozeOption.value) {
 | 
				
			||||||
 | 
					      return prepareActions(SNOOZE_CONVERSATION_ACTIONS, t);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (isConversationOrInboxRoute.value) {
 | 
				
			||||||
 | 
					      return getDefaultConversationHotKeys.value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return [];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    conversationHotKeys,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,3 +1,8 @@
 | 
				
			|||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useMapGetter } from 'dashboard/composables/store';
 | 
				
			||||||
 | 
					import { useRouter } from 'dashboard/composables/route';
 | 
				
			||||||
 | 
					import { useAdmin } from 'dashboard/composables/useAdmin';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ICON_ACCOUNT_SETTINGS,
 | 
					  ICON_ACCOUNT_SETTINGS,
 | 
				
			||||||
  ICON_AGENT_REPORTS,
 | 
					  ICON_AGENT_REPORTS,
 | 
				
			||||||
@@ -14,11 +19,9 @@ import {
 | 
				
			|||||||
  ICON_TEAM_REPORTS,
 | 
					  ICON_TEAM_REPORTS,
 | 
				
			||||||
  ICON_USER_PROFILE,
 | 
					  ICON_USER_PROFILE,
 | 
				
			||||||
  ICON_CONVERSATION_REPORTS,
 | 
					  ICON_CONVERSATION_REPORTS,
 | 
				
			||||||
} from './CommandBarIcons';
 | 
					} from 'dashboard/helper/commandbar/icons';
 | 
				
			||||||
import { frontendURL } from '../../../helper/URLHelper';
 | 
					import { frontendURL } from 'dashboard/helper/URLHelper';
 | 
				
			||||||
import { mapGetters } from 'vuex';
 | 
					import { FEATURE_FLAGS } from 'dashboard/featureFlags';
 | 
				
			||||||
import { useAdmin } from 'dashboard/composables/useAdmin';
 | 
					 | 
				
			||||||
import { FEATURE_FLAGS } from '../../../featureFlags';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GO_TO_COMMANDS = [
 | 
					const GO_TO_COMMANDS = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -172,45 +175,45 @@ const GO_TO_COMMANDS = [
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export function useGoToCommandHotKeys() {
 | 
				
			||||||
  setup() {
 | 
					  const { t } = useI18n();
 | 
				
			||||||
    const { isAdmin } = useAdmin();
 | 
					  const router = useRouter();
 | 
				
			||||||
    return {
 | 
					  const { isAdmin } = useAdmin();
 | 
				
			||||||
      isAdmin,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    ...mapGetters({
 | 
					 | 
				
			||||||
      accountId: 'getCurrentAccountId',
 | 
					 | 
				
			||||||
      isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
    goToCommandHotKeys() {
 | 
					 | 
				
			||||||
      let commands = GO_TO_COMMANDS.filter(cmd => {
 | 
					 | 
				
			||||||
        if (cmd.featureFlag) {
 | 
					 | 
				
			||||||
          return this.isFeatureEnabledonAccount(
 | 
					 | 
				
			||||||
            this.accountId,
 | 
					 | 
				
			||||||
            cmd.featureFlag
 | 
					 | 
				
			||||||
          );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!this.isAdmin) {
 | 
					  const currentAccountId = useMapGetter('getCurrentAccountId');
 | 
				
			||||||
        commands = commands.filter(command => command.role.includes('agent'));
 | 
					  const isFeatureEnabledOnAccount = useMapGetter(
 | 
				
			||||||
 | 
					    'accounts/isFeatureEnabledonAccount'
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const openRoute = url => {
 | 
				
			||||||
 | 
					    router.push(frontendURL(url));
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const goToCommandHotKeys = computed(() => {
 | 
				
			||||||
 | 
					    let commands = GO_TO_COMMANDS.filter(cmd => {
 | 
				
			||||||
 | 
					      if (cmd.featureFlag) {
 | 
				
			||||||
 | 
					        return isFeatureEnabledOnAccount.value(
 | 
				
			||||||
 | 
					          currentAccountId.value,
 | 
				
			||||||
 | 
					          cmd.featureFlag
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return commands.map(command => ({
 | 
					    if (!isAdmin.value) {
 | 
				
			||||||
        id: command.id,
 | 
					      commands = commands.filter(command => command.role.includes('agent'));
 | 
				
			||||||
        section: this.$t(command.section),
 | 
					    }
 | 
				
			||||||
        title: this.$t(command.title),
 | 
					
 | 
				
			||||||
        icon: command.icon,
 | 
					    return commands.map(command => ({
 | 
				
			||||||
        handler: () => this.openRoute(command.path(this.accountId)),
 | 
					      id: command.id,
 | 
				
			||||||
      }));
 | 
					      section: t(command.section),
 | 
				
			||||||
    },
 | 
					      title: t(command.title),
 | 
				
			||||||
  },
 | 
					      icon: command.icon,
 | 
				
			||||||
  methods: {
 | 
					      handler: () => openRoute(command.path(currentAccountId.value)),
 | 
				
			||||||
    openRoute(url) {
 | 
					    }));
 | 
				
			||||||
      this.$router.push(frontendURL(url));
 | 
					  });
 | 
				
			||||||
    },
 | 
					
 | 
				
			||||||
  },
 | 
					  return {
 | 
				
			||||||
};
 | 
					    goToCommandHotKeys,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,13 +1,19 @@
 | 
				
			|||||||
 | 
					import { computed } from 'vue';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useRoute } from 'dashboard/composables/route';
 | 
				
			||||||
import wootConstants from 'dashboard/constants/globals';
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { CMD_SNOOZE_NOTIFICATION } from './commandBarBusEvents';
 | 
					import { CMD_SNOOZE_NOTIFICATION } from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
import { ICON_SNOOZE_NOTIFICATION } from './CommandBarIcons';
 | 
					import { ICON_SNOOZE_NOTIFICATION } from 'dashboard/helper/commandbar/icons';
 | 
				
			||||||
import { emitter } from 'shared/helpers/mitt';
 | 
					import { emitter } from 'shared/helpers/mitt';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { isAInboxViewRoute } from 'dashboard/helper/routeHelpers';
 | 
					import { isAInboxViewRoute } from 'dashboard/helper/routeHelpers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
 | 
					const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const createSnoozeHandler = option => () =>
 | 
				
			||||||
 | 
					  emitter.emit(CMD_SNOOZE_NOTIFICATION, option);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const INBOX_SNOOZE_EVENTS = [
 | 
					const INBOX_SNOOZE_EVENTS = [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: 'snooze_notification',
 | 
					    id: 'snooze_notification',
 | 
				
			||||||
@@ -21,8 +27,7 @@ const INBOX_SNOOZE_EVENTS = [
 | 
				
			|||||||
    parent: 'snooze_notification',
 | 
					    parent: 'snooze_notification',
 | 
				
			||||||
    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
					    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
				
			||||||
    icon: ICON_SNOOZE_NOTIFICATION,
 | 
					    icon: ICON_SNOOZE_NOTIFICATION,
 | 
				
			||||||
    handler: () =>
 | 
					    handler: createSnoozeHandler(SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
 | 
				
			||||||
      emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: SNOOZE_OPTIONS.UNTIL_TOMORROW,
 | 
					    id: SNOOZE_OPTIONS.UNTIL_TOMORROW,
 | 
				
			||||||
@@ -30,8 +35,7 @@ const INBOX_SNOOZE_EVENTS = [
 | 
				
			|||||||
    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
					    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
				
			||||||
    parent: 'snooze_notification',
 | 
					    parent: 'snooze_notification',
 | 
				
			||||||
    icon: ICON_SNOOZE_NOTIFICATION,
 | 
					    icon: ICON_SNOOZE_NOTIFICATION,
 | 
				
			||||||
    handler: () =>
 | 
					    handler: createSnoozeHandler(SNOOZE_OPTIONS.UNTIL_TOMORROW),
 | 
				
			||||||
      emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_TOMORROW),
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK,
 | 
					    id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK,
 | 
				
			||||||
@@ -39,8 +43,7 @@ const INBOX_SNOOZE_EVENTS = [
 | 
				
			|||||||
    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
					    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
				
			||||||
    parent: 'snooze_notification',
 | 
					    parent: 'snooze_notification',
 | 
				
			||||||
    icon: ICON_SNOOZE_NOTIFICATION,
 | 
					    icon: ICON_SNOOZE_NOTIFICATION,
 | 
				
			||||||
    handler: () =>
 | 
					    handler: createSnoozeHandler(SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
 | 
				
			||||||
      emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH,
 | 
					    id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH,
 | 
				
			||||||
@@ -48,8 +51,7 @@ const INBOX_SNOOZE_EVENTS = [
 | 
				
			|||||||
    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
					    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
				
			||||||
    parent: 'snooze_notification',
 | 
					    parent: 'snooze_notification',
 | 
				
			||||||
    icon: ICON_SNOOZE_NOTIFICATION,
 | 
					    icon: ICON_SNOOZE_NOTIFICATION,
 | 
				
			||||||
    handler: () =>
 | 
					    handler: createSnoozeHandler(SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
 | 
				
			||||||
      emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME,
 | 
					    id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME,
 | 
				
			||||||
@@ -57,26 +59,30 @@ const INBOX_SNOOZE_EVENTS = [
 | 
				
			|||||||
    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
					    section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
 | 
				
			||||||
    parent: 'snooze_notification',
 | 
					    parent: 'snooze_notification',
 | 
				
			||||||
    icon: ICON_SNOOZE_NOTIFICATION,
 | 
					    icon: ICON_SNOOZE_NOTIFICATION,
 | 
				
			||||||
    handler: () =>
 | 
					    handler: createSnoozeHandler(SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
 | 
				
			||||||
      emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
export default {
 | 
					
 | 
				
			||||||
  computed: {
 | 
					export function useInboxHotKeys() {
 | 
				
			||||||
    inboxHotKeys() {
 | 
					  const { t } = useI18n();
 | 
				
			||||||
      if (isAInboxViewRoute(this.$route.name)) {
 | 
					  const route = useRoute();
 | 
				
			||||||
        return this.prepareActions(INBOX_SNOOZE_EVENTS);
 | 
					
 | 
				
			||||||
      }
 | 
					  const prepareActions = actions => {
 | 
				
			||||||
      return [];
 | 
					    return actions.map(action => ({
 | 
				
			||||||
    },
 | 
					      ...action,
 | 
				
			||||||
  },
 | 
					      title: t(action.title),
 | 
				
			||||||
  methods: {
 | 
					      section: action.section ? t(action.section) : undefined,
 | 
				
			||||||
    prepareActions(actions) {
 | 
					    }));
 | 
				
			||||||
      return actions.map(action => ({
 | 
					  };
 | 
				
			||||||
        ...action,
 | 
					
 | 
				
			||||||
        title: this.$t(action.title),
 | 
					  const inboxHotKeys = computed(() => {
 | 
				
			||||||
        section: this.$t(action.section),
 | 
					    if (isAInboxViewRoute(route.name)) {
 | 
				
			||||||
      }));
 | 
					      return prepareActions(INBOX_SNOOZE_EVENTS);
 | 
				
			||||||
    },
 | 
					    }
 | 
				
			||||||
  },
 | 
					    return [];
 | 
				
			||||||
};
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    inboxHotKeys,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -8,7 +8,7 @@ import {
 | 
				
			|||||||
  CMD_SEND_TRANSCRIPT,
 | 
					  CMD_SEND_TRANSCRIPT,
 | 
				
			||||||
  CMD_SNOOZE_CONVERSATION,
 | 
					  CMD_SNOOZE_CONVERSATION,
 | 
				
			||||||
  CMD_UNMUTE_CONVERSATION,
 | 
					  CMD_UNMUTE_CONVERSATION,
 | 
				
			||||||
} from './commandBarBusEvents';
 | 
					} from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  ICON_MUTE_CONVERSATION,
 | 
					  ICON_MUTE_CONVERSATION,
 | 
				
			||||||
@@ -17,7 +17,7 @@ import {
 | 
				
			|||||||
  ICON_SEND_TRANSCRIPT,
 | 
					  ICON_SEND_TRANSCRIPT,
 | 
				
			||||||
  ICON_SNOOZE_CONVERSATION,
 | 
					  ICON_SNOOZE_CONVERSATION,
 | 
				
			||||||
  ICON_UNMUTE_CONVERSATION,
 | 
					  ICON_UNMUTE_CONVERSATION,
 | 
				
			||||||
} from './CommandBarIcons';
 | 
					} from 'dashboard/helper/commandbar/icons';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
 | 
					const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,6 +46,7 @@ export const SNOOZE_CONVERSATION_ACTIONS = [
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    id: 'snooze_conversation',
 | 
					    id: 'snooze_conversation',
 | 
				
			||||||
    title: 'COMMAND_BAR.COMMANDS.SNOOZE_CONVERSATION',
 | 
					    title: 'COMMAND_BAR.COMMANDS.SNOOZE_CONVERSATION',
 | 
				
			||||||
 | 
					    section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
 | 
				
			||||||
    icon: ICON_SNOOZE_CONVERSATION,
 | 
					    icon: ICON_SNOOZE_CONVERSATION,
 | 
				
			||||||
    children: Object.values(SNOOZE_OPTIONS),
 | 
					    children: Object.values(SNOOZE_OPTIONS),
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@@ -6,7 +6,7 @@ import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			|||||||
import { useEmitter } from 'dashboard/composables/emitter';
 | 
					import { useEmitter } from 'dashboard/composables/emitter';
 | 
				
			||||||
import { getUnixTime } from 'date-fns';
 | 
					import { getUnixTime } from 'date-fns';
 | 
				
			||||||
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
 | 
					import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
 | 
				
			||||||
import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
 | 
					import { CMD_SNOOZE_CONVERSATION } from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
import wootConstants from 'dashboard/constants/globals';
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
 | 
					import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,65 +0,0 @@
 | 
				
			|||||||
import {
 | 
					 | 
				
			||||||
  ICON_APPEARANCE,
 | 
					 | 
				
			||||||
  ICON_LIGHT_MODE,
 | 
					 | 
				
			||||||
  ICON_DARK_MODE,
 | 
					 | 
				
			||||||
  ICON_SYSTEM_MODE,
 | 
					 | 
				
			||||||
} from './CommandBarIcons';
 | 
					 | 
				
			||||||
import { LocalStorage } from 'shared/helpers/localStorage';
 | 
					 | 
				
			||||||
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
 | 
					 | 
				
			||||||
import { setColorTheme } from 'dashboard/helper/themeHelper.js';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    themeOptions() {
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          key: 'light',
 | 
					 | 
				
			||||||
          label: this.$t('COMMAND_BAR.COMMANDS.LIGHT_MODE'),
 | 
					 | 
				
			||||||
          icon: ICON_LIGHT_MODE,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          key: 'dark',
 | 
					 | 
				
			||||||
          label: this.$t('COMMAND_BAR.COMMANDS.DARK_MODE'),
 | 
					 | 
				
			||||||
          icon: ICON_DARK_MODE,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          key: 'auto',
 | 
					 | 
				
			||||||
          label: this.$t('COMMAND_BAR.COMMANDS.SYSTEM_MODE'),
 | 
					 | 
				
			||||||
          icon: ICON_SYSTEM_MODE,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    goToAppearanceHotKeys() {
 | 
					 | 
				
			||||||
      const options = this.themeOptions.map(theme => ({
 | 
					 | 
				
			||||||
        id: theme.key,
 | 
					 | 
				
			||||||
        title: theme.label,
 | 
					 | 
				
			||||||
        parent: 'appearance_settings',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.APPEARANCE'),
 | 
					 | 
				
			||||||
        icon: theme.icon,
 | 
					 | 
				
			||||||
        handler: () => {
 | 
					 | 
				
			||||||
          this.setAppearance(theme.key);
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'appearance_settings',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.CHANGE_APPEARANCE'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.APPEARANCE'),
 | 
					 | 
				
			||||||
          icon: ICON_APPEARANCE,
 | 
					 | 
				
			||||||
          children: options.map(option => option.id),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        ...options,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  methods: {
 | 
					 | 
				
			||||||
    setAppearance(theme) {
 | 
					 | 
				
			||||||
      LocalStorage.set(LOCAL_STORAGE_KEYS.COLOR_SCHEME, theme);
 | 
					 | 
				
			||||||
      const isOSOnDarkMode = window.matchMedia(
 | 
					 | 
				
			||||||
        '(prefers-color-scheme: dark)'
 | 
					 | 
				
			||||||
      ).matches;
 | 
					 | 
				
			||||||
      setColorTheme(isOSOnDarkMode);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,86 +0,0 @@
 | 
				
			|||||||
import { mapGetters } from 'vuex';
 | 
					 | 
				
			||||||
import wootConstants from 'dashboard/constants/globals';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  CMD_BULK_ACTION_SNOOZE_CONVERSATION,
 | 
					 | 
				
			||||||
  CMD_BULK_ACTION_REOPEN_CONVERSATION,
 | 
					 | 
				
			||||||
  CMD_BULK_ACTION_RESOLVE_CONVERSATION,
 | 
					 | 
				
			||||||
} from './commandBarBusEvents';
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  ICON_SNOOZE_CONVERSATION,
 | 
					 | 
				
			||||||
  ICON_REOPEN_CONVERSATION,
 | 
					 | 
				
			||||||
  ICON_RESOLVE_CONVERSATION,
 | 
					 | 
				
			||||||
} from './CommandBarIcons';
 | 
					 | 
				
			||||||
import { emitter } from 'shared/helpers/mitt';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { createSnoozeHandlers } from './commandBarActions';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const SNOOZE_OPTIONS = wootConstants.SNOOZE_OPTIONS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const SNOOZE_CONVERSATION_BULK_ACTIONS = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'bulk_action_snooze_conversation',
 | 
					 | 
				
			||||||
    title: 'COMMAND_BAR.COMMANDS.SNOOZE_CONVERSATION',
 | 
					 | 
				
			||||||
    section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
					 | 
				
			||||||
    icon: ICON_SNOOZE_CONVERSATION,
 | 
					 | 
				
			||||||
    children: Object.values(SNOOZE_OPTIONS),
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  ...createSnoozeHandlers(
 | 
					 | 
				
			||||||
    CMD_BULK_ACTION_SNOOZE_CONVERSATION,
 | 
					 | 
				
			||||||
    'bulk_action_snooze_conversation',
 | 
					 | 
				
			||||||
    'COMMAND_BAR.SECTIONS.BULK_ACTIONS'
 | 
					 | 
				
			||||||
  ),
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const RESOLVED_CONVERSATION_BULK_ACTIONS = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'bulk_action_reopen_conversation',
 | 
					 | 
				
			||||||
    title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
 | 
					 | 
				
			||||||
    section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
					 | 
				
			||||||
    icon: ICON_REOPEN_CONVERSATION,
 | 
					 | 
				
			||||||
    handler: () => emitter.emit(CMD_BULK_ACTION_REOPEN_CONVERSATION),
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const OPEN_CONVERSATION_BULK_ACTIONS = [
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    id: 'bulk_action_resolve_conversation',
 | 
					 | 
				
			||||||
    title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
 | 
					 | 
				
			||||||
    section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
 | 
					 | 
				
			||||||
    icon: ICON_RESOLVE_CONVERSATION,
 | 
					 | 
				
			||||||
    handler: () => emitter.emit(CMD_BULK_ACTION_RESOLVE_CONVERSATION),
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    ...mapGetters({
 | 
					 | 
				
			||||||
      selectedConversations: 'bulkActions/getSelectedConversationIds',
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
    bulkActionsHotKeys() {
 | 
					 | 
				
			||||||
      let actions = [];
 | 
					 | 
				
			||||||
      if (this.selectedConversations.length > 0) {
 | 
					 | 
				
			||||||
        actions = [
 | 
					 | 
				
			||||||
          ...SNOOZE_CONVERSATION_BULK_ACTIONS,
 | 
					 | 
				
			||||||
          ...RESOLVED_CONVERSATION_BULK_ACTIONS,
 | 
					 | 
				
			||||||
          ...OPEN_CONVERSATION_BULK_ACTIONS,
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return this.prepareActions(actions);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  watch: {
 | 
					 | 
				
			||||||
    selectedConversations() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  methods: {
 | 
					 | 
				
			||||||
    prepareActions(actions) {
 | 
					 | 
				
			||||||
      return actions.map(action => ({
 | 
					 | 
				
			||||||
        ...action,
 | 
					 | 
				
			||||||
        title: this.$t(action.title),
 | 
					 | 
				
			||||||
        section: this.$t(action.section),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,118 +1,85 @@
 | 
				
			|||||||
<script>
 | 
					<script setup>
 | 
				
			||||||
import '@chatwoot/ninja-keys';
 | 
					import '@chatwoot/ninja-keys';
 | 
				
			||||||
import { useConversationLabels } from 'dashboard/composables/useConversationLabels';
 | 
					import { ref, computed, watchEffect, onMounted } from 'vue';
 | 
				
			||||||
import { useAI } from 'dashboard/composables/useAI';
 | 
					import { useStore } from 'dashboard/composables/store';
 | 
				
			||||||
import { useAgentsList } from 'dashboard/composables/useAgentsList';
 | 
					import { useTrack } from 'dashboard/composables';
 | 
				
			||||||
 | 
					import { useI18n } from 'dashboard/composables/useI18n';
 | 
				
			||||||
 | 
					import { useAppearanceHotKeys } from 'dashboard/composables/commands/useAppearanceHotKeys';
 | 
				
			||||||
 | 
					import { useInboxHotKeys } from 'dashboard/composables/commands/useInboxHotKeys';
 | 
				
			||||||
 | 
					import { useGoToCommandHotKeys } from 'dashboard/composables/commands/useGoToCommandHotKeys';
 | 
				
			||||||
 | 
					import { useBulkActionsHotKeys } from 'dashboard/composables/commands/useBulkActionsHotKeys';
 | 
				
			||||||
 | 
					import { useConversationHotKeys } from 'dashboard/composables/commands/useConversationHotKeys';
 | 
				
			||||||
import wootConstants from 'dashboard/constants/globals';
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
import conversationHotKeysMixin from './conversationHotKeys';
 | 
					import { GENERAL_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
 | 
				
			||||||
import bulkActionsHotKeysMixin from './bulkActionsHotKeys';
 | 
					 | 
				
			||||||
import inboxHotKeysMixin from './inboxHotKeys';
 | 
					 | 
				
			||||||
import goToCommandHotKeys from './goToCommandHotKeys';
 | 
					 | 
				
			||||||
import appearanceHotKeys from './appearanceHotKeys';
 | 
					 | 
				
			||||||
import { GENERAL_EVENTS } from '../../../helper/AnalyticsHelper/events';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					const store = useStore();
 | 
				
			||||||
  mixins: [
 | 
					const track = useTrack();
 | 
				
			||||||
    conversationHotKeysMixin,
 | 
					const { t } = useI18n();
 | 
				
			||||||
    bulkActionsHotKeysMixin,
 | 
					 | 
				
			||||||
    inboxHotKeysMixin,
 | 
					 | 
				
			||||||
    appearanceHotKeys,
 | 
					 | 
				
			||||||
    goToCommandHotKeys,
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  setup() {
 | 
					 | 
				
			||||||
    // used in conversationHotKeysMixin
 | 
					 | 
				
			||||||
    const {
 | 
					 | 
				
			||||||
      activeLabels,
 | 
					 | 
				
			||||||
      inactiveLabels,
 | 
					 | 
				
			||||||
      addLabelToConversation,
 | 
					 | 
				
			||||||
      removeLabelFromConversation,
 | 
					 | 
				
			||||||
    } = useConversationLabels();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { isAIIntegrationEnabled } = useAI();
 | 
					const ninjakeys = ref(null);
 | 
				
			||||||
    const { agentsList, assignableAgents } = useAgentsList();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					// Added selectedSnoozeType to track the selected snooze type
 | 
				
			||||||
      agentsList,
 | 
					// So if the selected snooze type is "custom snooze" then we set selectedSnoozeType with the CMD action id
 | 
				
			||||||
      assignableAgents,
 | 
					// So that we can track the selected snooze type and when we close the command bar
 | 
				
			||||||
      activeLabels,
 | 
					const selectedSnoozeType = ref(null);
 | 
				
			||||||
      inactiveLabels,
 | 
					
 | 
				
			||||||
      addLabelToConversation,
 | 
					const { goToAppearanceHotKeys } = useAppearanceHotKeys();
 | 
				
			||||||
      removeLabelFromConversation,
 | 
					const { inboxHotKeys } = useInboxHotKeys();
 | 
				
			||||||
      isAIIntegrationEnabled,
 | 
					const { goToCommandHotKeys } = useGoToCommandHotKeys();
 | 
				
			||||||
    };
 | 
					const { bulkActionsHotKeys } = useBulkActionsHotKeys();
 | 
				
			||||||
  },
 | 
					const { conversationHotKeys } = useConversationHotKeys();
 | 
				
			||||||
  data() {
 | 
					
 | 
				
			||||||
    return {
 | 
					const placeholder = computed(() => t('COMMAND_BAR.SEARCH_PLACEHOLDER'));
 | 
				
			||||||
      // Added selectedSnoozeType to track the selected snooze type
 | 
					
 | 
				
			||||||
      // So if the selected snooze type is "custom snooze" then we set selectedSnoozeType with the CMD action id
 | 
					const hotKeys = computed(() => [
 | 
				
			||||||
      // So that we can track the selected snooze type and when we close the command bar
 | 
					  ...inboxHotKeys.value,
 | 
				
			||||||
      selectedSnoozeType: null,
 | 
					  ...goToCommandHotKeys.value,
 | 
				
			||||||
    };
 | 
					  ...goToAppearanceHotKeys.value,
 | 
				
			||||||
  },
 | 
					  ...bulkActionsHotKeys.value,
 | 
				
			||||||
  computed: {
 | 
					  ...conversationHotKeys.value,
 | 
				
			||||||
    placeholder() {
 | 
					]);
 | 
				
			||||||
      return this.$t('COMMAND_BAR.SEARCH_PLACEHOLDER');
 | 
					
 | 
				
			||||||
    },
 | 
					const setCommandBarData = () => {
 | 
				
			||||||
    accountId() {
 | 
					  ninjakeys.value.data = hotKeys.value;
 | 
				
			||||||
      return this.$store.getters.getCurrentAccountId;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    routeName() {
 | 
					 | 
				
			||||||
      return this.$route.name;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    hotKeys() {
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        ...this.inboxHotKeys,
 | 
					 | 
				
			||||||
        ...this.conversationHotKeys,
 | 
					 | 
				
			||||||
        ...this.bulkActionsHotKeys,
 | 
					 | 
				
			||||||
        ...this.goToCommandHotKeys,
 | 
					 | 
				
			||||||
        ...this.goToAppearanceHotKeys,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  watch: {
 | 
					 | 
				
			||||||
    routeName() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  mounted() {
 | 
					 | 
				
			||||||
    this.setCommandbarData();
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  methods: {
 | 
					 | 
				
			||||||
    setCommandbarData() {
 | 
					 | 
				
			||||||
      this.$refs.ninjakeys.data = this.hotKeys;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    onSelected(item) {
 | 
					 | 
				
			||||||
      const {
 | 
					 | 
				
			||||||
        detail: {
 | 
					 | 
				
			||||||
          action: { title = null, section = null, id = null } = {},
 | 
					 | 
				
			||||||
        } = {},
 | 
					 | 
				
			||||||
      } = item;
 | 
					 | 
				
			||||||
      // Added this condition to prevent setting the selectedSnoozeType to null
 | 
					 | 
				
			||||||
      // When we select the "custom snooze" (CMD bar will close and the custom snooze modal will open)
 | 
					 | 
				
			||||||
      if (id === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
 | 
					 | 
				
			||||||
        this.selectedSnoozeType =
 | 
					 | 
				
			||||||
          wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        this.selectedSnoozeType = null;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      this.$track(GENERAL_EVENTS.COMMAND_BAR, {
 | 
					 | 
				
			||||||
        section,
 | 
					 | 
				
			||||||
        action: title,
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    onClosed() {
 | 
					 | 
				
			||||||
      // If the selectedSnoozeType is not "SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME (custom snooze)" then we set the context menu chat id to null
 | 
					 | 
				
			||||||
      // Else we do nothing and its handled in the ChatList.vue hideCustomSnoozeModal() method
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        this.selectedSnoozeType !==
 | 
					 | 
				
			||||||
        wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        this.$store.dispatch('setContextMenuChatId', null);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const onSelected = item => {
 | 
				
			||||||
 | 
					  const {
 | 
				
			||||||
 | 
					    detail: { action: { title = null, section = null, id = null } = {} } = {},
 | 
				
			||||||
 | 
					  } = item;
 | 
				
			||||||
 | 
					  // Added this condition to prevent setting the selectedSnoozeType to null
 | 
				
			||||||
 | 
					  // When we select the "custom snooze" (CMD bar will close and the custom snooze modal will open)
 | 
				
			||||||
 | 
					  if (id === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
 | 
				
			||||||
 | 
					    selectedSnoozeType.value = wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    selectedSnoozeType.value = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  track(GENERAL_EVENTS.COMMAND_BAR, {
 | 
				
			||||||
 | 
					    section,
 | 
				
			||||||
 | 
					    action: title,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  setCommandBarData();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const onClosed = () => {
 | 
				
			||||||
 | 
					  // If the selectedSnoozeType is not "SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME (custom snooze)" then we set the context menu chat id to null
 | 
				
			||||||
 | 
					  // Else we do nothing and its handled in the ChatList.vue hideCustomSnoozeModal() method
 | 
				
			||||||
 | 
					  if (
 | 
				
			||||||
 | 
					    selectedSnoozeType.value !== wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    store.dispatch('setContextMenuChatId', null);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					watchEffect(() => {
 | 
				
			||||||
 | 
					  if (ninjakeys.value) {
 | 
				
			||||||
 | 
					    ninjakeys.value.data = hotKeys.value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(setCommandBarData);
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- eslint-disable vue/attribute-hyphenation -->
 | 
					<!-- eslint-disable vue/attribute-hyphenation -->
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,413 +0,0 @@
 | 
				
			|||||||
import { mapGetters } from 'vuex';
 | 
					 | 
				
			||||||
import wootConstants from 'dashboard/constants/globals';
 | 
					 | 
				
			||||||
import { emitter } from 'shared/helpers/mitt';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { CMD_AI_ASSIST } from './commandBarBusEvents';
 | 
					 | 
				
			||||||
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  ICON_ADD_LABEL,
 | 
					 | 
				
			||||||
  ICON_ASSIGN_AGENT,
 | 
					 | 
				
			||||||
  ICON_ASSIGN_PRIORITY,
 | 
					 | 
				
			||||||
  ICON_ASSIGN_TEAM,
 | 
					 | 
				
			||||||
  ICON_REMOVE_LABEL,
 | 
					 | 
				
			||||||
  ICON_PRIORITY_URGENT,
 | 
					 | 
				
			||||||
  ICON_PRIORITY_HIGH,
 | 
					 | 
				
			||||||
  ICON_PRIORITY_LOW,
 | 
					 | 
				
			||||||
  ICON_PRIORITY_MEDIUM,
 | 
					 | 
				
			||||||
  ICON_PRIORITY_NONE,
 | 
					 | 
				
			||||||
  ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
  ICON_AI_SUMMARY,
 | 
					 | 
				
			||||||
  ICON_AI_SHORTEN,
 | 
					 | 
				
			||||||
  ICON_AI_EXPAND,
 | 
					 | 
				
			||||||
  ICON_AI_GRAMMAR,
 | 
					 | 
				
			||||||
} from './CommandBarIcons';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  OPEN_CONVERSATION_ACTIONS,
 | 
					 | 
				
			||||||
  SNOOZE_CONVERSATION_ACTIONS,
 | 
					 | 
				
			||||||
  RESOLVED_CONVERSATION_ACTIONS,
 | 
					 | 
				
			||||||
  SEND_TRANSCRIPT_ACTION,
 | 
					 | 
				
			||||||
  UNMUTE_ACTION,
 | 
					 | 
				
			||||||
  MUTE_ACTION,
 | 
					 | 
				
			||||||
} from './commandBarActions';
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  isAConversationRoute,
 | 
					 | 
				
			||||||
  isAInboxViewRoute,
 | 
					 | 
				
			||||||
} from '../../../helper/routeHelpers';
 | 
					 | 
				
			||||||
export default {
 | 
					 | 
				
			||||||
  watch: {
 | 
					 | 
				
			||||||
    assignableAgents() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    currentChat() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    teamsList() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    activeLabels() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    draftMessage() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    replyMode() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    contextMenuChatId() {
 | 
					 | 
				
			||||||
      this.setCommandbarData();
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  computed: {
 | 
					 | 
				
			||||||
    ...mapGetters({
 | 
					 | 
				
			||||||
      currentChat: 'getSelectedChat',
 | 
					 | 
				
			||||||
      replyMode: 'draftMessages/getReplyEditorMode',
 | 
					 | 
				
			||||||
      contextMenuChatId: 'getContextMenuChatId',
 | 
					 | 
				
			||||||
      teams: 'teams/getTeams',
 | 
					 | 
				
			||||||
    }),
 | 
					 | 
				
			||||||
    draftMessage() {
 | 
					 | 
				
			||||||
      return this.$store.getters['draftMessages/get'](this.draftKey);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    draftKey() {
 | 
					 | 
				
			||||||
      return `draft-${this.conversationId}-${this.replyMode}`;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    inboxId() {
 | 
					 | 
				
			||||||
      return this.currentChat?.inbox_id;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    conversationId() {
 | 
					 | 
				
			||||||
      return this.currentChat?.id;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    hasAnAssignedTeam() {
 | 
					 | 
				
			||||||
      return !!this.currentChat?.meta?.team;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    teamsList() {
 | 
					 | 
				
			||||||
      if (this.hasAnAssignedTeam) {
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
          { id: 0, name: this.$t('TEAMS_SETTINGS.LIST.NONE') },
 | 
					 | 
				
			||||||
          ...this.teams,
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return this.teams;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    statusActions() {
 | 
					 | 
				
			||||||
      const isOpen =
 | 
					 | 
				
			||||||
        this.currentChat?.status === wootConstants.STATUS_TYPE.OPEN;
 | 
					 | 
				
			||||||
      const isSnoozed =
 | 
					 | 
				
			||||||
        this.currentChat?.status === wootConstants.STATUS_TYPE.SNOOZED;
 | 
					 | 
				
			||||||
      const isResolved =
 | 
					 | 
				
			||||||
        this.currentChat?.status === wootConstants.STATUS_TYPE.RESOLVED;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      let actions = [];
 | 
					 | 
				
			||||||
      if (isOpen) {
 | 
					 | 
				
			||||||
        actions = [
 | 
					 | 
				
			||||||
          ...OPEN_CONVERSATION_ACTIONS,
 | 
					 | 
				
			||||||
          ...SNOOZE_CONVERSATION_ACTIONS,
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
      } else if (isResolved || isSnoozed) {
 | 
					 | 
				
			||||||
        actions = RESOLVED_CONVERSATION_ACTIONS;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return this.prepareActions(actions);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    priorityOptions() {
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('CONVERSATION.PRIORITY.OPTIONS.NONE'),
 | 
					 | 
				
			||||||
          key: null,
 | 
					 | 
				
			||||||
          icon: ICON_PRIORITY_NONE,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('CONVERSATION.PRIORITY.OPTIONS.URGENT'),
 | 
					 | 
				
			||||||
          key: 'urgent',
 | 
					 | 
				
			||||||
          icon: ICON_PRIORITY_URGENT,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('CONVERSATION.PRIORITY.OPTIONS.HIGH'),
 | 
					 | 
				
			||||||
          key: 'high',
 | 
					 | 
				
			||||||
          icon: ICON_PRIORITY_HIGH,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('CONVERSATION.PRIORITY.OPTIONS.MEDIUM'),
 | 
					 | 
				
			||||||
          key: 'medium',
 | 
					 | 
				
			||||||
          icon: ICON_PRIORITY_MEDIUM,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('CONVERSATION.PRIORITY.OPTIONS.LOW'),
 | 
					 | 
				
			||||||
          key: 'low',
 | 
					 | 
				
			||||||
          icon: ICON_PRIORITY_LOW,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ].filter(item => item.key !== this.currentChat?.priority);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    assignAgentActions() {
 | 
					 | 
				
			||||||
      const agentOptions = this.agentsList.map(agent => ({
 | 
					 | 
				
			||||||
        id: `agent-${agent.id}`,
 | 
					 | 
				
			||||||
        title: agent.name,
 | 
					 | 
				
			||||||
        parent: 'assign_an_agent',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.CHANGE_ASSIGNEE'),
 | 
					 | 
				
			||||||
        agentInfo: agent,
 | 
					 | 
				
			||||||
        icon: ICON_ASSIGN_AGENT,
 | 
					 | 
				
			||||||
        handler: this.onChangeAssignee,
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'assign_an_agent',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.ASSIGN_AN_AGENT'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
					 | 
				
			||||||
          icon: ICON_ASSIGN_AGENT,
 | 
					 | 
				
			||||||
          children: agentOptions.map(option => option.id),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        ...agentOptions,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    assignPriorityActions() {
 | 
					 | 
				
			||||||
      const options = this.priorityOptions.map(priority => ({
 | 
					 | 
				
			||||||
        id: `priority-${priority.key}`,
 | 
					 | 
				
			||||||
        title: priority.label,
 | 
					 | 
				
			||||||
        parent: 'assign_priority',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.CHANGE_PRIORITY'),
 | 
					 | 
				
			||||||
        priority: priority,
 | 
					 | 
				
			||||||
        icon: priority.icon,
 | 
					 | 
				
			||||||
        handler: this.onChangePriority,
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'assign_priority',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.ASSIGN_PRIORITY'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
					 | 
				
			||||||
          icon: ICON_ASSIGN_PRIORITY,
 | 
					 | 
				
			||||||
          children: options.map(option => option.id),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        ...options,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    assignTeamActions() {
 | 
					 | 
				
			||||||
      const teamOptions = this.teamsList.map(team => ({
 | 
					 | 
				
			||||||
        id: `team-${team.id}`,
 | 
					 | 
				
			||||||
        title: team.name,
 | 
					 | 
				
			||||||
        parent: 'assign_a_team',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.CHANGE_TEAM'),
 | 
					 | 
				
			||||||
        teamInfo: team,
 | 
					 | 
				
			||||||
        icon: ICON_ASSIGN_TEAM,
 | 
					 | 
				
			||||||
        handler: this.onChangeTeam,
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'assign_a_team',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.ASSIGN_A_TEAM'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
					 | 
				
			||||||
          icon: ICON_ASSIGN_TEAM,
 | 
					 | 
				
			||||||
          children: teamOptions.map(option => option.id),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        ...teamOptions,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    addLabelActions() {
 | 
					 | 
				
			||||||
      const availableLabels = this.inactiveLabels.map(label => ({
 | 
					 | 
				
			||||||
        id: label.title,
 | 
					 | 
				
			||||||
        title: `#${label.title}`,
 | 
					 | 
				
			||||||
        parent: 'add_a_label_to_the_conversation',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.ADD_LABEL'),
 | 
					 | 
				
			||||||
        icon: ICON_ADD_LABEL,
 | 
					 | 
				
			||||||
        handler: action => this.addLabelToConversation({ title: action.id }),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        ...availableLabels,
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'add_a_label_to_the_conversation',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.ADD_LABELS_TO_CONVERSATION'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
					 | 
				
			||||||
          icon: ICON_ADD_LABEL,
 | 
					 | 
				
			||||||
          children: this.inactiveLabels.map(label => label.title),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    removeLabelActions() {
 | 
					 | 
				
			||||||
      const activeLabels = this.activeLabels.map(label => ({
 | 
					 | 
				
			||||||
        id: label.title,
 | 
					 | 
				
			||||||
        title: `#${label.title}`,
 | 
					 | 
				
			||||||
        parent: 'remove_a_label_to_the_conversation',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.REMOVE_LABEL'),
 | 
					 | 
				
			||||||
        icon: ICON_REMOVE_LABEL,
 | 
					 | 
				
			||||||
        handler: action => this.removeLabelFromConversation(action.id),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        ...activeLabels,
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'remove_a_label_to_the_conversation',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.REMOVE_LABEL_FROM_CONVERSATION'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.CONVERSATION'),
 | 
					 | 
				
			||||||
          icon: ICON_REMOVE_LABEL,
 | 
					 | 
				
			||||||
          children: this.activeLabels.map(label => label.title),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    labelActions() {
 | 
					 | 
				
			||||||
      if (this.activeLabels.length) {
 | 
					 | 
				
			||||||
        return [...this.addLabelActions, ...this.removeLabelActions];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return this.addLabelActions;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    conversationAdditionalActions() {
 | 
					 | 
				
			||||||
      return this.prepareActions([
 | 
					 | 
				
			||||||
        this.currentChat.muted ? UNMUTE_ACTION : MUTE_ACTION,
 | 
					 | 
				
			||||||
        SEND_TRANSCRIPT_ACTION,
 | 
					 | 
				
			||||||
      ]);
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    nonDraftMessageAIAssistActions() {
 | 
					 | 
				
			||||||
      if (this.replyMode === REPLY_EDITOR_MODES.REPLY) {
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            label: this.$t(
 | 
					 | 
				
			||||||
              'INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.REPLY_SUGGESTION'
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            key: 'reply_suggestion',
 | 
					 | 
				
			||||||
            icon: ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.SUMMARIZE'),
 | 
					 | 
				
			||||||
          key: 'summarize',
 | 
					 | 
				
			||||||
          icon: ICON_AI_SUMMARY,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    draftMessageAIAssistActions() {
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.REPHRASE'),
 | 
					 | 
				
			||||||
          key: 'rephrase',
 | 
					 | 
				
			||||||
          icon: ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t(
 | 
					 | 
				
			||||||
            'INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.FIX_SPELLING_GRAMMAR'
 | 
					 | 
				
			||||||
          ),
 | 
					 | 
				
			||||||
          key: 'fix_spelling_grammar',
 | 
					 | 
				
			||||||
          icon: ICON_AI_GRAMMAR,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.EXPAND'),
 | 
					 | 
				
			||||||
          key: 'expand',
 | 
					 | 
				
			||||||
          icon: ICON_AI_EXPAND,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.SHORTEN'),
 | 
					 | 
				
			||||||
          key: 'shorten',
 | 
					 | 
				
			||||||
          icon: ICON_AI_SHORTEN,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.MAKE_FRIENDLY'),
 | 
					 | 
				
			||||||
          key: 'make_friendly',
 | 
					 | 
				
			||||||
          icon: ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.MAKE_FORMAL'),
 | 
					 | 
				
			||||||
          key: 'make_formal',
 | 
					 | 
				
			||||||
          icon: ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          label: this.$t('INTEGRATION_SETTINGS.OPEN_AI.OPTIONS.SIMPLIFY'),
 | 
					 | 
				
			||||||
          key: 'simplify',
 | 
					 | 
				
			||||||
          icon: ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    AIAssistActions() {
 | 
					 | 
				
			||||||
      const aiOptions = this.draftMessage
 | 
					 | 
				
			||||||
        ? this.draftMessageAIAssistActions
 | 
					 | 
				
			||||||
        : this.nonDraftMessageAIAssistActions;
 | 
					 | 
				
			||||||
      const options = aiOptions.map(item => ({
 | 
					 | 
				
			||||||
        id: `ai-assist-${item.key}`,
 | 
					 | 
				
			||||||
        title: item.label,
 | 
					 | 
				
			||||||
        parent: 'ai_assist',
 | 
					 | 
				
			||||||
        section: this.$t('COMMAND_BAR.SECTIONS.AI_ASSIST'),
 | 
					 | 
				
			||||||
        priority: item,
 | 
					 | 
				
			||||||
        icon: item.icon,
 | 
					 | 
				
			||||||
        handler: () => emitter.emit(CMD_AI_ASSIST, item.key),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
      return [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          id: 'ai_assist',
 | 
					 | 
				
			||||||
          title: this.$t('COMMAND_BAR.COMMANDS.AI_ASSIST'),
 | 
					 | 
				
			||||||
          section: this.$t('COMMAND_BAR.SECTIONS.AI_ASSIST'),
 | 
					 | 
				
			||||||
          icon: ICON_AI_ASSIST,
 | 
					 | 
				
			||||||
          children: options.map(option => option.id),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        ...options,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    isConversationOrInboxRoute() {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        isAConversationRoute(this.$route.name) ||
 | 
					 | 
				
			||||||
        isAInboxViewRoute(this.$route.name)
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    shouldShowSnoozeOption() {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        isAConversationRoute(this.$route.name, true, false) &&
 | 
					 | 
				
			||||||
        this.contextMenuChatId
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    getDefaultConversationHotKeys() {
 | 
					 | 
				
			||||||
      const defaultConversationHotKeys = [
 | 
					 | 
				
			||||||
        ...this.statusActions,
 | 
					 | 
				
			||||||
        ...this.conversationAdditionalActions,
 | 
					 | 
				
			||||||
        ...this.assignAgentActions,
 | 
					 | 
				
			||||||
        ...this.assignTeamActions,
 | 
					 | 
				
			||||||
        ...this.labelActions,
 | 
					 | 
				
			||||||
        ...this.assignPriorityActions,
 | 
					 | 
				
			||||||
      ];
 | 
					 | 
				
			||||||
      if (this.isAIIntegrationEnabled) {
 | 
					 | 
				
			||||||
        return [...defaultConversationHotKeys, ...this.AIAssistActions];
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return defaultConversationHotKeys;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    conversationHotKeys() {
 | 
					 | 
				
			||||||
      if (this.shouldShowSnoozeOption) {
 | 
					 | 
				
			||||||
        return this.prepareActions(SNOOZE_CONVERSATION_ACTIONS);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (this.isConversationOrInboxRoute) {
 | 
					 | 
				
			||||||
        return this.getDefaultConversationHotKeys;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return [];
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  methods: {
 | 
					 | 
				
			||||||
    onChangeAssignee(action) {
 | 
					 | 
				
			||||||
      this.$store.dispatch('assignAgent', {
 | 
					 | 
				
			||||||
        conversationId: this.currentChat.id,
 | 
					 | 
				
			||||||
        agentId: action.agentInfo.id,
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    onChangePriority(action) {
 | 
					 | 
				
			||||||
      this.$store.dispatch('assignPriority', {
 | 
					 | 
				
			||||||
        conversationId: this.currentChat.id,
 | 
					 | 
				
			||||||
        priority: action.priority.key,
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    onChangeTeam(action) {
 | 
					 | 
				
			||||||
      this.$store.dispatch('assignTeam', {
 | 
					 | 
				
			||||||
        conversationId: this.currentChat.id,
 | 
					 | 
				
			||||||
        teamId: action.teamInfo.id,
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    prepareActions(actions) {
 | 
					 | 
				
			||||||
      return actions.map(action => ({
 | 
					 | 
				
			||||||
        ...action,
 | 
					 | 
				
			||||||
        title: this.$t(action.title),
 | 
					 | 
				
			||||||
        section: this.$t(action.section),
 | 
					 | 
				
			||||||
      }));
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
import { mapGetters } from 'vuex';
 | 
					import { mapGetters } from 'vuex';
 | 
				
			||||||
import { useAlert } from 'dashboard/composables';
 | 
					import { useAlert } from 'dashboard/composables';
 | 
				
			||||||
import { getUnixTime } from 'date-fns';
 | 
					import { getUnixTime } from 'date-fns';
 | 
				
			||||||
import { CMD_SNOOZE_NOTIFICATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
 | 
					import { CMD_SNOOZE_NOTIFICATION } from 'dashboard/helper/commandbar/events';
 | 
				
			||||||
import wootConstants from 'dashboard/constants/globals';
 | 
					import wootConstants from 'dashboard/constants/globals';
 | 
				
			||||||
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
 | 
					import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
 | 
				
			||||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
 | 
					import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user