diff --git a/i18n/en-US.properties b/i18n/en-US.properties index f8449d69af..7d67b9ca7b 100644 --- a/i18n/en-US.properties +++ b/i18n/en-US.properties @@ -356,8 +356,6 @@ be.contentSidebar.boxSignRequestSignature = Request Signature be.contentSidebar.boxSignSecurityBlockedTooltip = This action is unavailable due to a security policy. # One of the dropdown options that opens a Box Sign sign myself experience be.contentSidebar.boxSignSignMyself = Sign Myself -# label for button that opens a Box Sign signature fulfillment experience -be.contentSidebar.boxSignSignature = Sign # Tooltip text for when Box Sign is blocked due to an item being watermarked be.contentSidebar.boxSignWatermarkBlockedTooltip = This action is unavailable, because the file is watermarked. # title for when editing an existing approval task diff --git a/src/elements/content-sidebar/ContentSidebar.js b/src/elements/content-sidebar/ContentSidebar.js index 35037d1d50..d2a36842d3 100644 --- a/src/elements/content-sidebar/ContentSidebar.js +++ b/src/elements/content-sidebar/ContentSidebar.js @@ -34,6 +34,7 @@ import type { DetailsSidebarProps } from './DetailsSidebar'; import type { DocGenSidebarProps } from './DocGenSidebar/DocGenSidebar'; import type { MetadataSidebarProps } from './MetadataSidebar'; import type { VersionsSidebarProps } from './versions'; +import type { SignSideBarProps } from './SidebarNavSign'; import type { WithLoggerProps } from '../../common/types/logging'; import type { ElementsXhrError, RequestOptions, ErrorContextProps } from '../../common/types/api'; import type { MetadataEditor } from '../../common/types/metadata'; @@ -87,6 +88,7 @@ type Props = { sharedLink?: string, sharedLinkPassword?: string, theme?: Theme, + signSidebarProps: SignSideBarProps, token: Token, versionsSidebarProps: VersionsSidebarProps, } & ErrorContextProps & @@ -368,6 +370,7 @@ class ContentSidebar extends React.Component { onVersionHistoryClick, theme, versionsSidebarProps, + signSidebarProps, }: Props = this.props; const { file, isLoading, metadataEditors }: State = this.state; const initialPath = defaultView.charAt(0) === '/' ? defaultView : `/${defaultView}`; @@ -410,6 +413,7 @@ class ContentSidebar extends React.Component { onVersionHistoryClick={onVersionHistoryClick} theme={theme} versionsSidebarProps={versionsSidebarProps} + signSidebarProps={signSidebarProps} wrappedComponentRef={ref => { this.sidebarRef = ref; }} diff --git a/src/elements/content-sidebar/Sidebar.js b/src/elements/content-sidebar/Sidebar.js index 1855db5777..a645f12fac 100644 --- a/src/elements/content-sidebar/Sidebar.js +++ b/src/elements/content-sidebar/Sidebar.js @@ -31,6 +31,7 @@ import type { VersionsSidebarProps } from './versions'; import type { AdditionalSidebarTab } from './flowTypes'; import type { MetadataEditor } from '../../common/types/metadata'; import type { BoxItem, User } from '../../common/types/core'; +import type { SignSideBarProps } from './SidebarNavSign'; import type { Errors } from '../common/flowTypes'; // $FlowFixMe TypeScript file import type { Theme } from '../common/theming'; @@ -70,6 +71,7 @@ type Props = { onVersionChange?: Function, onVersionHistoryClick?: Function, theme?: Theme, + signSidebarProps: SignSideBarProps, versionsSidebarProps: VersionsSidebarProps, }; @@ -311,6 +313,7 @@ class Sidebar extends React.Component { onVersionChange, theme, versionsSidebarProps, + signSidebarProps, }: Props = this.props; const isOpen = this.isOpen(); const hasBoxAI = SidebarUtils.canHaveBoxAISidebar(this.props); @@ -346,6 +349,7 @@ class Sidebar extends React.Component { hasMetadata={hasMetadata} hasSkills={hasSkills} hasDocGen={docGenSidebarProps.isDocGenTemplate} + signSideBarProps={signSidebarProps} isOpen={isOpen} onPanelChange={this.handlePanelChange} /> diff --git a/src/elements/content-sidebar/SidebarNav.js b/src/elements/content-sidebar/SidebarNav.js index 72dfa32174..18cd3461ae 100644 --- a/src/elements/content-sidebar/SidebarNav.js +++ b/src/elements/content-sidebar/SidebarNav.js @@ -33,6 +33,7 @@ import { import { useFeatureConfig } from '../common/feature-checking'; import type { NavigateOptions, AdditionalSidebarTab } from './flowTypes'; import './SidebarNav.scss'; +import type { SignSideBarProps } from './SidebarNavSign'; type Props = { additionalTabs?: Array, @@ -49,6 +50,7 @@ type Props = { isOpen?: boolean, onNavigate?: (SyntheticEvent<>, NavigateOptions) => void, onPanelChange?: (name: string, isInitialState: boolean) => void, + signSideBarProps: SignSideBarProps, }; const SidebarNav = ({ @@ -66,8 +68,9 @@ const SidebarNav = ({ isOpen, onNavigate, onPanelChange = noop, + signSideBarProps, }: Props) => { - const { enabled: hasBoxSign } = useFeatureConfig('boxSign'); + const { enabled: hasBoxSign } = signSideBarProps || {}; const { disabledTooltip: boxAIDisabledTooltip, showOnlyNavButton: showOnlyBoxAINavButton } = useFeatureConfig('boxai.sidebar'); @@ -159,7 +162,7 @@ const SidebarNav = ({ {hasBoxSign && (
- +
)} diff --git a/src/elements/content-sidebar/SidebarNavSign.tsx b/src/elements/content-sidebar/SidebarNavSign.tsx index 46a0981af3..6601781f1b 100644 --- a/src/elements/content-sidebar/SidebarNavSign.tsx +++ b/src/elements/content-sidebar/SidebarNavSign.tsx @@ -1,8 +1,6 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -// @ts-ignore Module is written in Flow -import { useFeatureConfig } from '../common/feature-checking'; // @ts-ignore Module is written in Flow import { SIDEBAR_NAV_TARGETS } from '../common/interactionTargets'; @@ -17,48 +15,43 @@ import { Menu, MenuItem } from '../../components/menu'; import messages from './messages'; import './SidebarNavSign.scss'; +// @ts-ignore Module is written in Flow +import type { TargetingApi } from '../../features/targeting/types'; + +export interface SignSideBarProps { + blockedReason: string; + enabled: boolean; + onClick: () => void; + onClickSignMyself: () => void; + targetingApi: TargetingApi | null; +} -export function SidebarNavSign() { +export function SidebarNavSign(signSideBarProps: SignSideBarProps) { const { blockedReason: boxSignBlockedReason, onClick: onBoxClickRequestSignature, onClickSignMyself: onBoxClickSignMyself, - status: boxSignStatus, targetingApi: boxSignTargetingApi, - isSignRemoveInterstitialEnabled, - } = useFeatureConfig('boxSign'); + } = signSideBarProps; return ( - <> - {isSignRemoveInterstitialEnabled ? ( - - - - - - - - - - - - - - ) : ( - - )} - + + + + + + + + + + + + + ); } diff --git a/src/elements/content-sidebar/SidebarNavSignButton.tsx b/src/elements/content-sidebar/SidebarNavSignButton.tsx index 539ace633a..353cf5303a 100644 --- a/src/elements/content-sidebar/SidebarNavSignButton.tsx +++ b/src/elements/content-sidebar/SidebarNavSignButton.tsx @@ -25,11 +25,11 @@ export type Props = PlainButtonProps & { export const PlaceholderTooltip = ({ children }: { children: React.ReactNode }) => children; -export function SidebarNavSignButton({ blockedReason, intl, status, targetingApi, ...rest }: Props) { +export function SidebarNavSignButton({ blockedReason, intl, targetingApi, ...rest }: Props) { const isSignDisabled = !!blockedReason; - const isTargeted = targetingApi && targetingApi.canShow; + const isTargeted = targetingApi?.canShow; const FtuxTooltip = !isSignDisabled && isTargeted ? TargetedClickThroughGuideTooltip : PlaceholderTooltip; - const label = intl.formatMessage(status === 'active' ? messages.boxSignSignature : messages.boxSignRequest); + const label = intl.formatMessage(messages.boxSignRequest); const buttonClassName = classnames('bcs-SidebarNavSignButton', { 'bdl-is-disabled': isSignDisabled }); let tooltipMessage = label; diff --git a/src/elements/content-sidebar/__tests__/SidebarNav.test.js b/src/elements/content-sidebar/__tests__/SidebarNav.test.js index 77afc84f73..97f3ef8d57 100644 --- a/src/elements/content-sidebar/__tests__/SidebarNav.test.js +++ b/src/elements/content-sidebar/__tests__/SidebarNav.test.js @@ -166,19 +166,15 @@ describe('elements/content-sidebar/SidebarNav', () => { }); test('should render the Box Sign entry point if its feature is enabled', () => { - const features = { - boxSign: { + const props = { + signSideBarProps: { enabled: true, onClick: () => {}, }, }; - const wrapper = getWrapper({}, 'activity', features); - expect(wrapper.exists(SidebarNavSignButton)).toBe(true); - }); + const wrapper = getWrapper(props); - test('should not render the Box Sign entry point if its feature is not enabled', () => { - const wrapper = getWrapper(); - expect(wrapper.exists(SidebarNavSignButton)).toBe(false); + expect(wrapper.exists(SidebarNavSignButton)).toBe(true); }); test('should render docgen tab', () => { const props = { diff --git a/src/elements/content-sidebar/__tests__/SidebarNavSign.test.tsx b/src/elements/content-sidebar/__tests__/SidebarNavSign.test.tsx index 35a1792279..ad9beaa0be 100644 --- a/src/elements/content-sidebar/__tests__/SidebarNavSign.test.tsx +++ b/src/elements/content-sidebar/__tests__/SidebarNavSign.test.tsx @@ -1,80 +1,53 @@ import * as React from 'react'; -import { render, fireEvent } from '@testing-library/react'; + +import { userEvent } from '@testing-library/user-event'; +import { render, screen } from '../../../test-utils/testing-library'; import SidebarNavSign from '../SidebarNavSign'; -// @ts-ignore Module is written in Flow -import FeatureProvider from '../../common/feature-checking/FeatureProvider'; describe('elements/content-sidebar/SidebarNavSign', () => { const onClickRequestSignature = jest.fn(); const onClickSignMyself = jest.fn(); - const renderComponent = (props = {}, features = {}) => - render( - - - , - ); + const defaultSignSideBarProps = { + blockedReason: '', + enabled: true, + onClick: onClickRequestSignature, + onClickSignMyself, + targetingApi: null, + }; + + const renderComponent = () => render(, {}); - test.each([true, false])('should render sign button', isRemoveInterstitialEnabled => { - const features = { - boxSign: { - isSignRemoveInterstitialEnabled: isRemoveInterstitialEnabled, - }, - }; + test('should render sign button', async () => { + renderComponent(); - const wrapper = renderComponent({}, features); - expect(wrapper.getByTestId('sign-button')).toBeVisible(); + expect(screen.getByRole('button', { name: 'Request Signature' })).toBeInTheDocument(); }); - test('should call correct handler when sign button is clicked', () => { - const features = { - boxSign: { - isSignRemoveInterstitialEnabled: false, - onClick: onClickRequestSignature, - }, - }; - const { getByTestId } = renderComponent({}, features); + test('should open dropdown with 2 menu items when sign button is clicked', async () => { + renderComponent(); - fireEvent.click(getByTestId('sign-button')); + await userEvent.click(screen.getByRole('button', { name: 'Request Signature' })); - expect(onClickRequestSignature).toBeCalled(); + expect(screen.getByRole('menuitem', { name: 'Request Signature' })).toBeVisible(); + expect(screen.getByRole('menuitem', { name: 'Sign Myself' })).toBeVisible(); }); - test('should open dropdown with 2 menu items when sign button is clicked', () => { - const features = { - boxSign: { - isSignRemoveInterstitialEnabled: true, - }, - }; - const { getByTestId } = renderComponent({}, features); - fireEvent.click(getByTestId('sign-button')); - expect(getByTestId('sign-request-signature-button')).toBeVisible(); - expect(getByTestId('sign-sign-myself-button')).toBeVisible(); - }); + test('should call correct handler when request signature option is clicked', async () => { + renderComponent(); - test('should call correct handler when request signature option is clicked', () => { - const features = { - boxSign: { - isSignRemoveInterstitialEnabled: true, - onClick: onClickRequestSignature, - }, - }; - const { getByTestId } = renderComponent({}, features); - fireEvent.click(getByTestId('sign-button')); - fireEvent.click(getByTestId('sign-request-signature-button')); - expect(onClickRequestSignature).toBeCalled(); + await userEvent.click(screen.getByRole('button', { name: 'Request Signature' })); + await userEvent.click(screen.getByRole('menuitem', { name: 'Request Signature' })); + + expect(onClickRequestSignature).toHaveBeenCalled(); }); - test('should call correct handler when sign myself option is clicked', () => { - const features = { - boxSign: { - isSignRemoveInterstitialEnabled: true, - onClickSignMyself, - }, - }; - const { getByTestId } = renderComponent({}, features); - fireEvent.click(getByTestId('sign-button')); - fireEvent.click(getByTestId('sign-sign-myself-button')); - expect(onClickSignMyself).toBeCalled(); + test('should call correct handler when sign myself option is clicked', async () => { + renderComponent(); + + await userEvent.click(screen.getByRole('button', { name: 'Request Signature' })); + await userEvent.click(screen.getByRole('menuitem', { name: 'Sign Myself' })); + + expect(onClickSignMyself).toHaveBeenCalled(); }); }); diff --git a/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx b/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx index cb1205a1af..1c9306c9b9 100644 --- a/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx +++ b/src/elements/content-sidebar/__tests__/SidebarNavSignButton.test.tsx @@ -10,16 +10,11 @@ import Tooltip from '../../../components/tooltip'; describe('elements/content-sidebar/SidebarNavSignButton', () => { const getWrapper = (props = {}) => shallow().dive(); - test.each` - status | label - ${undefined} | ${'Request Signature'} - ${'random'} | ${'Request Signature'} - ${'active'} | ${'Sign'} - `('should render the correct label based on the current signature status', ({ label, status }) => { - const wrapper = getWrapper({ status }); + test('should render the correct label', () => { + const wrapper = getWrapper(); - expect(wrapper.find(Tooltip).prop('text')).toBe(label); - expect(wrapper.find(PlainButton).prop('aria-label')).toBe(label); + expect(wrapper.find(Tooltip).prop('text')).toBe('Request Signature'); + expect(wrapper.find(PlainButton).prop('aria-label')).toBe('Request Signature'); expect(wrapper.exists(BoxSign28)).toBe(true); }); diff --git a/src/elements/content-sidebar/messages.js b/src/elements/content-sidebar/messages.js index ee5a9f669e..e6b2a16862 100644 --- a/src/elements/content-sidebar/messages.js +++ b/src/elements/content-sidebar/messages.js @@ -57,11 +57,6 @@ const messages = defineMessages({ defaultMessage: 'Sign Myself', description: 'One of the dropdown options that opens a Box Sign sign myself experience', }, - boxSignSignature: { - id: 'be.contentSidebar.boxSignSignature', - defaultMessage: 'Sign', - description: 'label for button that opens a Box Sign signature fulfillment experience', - }, boxSignSecurityBlockedTooltip: { defaultMessage: 'This action is unavailable due to a security policy.', description: 'Tooltip text for when Box Sign is blocked due to a security policy',