diff --git a/.changeset/thick-spoons-compete.md b/.changeset/thick-spoons-compete.md new file mode 100644 index 000000000000..cf6e9eb2697d --- /dev/null +++ b/.changeset/thick-spoons-compete.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': minor +--- + +Added new Omnichannel setting 'Hide conversation after closing' diff --git a/apps/meteor/client/hooks/omnichannel/useOmnichannelCloseRoute.ts b/apps/meteor/client/hooks/omnichannel/useOmnichannelCloseRoute.ts new file mode 100644 index 000000000000..746a62bd87e6 --- /dev/null +++ b/apps/meteor/client/hooks/omnichannel/useOmnichannelCloseRoute.ts @@ -0,0 +1,23 @@ +import { useRouter, useUserPreference } from '@rocket.chat/ui-contexts'; +import { useCallback } from 'react'; + +export const useOmnichannelCloseRoute = () => { + const hideConversationAfterClosing = useUserPreference('omnichannelHideConversationAfterClosing') ?? true; + const router = useRouter(); + + const navigateHome = useCallback(() => { + if (!hideConversationAfterClosing) { + return; + } + + const routeName = router.getRouteName(); + + if (routeName === 'omnichannel-current-chats') { + router.navigate({ name: 'omnichannel-current-chats' }); + } else { + router.navigate({ name: 'home' }); + } + }, [hideConversationAfterClosing, router]); + + return { navigateHome }; +}; diff --git a/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.tsx b/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.tsx index 515446a154f6..d448a180f834 100644 --- a/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.tsx +++ b/apps/meteor/client/views/account/omnichannel/OmnichannelPreferencesPage.tsx @@ -6,6 +6,7 @@ import { useForm, FormProvider } from 'react-hook-form'; import Page from '../../../components/Page'; import PreferencesConversationTranscript from './PreferencesConversationTranscript'; +import { PreferencesGeneral } from './PreferencesGeneral'; type FormData = { omnichannelTranscriptPDF: boolean; @@ -18,9 +19,10 @@ const OmnichannelPreferencesPage = (): ReactElement => { const omnichannelTranscriptPDF = useUserPreference('omnichannelTranscriptPDF') ?? false; const omnichannelTranscriptEmail = useUserPreference('omnichannelTranscriptEmail') ?? false; + const omnichannelHideConversationAfterClosing = useUserPreference('omnichannelHideConversationAfterClosing') ?? true; const methods = useForm({ - defaultValues: { omnichannelTranscriptPDF, omnichannelTranscriptEmail }, + defaultValues: { omnichannelTranscriptPDF, omnichannelTranscriptEmail, omnichannelHideConversationAfterClosing }, }); const { @@ -48,6 +50,7 @@ const OmnichannelPreferencesPage = (): ReactElement => { + diff --git a/apps/meteor/client/views/account/omnichannel/PreferencesGeneral.tsx b/apps/meteor/client/views/account/omnichannel/PreferencesGeneral.tsx new file mode 100644 index 000000000000..67c06bd2c5b2 --- /dev/null +++ b/apps/meteor/client/views/account/omnichannel/PreferencesGeneral.tsx @@ -0,0 +1,26 @@ +import { Box, Field, FieldGroup, FieldHint, FieldLabel, FieldRow, ToggleSwitch } from '@rocket.chat/fuselage'; +import { useUniqueId } from '@rocket.chat/fuselage-hooks'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import type { ReactElement } from 'react'; +import React from 'react'; +import { useFormContext } from 'react-hook-form'; + +export const PreferencesGeneral = (): ReactElement => { + const t = useTranslation(); + const { register } = useFormContext(); + const omnichannelHideAfterClosing = useUniqueId(); + + return ( + + + + {t('Omnichannel_hide_conversation_after_closing')} + + + + + {t('Omnichannel_hide_conversation_after_closing_description')} + + + ); +}; diff --git a/apps/meteor/client/views/room/body/hooks/useGoToHomeOnRemoved.ts b/apps/meteor/client/views/room/body/hooks/useGoToHomeOnRemoved.ts index a087d288d0d7..068c97a2de4b 100644 --- a/apps/meteor/client/views/room/body/hooks/useGoToHomeOnRemoved.ts +++ b/apps/meteor/client/views/room/body/hooks/useGoToHomeOnRemoved.ts @@ -1,9 +1,9 @@ -import type { IRoom } from '@rocket.chat/core-typings'; +import { isOmnichannelRoom, type IRoom } from '@rocket.chat/core-typings'; import { useRoute, useStream, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; import { useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; -const IGNORED_ROOMS = ['l', 'v']; +import { useOmnichannelCloseRoute } from '../../../../hooks/omnichannel/useOmnichannelCloseRoute'; export function useGoToHomeOnRemoved(room: IRoom, userId: string | undefined): void { const homeRouter = useRoute('home'); @@ -11,6 +11,7 @@ export function useGoToHomeOnRemoved(room: IRoom, userId: string | undefined): v const dispatchToastMessage = useToastMessageDispatch(); const subscribeToNotifyUser = useStream('notify-user'); const t = useTranslation(); + const { navigateHome } = useOmnichannelCloseRoute(); useEffect(() => { if (!userId) { @@ -21,19 +22,35 @@ export function useGoToHomeOnRemoved(room: IRoom, userId: string | undefined): v if (event === 'removed' && subscription.rid === room._id) { queryClient.invalidateQueries(['rooms', room._id]); - if (!IGNORED_ROOMS.includes(room.t)) { - dispatchToastMessage({ - type: 'info', - message: t('You_have_been_removed_from__roomName_', { - roomName: room?.fname || room?.name || '', - }), - }); + if (isOmnichannelRoom(room)) { + navigateHome(); + return; } + dispatchToastMessage({ + type: 'info', + message: t('You_have_been_removed_from__roomName_', { + roomName: room?.fname || room?.name || '', + }), + }); + homeRouter.push({}); } }); return unSubscribeFromNotifyUser; - }, [userId, homeRouter, subscribeToNotifyUser, room._id, room?.fname, room?.name, t, dispatchToastMessage, queryClient, room.t]); + }, [ + userId, + homeRouter, + subscribeToNotifyUser, + room._id, + room?.fname, + room?.name, + t, + dispatchToastMessage, + queryClient, + room.t, + room, + navigateHome, + ]); } diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 00398e8c2f66..9e8e00500c97 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3099,6 +3099,8 @@ "Omnichannel_sorting_disclaimer": "Omnichannel conversations are sorted by {{sortingMechanism}}, edit a room to apply.", "Livechat_online": "Omnichannel on-line", "Omnichannel_placed_chat_on_hold": "Chat On Hold: {{comment}}", + "Omnichannel_hide_conversation_after_closing": "Hide conversation after closing", + "Omnichannel_hide_conversation_after_closing_description": "After closing the conversation you will be redirected to Home.", "Livechat_Queue": "Omnichannel Queue", "Livechat_registration_form": "Registration Form", "Livechat_registration_form_message": "Registration Form Message", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json index de5c2356a6b9..e5b8f7e2bdcd 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/pt-BR.i18n.json @@ -2673,6 +2673,8 @@ "Omnichannel_sorting_disclaimer": "Conversar do Omnichannel são ordenadas por {{sortingMechanism}}, edite a sala para alterar.", "Livechat_online": "Omnichannel online", "Omnichannel_placed_chat_on_hold": "Conversa em espera: {{comment}}", + "Omnichannel_hide_conversation_after_closing": "Ocultar conversa após fechar", + "Omnichannel_hide_conversation_after_closing_description": "Após encerrar a conversa, você será redirecionado para a página inicial.", "Livechat_Queue": "Fila omnichannel", "Livechat_registration_form": "Formulário de registro", "Livechat_registration_form_message": "Mensagem do formulário de registro", diff --git a/apps/meteor/server/methods/saveUserPreferences.ts b/apps/meteor/server/methods/saveUserPreferences.ts index 71abe7bea3b1..814627a745bc 100644 --- a/apps/meteor/server/methods/saveUserPreferences.ts +++ b/apps/meteor/server/methods/saveUserPreferences.ts @@ -86,6 +86,7 @@ export const saveUserPreferences = async (settings: Partial, us fontSize: Match.Optional(String), omnichannelTranscriptEmail: Match.Optional(Boolean), omnichannelTranscriptPDF: Match.Optional(Boolean), + omnichannelHideConversationAfterClosing: Match.Optional(Boolean), notifyCalendarEvents: Match.Optional(Boolean), enableMobileRinging: Match.Optional(Boolean), mentionsWithSymbol: Match.Optional(Boolean), diff --git a/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts b/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts index bb32dc27fb04..1c89fdc04d5d 100644 --- a/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts +++ b/packages/rest-typings/src/v1/users/UsersSetPreferenceParamsPOST.ts @@ -49,6 +49,7 @@ export type UsersSetPreferencesParamsPOST = { idleTimeLimit?: number; omnichannelTranscriptEmail?: boolean; omnichannelTranscriptPDF?: boolean; + omnichannelHideConversationAfterClosing?: boolean; enableMobileRinging?: boolean; mentionsWithSymbol?: boolean; }; @@ -242,6 +243,10 @@ const UsersSetPreferencesParamsPostSchema = { type: 'boolean', nullable: true, }, + omnichannelHideConversationAfterClosing: { + type: 'boolean', + nullable: true, + }, enableMobileRinging: { type: 'boolean', nullable: true,