diff --git a/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableHeaderRow.js b/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableHeaderRow.js index 411a3edfd..ddec80849 100644 --- a/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableHeaderRow.js +++ b/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableHeaderRow.js @@ -1,7 +1,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -const AdditionalFilesTableHeaderRow = () => ( +const AdditionalFilesTableHeaderRow = () => ( defaultMessage="Uploaded at" /> - -); + + ; export default AdditionalFilesTableHeaderRow; diff --git a/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableRow.js b/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableRow.js index 0d68c8ebf..c21e5632b 100644 --- a/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableRow.js +++ b/src/components/Exercises/AttachedFilesTable/AdditionalFilesTableRow.js @@ -1,38 +1,68 @@ import React from 'react'; import PropTypes from 'prop-types'; import prettyBytes from 'pretty-bytes'; -import { FormattedDate, FormattedTime } from 'react-intl'; +import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'; import withLinks from '../../../hoc/withLinks'; +import { Button } from 'react-bootstrap'; +import Confirm from '../../../components/forms/Confirm'; +import { DeleteIcon } from '../../../components/icons'; const AdditionalFilesTableRow = ({ id, name, size, uploadedAt, + removeFile, links: { DOWNLOAD } -}) => ( +}) => - {name} + + {name} + {DOWNLOAD(id)} - {prettyBytes(size)} + + {prettyBytes(size)} +   - -); + + {removeFile && + removeFile(id)} + question={ + + } + className="pull-right" + > + + } + + ; AdditionalFilesTableRow.propTypes = { id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, size: PropTypes.number.isRequired, uploadedAt: PropTypes.number.isRequired, - links: PropTypes.object.isRequired + links: PropTypes.object.isRequired, + removeFile: PropTypes.func }; export default withLinks(AdditionalFilesTableRow); diff --git a/src/containers/AdditionalExerciseFilesTableContainer/AdditionalExerciseFilesTableContainer.js b/src/containers/AdditionalExerciseFilesTableContainer/AdditionalExerciseFilesTableContainer.js index 751f17d96..510e20810 100644 --- a/src/containers/AdditionalExerciseFilesTableContainer/AdditionalExerciseFilesTableContainer.js +++ b/src/containers/AdditionalExerciseFilesTableContainer/AdditionalExerciseFilesTableContainer.js @@ -12,24 +12,25 @@ import { import { fetchAdditionalExerciseFiles, - addAdditionalExerciseFiles + addAdditionalExerciseFiles, + removeAdditionalExerciseFile } from '../../redux/modules/additionalExerciseFiles'; -import { - createGetAdditionalExerciseFiles -} from '../../redux/selectors/additionalExerciseFiles'; +import { createGetAdditionalExerciseFiles } from '../../redux/selectors/additionalExerciseFiles'; const AdditionalExerciseFilesTableContainer = ({ exercise, additionalExerciseFiles, loadFiles, - addFiles -}) => ( + addFiles, + removeFile +}) => -); + />; AdditionalExerciseFilesTableContainer.propTypes = { exercise: PropTypes.shape({ @@ -54,7 +54,8 @@ AdditionalExerciseFilesTableContainer.propTypes = { }).isRequired, additionalExerciseFiles: ImmutablePropTypes.map, loadFiles: PropTypes.func.isRequired, - addFiles: PropTypes.func.isRequired + addFiles: PropTypes.func.isRequired, + removeFile: PropTypes.func.isRequired }; export default connect( @@ -68,6 +69,7 @@ export default connect( }, (dispatch, { exercise }) => ({ loadFiles: () => dispatch(fetchAdditionalExerciseFiles(exercise.id)), - addFiles: files => dispatch(addAdditionalExerciseFiles(exercise.id, files)) + addFiles: files => dispatch(addAdditionalExerciseFiles(exercise.id, files)), + removeFile: id => dispatch(removeAdditionalExerciseFile(exercise.id, id)) }) )(AdditionalExerciseFilesTableContainer); diff --git a/src/redux/modules/additionalExerciseFiles.js b/src/redux/modules/additionalExerciseFiles.js index 6fc997f31..05353554c 100644 --- a/src/redux/modules/additionalExerciseFiles.js +++ b/src/redux/modules/additionalExerciseFiles.js @@ -17,7 +17,9 @@ export const actionTypes = { ADD_FILES: 'recodex/additionalExerciseFiles/ADD_FILES', ADD_FILES_PENDING: 'recodex/additionalExerciseFiles/ADD_FILES_PENDING', ADD_FILES_FULFILLED: 'recodex/additionalExerciseFiles/ADD_FILES_FULFILLED', - ADD_FILES_FAILED: 'recodex/additionalExerciseFiles/ADD_FILES_REJECTED' + ADD_FILES_FAILED: 'recodex/additionalExerciseFiles/ADD_FILES_REJECTED', + REMOVE_FILE: 'recodex/additionalExerciseFiles/REMOVE_FILE', + REMOVE_FILE_FULFILLED: 'recodex/additionalExerciseFiles/REMOVE_FILE_FULFILLED' }; export const fetchAdditionalExerciseFiles = exerciseId => @@ -42,6 +44,14 @@ export const addAdditionalExerciseFiles = (exerciseId, files) => } }); +export const removeAdditionalExerciseFile = (exerciseId, fileId) => + createApiAction({ + type: actionTypes.REMOVE_FILE, + endpoint: `/exercises/${exerciseId}/additional-files/${fileId}`, + method: 'DELETE', + meta: { exerciseId, fileId } + }); + /** * Reducer */ @@ -56,7 +66,11 @@ const reducer = handleActions( createRecord({ data, state: resourceStatus.FULFILLED }) ), state - ) + ), + [actionTypes.REMOVE_FILE_FULFILLED]: ( + state, + { payload, meta: { fileId } } + ) => state.deleteIn(['resources', fileId]) }), initialState );