Skip to content

Commit 2b083a6

Browse files
fix: add FileUpload component
1 parent b6fa0cf commit 2b083a6

File tree

4 files changed

+174
-25
lines changed

4 files changed

+174
-25
lines changed

src/components/FileUpload/UploadConfirmModal.jsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ const UploadConfirmModal = ({
1414
const { formatMessage } = useIntl();
1515

1616
const {
17-
errors, exitHandler, confirmUploadClickHandler, onFileDescriptionChange,
17+
errors,
18+
exitHandler,
19+
confirmUploadClickHandler,
20+
onFileDescriptionChange,
1821
} = useUploadConfirmModalHooks({
1922
files,
2023
closeHandler,
@@ -37,6 +40,7 @@ const UploadConfirmModal = ({
3740
<ModalDialog.Body>
3841
<div>
3942
{files.map((file, i) => (
43+
// note: we only support one file
4044
// eslint-disable-next-line react/no-array-index-key
4145
<Form.Group key={i}>
4246
<FormLabel>
@@ -48,7 +52,7 @@ const UploadConfirmModal = ({
4852
<Form.Control
4953
isInvalid={errors[i]}
5054
name={`file-${i}-description`}
51-
onChange={onFileDescriptionChange(file)}
55+
onChange={onFileDescriptionChange}
5256
/>
5357
{errors[i] && (
5458
<Form.Control.Feedback type="invalid">

src/components/FileUpload/UploadConfirmModal.test.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('<UploadConfirmModal />', () => {
2020
errors: [],
2121
exitHandler: jest.fn().mockName('exitHandler'),
2222
confirmUploadClickHandler: jest.fn().mockName('confirmUploadClickHandler'),
23-
onFileDescriptionChange: () => jest.fn().mockName('onFileDescriptionChange'),
23+
onFileDescriptionChange: jest.fn().mockName('onFileDescriptionChange'),
2424
...overrides,
2525
});
2626
};

src/components/FileUpload/__snapshots__/index.test.jsx.snap

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,144 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`<FileUpload /> render default 1`] = `
4+
<div>
5+
<h3>
6+
File Upload
7+
</h3>
8+
<Fragment>
9+
<b>
10+
Uploaded Files
11+
</b>
12+
<DataTable
13+
columns={
14+
Array [
15+
Object {
16+
"Header": "File Name",
17+
"accessor": "fileName",
18+
},
19+
Object {
20+
"Header": "File Description",
21+
"accessor": "fileDescription",
22+
},
23+
Object {
24+
"Header": "File Size",
25+
"accessor": "fileSize",
26+
},
27+
Object {
28+
"Cell": "ActionCell",
29+
"Header": "Actions",
30+
"accessor": "actions",
31+
},
32+
]
33+
}
34+
data={
35+
Array [
36+
Object {
37+
"fileDescription": "file1 desc",
38+
"fileName": "file1",
39+
"fileSize": 100,
40+
"size": "Unknown",
41+
},
42+
Object {
43+
"fileDescription": "file2 desc",
44+
"fileName": "file2",
45+
"fileSize": 200,
46+
"size": "Unknown",
47+
},
48+
]
49+
}
50+
itemCount={2}
51+
/>
52+
</Fragment>
53+
<Dropzone
54+
multiple={true}
55+
onProcessUpload={[MockFunction onProcessUpload]}
56+
progressVariant="bar"
57+
/>
58+
<UploadConfirmModal
59+
closeHandler={[MockFunction closeUploadModal]}
60+
open={false}
61+
uploadHandler={[MockFunction confirmUpload]}
62+
/>
63+
</div>
64+
`;
65+
66+
exports[`<FileUpload /> render no uploaded files 1`] = `
67+
<div>
68+
<h3>
69+
File Upload
70+
</h3>
71+
<Dropzone
72+
multiple={true}
73+
onProcessUpload={[MockFunction onProcessUpload]}
74+
progressVariant="bar"
75+
/>
76+
<UploadConfirmModal
77+
closeHandler={[MockFunction closeUploadModal]}
78+
open={false}
79+
uploadHandler={[MockFunction confirmUpload]}
80+
/>
81+
</div>
82+
`;
83+
84+
exports[`<FileUpload /> render read only 1`] = `
85+
<div>
86+
<h3>
87+
File Upload
88+
</h3>
89+
<Fragment>
90+
<b>
91+
Uploaded Files
92+
</b>
93+
<DataTable
94+
columns={
95+
Array [
96+
Object {
97+
"Header": "File Name",
98+
"accessor": "fileName",
99+
},
100+
Object {
101+
"Header": "File Description",
102+
"accessor": "fileDescription",
103+
},
104+
Object {
105+
"Header": "File Size",
106+
"accessor": "fileSize",
107+
},
108+
Object {
109+
"Cell": "ActionCell",
110+
"Header": "Actions",
111+
"accessor": "actions",
112+
},
113+
]
114+
}
115+
data={
116+
Array [
117+
Object {
118+
"fileDescription": "file1 desc",
119+
"fileName": "file1",
120+
"fileSize": 100,
121+
"size": "Unknown",
122+
},
123+
Object {
124+
"fileDescription": "file2 desc",
125+
"fileName": "file2",
126+
"fileSize": 200,
127+
"size": "Unknown",
128+
},
129+
]
130+
}
131+
itemCount={2}
132+
/>
133+
</Fragment>
134+
<UploadConfirmModal
135+
closeHandler={[MockFunction closeUploadModal]}
136+
open={false}
137+
uploadHandler={[MockFunction confirmUpload]}
138+
/>
139+
</div>
140+
`;
141+
3142
exports[`<FileUpload /> renders default 1`] = `
4143
<div>
5144
<h3>

src/components/FileUpload/hooks.js

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
import { useState, useReducer, useCallback } from 'react';
1+
import { useCallback } from 'react';
22

3+
import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils';
4+
5+
export const stateKeys = StrictDict({
6+
errors: 'errors',
7+
isModalOpen: 'isModalOpen',
8+
uploadArgs: 'uploadArgs',
9+
description: 'description',
10+
});
311
export const useUploadConfirmModalHooks = ({
412
files, closeHandler, uploadHandler,
513
}) => {
6-
const [errors, setErrors] = useState([]);
14+
const [description, setDescription] = useKeyedState(stateKeys.description, null);
15+
const [errors, setErrors] = useKeyedState(stateKeys.errors, []);
716

817
const confirmUploadClickHandler = () => {
918
const errorList = files.map((file) => (!file.description));
@@ -21,7 +30,7 @@ export const useUploadConfirmModalHooks = ({
2130

2231
// Modifying pointer of file object. This is not a good practice.
2332
// eslint-disable-next-line no-param-reassign, no-return-assign
24-
const onFileDescriptionChange = (file) => (event) => file.description = event.target.value;
33+
const onFileDescriptionChange = (event) => setDescription(event.target.value);
2534

2635
return {
2736
errors,
@@ -34,33 +43,30 @@ export const useUploadConfirmModalHooks = ({
3443
export const useFileUploadHooks = ({
3544
onFileUploaded,
3645
}) => {
37-
const [uploadState, dispatchUploadState] = useReducer(
38-
(state, payload) => ({ ...state, ...payload }),
39-
{
40-
onProcessUploadArgs: {},
41-
openModal: false,
42-
},
43-
);
46+
const [uploadArgs, setUploadArgs] = useKeyedState(stateKeys.uploadArgs, {});
47+
const [isModalOpen, setIsModalOpen] = useKeyedState(stateKeys.isModalOpen, false);
4448

4549
const confirmUpload = useCallback(async () => {
46-
dispatchUploadState({ openModal: false });
47-
await onFileUploaded(uploadState.onProcessUploadArgs);
48-
dispatchUploadState({ onProcessUploadArgs: {} });
49-
}, [uploadState, onFileUploaded]);
50+
setIsModalOpen(false);
51+
if (onFileUploaded) {
52+
await onFileUploaded(uploadArgs);
53+
}
54+
setUploadArgs({});
55+
}, [uploadArgs, onFileUploaded, setIsModalOpen, setUploadArgs]);
5056

5157
const closeUploadModal = useCallback(() => {
52-
dispatchUploadState({ openModal: false, onProcessUploadArgs: {} });
53-
}, []);
58+
setIsModalOpen(false);
59+
setUploadArgs({});
60+
}, [setIsModalOpen, setUploadArgs]);
5461

5562
const onProcessUpload = useCallback(({ fileData, handleError, requestConfig }) => {
56-
dispatchUploadState({
57-
onProcessUploadArgs: { fileData, handleError, requestConfig },
58-
openModal: true,
59-
});
60-
}, []);
63+
setIsModalOpen(true);
64+
setUploadArgs({ fileData, handleError, requestConfig });
65+
}, [setIsModalOpen, setUploadArgs]);
6166

6267
return {
63-
uploadState,
68+
isModalOpen,
69+
uploadArgs,
6470
confirmUpload,
6571
closeUploadModal,
6672
onProcessUpload,

0 commit comments

Comments
 (0)