Skip to content

Commit

Permalink
chore(content-uploader): Migrate Footer (#3595)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-in-a-box authored Aug 7, 2024
1 parent dee4eee commit 423c6e1
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 96 deletions.
2 changes: 2 additions & 0 deletions i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ be.keywordsAppliedList = Keywords were applied
be.keywordsList = Keywords: {words}
# Label for switching to list view
be.listView = Switch to List View
# Loading aria label.
be.loading = loading
# Message shown when folder items are still fetching.
be.loadingState = Please wait while the items load...
# Placeholder for a logo.
Expand Down
5 changes: 5 additions & 0 deletions src/elements/common/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,11 @@ const messages = defineMessages({
defaultMessage: 'Box Doc Gen',
description: 'Icon title for a Box file of type DocGen template',
},
loading: {
id: 'be.loading',
description: 'Loading aria label.',
defaultMessage: 'loading',
},
});

export default messages;
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
/**
* @flow
* @file Footer component
*/

import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import PrimaryButton from '../../components/primary-button/PrimaryButton';
import Button from '../../components/button/Button';
import { FormattedMessage, useIntl } from 'react-intl';
import { Button } from '@box/blueprint-web';
import messages from '../common/messages';
import { ERROR_CODE_UPLOAD_FILE_LIMIT } from '../../constants';
import './Footer.scss';
Expand All @@ -17,12 +11,13 @@ type Props = {
hasFiles: boolean,
isDone: boolean,
isLoading: boolean,
onCancel: Function,
onClose?: Function,
onUpload: Function,
onCancel: any,
onClose?: any,
onUpload: any,
};

const Footer = ({ isLoading, hasFiles, errorCode, onCancel, onClose, onUpload, fileLimit, isDone }: Props) => {
const intl = useIntl();
const isCloseButtonDisabled = hasFiles;
const isCancelButtonDisabled = !hasFiles || isDone;
const isUploadButtonDisabled = !hasFiles;
Expand All @@ -40,35 +35,26 @@ const Footer = ({ isLoading, hasFiles, errorCode, onCancel, onClose, onUpload, f
<div className="bcu-footer">
<div className="bcu-footer-left">
{onClose ? (
<Button
disabled={isCloseButtonDisabled}
isDisabled={isCloseButtonDisabled}
onClick={onClose}
type="button"
>
<FormattedMessage {...messages.close} />
<Button disabled={isCloseButtonDisabled} onClick={onClose} size="large" variant="secondary">
{intl.formatMessage(messages.close)}
</Button>
) : null}
</div>
{message && <div className="bcu-footer-message">{message}</div>}
<div className="bcu-footer-right">
<Button
disabled={isCancelButtonDisabled}
isDisabled={isCancelButtonDisabled}
onClick={onCancel}
type="button"
>
<FormattedMessage {...messages.cancel} />
<Button disabled={isCancelButtonDisabled} onClick={onCancel} size="large" variant="secondary">
{intl.formatMessage(messages.cancel)}
</Button>
<PrimaryButton
<Button
disabled={isUploadButtonDisabled}
isDisabled={isUploadButtonDisabled}
isLoading={isLoading}
loading={isLoading}
loadingAriaLabel={intl.formatMessage(messages.loading)}
onClick={onUpload}
type="button"
size="large"
variant="primary"
>
<FormattedMessage {...messages.upload} />
</PrimaryButton>
{intl.formatMessage(messages.upload)}
</Button>
</div>
</div>
);
Expand Down
11 changes: 5 additions & 6 deletions src/elements/content-uploader/Footer.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@use '@box/blueprint-web-assets/tokens/tokens.scss';

@import '../common/variables';

.bcu-footer {
Expand All @@ -9,16 +11,13 @@
background-color: $almost-white;
border-top: 1px solid $bdl-gray-10;

.btn {
@include bdl-Button--large;
}

.bcu-footer-message {
padding: 0 10px;
text-align: center;
}

.bcu-footer-right .btn {
margin-left: 8px;
.bcu-footer-right {
display: flex;
gap: tokens.$size-2;
}
}
62 changes: 62 additions & 0 deletions src/elements/content-uploader/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import { Button } from '@box/blueprint-web';
import { ERROR_CODE_UPLOAD_FILE_LIMIT } from '../../constants';

import messages from '../common/messages';

import './Footer.scss';

export interface FooterProps {
errorCode?: string;
fileLimit: number;
hasFiles: boolean;
isDone: boolean;
isLoading: boolean;
onCancel: () => void;
onClose?: () => void;
onUpload: () => void;
}

const Footer = ({ isLoading, hasFiles, errorCode, onCancel, onClose, onUpload, fileLimit, isDone }: FooterProps) => {
const intl = useIntl();
const isCloseButtonDisabled = hasFiles;
const isCancelButtonDisabled = !hasFiles || isDone;
const isUploadButtonDisabled = !hasFiles;

let message;

if (errorCode === ERROR_CODE_UPLOAD_FILE_LIMIT) {
message = <FormattedMessage {...messages.uploadErrorTooManyFiles} values={{ fileLimit }} />;
}

return (
<div className="bcu-footer">
<div className="bcu-footer-left">
{onClose ? (
<Button disabled={isCloseButtonDisabled} onClick={onClose} size="large" variant="secondary">
{intl.formatMessage(messages.close)}
</Button>
) : null}
</div>
{message && <div className="bcu-footer-message">{message}</div>}
<div className="bcu-footer-right">
<Button disabled={isCancelButtonDisabled} onClick={onCancel} size="large" variant="secondary">
{intl.formatMessage(messages.cancel)}
</Button>
<Button
disabled={isUploadButtonDisabled}
loading={isLoading}
loadingAriaLabel={intl.formatMessage(messages.loading)}
onClick={onUpload}
size="large"
variant="primary"
>
{intl.formatMessage(messages.upload)}
</Button>
</div>
</div>
);
};

export default Footer;
59 changes: 0 additions & 59 deletions src/elements/content-uploader/__tests__/Footer.test.js

This file was deleted.

70 changes: 70 additions & 0 deletions src/elements/content-uploader/__tests__/Footer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import noop from 'lodash/noop';
import { render, screen } from '../../../test-utils/testing-library';
import Footer from '../Footer';
import { ERROR_CODE_UPLOAD_FILE_LIMIT } from '../../../constants';

describe('elements/content-uploader/Footer', () => {
const defaultProps = {
fileLimit: 10,
hasFiles: false,
isDone: false,
isLoading: false,
onCancel: noop,
onUpload: noop,
};
const renderComponent = (props = {}) => render(<Footer {...defaultProps} {...props} />);

test('cancel button should not be disabled when hasFiles is $hasFiles and isDone is $isDone', () => {
renderComponent({ hasFiles: true, isDone: false });
const closeButton = screen.getByRole('button', { name: 'Cancel' });

expect(closeButton).not.toHaveAttribute('aria-disabled');
});

test.each`
hasFiles | isDone
${false} | ${true}
${false} | ${false}
${true} | ${true}
`('cancel button should be disabled when hasFiles is $hasFiles and isDone is $isDone', ({ hasFiles, isDone }) => {
renderComponent({ hasFiles, isDone });
const closeButton = screen.getByRole('button', { name: 'Cancel' });

expect(closeButton).toHaveAttribute('aria-disabled', 'true');
});

test('upload button should not be disabled there are files', () => {
renderComponent({ hasFiles: true });
const uploadButton = screen.getByRole('button', { name: 'Upload' });

expect(uploadButton).not.toHaveAttribute('aria-disabled');
});

test('upload button should be disabled when there are not any files', () => {
renderComponent({ hasFiles: false });
const uploadButton = screen.getByRole('button', { name: 'Upload' });

expect(uploadButton).toHaveAttribute('aria-disabled');
});

test('close button should be disabled when there are files', () => {
renderComponent({ hasFiles: true, onClose: noop });
const closeButton = screen.getByRole('button', { name: 'Close' });

expect(closeButton).toHaveAttribute('aria-disabled');
});

test('close button should not be disabled when there are not any files', () => {
renderComponent({ hasFiles: false, onClose: noop });
const closeButton = screen.getByRole('button', { name: 'Close' });

expect(closeButton).not.toHaveAttribute('aria-disabled');
});

test('should render upload error message when errorCode is ERROR_CODE_UPLOAD_FILE_LIMIT', () => {
renderComponent({ errorCode: ERROR_CODE_UPLOAD_FILE_LIMIT });

expect(screen.getByText('You can only upload up to 10 file(s) at a time.')).toBeInTheDocument();
});
});

0 comments on commit 423c6e1

Please sign in to comment.