Skip to content

Commit 8130075

Browse files
committed
fix: attachment fixes and implevements
- updated code to use changed POST endpoint which accepts multiple attachments at once - fix callback which is called after all attachments are loaded - fix internal FilePicker logic, which had issue when uploading many attachments in the same time (replaced useState with useReducer) - fix view attachments mode - improve error handling - fix issue caused by reverting PR for attachments
1 parent c141563 commit 8130075

File tree

10 files changed

+222
-134
lines changed

10 files changed

+222
-134
lines changed

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/actions/challenges.js

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
fetchGroups,
66
fetchTimelineTemplates,
77
fetchChallengePhases,
8-
createAttachment as createAttachmentAPI,
8+
createAttachments as createAttachmentsAPI,
99
removeAttachment as removeAttachmentAPI,
1010
fetchChallenge,
1111
fetchChallenges,
@@ -383,31 +383,24 @@ export function loadGroups () {
383383
}
384384
}
385385

386-
export function createAttachment (challengeId, file) {
386+
export function createAttachments (challengeId, files) {
387387
return async (dispatch) => {
388-
// create a temporary uploading id for each attachment
389-
// so we can identify them for various actions (names theoretically can duplicate)
390-
const uploadingId = _.uniqueId('uploadingId_')
391-
392388
dispatch({
393389
type: CREATE_ATTACHMENT_PENDING,
394390
challengeId,
395-
file,
396-
uploadingId
391+
files
397392
})
398393

399394
try {
400-
const attachment = await createAttachmentAPI(challengeId, file)
395+
const attachment = await createAttachmentsAPI(challengeId, files)
401396
dispatch({
402397
type: CREATE_ATTACHMENT_SUCCESS,
403-
attachment: attachment.data,
404-
uploadingId
398+
attachments: attachment.data
405399
})
406400
} catch (error) {
407401
dispatch({
408402
type: CREATE_ATTACHMENT_FAILURE,
409-
file,
410-
uploadingId
403+
files
411404
})
412405
}
413406
}

src/components/ChallengeEditor/Attachment-Field/index.js

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _ from 'lodash'
2-
import React from 'react'
2+
import React, { useCallback } from 'react'
33
import PropTypes from 'prop-types'
44
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
55
import { downloadAttachmentURL, SPECIFICATION_ATTACHMENTS_FOLDER, getAWSContainerFileURL } from '../../../config/constants'
@@ -8,18 +8,32 @@ import FilestackFilePicker from '../../FilestackFilePicker'
88
import styles from './Attachment-Field.module.scss'
99
import Loader from '../../Loader'
1010

11-
const AttachmentField = ({ challengeId, attachments, removeAttachment, onUploadFile, token, readOnly }) => {
11+
const AttachmentField = ({ challengeId, attachments, removeAttachment, onUploadFiles, token, readOnly }) => {
12+
// when all files are upload to the S3 this method would be called to create attachments via Challenge API
13+
const onUploadDone = useCallback(({ filesUploaded }) => {
14+
if (filesUploaded && filesUploaded.length > 0) {
15+
onUploadFiles(
16+
challengeId,
17+
filesUploaded.map(file => ({
18+
name: file.originalFile.name,
19+
fileSize: file.originalFile.size,
20+
url: encodeURI(getAWSContainerFileURL(file.key))
21+
}))
22+
)
23+
}
24+
}, [challengeId, onUploadFiles])
25+
1226
const renderAttachments = (attachments) => (
1327
_.map(attachments, (att, index) => (
14-
<div className={styles.fileRow} key={att.id || att.uploadingId}>
28+
<div className={styles.fileRow} key={att.id || att.url}>
1529
<a className={styles.col1} href={downloadAttachmentURL(challengeId, att.id, token)} target='_blank'>{att.name}</a>
1630
<div className={styles.col2}>{formatBytes(att.fileSize)}</div>
1731
{!readOnly && (
1832
<div className={styles.actions}>
19-
{!att.isDeleting && !att.isUploading && (
33+
{!att.isDeleting && att.id && (
2034
<FontAwesomeIcon icon={faTrash} size={'lg'} onClick={() => removeAttachment(challengeId, att.id)} className={styles.removeIcon} />
2135
)}
22-
{(att.isDeleting || att.isUploading) && (
36+
{(att.isDeleting || !att.id) && (
2337
<div className={styles.loader}><Loader /></div>
2438
)}
2539
</div>
@@ -47,11 +61,7 @@ const AttachmentField = ({ challengeId, attachments, removeAttachment, onUploadF
4761
<div className={styles.row}>
4862
<FilestackFilePicker
4963
path={`challenges/${challengeId}/${SPECIFICATION_ATTACHMENTS_FOLDER}/`}
50-
onFileUploadFinished={(file) => onUploadFile(challengeId, {
51-
name: file.filename,
52-
fileSize: file.size,
53-
url: getAWSContainerFileURL(file.key)
54-
})}
64+
onUploadDone={onUploadDone}
5565
/>
5666
</div>
5767
)}
@@ -61,7 +71,7 @@ const AttachmentField = ({ challengeId, attachments, removeAttachment, onUploadF
6171
<div className={styles.header}>
6272
<div className={styles.col1}>File Name</div>
6373
<div className={styles.col2}>Size</div>
64-
<div className={styles.col3}>Action</div>
74+
{!readOnly && <div className={styles.col3}>Action</div>}
6575
</div>
6676
{ renderAttachments(attachments) }
6777
</div>
@@ -73,7 +83,7 @@ const AttachmentField = ({ challengeId, attachments, removeAttachment, onUploadF
7383

7484
AttachmentField.defaultProps = {
7585
removeAttachment: () => {},
76-
onUploadFile: () => {},
86+
onUploadFiles: () => {},
7787
readOnly: false,
7888
attachments: []
7989
}
@@ -82,7 +92,7 @@ AttachmentField.propTypes = {
8292
challengeId: PropTypes.string.isRequired,
8393
attachments: PropTypes.array,
8494
removeAttachment: PropTypes.func,
85-
onUploadFile: PropTypes.func,
95+
onUploadFiles: PropTypes.func,
8696
token: PropTypes.string.isRequired,
8797
readOnly: PropTypes.bool
8898
}

src/components/ChallengeEditor/index.js

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -755,18 +755,6 @@ class ChallengeEditor extends Component {
755755
this.setState({ challenge: newChallenge })
756756
}
757757

758-
onUploadFile (files) {
759-
const { challenge: oldChallenge } = this.state
760-
const newChallenge = { ...oldChallenge }
761-
_.forEach(files, (file) => {
762-
newChallenge.attachments.push({
763-
fileName: file.name,
764-
size: file.size
765-
})
766-
})
767-
this.setState({ challenge: newChallenge })
768-
}
769-
770758
collectChallengeData (status) {
771759
const { attachments, metadata } = this.props
772760
const challenge = pick([
@@ -1141,7 +1129,7 @@ class ChallengeEditor extends Component {
11411129
isNew,
11421130
isLoading,
11431131
metadata,
1144-
uploadAttachment,
1132+
uploadAttachments,
11451133
token,
11461134
removeAttachment,
11471135
failedToLoad,
@@ -1470,7 +1458,7 @@ class ChallengeEditor extends Component {
14701458
challenge={{ ...challenge, id: currentChallengeId }}
14711459
challengeId={currentChallengeId}
14721460
attachments={attachments}
1473-
onUploadFile={uploadAttachment}
1461+
onUploadFiles={uploadAttachments}
14741462
token={token}
14751463
removeAttachment={removeAttachment}
14761464
/>
@@ -1525,7 +1513,7 @@ ChallengeEditor.propTypes = {
15251513
challengeId: PropTypes.string,
15261514
metadata: PropTypes.object.isRequired,
15271515
isLoading: PropTypes.bool.isRequired,
1528-
uploadAttachment: PropTypes.func.isRequired,
1516+
uploadAttachments: PropTypes.func.isRequired,
15291517
removeAttachment: PropTypes.func.isRequired,
15301518
attachments: PropTypes.arrayOf(PropTypes.shape()),
15311519
token: PropTypes.string.isRequired,

src/components/FilestackFilePicker/FilestackFilePicker.module.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
padding: 20px;
99
border: 1px solid $tc-gray-40;
1010
border-radius: 6px;
11-
height: 227px;
11+
min-height: 227px;
1212
position: relative;
1313
font-size: 16px;
1414
font-weight: 400;

0 commit comments

Comments
 (0)