refactor: Migrate quick actions to hooks (#29948)

pull/29932/head^2
Tasso Evangelista 2 years ago committed by GitHub
parent 3d039db6af
commit 0187ef0a4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      apps/meteor/client/hooks/quickActions/useChatForwardQuickAction.ts
  2. 17
      apps/meteor/client/hooks/quickActions/useCloseChatQuickAction.ts
  3. 16
      apps/meteor/client/hooks/quickActions/useMoveQueueQuickAction.ts
  4. 28
      apps/meteor/client/hooks/quickActions/useTranscriptQuickAction.ts
  5. 14
      apps/meteor/client/ui.ts
  6. 4
      apps/meteor/client/views/room/Header/Omnichannel/OmnichannelRoomHeader.tsx
  7. 9
      apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActionOptions.tsx
  8. 18
      apps/meteor/client/views/room/Header/Omnichannel/QuickActions/QuickActions.tsx
  9. 47
      apps/meteor/client/views/room/Header/Omnichannel/QuickActions/hooks/useQuickActions.tsx
  10. 4
      apps/meteor/client/views/room/Header/Omnichannel/QuickActions/index.ts
  11. 21
      apps/meteor/client/views/room/lib/QuickActions/QuickActionsContext.tsx
  12. 45
      apps/meteor/client/views/room/lib/QuickActions/defaultActions.ts
  13. 4
      apps/meteor/client/views/room/lib/Toolbox/index.tsx
  14. 22
      apps/meteor/client/views/room/lib/quickActions.tsx
  15. 14
      apps/meteor/ee/app/livechat-enterprise/client/index.js
  16. 11
      apps/meteor/ee/app/livechat-enterprise/client/index.ts
  17. 9
      apps/meteor/ee/app/livechat-enterprise/lib/QuickActions/defaultActions.ts
  18. 22
      apps/meteor/ee/client/hooks/quickActions/useOnHoldChatQuickAction.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,
}),
[],
);
};

@ -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',
}),
[],
);
};

@ -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,
}),
[],
);
};

@ -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,
}),
},
],
}),
[],
);
};

@ -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)[];

@ -48,9 +48,9 @@ const OmnichannelRoomHeader: FC<OmnichannelRoomHeaderProps> = ({ slots: parentSl
<BackButton routeName={currentRouteName} />
</HeaderToolbox>
),
posContent: <QuickActions room={room} />,
posContent: <QuickActions />,
}),
[isMobile, currentRouteName, parentSlot, room],
[isMobile, currentRouteName, parentSlot],
);
return (

@ -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<ToolBoxActionOptionsProps> = ({ 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<ToolBoxActionOptionsProps> = ({ options, room, ac
);
};
export default memo(ToolBoxActionOptions);
export default memo(QuickActionOptions);

@ -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<typeof Box>['className'];
};
const QuickActions: FC<QuickActionsProps> = ({ room, className }) => {
const QuickActions = ({ className }: QuickActionsProps) => {
const t = useTranslation();
const { visibleActions, actionDefault } = useQuickActions(room);
const room = useOmnichannelRoom();
const { quickActions, actionDefault } = useQuickActions();
return (
<HeaderToolbox aria-label={t('Omnichannel_quick_actions')}>
{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<QuickActionsProps> = ({ room, className }) => {
};
if (options) {
return <ToolBoxActionOptions options={options} {...props} key={id} />;
return <QuickActionOptions options={options} {...props} key={id} />;
}
return <HeaderToolboxAction {...props} key={id} />;
})}
{visibleActions.length > 0 && <HeaderToolboxDivider />}
{quickActions.length > 0 && <HeaderToolboxDivider />}
</HeaderToolbox>
);
};

@ -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 };
};

@ -1 +1,3 @@
export { default } from './QuickActions';
import { lazy } from 'react';
export default lazy(() => import('./QuickActions'));

@ -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<Events, 'change'>) => unknown;
type QuickActionsContextValue = {
actions: Map<QuickActionsActionConfig['id'], QuickActionsAction>;
listen: QuickActionsEventHandler;
};
const QuickActionsContext = createContext<QuickActionsContextValue>({
actions,
listen,
});
export const useQuickActionsContext = (): QuickActionsContextValue => useContext(QuickActionsContext);

@ -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',
});

@ -46,8 +46,8 @@ export type ToolboxActionConfig = {
export type ToolboxAction = ToolboxHook | ToolboxActionConfig;
const { listen, add: addAction, store: actions } = generator<ToolboxAction>();
const { listen, store: actions } = generator<ToolboxAction>();
export type Events = GeneratorEvents<ToolboxAction>;
export { listen, addAction, actions };
export { listen, actions };

@ -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<QuickActionsAction>();
export type Events = GeneratorEvents<QuickActionsAction>;
export { listen, addAction, deleteAction, actions };
export enum QuickActionsEnum {
MoveQueue = 'rocket-move-to-queue',
ChatForward = 'rocket-chat-forward',

@ -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');
});

@ -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')]);
});

@ -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,
});

@ -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]);
};
Loading…
Cancel
Save