Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/thin-cycles-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@rocket.chat/ui-contexts': minor
'@rocket.chat/ui-client': minor
'@rocket.chat/i18n': minor
'@rocket.chat/meteor': minor
---

Moves the room search functionality from the sidebar to the navbar and reorganize their relative actions
> This change is being tested under `Enhanced navigation experience` feature preview, in order to check it you need to enabled it
85 changes: 9 additions & 76 deletions apps/meteor/client/NavBarV2/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,18 @@
import { useToolbar } from '@react-aria/toolbar';
import { NavBar as NavBarComponent, NavBarSection, NavBarGroup, NavBarDivider } from '@rocket.chat/fuselage';
import { usePermission, useTranslation, useUser } from '@rocket.chat/ui-contexts';
import { useVoipState } from '@rocket.chat/ui-voip';
import { useRef } from 'react';
import { NavBar as NavBarComponent } from '@rocket.chat/fuselage';
import { useLayout } from '@rocket.chat/ui-contexts';

import {
NavBarItemOmniChannelCallDialPad,
NavBarItemOmnichannelContact,
NavBarItemOmnichannelLivechatToggle,
NavBarItemOmnichannelQueue,
NavBarItemOmnichannelCallToggle,
} from './NavBarOmnichannelToolbar';
import { NavBarItemMarketPlaceMenu, NavBarItemAuditMenu, NavBarItemDirectoryPage, NavBarItemHomePage } from './NavBarPagesToolbar';
import { NavBarItemLoginPage, NavBarItemAdministrationMenu, UserMenu } from './NavBarSettingsToolbar';
import { NavBarItemVoipDialer } from './NavBarVoipToolbar';
import { useIsCallEnabled, useIsCallReady } from '../contexts/CallContext';
import { useOmnichannelEnabled } from '../hooks/omnichannel/useOmnichannelEnabled';
import { useOmnichannelShowQueueLink } from '../hooks/omnichannel/useOmnichannelShowQueueLink';
import { useHasLicenseModule } from '../hooks/useHasLicenseModule';
import NavBarControlsSection from './NavBarControls/NavBarControlsSection';
import NavBarNavigation from './NavBarNavigation';
import NavBarPagesSection from './NavBarPagesSection';

const NavBar = () => {
const t = useTranslation();
const user = useUser();

const hasAuditLicense = useHasLicenseModule('auditing') === true;

const showOmnichannel = useOmnichannelEnabled();
const hasManageAppsPermission = usePermission('manage-apps');
const hasAccessMarketplacePermission = usePermission('access-marketplace');
const showMarketplace = hasAccessMarketplacePermission || hasManageAppsPermission;

const showOmnichannelQueueLink = useOmnichannelShowQueueLink();
const isCallEnabled = useIsCallEnabled();
const isCallReady = useIsCallReady();
const { isEnabled: showVoip } = useVoipState();

const pagesToolbarRef = useRef(null);
const { toolbarProps: pagesToolbarProps } = useToolbar({ 'aria-label': t('Pages') }, pagesToolbarRef);

const omnichannelToolbarRef = useRef(null);
const { toolbarProps: omnichannelToolbarProps } = useToolbar({ 'aria-label': t('Omnichannel') }, omnichannelToolbarRef);

const voipToolbarRef = useRef(null);
const { toolbarProps: voipToolbarProps } = useToolbar({ 'aria-label': t('Voice_Call') }, voipToolbarRef);
const { navbar } = useLayout();

return (
<NavBarComponent aria-label='header'>
<NavBarSection>
<NavBarGroup role='toolbar' ref={pagesToolbarRef} {...pagesToolbarProps}>
<NavBarItemHomePage title={t('Home')} />
<NavBarItemDirectoryPage title={t('Directory')} />
{showMarketplace && <NavBarItemMarketPlaceMenu />}
{hasAuditLicense && <NavBarItemAuditMenu />}
</NavBarGroup>
{showOmnichannel && (
<>
<NavBarDivider />
<NavBarGroup role='toolbar' ref={omnichannelToolbarRef} {...omnichannelToolbarProps}>
{showOmnichannelQueueLink && <NavBarItemOmnichannelQueue title={t('Queue')} />}
{isCallReady && <NavBarItemOmniChannelCallDialPad />}
<NavBarItemOmnichannelContact title={t('Contact_Center')} />
{isCallEnabled && <NavBarItemOmnichannelCallToggle />}
<NavBarItemOmnichannelLivechatToggle />
</NavBarGroup>
</>
)}
{showVoip && (
<>
<NavBarDivider />
<NavBarGroup role='toolbar' ref={voipToolbarRef} {...voipToolbarProps}>
<NavBarItemVoipDialer primary={isCallEnabled} />
</NavBarGroup>
</>
)}
</NavBarSection>
<NavBarSection>
<NavBarGroup aria-label={t('Workspace_and_user_settings')}>
<NavBarItemAdministrationMenu />
{user ? <UserMenu user={user} /> : <NavBarItemLoginPage />}
</NavBarGroup>
</NavBarSection>
{!navbar.searchExpanded && <NavBarPagesSection />}
<NavBarNavigation />
{!navbar.searchExpanded && <NavBarControlsSection />}
</NavBarComponent>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { NavBarItem } from '@rocket.chat/fuselage';
import type { GenericMenuItemProps } from '@rocket.chat/ui-client';
import { GenericMenu } from '@rocket.chat/ui-client';
import { useVoipState } from '@rocket.chat/ui-voip';
import type { HTMLAttributes } from 'react';
import { useTranslation } from 'react-i18next';

import { useOmnichannelEnabled } from '../../hooks/omnichannel/useOmnichannelEnabled';

type NavBarControlsMenuProps = Omit<HTMLAttributes<HTMLElement>, 'is'> & {
voipItems: GenericMenuItemProps[];
omnichannelItems: GenericMenuItemProps[];
isPressed: boolean;
};

const NavBarControlsMenu = ({ voipItems, omnichannelItems, isPressed, ...props }: NavBarControlsMenuProps) => {
const { t } = useTranslation();
const { isEnabled: showVoip } = useVoipState();
const showOmnichannel = useOmnichannelEnabled();

const sections = [
{
title: t('Voice_Call'),
items: showVoip ? voipItems : [],
},
{
title: t('Omnichannel'),
items: showOmnichannel ? omnichannelItems : [],
},
].filter((section) => section.items.length > 0);

if (sections.length === 0) {
return null;
}

return (
<GenericMenu
sections={sections}
title={t('Voice_and_omnichannel')}
is={NavBarItem}
placement='bottom-start'
icon='kebab'
pressed={isPressed}
{...props}
/>
);
};

export default NavBarControlsMenu;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { NavBarSection, NavBarGroup, NavBarDivider } from '@rocket.chat/fuselage';
import { useUser, useLayout } from '@rocket.chat/ui-contexts';
import { useTranslation } from 'react-i18next';

import NavBarControlsWithData from './NavBarControlsWithData';
import NavBarOmnichannelGroup from '../NavBarOmnichannelGroup';
import { NavBarItemLoginPage, NavBarItemAdministrationMenu, UserMenu } from '../NavBarSettingsToolbar';
import NavBarVoipGroup from '../NavBarVoipGroup';

const NavBarControlsSection = () => {
const { t } = useTranslation();
const user = useUser();

const { isMobile } = useLayout();

if (isMobile) {
return (
<NavBarSection>
<NavBarControlsWithData />
<NavBarDivider />
<NavBarGroup aria-label={t('Workspace_and_user_preferences')}>
<NavBarItemAdministrationMenu />
{user ? <UserMenu user={user} /> : <NavBarItemLoginPage />}
</NavBarGroup>
</NavBarSection>
);
}

return (
<NavBarSection>
<NavBarVoipGroup />
<NavBarOmnichannelGroup />
<NavBarGroup aria-label={t('Workspace_and_user_preferences')}>
<NavBarItemAdministrationMenu />
{user ? <UserMenu user={user} /> : <NavBarItemLoginPage />}
</NavBarGroup>
</NavBarSection>
);
};

export default NavBarControlsSection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { GenericMenuItemProps } from '@rocket.chat/ui-client';
import type { HTMLAttributes } from 'react';

import NavBarControlsMenu from './NavBarControlsMenu';
import { useOmnichannelCallDialPadAction } from '../NavBarOmnichannelGroup/hooks/useOmnichannelCallDialPadAction';
import { useOmnichannelCallToggleAction } from '../NavBarOmnichannelGroup/hooks/useOmnichannelCallToggleAction';

type NavBarControlsMenuProps = Omit<HTMLAttributes<HTMLElement>, 'is'> & {
voipItems: GenericMenuItemProps[];
omnichannelItems: GenericMenuItemProps[];
isPressed: boolean;
};

const NavBarControlsWithCall = ({ voipItems, omnichannelItems, isPressed, ...props }: NavBarControlsMenuProps) => {
const {
icon: omnichannelCallIcon,
title: omnichannelCallTitle,
handleOpenDialModal,
isDisabled: callDialPadDisabled,
} = useOmnichannelCallDialPadAction();

const {
title: omnichannelCallTogglerTitle,
icon: omnichannelCallTogglerIcon,
handleToggleCall,
isDisabled: callTogglerDisabled,
} = useOmnichannelCallToggleAction();

const omnichannelItemsWithCall = [
...omnichannelItems,
{
id: 'omnichannelCallDialPad',
icon: omnichannelCallIcon,
content: omnichannelCallTitle,
onClick: handleOpenDialModal,
disabled: callDialPadDisabled,
},
{
id: 'omnichannelCallToggler',
icon: omnichannelCallTogglerIcon,
content: omnichannelCallTogglerTitle,
onClick: handleToggleCall,
disabled: callTogglerDisabled,
},
] as GenericMenuItemProps[];

return <NavBarControlsMenu voipItems={voipItems} omnichannelItems={omnichannelItemsWithCall} isPressed={isPressed} {...props} />;
};

export default NavBarControlsWithCall;
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { GenericMenuItemProps } from '@rocket.chat/ui-client';
import type { HTMLAttributes } from 'react';

import NavBarControlsMenu from './NavBarControlsMenu';
import NavbarControlsWithCall from './NavBarControlsWithCall';
import { useIsCallEnabled } from '../../contexts/CallContext';
import { useOmnichannelContactAction } from '../NavBarOmnichannelGroup/hooks/useOmnichannelContactAction';
import { useOmnichannelLivechatToggle } from '../NavBarOmnichannelGroup/hooks/useOmnichannelLivechatToggle';
import { useOmnichannelQueueAction } from '../NavBarOmnichannelGroup/hooks/useOmnichannelQueueAction';
import { useVoipDialerAction } from '../NavBarVoipGroup/hooks/useVoipDialerAction';
import { useVoipTogglerAction } from '../NavBarVoipGroup/hooks/useVoipTogglerAction';

type NavBarControlsMenuProps = Omit<HTMLAttributes<HTMLElement>, 'is'>;

const NavBarControlsWithData = (props: NavBarControlsMenuProps) => {
const isCallEnabled = useIsCallEnabled();

const { title: dialerTitle, handleToggleDialer, isPressed: isVoipDialerPressed, isDisabled: dialerDisabled } = useVoipDialerAction();
const { isRegistered, title: togglerTitle, handleToggleVoip, isDisabled: togglerDisabled } = useVoipTogglerAction();

const {
isEnabled: queueEnabled,
icon: queueIcon,
title: queueTitle,
handleGoToQueue,
isPressed: isQueuePressed,
} = useOmnichannelQueueAction();

const {
title: contactCenterTitle,
icon: contactCenterIcon,
handleGoToContactCenter,
isPressed: isContactPressed,
} = useOmnichannelContactAction();

const {
title: omnichannelLivechatTogglerTitle,
icon: omnichannelLivechatTogglerIcon,
handleAvailableStatusChange,
} = useOmnichannelLivechatToggle();

const voipItems = [
{
id: 'voipDialer',
icon: 'dialpad',
content: dialerTitle,
onClick: handleToggleDialer,
disabled: dialerDisabled,
},
{
id: 'voipToggler',
icon: isRegistered ? 'phone-disabled' : 'phone',
content: togglerTitle,
onClick: handleToggleVoip,
disabled: togglerDisabled,
},
].filter(Boolean) as GenericMenuItemProps[];

const omnichannelItems = [
queueEnabled && {
id: 'omnichannelQueue',
icon: queueIcon,
content: queueTitle,
onClick: handleGoToQueue,
disabled: dialerDisabled,
},
{
id: 'omnichannelContact',
icon: contactCenterIcon,
content: contactCenterTitle,
onClick: handleGoToContactCenter,
},
{
id: 'omnichannelLivechatToggler',
icon: omnichannelLivechatTogglerIcon,
content: omnichannelLivechatTogglerTitle,
onClick: handleAvailableStatusChange,
},
].filter(Boolean) as GenericMenuItemProps[];

const isPressed = isVoipDialerPressed || isQueuePressed || isContactPressed;

if (isCallEnabled) {
return <NavbarControlsWithCall voipItems={voipItems} omnichannelItems={omnichannelItems} isPressed={isPressed} {...props} />;
}

return <NavBarControlsMenu voipItems={voipItems} omnichannelItems={omnichannelItems} isPressed={isPressed} {...props} />;
};

export default NavBarControlsWithData;
28 changes: 28 additions & 0 deletions apps/meteor/client/NavBarV2/NavBarNavigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NavBarGroup, NavBarItem, Box } from '@rocket.chat/fuselage';
import { useLayout, useRouter } from '@rocket.chat/ui-contexts';
import { FocusScope } from 'react-aria';
import { useTranslation } from 'react-i18next';

import NavBarSearch from './NavBarSearch';

const NavbarNavigation = () => {
const { t } = useTranslation();
const { navigate } = useRouter();
const { isMobile } = useLayout();

return (
<Box display='flex' flexGrow={1} justifyContent='center'>
<FocusScope>
<NavBarSearch />
</FocusScope>
{!isMobile && (
<NavBarGroup aria-label={t('History_navigation')}>
<NavBarItem title={t('Back_in_history')} onClick={() => navigate(-1)} icon='chevron-right' small />
<NavBarItem title={t('Forward_in_history')} onClick={() => navigate(1)} icon='chevron-left' small />
</NavBarGroup>
)}
</Box>
);
};

export default NavbarNavigation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NavBarItem } from '@rocket.chat/fuselage';
import type { ComponentPropsWithoutRef } from 'react';
import { useTranslation } from 'react-i18next';

import { useOmnichannelCallDialPadAction } from './hooks/useOmnichannelCallDialPadAction';

type NavBarItemOmniChannelCallDialPadProps = ComponentPropsWithoutRef<typeof NavBarItem>;

const NavBarItemOmniChannelCallDialPad = (props: NavBarItemOmniChannelCallDialPadProps) => {
const { t } = useTranslation();

const { title, icon, handleOpenDialModal, isDisabled } = useOmnichannelCallDialPadAction();

return (
<NavBarItem icon={icon} onClick={handleOpenDialModal} disabled={isDisabled} aria-label={t('Open_Dialpad')} title={title} {...props} />
);
};

export default NavBarItemOmniChannelCallDialPad;
Loading
Loading