Skip to content

Commit 45166f4

Browse files
feat(content-answers): Avatar (#3418)
* feat(content-answers): Avatar * feat(content-answers): feedback --------- Co-authored-by: TaoJiang98 <[email protected]>
1 parent 68b2def commit 45166f4

File tree

9 files changed

+154
-77
lines changed

9 files changed

+154
-77
lines changed

src/elements/content-preview/ContentPreview.js

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { withFeatureProvider } from '../common/feature-checking';
3535
import { EVENT_JS_READY } from '../common/logger/constants';
3636
import ReloadNotification from './ReloadNotification';
3737
import API from '../../api';
38+
import APIContext from '../common/api-context';
3839
import PreviewHeader from './preview-header';
3940
import PreviewMask from './PreviewMask';
4041
import PreviewNavigation from './PreviewNavigation';
@@ -1312,64 +1313,77 @@ class ContentPreview extends React.PureComponent<Props, State> {
13121313
/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
13131314
return (
13141315
<Internationalize language={language} messages={messages}>
1315-
<div id={this.id} className={styleClassName} ref={measureRef} onKeyDown={this.onKeyDown} tabIndex={0}>
1316-
{hasHeader && (
1317-
<PreviewHeader
1318-
file={file}
1319-
logoUrl={logoUrl}
1320-
token={token}
1321-
onClose={onHeaderClose}
1322-
onPrint={this.print}
1323-
canDownload={this.canDownload()}
1324-
canPrint={canPrint}
1325-
onDownload={this.download}
1326-
contentAnswersProps={contentAnswersProps}
1327-
contentOpenWithProps={contentOpenWithProps}
1328-
canAnnotate={this.canAnnotate()}
1329-
selectedVersion={selectedVersion}
1330-
/>
1331-
)}
1332-
<div className="bcpr-body">
1333-
<div className="bcpr-container" onMouseMove={this.onMouseMove} ref={this.containerRef}>
1316+
<APIContext.Provider value={(this.api: API)}>
1317+
<div
1318+
id={this.id}
1319+
className={styleClassName}
1320+
ref={measureRef}
1321+
onKeyDown={this.onKeyDown}
1322+
tabIndex={0}
1323+
>
1324+
{hasHeader && (
1325+
<PreviewHeader
1326+
file={file}
1327+
logoUrl={logoUrl}
1328+
token={token}
1329+
onClose={onHeaderClose}
1330+
onPrint={this.print}
1331+
canDownload={this.canDownload()}
1332+
canPrint={canPrint}
1333+
onDownload={this.download}
1334+
contentAnswersProps={contentAnswersProps}
1335+
contentOpenWithProps={contentOpenWithProps}
1336+
canAnnotate={this.canAnnotate()}
1337+
selectedVersion={selectedVersion}
1338+
/>
1339+
)}
1340+
<div className="bcpr-body">
1341+
<div className="bcpr-container" onMouseMove={this.onMouseMove} ref={this.containerRef}>
1342+
{file && (
1343+
<Measure bounds onResize={this.onResize}>
1344+
{({ measureRef: previewRef }) => (
1345+
<div ref={previewRef} className="bcpr-content" />
1346+
)}
1347+
</Measure>
1348+
)}
1349+
<PreviewMask errorCode={errorCode} extension={currentExtension} isLoading={isLoading} />
1350+
<PreviewNavigation
1351+
collection={collection}
1352+
currentIndex={this.getFileIndex()}
1353+
onNavigateLeft={this.navigateLeft}
1354+
onNavigateRight={this.navigateRight}
1355+
/>
1356+
</div>
13341357
{file && (
1335-
<Measure bounds onResize={this.onResize}>
1336-
{({ measureRef: previewRef }) => <div ref={previewRef} className="bcpr-content" />}
1337-
</Measure>
1358+
<LoadableSidebar
1359+
{...contentSidebarProps}
1360+
apiHost={apiHost}
1361+
token={token}
1362+
cache={this.api.getCache()}
1363+
fileId={currentFileId}
1364+
getPreview={this.getPreview}
1365+
getViewer={this.getViewer}
1366+
history={history}
1367+
isDefaultOpen={isLarge || isVeryLarge}
1368+
language={language}
1369+
ref={this.contentSidebar}
1370+
sharedLink={sharedLink}
1371+
sharedLinkPassword={sharedLinkPassword}
1372+
requestInterceptor={requestInterceptor}
1373+
responseInterceptor={responseInterceptor}
1374+
onAnnotationSelect={this.handleAnnotationSelect}
1375+
onVersionChange={this.onVersionChange}
1376+
/>
13381377
)}
1339-
<PreviewMask errorCode={errorCode} extension={currentExtension} isLoading={isLoading} />
1340-
<PreviewNavigation
1341-
collection={collection}
1342-
currentIndex={this.getFileIndex()}
1343-
onNavigateLeft={this.navigateLeft}
1344-
onNavigateRight={this.navigateRight}
1345-
/>
13461378
</div>
1347-
{file && (
1348-
<LoadableSidebar
1349-
{...contentSidebarProps}
1350-
apiHost={apiHost}
1351-
token={token}
1352-
cache={this.api.getCache()}
1353-
fileId={currentFileId}
1354-
getPreview={this.getPreview}
1355-
getViewer={this.getViewer}
1356-
history={history}
1357-
isDefaultOpen={isLarge || isVeryLarge}
1358-
language={language}
1359-
ref={this.contentSidebar}
1360-
sharedLink={sharedLink}
1361-
sharedLinkPassword={sharedLinkPassword}
1362-
requestInterceptor={requestInterceptor}
1363-
responseInterceptor={responseInterceptor}
1364-
onAnnotationSelect={this.handleAnnotationSelect}
1365-
onVersionChange={this.onVersionChange}
1379+
{isReloadNotificationVisible && (
1380+
<ReloadNotification
1381+
onClose={this.closeReloadNotification}
1382+
onClick={this.loadFileFromStage}
13661383
/>
13671384
)}
13681385
</div>
1369-
{isReloadNotificationVisible && (
1370-
<ReloadNotification onClose={this.closeReloadNotification} onClick={this.loadFileFromStage} />
1371-
)}
1372-
</div>
1386+
</APIContext.Provider>
13731387
</Internationalize>
13741388
);
13751389
/* eslint-enable jsx-a11y/no-static-element-interactions */

src/elements/content-preview/preview-header/PreviewHeader.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ const PreviewHeader = ({
6363
const fileId = file && file.id;
6464
const shouldRenderAnswers = fileId && contentAnswersProps.show;
6565
const shouldRenderOpenWith = fileId && contentOpenWithProps.show;
66-
const currentExtension = getProp(file, 'extension');
6766
const currentVersionId = getProp(file, 'file_version.id');
6867
const selectedVersionId = getProp(selectedVersion, 'id', currentVersionId);
6968
const isPreviewingCurrentVersion = currentVersionId === selectedVersionId;
@@ -101,13 +100,7 @@ const PreviewHeader = ({
101100
{...contentOpenWithProps}
102101
/>
103102
)}
104-
{shouldRenderAnswers && (
105-
<ContentAnswers
106-
fileExtension={currentExtension}
107-
fileId={fileId}
108-
versionId={selectedVersionId}
109-
/>
110-
)}
103+
{shouldRenderAnswers && <ContentAnswers file={file} />}
111104
{canAnnotate && (
112105
<>
113106
<PlainButton

src/elements/content-preview/preview-header/__tests__/PreviewHeader.test.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,13 @@ describe('elements/content-preview/preview-header/PreviewHeader', () => {
3535
});
3636

3737
it('should render ContentAnswers correctly and provided the correct props', () => {
38+
const file = { extension: 'doc', file_version: { id: '1' }, id: '123' };
3839
const contentAnswersProps = { show: true };
3940
const wrapper = getWrapper({
4041
contentAnswersProps,
41-
file: { extension: 'doc', file_version: { id: '1' }, id: '123' },
42+
file,
4243
});
43-
expect(wrapper.find(ContentAnswers).prop('fileExtension')).toBe('doc');
44-
expect(wrapper.find(ContentAnswers).prop('fileId')).toBe('123');
45-
expect(wrapper.find(ContentAnswers).prop('versionId')).toBe('1');
44+
expect(wrapper.find(ContentAnswers).prop('file')).toBe(file);
4645
});
4746

4847
test.each([

src/features/content-answers/ContentAnswers.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import React, { useState } from 'react';
22

3+
import getProp from 'lodash/get';
34
import ContentAnswersModal from './ContentAnswersModal';
45
import ContentAnswersOpenButton from './ContentAnswersOpenButton';
6+
// @ts-ignore: no ts definition
7+
// eslint-disable-next-line import/named
8+
import { BoxItem } from '../../common/types/core';
59

610
type ExternalProps = {
711
show?: boolean;
812
};
913

1014
type Props = {
11-
fileExtension: string;
12-
fileId: string;
13-
versionId: string;
15+
file: BoxItem;
1416
};
1517

16-
const ContentAnswers = ({ fileExtension }: Props) => {
18+
const ContentAnswers = ({ file }: Props) => {
1719
const [isModalOpen, setIsModalOpen] = useState(false);
1820

1921
const handleClick = () => {
@@ -24,10 +26,20 @@ const ContentAnswers = ({ fileExtension }: Props) => {
2426
setIsModalOpen(false);
2527
};
2628

29+
const currentExtension = getProp(file, 'extension');
2730
return (
2831
<div className="bdl-ContentAnswers">
29-
<ContentAnswersOpenButton fileExtension={fileExtension} onClick={handleClick} />
30-
<ContentAnswersModal isOpen={isModalOpen} onRequestClose={handleClose} />
32+
<ContentAnswersOpenButton
33+
data-testid="content-answers-open-button"
34+
fileExtension={currentExtension}
35+
onClick={handleClick}
36+
/>
37+
<ContentAnswersModal
38+
data-testid="content-answers-modal"
39+
file={file}
40+
isOpen={isModalOpen}
41+
onRequestClose={handleClose}
42+
/>
3143
</div>
3244
);
3345
};

src/features/content-answers/ContentAnswersModal.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@ import ContentAnswersModalContent from './ContentAnswersModalContent';
66
import ContentAnswersModalFooter from './ContentAnswersModalFooter';
77
// @ts-ignore flow import
88
import Modal from '../../components/modal/Modal';
9+
// @ts-ignore: no ts definition
10+
// eslint-disable-next-line import/named
11+
import { BoxItem } from '../../common/types/core';
912

1013
import messages from './messages';
1114

1215
import './ContentAnswersModal.scss';
1316

1417
type Props = {
18+
file: BoxItem;
1519
isOpen: boolean;
1620
onRequestClose: () => void;
1721
};
1822

19-
const ContentAnswersModal = ({ isOpen, onRequestClose }: Props) => {
23+
const ContentAnswersModal = ({ file, isOpen, onRequestClose }: Props) => {
2024
return (
2125
<Modal
2226
className="bdl-ContentAnswersModal"
@@ -36,7 +40,7 @@ const ContentAnswersModal = ({ isOpen, onRequestClose }: Props) => {
3640
}
3741
>
3842
<ContentAnswersModalContent />
39-
<ContentAnswersModalFooter />
43+
<ContentAnswersModalFooter data-testid="content-answers-modal-footer" file={file} />
4044
</Modal>
4145
);
4246
};

src/features/content-answers/ContentAnswersModalFooter.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,25 @@ import PrimaryButton from '../../components/primary-button';
66
// @ts-ignore flow import
77
import TextArea from '../../components/text-area';
88
import { TEXT_AREA } from './constants';
9+
import withCurrentUser from '../../elements/common/current-user';
10+
11+
// @ts-ignore: no ts definition
12+
// eslint-disable-next-line import/named
13+
import { BoxItem, User } from '../../../common/types/core';
914

1015
import './ContentAnswersModalFooter.scss';
1116

1217
import messages from './messages';
1318

1419
type Props = {
20+
file: BoxItem;
21+
currentUser?: User;
1522
intl: IntlShape;
1623
};
1724

18-
const ContentAnswersModalFooter = ({ intl }: Props) => {
25+
const ContentAnswersModalFooter = ({ currentUser, intl }: Props) => {
1926
const { formatMessage } = intl;
27+
const { id, name } = currentUser || {};
2028
const [inputMessage, setInputMessage] = useState('');
2129
const [isSubmitDisabled, setIsSubmitDisabled] = useState(true);
2230
const [hasMaxCharacterError, setHasMaxCharacterError] = useState(false);
@@ -34,7 +42,7 @@ const ContentAnswersModalFooter = ({ intl }: Props) => {
3442
return (
3543
<div className="bdl-ContentAnswersModalFooter">
3644
<div className="bdl-ContentAnswersModalFooter-avatar">
37-
<Avatar />
45+
<Avatar id={id} name={name} />
3846
</div>
3947
<TextArea
4048
data-testid="content-answers-question-input"
@@ -62,4 +70,4 @@ const ContentAnswersModalFooter = ({ intl }: Props) => {
6270
);
6371
};
6472

65-
export default injectIntl(ContentAnswersModalFooter);
73+
export default withCurrentUser(injectIntl(ContentAnswersModalFooter));
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import { fireEvent, render, screen } from '@testing-library/react';
3+
4+
import ContentAnswers from '../ContentAnswers';
5+
6+
jest.mock('../ContentAnswersModalFooter', () => () => <div />);
7+
8+
describe('features/content-answers', () => {
9+
const file = { extension: 'doc' };
10+
const renderComponent = (props?: {}) => render(<ContentAnswers file={file} {...props} />);
11+
12+
test('should render the content answers', () => {
13+
renderComponent();
14+
15+
const button = screen.getByTestId('content-answers-open-button');
16+
expect(button).toBeInTheDocument();
17+
fireEvent.click(button);
18+
const modal = screen.getByTestId('content-answers-modal');
19+
expect(modal).toBeInTheDocument();
20+
});
21+
});

src/features/content-answers/__tests__/ContentAnswersModal.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import { render, screen } from '@testing-library/react';
33

44
import ContentAnswersModal from '../ContentAnswersModal';
55

6+
jest.mock('../ContentAnswersModalFooter', () => () => <div />);
7+
68
describe('features/content-answers/ContentAnswersModal', () => {
9+
const file = { extension: 'doc' };
710
const renderComponent = (props?: {}) =>
8-
render(<ContentAnswersModal isOpen onRequestClose={jest.fn()} {...props} />);
11+
render(<ContentAnswersModal file={file} isOpen onRequestClose={jest.fn()} {...props} />);
912

1013
test('should render the header icon', () => {
1114
renderComponent();

src/features/content-answers/__tests__/ContentAnswersModalFooter.test.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,28 @@ import { fireEvent, render, screen } from '@testing-library/react';
55
import localize from '../../../../test/support/i18n';
66
import ContentAnswersModalFooter from '../ContentAnswersModalFooter';
77
import { MOCK_LONG_PROMPT, TEXT_AREA } from '../constants';
8+
// @ts-ignore: no ts definition
9+
// eslint-disable-next-line import/named
10+
import APIContext from '../../../elements/common/api-context';
811

912
import messages from '../messages';
1013

1114
describe('features/content-answers/ContentAnswersModalFooter', () => {
12-
const renderComponent = (props?: {}) => render(<ContentAnswersModalFooter {...props} />);
15+
const usersAPI = {
16+
getUser: (id: string, success: Function) => {
17+
success({ id: '123', name: 'Greg Wong' });
18+
},
19+
};
20+
const api = {
21+
getUsersAPI: () => usersAPI,
22+
};
23+
const file = { id: '123' };
24+
const renderComponent = (props?: {}) =>
25+
render(
26+
<APIContext.Provider value={api}>
27+
<ContentAnswersModalFooter file={file} {...props} />
28+
</APIContext.Provider>,
29+
);
1330

1431
test('should disable submit button if input is empty', () => {
1532
renderComponent();
@@ -37,4 +54,10 @@ describe('features/content-answers/ContentAnswersModalFooter', () => {
3754
);
3855
expect(error.length).not.toBe(0);
3956
});
57+
58+
test('should render avatar', () => {
59+
renderComponent();
60+
const initials = screen.getByText('GW');
61+
expect(initials).toBeInTheDocument();
62+
});
4063
});

0 commit comments

Comments
 (0)