Skip to content

Commit

Permalink
chore: Improve Omnichannel Contact Center routing (#33943)
Browse files Browse the repository at this point in the history
  • Loading branch information
dougfabris authored Nov 13, 2024
1 parent 5637551 commit 6d4a6be
Show file tree
Hide file tree
Showing 19 changed files with 192 additions and 185 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { lazy, useMemo } from 'react';

import type { RoomToolboxActionConfig } from '../../views/room/contexts/RoomToolboxContext';

const ContactsContextualBar = lazy(() => import('../../views/omnichannel/directory/contacts/contextualBar/ContactsContextualBar'));
const ContactInfoRouter = lazy(() => import('../../views/omnichannel/directory/contacts/contactInfo/ContactInfoRouter'));

export const useContactProfileRoomAction = () => {
return useMemo(
Expand All @@ -11,7 +11,7 @@ export const useContactProfileRoomAction = () => {
groups: ['live' /* , 'voip'*/],
title: 'Contact_Info',
icon: 'user',
tabComponent: ContactsContextualBar,
tabComponent: ContactInfoRouter,
order: 1,
}),
[],
Expand Down
12 changes: 5 additions & 7 deletions apps/meteor/client/startup/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const IndexRoute = lazy(() => import('../views/root/IndexRoute'));
const MeetRoute = lazy(() => import('../views/meet/MeetRoute'));
const HomePage = lazy(() => import('../views/home/HomePage'));
const DirectoryPage = lazy(() => import('../views/directory'));
const OmnichannelDirectoryPage = lazy(() => import('../views/omnichannel/directory/OmnichannelDirectoryPage'));
const OmnichannelDirectoryRouter = lazy(() => import('../views/omnichannel/directory/OmnichannelDirectoryRouter'));
const OmnichannelQueueList = lazy(() => import('../views/omnichannel/queueList'));
const CMSPage = lazy(() => import('@rocket.chat/web-ui-registration').then(({ CMSPage }) => ({ default: CMSPage })));
const SecretURLPage = lazy(() => import('../views/invite/SecretURLPage'));
Expand Down Expand Up @@ -48,10 +48,8 @@ declare module '@rocket.chat/ui-contexts' {
pattern: '/directory/:tab?';
};
'omnichannel-directory': {
pathname: `/omnichannel-directory${`/${string}` | ''}${`/${string}` | ''}${`/${string}` | ''}${`/${string}` | ''}${
| `/${string}`
| ''}`;
pattern: '/omnichannel-directory/:page?/:bar?/:id?/:tab?/:context?';
pathname: `/omnichannel-directory${`/${string}` | ''}${`/${string}` | ''}${`/${string}` | ''}`;
pattern: '/omnichannel-directory/:tab?/:context?/:id?/';
};
'livechat-queue': {
pathname: '/livechat-queue';
Expand Down Expand Up @@ -153,11 +151,11 @@ router.defineRoutes([
),
},
{
path: '/omnichannel-directory/:page?/:bar?/:id?/:tab?/:context?',
path: '/omnichannel-directory/:tab?/:context?/:id?/',
id: 'omnichannel-directory',
element: appLayout.wrap(
<MainLayout>
<OmnichannelDirectoryPage />
<OmnichannelDirectoryRouter />
</MainLayout>,
),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import { VoipInfo } from './calls/contextualBar/VoipInfo';
import { FormSkeleton } from './components/FormSkeleton';

const CallsContextualBarDirectory = () => {
const directoryRoute = useRoute('omnichannel-directory');
const { t } = useTranslation();

const bar = useRouteParameter('bar') || 'info';
const id = useRouteParameter('id');
const token = useSearchParameter('token');
const context = useRouteParameter('context');

const { t } = useTranslation();
const directoryRoute = useRoute('omnichannel-directory');

const handleClose = (): void => {
directoryRoute.push({ page: 'calls' });
directoryRoute.push({ tab: 'calls' });
};

const query = useMemo(
Expand All @@ -34,7 +34,7 @@ const CallsContextualBarDirectory = () => {

const { value: data, phase: state, error } = useEndpointData(`/v1/voip/room`, { params: query });

if (bar === 'view' && id) {
if (context === 'view' && id) {
return <Call rid={id} />;
}

Expand All @@ -52,7 +52,7 @@ const CallsContextualBarDirectory = () => {

const room = data.room as unknown as IVoipRoom; // TODO Check why types are incompatible even though the endpoint returns an IVoipRooms

return <Contextualbar>{bar === 'info' && <VoipInfo room={room} onClickClose={handleClose} />}</Contextualbar>;
return <Contextualbar>{context === 'info' && <VoipInfo room={room} onClickClose={handleClose} />}</Contextualbar>;
};

export default CallsContextualBarDirectory;
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,23 @@ import { RoomEditWithData } from './chats/contextualBar/RoomEdit';
import { FormSkeleton } from './components';
import { useOmnichannelRoomInfo } from './hooks/useOmnichannelRoomInfo';

type ChatsContextualBarProps = { chatReload?: () => void };
const ChatsContextualBar = ({ chatReload }: { chatReload?: () => void }) => {
const { t } = useTranslation();

const ChatsContextualBar = ({ chatReload }: ChatsContextualBarProps) => {
const directoryRoute = useRoute('omnichannel-directory');

const bar = useRouteParameter('bar') || 'info';
const context = useRouteParameter('context');
const id = useRouteParameter('id') || '';

const { t } = useTranslation();

const openInRoom = (): void => {
id && directoryRoute.push({ page: 'chats', id, bar: 'view' });
};
const openInRoom = () => id && directoryRoute.push({ tab: 'chats', id, context: 'view' });

const handleChatsContextualbarCloseButtonClick = (): void => {
directoryRoute.push({ page: 'chats' });
};
const handleClose = () => directoryRoute.push({ tab: 'chats' });

const handleChatsContextualbarBackButtonClick = (): void => {
id && directoryRoute.push({ page: 'chats', id, bar: 'info' });
};
const handleCancel = () => id && directoryRoute.push({ tab: 'chats', id, context: 'info' });

const { data: room, isLoading, isError, refetch: reloadInfo } = useOmnichannelRoomInfo(id);

if (bar === 'view' && id) {
if (context === 'view' && id) {
return <Chat rid={id} />;
}

Expand All @@ -60,25 +52,23 @@ const ChatsContextualBar = ({ chatReload }: ChatsContextualBarProps) => {
return (
<Contextualbar>
<ContextualbarHeader expanded>
{bar === 'info' && (
{context === 'info' && (
<>
<ContextualbarIcon name='info-circled' />
<ContextualbarTitle>{t('Room_Info')}</ContextualbarTitle>
<ContextualbarAction title={t('View_full_conversation')} name='new-window' onClick={openInRoom} />
</>
)}
{bar === 'edit' && (
{context === 'edit' && (
<>
<ContextualbarIcon name='pencil' />
<ContextualbarTitle>{t('edit-room')}</ContextualbarTitle>
</>
)}
<ContextualbarClose onClick={handleChatsContextualbarCloseButtonClick} />
<ContextualbarClose onClick={handleClose} />
</ContextualbarHeader>
{bar === 'info' && <ChatInfoDirectory id={id} room={room} />}
{bar === 'edit' && (
<RoomEditWithData id={id} reload={chatReload} reloadInfo={reloadInfo} onClose={handleChatsContextualbarBackButtonClick} />
)}
{context === 'info' && <ChatInfoDirectory id={id} room={room} />}
{context === 'edit' && id && <RoomEditWithData id={id} reload={chatReload} reloadInfo={reloadInfo} onClose={handleCancel} />}
</Contextualbar>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import {
ContextualbarTitle,
ContextualbarClose,
} from '../../../components/Contextualbar';
import ContactEditWithData from './contacts/contextualBar/ContactEditWithData';
import ContactInfo from './contacts/contextualBar/ContactInfo';
import ContactNewEdit from './contacts/contextualBar/ContactNewEdit';
import ContactInfo from './contacts/contactInfo/ContactInfo';
import EditContactInfo from './contacts/contactInfo/EditContactInfo';
import EditContactInfoWithData from './contacts/contactInfo/EditContactInfoWithData';

const HEADER_OPTIONS = {
new: { icon: 'user', title: 'New_contact' },
Expand All @@ -22,18 +22,19 @@ const HEADER_OPTIONS = {
type BarOptions = keyof typeof HEADER_OPTIONS;

const ContactContextualBar = () => {
const { t } = useTranslation();

const directoryRoute = useRoute('omnichannel-directory');
const bar = (useRouteParameter('bar') || 'info') as BarOptions;
const contactId = useRouteParameter('id') || '';
const context = useRouteParameter('context');

const { t } = useTranslation();

const handleContactsContextualbarCloseButtonClick = () => {
directoryRoute.push({ page: 'contacts' });
const handleClose = () => {
directoryRoute.push({ tab: 'contacts' });
};

const handleContactsContextualbarBackButtonClick = () => {
directoryRoute.push({ page: 'contacts', id: contactId, bar: 'info' });
const handleCancel = () => {
directoryRoute.push({ tab: 'contacts', context: 'info', id: contactId });
};

const header = useMemo(() => HEADER_OPTIONS[bar] || HEADER_OPTIONS.info, [bar]);
Expand All @@ -43,11 +44,11 @@ const ContactContextualBar = () => {
<ContextualbarHeader>
<ContextualbarIcon name={header.icon} />
<ContextualbarTitle>{t(header.title)}</ContextualbarTitle>
<ContextualbarClose onClick={handleContactsContextualbarCloseButtonClick} />
<ContextualbarClose onClick={handleClose} />
</ContextualbarHeader>
{bar === 'new' && <ContactNewEdit id={contactId} close={handleContactsContextualbarCloseButtonClick} />}
{bar === 'info' && <ContactInfo id={contactId} />}
{bar === 'edit' && <ContactEditWithData id={contactId} close={handleContactsContextualbarBackButtonClick} />}
{context === 'new' && <EditContactInfo id={contactId} onCancel={handleClose} />}
{context === 'edit' && <EditContactInfoWithData id={contactId} onCancel={handleCancel} />}
{context !== 'new' && context !== 'edit' && <ContactInfo id={contactId} />}
</Contextualbar>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ import CallsContextualBarDirectory from './CallsContextualBarDirectory';
import ChatsContextualBar from './ChatsContextualBar';
import ContactContextualBar from './ContactContextualBar';

type ContextualBarProps = {
chatReload?: () => void;
};

const ContextualBar = ({ chatReload }: ContextualBarProps) => {
const page = useRouteParameter('page');
const ContextualBarRouter = ({ chatReload }: { chatReload?: () => void }) => {
const tab = useRouteParameter('tab');

switch (page) {
switch (tab) {
case 'contacts':
return <ContactContextualBar />;
case 'chats':
Expand All @@ -24,4 +20,4 @@ const ContextualBar = ({ chatReload }: ContextualBarProps) => {
}
};

export default ContextualBar;
export default ContextualBarRouter;
Original file line number Diff line number Diff line change
@@ -1,71 +1,66 @@
import { Tabs } from '@rocket.chat/fuselage';
import { useRouteParameter, usePermission, useTranslation, useRouter } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import { useRouteParameter, useTranslation, useRouter } from '@rocket.chat/ui-contexts';
import React, { useEffect, useCallback } from 'react';

import { ContextualbarDialog } from '../../../components/Contextualbar';
import { Page, PageHeader, PageContent } from '../../../components/Page';
import { queryClient } from '../../../lib/queryClient';
import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
import ContextualBar from './ContextualBar';
import ContextualBarRouter from './ContextualBarRouter';
import CallTab from './calls/CallTab';
import ChatTab from './chats/ChatTab';
import ContactTab from './contacts/ContactTab';

const DEFAULT_TAB = 'contacts';

const OmnichannelDirectoryPage = (): ReactElement => {
const OmnichannelDirectoryPage = () => {
const t = useTranslation();
const router = useRouter();
const page = useRouteParameter('page');
const bar = useRouteParameter('bar');
const canViewDirectory = usePermission('view-omnichannel-contact-center');
const tab = useRouteParameter('tab');
const context = useRouteParameter('context');

useEffect(
() =>
router.subscribeToRouteChange(() => {
if (router.getRouteName() !== 'omnichannel-directory' || !!router.getRouteParameters().page) {
if (router.getRouteName() !== 'omnichannel-directory' || !!router.getRouteParameters().tab) {
return;
}

router.navigate({
name: 'omnichannel-directory',
params: { page: DEFAULT_TAB },
params: { tab: DEFAULT_TAB },
});
}),
[router],
);

const handleTabClick = useCallback((tab) => () => router.navigate({ name: 'omnichannel-directory', params: { tab } }), [router]);
const handleTabClick = useCallback((tab) => router.navigate({ name: 'omnichannel-directory', params: { tab } }), [router]);

const chatReload = () => queryClient.invalidateQueries({ queryKey: ['current-chats'] });

if (!canViewDirectory) {
return <NotAuthorizedPage />;
}

return (
<Page flexDirection='row'>
<Page>
<PageHeader title={t('Omnichannel_Contact_Center')} />
<Tabs flexShrink={0}>
<Tabs.Item selected={page === 'contacts'} onClick={handleTabClick('contacts')}>
<Tabs.Item selected={tab === 'contacts'} onClick={() => handleTabClick('contacts')}>
{t('Contacts')}
</Tabs.Item>
<Tabs.Item selected={page === 'chats'} onClick={handleTabClick('chats')}>
{t('Chats' as 'color')}
<Tabs.Item selected={tab === 'chats'} onClick={() => handleTabClick('chats')}>
{t('Chats' as any /* TODO: this is going to change to Conversations */)}
</Tabs.Item>
<Tabs.Item selected={page === 'calls'} onClick={handleTabClick('calls')}>
{t('Calls' as 'color')}
<Tabs.Item selected={tab === 'calls'} onClick={() => handleTabClick('calls')}>
{t('Calls')}
</Tabs.Item>
</Tabs>
<PageContent>
{(page === 'contacts' && <ContactTab />) || (page === 'chats' && <ChatTab />) || (page === 'calls' && <CallTab />)}
{tab === 'contacts' && <ContactTab />}
{tab === 'chats' && <ChatTab />}
{tab === 'calls' && <CallTab />}
</PageContent>
</Page>
{bar && (
{context && (
<ContextualbarDialog>
<ContextualBar chatReload={chatReload} />
<ContextualBarRouter chatReload={chatReload} />
</ContextualbarDialog>
)}
</Page>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { usePermission } from '@rocket.chat/ui-contexts';
import React from 'react';

import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage';
import OmnichannelDirectoryPage from './OmnichannelDirectoryPage';

const OmnichannelDirectoryRouter = () => {
const canViewDirectory = usePermission('view-omnichannel-contact-center');

if (!canViewDirectory) {
return <NotAuthorizedPage />;
}

return <OmnichannelDirectoryPage />;
};

export default OmnichannelDirectoryRouter;
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ const CallTable = () => {
const onRowClick = useMutableCallback((id, token) => {
directoryRoute.push(
{
page: 'calls',
bar: 'info',
tab: 'calls',
context: 'info',
id,
},
{ token },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ const ChatTable = () => {

const onRowClick = useMutableCallback((id) =>
directoryRoute.push({
page: 'chats',
bar: 'info',
tab: 'chats',
context: 'info',
id,
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,11 @@ function ChatInfoDirectory({ id, route = undefined, room }: ChatInfoDirectoryPro
return dispatchToastMessage({ type: 'error', message: t('Not_authorized') });
}

routePath.push(
route
? {
tab: 'room-info',
context: 'edit',
id,
}
: {
page: 'chats',
id,
bar: 'edit',
},
);
routePath.push({
tab: route ? 'room-info' : 'chats',
context: 'edit',
id,
});
});

return (
Expand Down
Loading

0 comments on commit 6d4a6be

Please sign in to comment.