box-ui-elements
Version:
Box UI Elements
316 lines (299 loc) • 13.3 kB
JavaScript
/**
* @flow
* @file Preview sidebar nav component
* @author Box
*/
import * as React from 'react';
import { injectIntl } from 'react-intl';
import type { IntlShape } from 'react-intl';
import classNames from 'classnames';
import noop from 'lodash/noop';
import { BoxAiLogo, BoxAiLogo24 } from '@box/blueprint-web-assets/icons/Logo';
import {
Comment as CommentIcon,
InformationCircle as InformationCircleIcon,
Metadata as MetadataIcon,
MagicWand as MagicWandIcon,
DocGen as BPDocGenIcon,
} from '@box/blueprint-web-assets/icons/Medium';
import {
Comment as CommentIconFilled,
InformationCircle as InformationCircleIconFilled,
Metadata as MetadataIconFilled,
MagicWand as MagicWandIconFilled,
} from '@box/blueprint-web-assets/icons/MediumFilled';
import { Size6, Size5, IconIconBlue } from '@box/blueprint-web-assets/tokens/tokens';
import { usePromptFocus } from '@box/box-ai-content-answers';
import AdditionalTabs from './additional-tabs';
import DocGenIcon from '../../icon/fill/DocGenIcon';
import IconChatRound from '../../icons/general/IconChatRound';
import IconDocInfo from '../../icons/general/IconDocInfo';
import IconMagicWand from '../../icons/general/IconMagicWand';
import IconMetadataThick from '../../icons/general/IconMetadataThick';
import SidebarNavButton from './SidebarNavButton';
import SidebarNavSign from './SidebarNavSign';
import SidebarNavTablist from './SidebarNavTablist';
import SidebarToggle from './SidebarToggle';
import messages from '../common/messages';
import { SIDEBAR_NAV_TARGETS } from '../common/interactionTargets';
import {
SIDEBAR_VIEW_ACTIVITY,
SIDEBAR_VIEW_BOXAI,
SIDEBAR_VIEW_DETAILS,
SIDEBAR_VIEW_DOCGEN,
SIDEBAR_VIEW_METADATA,
SIDEBAR_VIEW_SKILLS,
} from '../../constants';
import { useFeatureConfig } from '../common/feature-checking';
import type { NavigateOptions, AdditionalSidebarTab } from './flowTypes';
import type { InternalSidebarNavigation, InternalSidebarNavigationHandler } from '../common/types/SidebarNavigation';
import './SidebarNav.scss';
import type { SignSidebarProps } from './SidebarNavSign';
const SIDEBAR_TAB_ICON_PROPS = {
height: Size5,
width: Size5,
};
type IconWrapperProps = {
isActive?: boolean,
isPreviewModernizationEnabled: boolean,
};
// Icon wrapper components that receive isActive prop from SidebarNavButton
const ActivityIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => {
if (!isPreviewModernizationEnabled) {
return <IconChatRound className="bcs-SidebarNav-icon" />;
}
return isActive ? (
<CommentIconFilled {...SIDEBAR_TAB_ICON_PROPS} color={IconIconBlue} />
) : (
<CommentIcon {...SIDEBAR_TAB_ICON_PROPS} />
);
};
const DetailsIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => {
if (!isPreviewModernizationEnabled) {
return <IconDocInfo className="bcs-SidebarNav-icon" />;
}
return isActive ? (
<InformationCircleIconFilled {...SIDEBAR_TAB_ICON_PROPS} color={IconIconBlue} />
) : (
<InformationCircleIcon {...SIDEBAR_TAB_ICON_PROPS} />
);
};
const MetadataIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => {
if (!isPreviewModernizationEnabled) {
return <IconMetadataThick className="bcs-SidebarNav-icon" />;
}
return isActive ? (
<MetadataIconFilled {...SIDEBAR_TAB_ICON_PROPS} color={IconIconBlue} />
) : (
<MetadataIcon {...SIDEBAR_TAB_ICON_PROPS} />
);
};
const SkillsIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => {
if (!isPreviewModernizationEnabled) {
return <IconMagicWand className="bcs-SidebarNav-icon" />;
}
return isActive ? (
<MagicWandIconFilled {...SIDEBAR_TAB_ICON_PROPS} color={IconIconBlue} />
) : (
<MagicWandIcon {...SIDEBAR_TAB_ICON_PROPS} />
);
};
const DocGenIconWrapper = ({ isActive, isPreviewModernizationEnabled }: IconWrapperProps) => {
if (!isPreviewModernizationEnabled) {
return <DocGenIcon className="bcs-SidebarNav-icon" />;
}
return isActive ? (
<BPDocGenIcon {...SIDEBAR_TAB_ICON_PROPS} color={IconIconBlue} />
) : (
<BPDocGenIcon {...SIDEBAR_TAB_ICON_PROPS} />
);
};
type Props = {
additionalTabs?: Array<AdditionalSidebarTab>,
elementId: string,
fileId: string,
hasActivity: boolean,
hasAdditionalTabs: boolean,
hasBoxAI: boolean,
hasDetails: boolean,
hasDocGen?: boolean,
hasMetadata: boolean,
hasSkills: boolean,
internalSidebarNavigation?: InternalSidebarNavigation,
internalSidebarNavigationHandler?: InternalSidebarNavigationHandler,
intl: IntlShape,
isOpen?: boolean,
onNavigate?: (SyntheticEvent<>, NavigateOptions) => void,
onPanelChange?: (name: string, isInitialState: boolean) => void,
routerDisabled?: boolean,
signSidebarProps: SignSidebarProps,
};
const SidebarNav = ({
additionalTabs,
elementId,
fileId,
hasActivity,
hasAdditionalTabs,
hasBoxAI,
hasDetails,
hasMetadata,
hasSkills,
hasDocGen = false,
internalSidebarNavigation,
internalSidebarNavigationHandler,
intl,
isOpen,
onNavigate,
onPanelChange = noop,
routerDisabled,
signSidebarProps,
}: Props) => {
const { enabled: hasBoxSign } = signSidebarProps || {};
const { disabledTooltip: boxAIDisabledTooltip, showOnlyNavButton: showOnlyBoxAINavButton } =
useFeatureConfig('boxai.sidebar');
const { enabled: isPreviewModernizationEnabled } = useFeatureConfig('previewModernization');
const { focusPrompt } = usePromptFocus('.be.bcs');
const handleSidebarNavButtonClick = (sidebarview: string) => {
onPanelChange(sidebarview, false);
// If the Box AI sidebar is enabled, focus the Box AI sidebar prompt
if (sidebarview === SIDEBAR_VIEW_BOXAI) {
focusPrompt();
}
};
return (
<div
className={classNames('bcs-SidebarNav', {
'bcs-SidebarNav--modernized': isPreviewModernizationEnabled,
})}
aria-label={intl.formatMessage(messages.sidebarNavLabel)}
>
<div className="bcs-SidebarNav-tabs">
<SidebarNavTablist
elementId={elementId}
internalSidebarNavigation={internalSidebarNavigation}
internalSidebarNavigationHandler={internalSidebarNavigationHandler}
isOpen={isOpen}
onNavigate={onNavigate}
routerDisabled={routerDisabled}
>
{hasBoxAI && (
<SidebarNavButton
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
data-resin-target={SIDEBAR_NAV_TARGETS.BOXAI}
data-target-id="SidebarNavButton-boxAI"
data-testid="sidebarboxai"
isDisabled={showOnlyBoxAINavButton}
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_BOXAI}
tooltip={
showOnlyBoxAINavButton
? boxAIDisabledTooltip
: intl.formatMessage(messages.sidebarBoxAITitle)
}
>
{isPreviewModernizationEnabled ? (
<BoxAiLogo24 {...SIDEBAR_TAB_ICON_PROPS} />
) : (
<BoxAiLogo height={Size6} width={Size6} />
)}
</SidebarNavButton>
)}
{hasActivity && (
<SidebarNavButton
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
data-resin-target={SIDEBAR_NAV_TARGETS.ACTIVITY}
data-target-id="SidebarNavButton-activity"
data-testid="sidebaractivity"
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_ACTIVITY}
tooltip={intl.formatMessage(messages.sidebarActivityTitle)}
>
<ActivityIconWrapper isPreviewModernizationEnabled={isPreviewModernizationEnabled} />
</SidebarNavButton>
)}
{hasDetails && (
<SidebarNavButton
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
data-resin-target={SIDEBAR_NAV_TARGETS.DETAILS}
data-target-id="SidebarNavButton-details"
data-testid="sidebardetails"
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_DETAILS}
tooltip={intl.formatMessage(messages.sidebarDetailsTitle)}
>
<DetailsIconWrapper isPreviewModernizationEnabled={isPreviewModernizationEnabled} />
</SidebarNavButton>
)}
{hasSkills && (
<SidebarNavButton
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
data-resin-target={SIDEBAR_NAV_TARGETS.SKILLS}
data-target-id="SidebarNavButton-skills"
data-testid="sidebarskills"
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_SKILLS}
tooltip={intl.formatMessage(messages.sidebarSkillsTitle)}
>
<SkillsIconWrapper isPreviewModernizationEnabled={isPreviewModernizationEnabled} />
</SidebarNavButton>
)}
{hasMetadata && (
<SidebarNavButton
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
data-resin-target={SIDEBAR_NAV_TARGETS.METADATA}
data-target-id="SidebarNavButton-metadata"
data-testid="sidebarmetadata"
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_METADATA}
tooltip={intl.formatMessage(messages.sidebarMetadataTitle)}
>
<MetadataIconWrapper isPreviewModernizationEnabled={isPreviewModernizationEnabled} />
</SidebarNavButton>
)}
{hasDocGen && (
<SidebarNavButton
elementId=""
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
data-resin-target={SIDEBAR_NAV_TARGETS.DOCGEN}
data-target-id="SidebarNavButton-docGen"
data-testid="sidebardocgen"
onClick={handleSidebarNavButtonClick}
sidebarView={SIDEBAR_VIEW_DOCGEN}
tooltip={intl.formatMessage(messages.sidebarDocGenTooltip)}
>
<DocGenIconWrapper isPreviewModernizationEnabled={isPreviewModernizationEnabled} />
</SidebarNavButton>
)}
</SidebarNavTablist>
{hasBoxSign && (
<div className="bcs-SidebarNav-secondary">
<SidebarNavSign {...signSidebarProps} />
</div>
)}
{hasAdditionalTabs && (
<div
className={classNames('bcs-SidebarNav-overflow', {
'bcs-SidebarNav-overflow--modernized': isPreviewModernizationEnabled,
})}
data-testid="additional-tabs-overflow"
>
<AdditionalTabs
isPreviewModernizationEnabled={isPreviewModernizationEnabled}
key={fileId}
tabs={additionalTabs}
/>
</div>
)}
</div>
<div className="bcs-SidebarNav-footer">
<SidebarToggle
internalSidebarNavigation={internalSidebarNavigation}
internalSidebarNavigationHandler={internalSidebarNavigationHandler}
isOpen={isOpen}
routerDisabled={routerDisabled}
/>
</div>
</div>
);
};
export default injectIntl(SidebarNav);