diff --git a/apps/meteor/client/hooks/quickActions/useChatForwardQuickAction.ts b/apps/meteor/client/hooks/quickActions/useChatForwardQuickAction.ts new file mode 100644 index 00000000000..9d686a96aaf --- /dev/null +++ b/apps/meteor/client/hooks/quickActions/useChatForwardQuickAction.ts @@ -0,0 +1,16 @@ +import { useMemo } from 'react'; + +import { QuickActionsEnum, type QuickActionsActionConfig } from '../../views/room/lib/quickActions'; + +export const useChatForwardQuickAction = (): QuickActionsActionConfig => { + return useMemo( + () => ({ + groups: ['live'], + id: QuickActionsEnum.ChatForward, + title: 'Forward_chat', + icon: 'balloon-arrow-top-right', + order: 2, + }), + [], + ); +}; diff --git a/apps/meteor/client/hooks/quickActions/useCloseChatQuickAction.ts b/apps/meteor/client/hooks/quickActions/useCloseChatQuickAction.ts new file mode 100644 index 00000000000..bce23ebe508 --- /dev/null +++ b/apps/meteor/client/hooks/quickActions/useCloseChatQuickAction.ts @@ -0,0 +1,17 @@ +import { useMemo } from 'react'; + +import { QuickActionsEnum, type QuickActionsActionConfig } from '../../views/room/lib/quickActions'; + +export const useCloseChatQuickAction = (): QuickActionsActionConfig => { + return useMemo( + () => ({ + groups: ['live'], + id: QuickActionsEnum.CloseChat, + title: 'End_conversation', + icon: 'balloon-close-top-right', + order: 5, + color: 'danger', + }), + [], + ); +}; diff --git a/apps/meteor/client/hooks/quickActions/useMoveQueueQuickAction.ts b/apps/meteor/client/hooks/quickActions/useMoveQueueQuickAction.ts new file mode 100644 index 00000000000..5ae4cf6b50e --- /dev/null +++ b/apps/meteor/client/hooks/quickActions/useMoveQueueQuickAction.ts @@ -0,0 +1,16 @@ +import { useMemo } from 'react'; + +import { QuickActionsEnum, type QuickActionsActionConfig } from '../../views/room/lib/quickActions'; + +export const useMoveQueueQuickAction = (): QuickActionsActionConfig => { + return useMemo( + () => ({ + groups: ['live'], + id: QuickActionsEnum.MoveQueue, + title: 'Move_queue', + icon: 'burger-arrow-left', + order: 1, + }), + [], + ); +}; diff --git a/apps/meteor/client/hooks/quickActions/useTranscriptQuickAction.ts b/apps/meteor/client/hooks/quickActions/useTranscriptQuickAction.ts new file mode 100644 index 00000000000..7d0a003a21a --- /dev/null +++ b/apps/meteor/client/hooks/quickActions/useTranscriptQuickAction.ts @@ -0,0 +1,28 @@ +import { useMemo } from 'react'; + +import type { QuickActionsActionConfig } from '../../views/room/lib/quickActions'; +import { QuickActionsEnum } from '../../views/room/lib/quickActions'; + +export const useTranscriptQuickAction = (): QuickActionsActionConfig => { + return useMemo( + () => ({ + groups: ['live'], + id: QuickActionsEnum.Transcript, + title: 'Send_transcript', + icon: 'mail-arrow-top-right', + order: 3, + options: [ + { label: 'Send_via_email', id: QuickActionsEnum.TranscriptEmail }, + { + label: 'Export_as_PDF', + id: QuickActionsEnum.TranscriptPDF, + validate: (room) => ({ + tooltip: 'Export_enabled_at_the_end_of_the_conversation', + value: !room?.open, + }), + }, + ], + }), + [], + ); +}; diff --git a/apps/meteor/client/ui.ts b/apps/meteor/client/ui.ts index b69661d50e6..5fbde8626eb 100644 --- a/apps/meteor/client/ui.ts +++ b/apps/meteor/client/ui.ts @@ -1,6 +1,11 @@ +import { useOnHoldChatQuickAction } from '../ee/client/hooks/quickActions/useOnHoldChatQuickAction'; import { useCallsRoomAction } from '../ee/client/hooks/roomActions/useCallsRoomAction'; import { useCannedResponsesRoomAction } from '../ee/client/hooks/roomActions/useCannedResponsesRoomAction'; import { useGameCenterRoomAction } from '../ee/client/hooks/roomActions/useGameCenterRoomAction'; +import { useChatForwardQuickAction } from './hooks/quickActions/useChatForwardQuickAction'; +import { useCloseChatQuickAction } from './hooks/quickActions/useCloseChatQuickAction'; +import { useMoveQueueQuickAction } from './hooks/quickActions/useMoveQueueQuickAction'; +import { useTranscriptQuickAction } from './hooks/quickActions/useTranscriptQuickAction'; import { useAutotranslateRoomAction } from './hooks/roomActions/useAutotranslateRoomAction'; import { useChannelSettingsRoomAction } from './hooks/roomActions/useChannelSettingsRoomAction'; import { useCleanHistoryRoomAction } from './hooks/roomActions/useCleanHistoryRoomAction'; @@ -30,6 +35,7 @@ import { useUserInfoRoomAction } from './hooks/roomActions/useUserInfoRoomAction import { useVoIPRoomInfoRoomAction } from './hooks/roomActions/useVoIPRoomInfoRoomAction'; import { useWebRTCVideoRoomAction } from './hooks/roomActions/useWebRTCVideoRoomAction'; import type { ToolboxActionConfig } from './views/room/lib/Toolbox'; +import type { QuickActionsActionConfig } from './views/room/lib/quickActions'; export const roomActionHooks = [ useAutotranslateRoomAction, @@ -64,3 +70,11 @@ export const roomActionHooks = [ useVoIPRoomInfoRoomAction, useWebRTCVideoRoomAction, ] satisfies (() => ToolboxActionConfig | undefined)[]; + +export const quickActionHooks = [ + useMoveQueueQuickAction, + useChatForwardQuickAction, + useTranscriptQuickAction, + useCloseChatQuickAction, + useOnHoldChatQuickAction, +] satisfies (() => QuickActionsActionConfig | undefined)[]; diff --git a/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx b/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx index a78e7c7546e..cc7df975051 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx +++ b/apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx @@ -48,9 +48,9 @@ const OmnichannelRoomHeader: FC = ({ slots: parentSl ), - posContent: , + posContent: , }), - [isMobile, currentRouteName, parentSlot, room], + [isMobile, currentRouteName, parentSlot], ); return ( diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/ToolBoxActionOptions.tsx b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActionOptions.tsx similarity index 82% rename from apps/meteor/client/views/room/Header/Omnichannel/QuickActions/ToolBoxActionOptions.tsx rename to apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActionOptions.tsx index 96b41cb0df5..c591e615042 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/ToolBoxActionOptions.tsx +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActionOptions.tsx @@ -2,19 +2,18 @@ import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; import { Box, Dropdown, Option } from '@rocket.chat/fuselage'; import { HeaderToolboxAction } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { FC } from 'react'; import React, { memo, useRef } from 'react'; import { useDropdownVisibility } from '../../../../../sidebar/header/hooks/useDropdownVisibility'; -import type { QuickActionsActionOptions } from '../../../lib/QuickActions'; +import type { QuickActionsActionOptions } from '../../../lib/quickActions'; -type ToolBoxActionOptionsProps = { +type QuickActionOptionsProps = { options: QuickActionsActionOptions; action: (id: string) => void; room: IOmnichannelRoom; }; -const ToolBoxActionOptions: FC = ({ options, room, action, ...props }) => { +const QuickActionOptions = ({ options, room, action, ...props }: QuickActionOptionsProps) => { const t = useTranslation(); const reference = useRef(null); const target = useRef(null); @@ -46,4 +45,4 @@ const ToolBoxActionOptions: FC = ({ options, room, ac ); }; -export default memo(ToolBoxActionOptions); +export default memo(QuickActionOptions); diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx index 65d0282e6de..b46a07555c6 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx @@ -1,25 +1,25 @@ -import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; import type { Box } from '@rocket.chat/fuselage'; import { HeaderToolbox, HeaderToolboxAction, HeaderToolboxDivider } from '@rocket.chat/ui-client'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { FC, ComponentProps } from 'react'; +import type { ComponentProps } from 'react'; import React, { memo } from 'react'; -import ToolBoxActionOptions from './ToolBoxActionOptions'; +import { useOmnichannelRoom } from '../../../contexts/RoomContext'; +import QuickActionOptions from './QuickActionOptions'; import { useQuickActions } from './hooks/useQuickActions'; type QuickActionsProps = { - room: IOmnichannelRoom; className?: ComponentProps['className']; }; -const QuickActions: FC = ({ room, className }) => { +const QuickActions = ({ className }: QuickActionsProps) => { const t = useTranslation(); - const { visibleActions, actionDefault } = useQuickActions(room); + const room = useOmnichannelRoom(); + const { quickActions, actionDefault } = useQuickActions(); return ( - {visibleActions.map(({ id, color, icon, title, action = actionDefault, options }, index) => { + {quickActions.map(({ id, color, icon, title, action = actionDefault, options }, index) => { const props = { id, icon, @@ -33,12 +33,12 @@ const QuickActions: FC = ({ room, className }) => { }; if (options) { - return ; + return ; } return ; })} - {visibleActions.length > 0 && } + {quickActions.length > 0 && } ); }; diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx index c8b642e56d9..880a4bea5c8 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx @@ -1,4 +1,3 @@ -import type { IOmnichannelRoom } from '@rocket.chat/core-typings'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useSetModal, @@ -24,26 +23,23 @@ import ForwardChatModal from '../../../../../../components/Omnichannel/modals/Fo import ReturnChatQueueModal from '../../../../../../components/Omnichannel/modals/ReturnChatQueueModal'; import TranscriptModal from '../../../../../../components/Omnichannel/modals/TranscriptModal'; import { useOmnichannelRouteConfig } from '../../../../../../hooks/omnichannel/useOmnichannelRouteConfig'; -import type { QuickActionsActionConfig } from '../../../../lib/QuickActions'; -import { QuickActionsEnum } from '../../../../lib/QuickActions'; -import { useQuickActionsContext } from '../../../../lib/QuickActions/QuickActionsContext'; +import { quickActionHooks } from '../../../../../../ui'; +import { useOmnichannelRoom } from '../../../../contexts/RoomContext'; +import type { QuickActionsActionConfig } from '../../../../lib/quickActions'; +import { QuickActionsEnum } from '../../../../lib/quickActions'; import { usePutChatOnHoldMutation } from './usePutChatOnHoldMutation'; import { useReturnChatToQueueMutation } from './useReturnChatToQueueMutation'; -export const useQuickActions = ( - room: IOmnichannelRoom, -): { - visibleActions: QuickActionsActionConfig[]; - actionDefault: (e: unknown) => void; - getAction: (id: string) => void; +export const useQuickActions = (): { + quickActions: QuickActionsActionConfig[]; + actionDefault: (actionId: string) => void; } => { + const room = useOmnichannelRoom(); const setModal = useSetModal(); const router = useRouter(); const t = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); - const context = useQuickActionsContext(); - const actions = (Array.from(context.actions.values()) as QuickActionsActionConfig[]).sort((a, b) => (a.order || 0) - (b.order || 0)); const [onHoldModalActive, setOnHoldModalActive] = useState(false); @@ -337,21 +333,22 @@ export const useQuickActions = ( return false; }; - const visibleActions = actions.filter((action) => { - const { options, id } = action; - if (options) { - action.options = options.filter(({ id }) => hasPermissionButtons(id)); - } - return hasPermissionButtons(id); - }); + const quickActions = quickActionHooks + .map((quickActionHook) => quickActionHook()) + .filter((quickAction): quickAction is QuickActionsActionConfig => !!quickAction) + .filter((action) => { + const { options, id } = action; + if (options) { + action.options = options.filter(({ id }) => hasPermissionButtons(id)); + } - const actionDefault = useMutableCallback((actionId) => { - handleAction(actionId); - }); + return hasPermissionButtons(id); + }) + .sort((a, b) => (a.order ?? 0) - (b.order ?? 0)); - const getAction = useMutableCallback((id) => { - handleAction(id); + const actionDefault = useMutableCallback((actionId: string) => { + handleAction(actionId); }); - return { visibleActions, actionDefault, getAction }; + return { quickActions, actionDefault }; }; diff --git a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts index 128c5683366..5ec9f10150e 100644 --- a/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts +++ b/apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts @@ -1 +1,3 @@ -export { default } from './QuickActions'; +import { lazy } from 'react'; + +export default lazy(() => import('./QuickActions')); diff --git a/apps/meteor/client/views/room/lib/QuickActions/QuickActionsContext.tsx b/apps/meteor/client/views/room/lib/QuickActions/QuickActionsContext.tsx deleted file mode 100644 index 669fdf43e08..00000000000 --- a/apps/meteor/client/views/room/lib/QuickActions/QuickActionsContext.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { EventHandlerOf } from '@rocket.chat/emitter'; -import { createContext, useContext } from 'react'; - -import type { QuickActionsActionConfig, QuickActionsAction, Events } from '.'; -import { actions, listen } from '.'; - -import './defaultActions'; - -type QuickActionsEventHandler = (handler: EventHandlerOf) => unknown; - -type QuickActionsContextValue = { - actions: Map; - listen: QuickActionsEventHandler; -}; - -const QuickActionsContext = createContext({ - actions, - listen, -}); - -export const useQuickActionsContext = (): QuickActionsContextValue => useContext(QuickActionsContext); diff --git a/apps/meteor/client/views/room/lib/QuickActions/defaultActions.ts b/apps/meteor/client/views/room/lib/QuickActions/defaultActions.ts deleted file mode 100644 index e328c1b7dad..00000000000 --- a/apps/meteor/client/views/room/lib/QuickActions/defaultActions.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { addAction, QuickActionsEnum } from '.'; - -addAction(QuickActionsEnum.MoveQueue, { - groups: ['live'], - id: QuickActionsEnum.MoveQueue, - title: 'Move_queue', - icon: 'burger-arrow-left', - order: 1, -}); - -addAction(QuickActionsEnum.ChatForward, { - groups: ['live'], - id: QuickActionsEnum.ChatForward, - title: 'Forward_chat', - icon: 'balloon-arrow-top-right', - order: 2, -}); - -addAction(QuickActionsEnum.Transcript, { - groups: ['live'], - id: QuickActionsEnum.Transcript, - title: 'Send_transcript', - icon: 'mail-arrow-top-right', - order: 3, - options: [ - { label: 'Send_via_email', id: QuickActionsEnum.TranscriptEmail }, - { - label: 'Export_as_PDF', - id: QuickActionsEnum.TranscriptPDF, - validate: (room) => ({ - tooltip: 'Export_enabled_at_the_end_of_the_conversation', - value: !room?.open, - }), - }, - ], -}); - -addAction(QuickActionsEnum.CloseChat, { - groups: ['live'], - id: QuickActionsEnum.CloseChat, - title: 'End_conversation', - icon: 'balloon-close-top-right', - order: 5, - color: 'danger', -}); diff --git a/apps/meteor/client/views/room/lib/Toolbox/index.tsx b/apps/meteor/client/views/room/lib/Toolbox/index.tsx index 06f18c9e90b..a805172d63e 100644 --- a/apps/meteor/client/views/room/lib/Toolbox/index.tsx +++ b/apps/meteor/client/views/room/lib/Toolbox/index.tsx @@ -46,8 +46,8 @@ export type ToolboxActionConfig = { export type ToolboxAction = ToolboxHook | ToolboxActionConfig; -const { listen, add: addAction, store: actions } = generator(); +const { listen, store: actions } = generator(); export type Events = GeneratorEvents; -export { listen, addAction, actions }; +export { listen, actions }; diff --git a/apps/meteor/client/views/room/lib/QuickActions/index.tsx b/apps/meteor/client/views/room/lib/quickActions.tsx similarity index 54% rename from apps/meteor/client/views/room/lib/QuickActions/index.tsx rename to apps/meteor/client/views/room/lib/quickActions.tsx index 9f3a67f207d..5fc23f41057 100644 --- a/apps/meteor/client/views/room/lib/QuickActions/index.tsx +++ b/apps/meteor/client/views/room/lib/quickActions.tsx @@ -1,12 +1,7 @@ import type { IRoom } from '@rocket.chat/core-typings'; +import type { Keys as IconName } from '@rocket.chat/icons'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; -import type { ToolboxActionConfig } from '../Toolbox'; -import type { Events as GeneratorEvents } from '../Toolbox/generator'; -import { generator } from '../Toolbox/generator'; - -type QuickActionsHook = ({ room }: { room: IRoom }) => QuickActionsActionConfig | null; - export type QuickActionsActionOptions = Array<{ id: string; label: TranslationKey; @@ -14,21 +9,18 @@ export type QuickActionsActionOptions = Array<{ validate?: (room: IRoom) => { value: boolean; tooltip: TranslationKey }; }>; -export type QuickActionsActionConfig = ToolboxActionConfig & { +export type QuickActionsActionConfig = { + id: string; + icon?: IconName; + title: TranslationKey; + order?: number; + featured?: boolean; action?: (id?: QuickActionsActionConfig['id']) => void; groups: Array<'live'>; color?: string; options?: QuickActionsActionOptions; }; -export type QuickActionsAction = QuickActionsHook | QuickActionsActionConfig; - -const { listen, add: addAction, remove: deleteAction, store: actions } = generator(); - -export type Events = GeneratorEvents; - -export { listen, addAction, deleteAction, actions }; - export enum QuickActionsEnum { MoveQueue = 'rocket-move-to-queue', ChatForward = 'rocket-chat-forward', diff --git a/apps/meteor/ee/app/livechat-enterprise/client/index.js b/apps/meteor/ee/app/livechat-enterprise/client/index.js deleted file mode 100644 index 5266c01d9e9..00000000000 --- a/apps/meteor/ee/app/livechat-enterprise/client/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import { hasLicense } from '../../license/client'; -import '../lib/messageTypes'; -import './startup'; - -hasLicense('livechat-enterprise').then((enabled) => { - if (!enabled) { - return; - } - - require('./views/livechatSideNavItems'); - require('./views/business-hours/Multiple'); - require('../lib/QuickActions/defaultActions'); - require('./messageTypes'); -}); diff --git a/apps/meteor/ee/app/livechat-enterprise/client/index.ts b/apps/meteor/ee/app/livechat-enterprise/client/index.ts new file mode 100644 index 00000000000..1fc3ef70413 --- /dev/null +++ b/apps/meteor/ee/app/livechat-enterprise/client/index.ts @@ -0,0 +1,11 @@ +import { hasLicense } from '../../license/client'; +import '../lib/messageTypes'; +import './startup'; + +void hasLicense('livechat-enterprise').then((enabled) => { + if (!enabled) { + return; + } + + return Promise.all([import('./views/livechatSideNavItems'), import('./views/business-hours/Multiple'), import('./messageTypes')]); +}); diff --git a/apps/meteor/ee/app/livechat-enterprise/lib/QuickActions/defaultActions.ts b/apps/meteor/ee/app/livechat-enterprise/lib/QuickActions/defaultActions.ts deleted file mode 100644 index e592689f22e..00000000000 --- a/apps/meteor/ee/app/livechat-enterprise/lib/QuickActions/defaultActions.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { addAction, QuickActionsEnum } from '../../../../../client/views/room/lib/QuickActions'; - -addAction(QuickActionsEnum.OnHoldChat, { - groups: ['live'], - id: QuickActionsEnum.OnHoldChat, - title: 'Omnichannel_onHold_Chat', - icon: 'pause-unfilled', - order: 4, -}); diff --git a/apps/meteor/ee/client/hooks/quickActions/useOnHoldChatQuickAction.ts b/apps/meteor/ee/client/hooks/quickActions/useOnHoldChatQuickAction.ts new file mode 100644 index 00000000000..7a3f5bbd51f --- /dev/null +++ b/apps/meteor/ee/client/hooks/quickActions/useOnHoldChatQuickAction.ts @@ -0,0 +1,22 @@ +import { useMemo } from 'react'; + +import { QuickActionsEnum, type QuickActionsActionConfig } from '../../../../client/views/room/lib/quickActions'; +import { useHasLicenseModule } from '../useHasLicenseModule'; + +export const useOnHoldChatQuickAction = (): QuickActionsActionConfig | undefined => { + const licensed = useHasLicenseModule('livechat-enterprise') === true; + + return useMemo(() => { + if (!licensed) { + return undefined; + } + + return { + groups: ['live'], + id: QuickActionsEnum.OnHoldChat, + title: 'Omnichannel_onHold_Chat', + icon: 'pause-unfilled', + order: 4, + }; + }, [licensed]); +};