Skip to content

Commit cc33edb

Browse files
authored
lk/submission actions (#43)
* chore: remove debris * feat: interactive submission actions * chore: add dirty for finishing later * chore: update fake api because of camelcase * chore: linting * chore: component tests for file upload * chore: component test for prompt * chore: component test for test response * chore: add component tests to submission view * chore: linting * chore: update test for data * chore: rename * chore: fix rich text editor
1 parent 50d2870 commit cc33edb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1932
-174
lines changed

src/App.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { Routes, Route } from 'react-router-dom';
22
import { ErrorPage } from '@edx/frontend-platform/react';
33
import { useIntl } from '@edx/frontend-platform/i18n';
4+
import { Spinner } from '@edx/paragon';
5+
6+
import { useIsORAConfigLoaded, useIsPageDataLoaded } from 'data/services/lms/hooks/selectors';
47

58
import PeerAssessmentView from 'views/PeerAssessmentView';
69
import SelfAssessmentView from 'views/SelfAssessmentView';
@@ -12,6 +15,22 @@ import routes from './routes';
1215
const RouterRoot = () => {
1316
const { formatMessage } = useIntl();
1417

18+
const isConfigLoaded = useIsORAConfigLoaded();
19+
const isPageLoaded = useIsPageDataLoaded();
20+
21+
if (!isConfigLoaded || !isPageLoaded) {
22+
return (
23+
<div className="h-screen d-flex justify-content-center align-items-center">
24+
<Spinner
25+
animation="border"
26+
variant="primary"
27+
className="mr-3 spinner-md"
28+
screenReaderText="loading"
29+
/>
30+
</div>
31+
);
32+
}
33+
1534
return (
1635
<Routes>
1736
<Route path={routes.peerAssessment} element={<PeerAssessmentView />} />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
import { IconButton, Icon } from '@edx/paragon';
3+
4+
import { useIntl } from '@edx/frontend-platform/i18n';
5+
import { Delete, Preview } from '@edx/paragon/icons';
6+
7+
import messages from './messages';
8+
9+
const ActionCell = () => {
10+
const { formatMessage } = useIntl();
11+
return (
12+
<>
13+
<IconButton
14+
src={Delete}
15+
alt={formatMessage(messages.deleteButtonAltText)}
16+
iconAs={Icon}
17+
/>
18+
<IconButton
19+
src={Preview}
20+
alt={formatMessage(messages.previewButtonAltText)}
21+
iconAs={Icon}
22+
/>
23+
</>
24+
);
25+
};
26+
27+
export default ActionCell;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { shallow } from '@edx/react-unit-test-utils';
2+
import ActionCell from './ActionCell';
3+
4+
describe('<ActionCell />', () => {
5+
it('renders', () => {
6+
const wrapper = shallow(<ActionCell />);
7+
expect(wrapper.snapshot).toMatchSnapshot();
8+
});
9+
});

src/components/FileUpload/FileMetaDisplay.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import messages from './messages';
88

99
const FileMetaDisplay = ({ name, description, size }) => (
1010
<>
11-
{console.log({ name, description, size })}
1211
<div className="file-meta-option">
1312
<strong><FormattedMessage {...messages.filePopoverNameTitle} /></strong>
1413
<br />
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
import {
5+
Form, FormLabel, ModalDialog, Button, ActionRow,
6+
} from '@edx/paragon';
7+
import { useIntl } from '@edx/frontend-platform/i18n';
8+
import messages from './messages';
9+
import { useUploadConfirmModalHooks } from './hooks';
10+
11+
const UploadConfirmModal = ({
12+
open, files, closeHandler, uploadHandler,
13+
}) => {
14+
const { formatMessage } = useIntl();
15+
16+
const {
17+
errors, exitHandler, confirmUploadClickHandler, onFileDescriptionChange,
18+
} = useUploadConfirmModalHooks({
19+
files,
20+
closeHandler,
21+
uploadHandler,
22+
});
23+
24+
return (
25+
<ModalDialog
26+
isOpen={open}
27+
title={formatMessage(messages.uploadFileModalTitle)}
28+
hasCloseButton={false}
29+
onClose={exitHandler}
30+
>
31+
<ModalDialog.Header>
32+
<ModalDialog.Title>
33+
{formatMessage(messages.uploadFileModalTitle)}
34+
</ModalDialog.Title>
35+
</ModalDialog.Header>
36+
37+
<ModalDialog.Body>
38+
<div>
39+
{files.map((file, i) => (
40+
// eslint-disable-next-line react/no-array-index-key
41+
<Form.Group key={i}>
42+
<FormLabel>
43+
<strong>
44+
{formatMessage(messages.uploadFileDescriptionFieldLabel)}
45+
</strong>
46+
<span className="file-name-ellipsis">{file.name}</span>
47+
</FormLabel>
48+
<Form.Control
49+
isInvalid={errors[i]}
50+
name={`file-${i}-description`}
51+
onChange={onFileDescriptionChange(file)}
52+
/>
53+
{errors[i] && (
54+
<Form.Control.Feedback type="invalid">
55+
{errors[i] && formatMessage(messages.fileDescriptionMissingError)}
56+
</Form.Control.Feedback>
57+
)}
58+
</Form.Group>
59+
))}
60+
</div>
61+
</ModalDialog.Body>
62+
<ModalDialog.Footer>
63+
<ActionRow>
64+
<ModalDialog.CloseButton variant="tertiary" onClick={exitHandler}>
65+
{formatMessage(messages.cancelUploadFileButton)}
66+
</ModalDialog.CloseButton>
67+
<Button variant="primary" onClick={confirmUploadClickHandler}>
68+
{formatMessage(messages.confirmUploadFileButton)}
69+
</Button>
70+
</ActionRow>
71+
</ModalDialog.Footer>
72+
</ModalDialog>
73+
);
74+
};
75+
76+
UploadConfirmModal.defaultProps = {
77+
open: false,
78+
files: [],
79+
closeHandler: () => {},
80+
uploadHandler: () => {},
81+
};
82+
UploadConfirmModal.propTypes = {
83+
open: PropTypes.bool,
84+
files: PropTypes.arrayOf(
85+
PropTypes.shape({
86+
name: PropTypes.string,
87+
description: PropTypes.string,
88+
}),
89+
),
90+
closeHandler: PropTypes.func,
91+
uploadHandler: PropTypes.func,
92+
};
93+
94+
export default UploadConfirmModal;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { shallow } from '@edx/react-unit-test-utils';
2+
import UploadConfirmModal from './UploadConfirmModal';
3+
4+
import { useUploadConfirmModalHooks } from './hooks';
5+
6+
jest.mock('./hooks', () => ({
7+
useUploadConfirmModalHooks: jest.fn(),
8+
}));
9+
10+
describe('<UploadConfirmModal />', () => {
11+
const props = {
12+
open: true,
13+
files: [],
14+
closeHandler: jest.fn().mockName('closeHandler'),
15+
uploadHandler: jest.fn().mockName('uploadHandler'),
16+
};
17+
18+
const mockHooks = (overrides) => {
19+
useUploadConfirmModalHooks.mockReturnValueOnce({
20+
errors: [],
21+
exitHandler: jest.fn().mockName('exitHandler'),
22+
confirmUploadClickHandler: jest.fn().mockName('confirmUploadClickHandler'),
23+
onFileDescriptionChange: () => jest.fn().mockName('onFileDescriptionChange'),
24+
...overrides,
25+
});
26+
};
27+
describe('renders', () => {
28+
test('no files', () => {
29+
mockHooks();
30+
const wrapper = shallow(<UploadConfirmModal {...props} />);
31+
expect(wrapper.snapshot).toMatchSnapshot();
32+
33+
expect(wrapper.instance.findByType('Form.Group').length).toBe(0);
34+
});
35+
36+
test('multiple files', () => {
37+
mockHooks(
38+
{ errors: new Array(2) },
39+
);
40+
const wrapper = shallow(<UploadConfirmModal {...props} files={[{ name: 'file1' }, { name: 'file2' }]} />);
41+
expect(wrapper.snapshot).toMatchSnapshot();
42+
43+
expect(wrapper.instance.findByType('Form.Group').length).toBe(2);
44+
expect(wrapper.instance.findByType('Form.Control.Feedback').length).toBe(0);
45+
});
46+
47+
test('with errors', () => {
48+
mockHooks({ errors: [true, false] });
49+
const wrapper = shallow(<UploadConfirmModal {...props} files={[{ name: 'file1' }, { name: 'file2' }]} />);
50+
// wrapper.setState({ errors: [true, false] });
51+
expect(wrapper.snapshot).toMatchSnapshot();
52+
53+
expect(wrapper.instance.findByType('Form.Group').length).toBe(2);
54+
expect(wrapper.instance.findByType('Form.Control.Feedback').length).toBe(1);
55+
});
56+
});
57+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<ActionCell /> renders 1`] = `
4+
<Fragment>
5+
<IconButton
6+
alt="Delete"
7+
iconAs="Icon"
8+
src={[Function]}
9+
/>
10+
<IconButton
11+
alt="Preview"
12+
iconAs="Icon"
13+
src={[Function]}
14+
/>
15+
</Fragment>
16+
`;

0 commit comments

Comments
 (0)