Skip to content

Commit

Permalink
Lk/add download (#72)
Browse files Browse the repository at this point in the history
* chore: update message id

* feat: implement download all

* chore: update progress bar url logic
  • Loading branch information
leangseu-edx authored Nov 2, 2023
1 parent aedd210 commit 3f613f7
Show file tree
Hide file tree
Showing 32 changed files with 2,158 additions and 550 deletions.
1,911 changes: 1,643 additions & 268 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@
"@tanstack/react-query": "^4.29.25",
"@tanstack/react-query-devtools": "^4.35.3",
"@tinymce/tinymce-react": "3.14.0",
"@zip.js/zip.js": "^2.7.30",
"axios": "^1.5.1",
"classnames": "^2.3.2",
"core-js": "3.32.2",
"file-saver": "^2.0.5",
"filesize": "^8.0.6",
"jest-when": "^3.6.0",
"moment": "^2.29.4",
Expand Down
18 changes: 9 additions & 9 deletions src/components/Assessment/ReadonlyAssessment/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,37 @@ import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
readMore: {
id: 'ora-collapsible-comment.readMore',
id: 'frontend-app-ora.readMore',
defaultMessage: 'Read more',
description: 'Read more button text',
},
readLess: {
id: 'ora-collapsible-comment.readLess',
id: 'frontend-app-ora.readLess',
defaultMessage: 'Read less',
description: 'Read less button text',
},
unweightedGrade: {
id: 'ora-collapsible-comment.grade',
id: 'ora-collapsible-comment.unweightedGrade',
defaultMessage: '{stepLabel} Grade',
description: 'Unweighted grade group text',
},
grade: {
id: 'ora-collapsible-comment.grade',
defaultMessage: '{stepLabel} Grade: ',
description: 'Grade group text',
id: 'frontend-app-ora.grade',
defaultMessage: '{stepLabel} Grade:',
description: 'Grade button text',
},
gradePoints: {
id: 'ora-collapsible-comment.gradePoints',
id: 'frontend-app-ora.gradePoints',
defaultMessage: '{earned} / {possible}',
description: 'Grade points button text',
},
notWeightedGradeLabel: {
id: 'ora-collapsible-comment.notWeightedGradeLabel',
id: 'frontend-app-ora.notWeightedGradeLabel',
defaultMessage: '(Not weighted toward final grade))',
description: 'Not weighted grade label',
},
overallFeedback: {
id: 'ora-collapsible-comment.overallFeedback',
id: 'frontend-app-ora.overallFeedback',
defaultMessage: 'Overall Feedback',
description: 'Overall feedback label',
},
Expand Down
16 changes: 8 additions & 8 deletions src/components/Assessment/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,42 @@ import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
gradeSubmitted: {
id: 'ora-grading.Rubric.gradeSubmitted',
id: 'frontend-app-ora.Rubric.gradeSubmitted',
defaultMessage: 'Grade Submitted',
description: 'Submit Grade button text after successful submission',
},
rubric: {
id: 'ora-grading.Rubric.rubric',
id: 'frontend-app-ora.Rubric.rubric',
defaultMessage: 'Rubric',
description: 'Rubric interface label',
},
submitGrade: {
id: 'ora-grading.Rubric.submitGrade',
id: 'frontend-app-ora.Rubric.submitGrade',
defaultMessage: 'Submit grade',
description: 'Submit Grade button text',
},
submittingGrade: {
id: 'ora-grading.Rubric.submittingGrade',
id: 'frontend-app-ora.Rubric.submittingGrade',
defaultMessage: 'Submitting grade',
description: 'Submit Grade button text while submitting',
},
overallComments: {
id: 'ora-grading.Rubric.overallComments',
id: 'frontend-app-ora.Rubric.overallComments',
defaultMessage: 'Overall comments',
description: 'Rubric overall commnents label',
},
addComments: {
id: 'ora-grading.Rubric.addComments',
id: 'frontend-app-ora.Rubric.addComments',
defaultMessage: 'Add comments (Optional)',
description: 'Rubric comments input label',
},
comments: {
id: 'ora-grading.Rubric.comments',
id: 'frontend-app-ora.Rubric.comments',
defaultMessage: 'Comments (Optional)',
description: 'Rubric comments display label',
},
overallFeedbackError: {
id: 'ora-grading.RubricFeedback.error',
id: 'frontend-app-ora.RubricFeedback.error',
defaultMessage: 'The overall feedback is required',
description: 'Error message when feedback input is required',
},
Expand Down
12 changes: 6 additions & 6 deletions src/components/CriterionContainer/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@ import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
addComments: {
id: 'ora-grading.CriterionFeedback.addCommentsLabel',
id: 'frontend-app-ora.CriterionFeedback.addCommentsLabel',
defaultMessage: 'Add comments',
description: 'label for editable feedback field',
},
comments: {
id: 'ora-grading.CriterionFeedback.commentsLabel',
id: 'frontend-app-ora.CriterionFeedback.commentsLabel',
defaultMessage: 'Comments',
description: 'label for read-only feedback field',
},
optional: {
id: 'ora-grading.CriterionFeedback.optional',
id: 'frontend-app-ora.CriterionFeedback.optional',
defaultMessage: '(Optional)',
description: 'addtional label for optional feedback field',
},
optionPoints: {
id: 'ora-grading.RadioCriterion.optionPoints',
id: 'frontend-app-ora.RadioCriterion.optionPoints',
defaultMessage: '{points} points',
description: 'criterion option point value display',
},
rubricSelectedError: {
id: 'ora-grading.RadioCriterion.rubricSelectedError',
id: 'frontend-app-ora.RadioCriterion.rubricSelectedError',
defaultMessage: 'Rubric selection is required',
description: 'Error message when rubric radio did not get selected',
},
criterionFeedbackError: {
id: 'ora-grading.CriterionFeedback.criterionFeedbackError',
id: 'frontend-app-ora.CriterionFeedback.criterionFeedbackError',
defaultMessage: 'The feedback is required',
description: 'Error message when feedback is required',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
fileInfo: {
id: 'ora-grading.InfoPopover.fileInfo',
id: 'frontend-app-ora.InfoPopover.fileInfo',
defaultMessage: 'File info',
description: 'Popover trigger button text for file preview card',
},
retryButton: {
id: 'ora-grading.ResponseDisplay.FileRenderer.retryButton',
id: 'frontend-app-ora.ResponseDisplay.FileRenderer.retryButton',
defaultMessage: 'Retry',
description: 'Retry button for error in file renderer',
},
Expand Down
4 changes: 2 additions & 2 deletions src/components/FilePreview/components/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
fileNotFoundError: {
id: 'ora-grading.ResponseDisplay.FileRenderer.fileNotFound',
id: 'frontend-app-ora.ResponseDisplay.FileRenderer.fileNotFound',
defaultMessage: 'File not found',
description: 'File not found error message',
},
unknownError: {
id: 'ora-grading.ResponseDisplay.FileRenderer.unknownError',
id: 'frontend-app-ora.ResponseDisplay.FileRenderer.unknownError',
defaultMessage: 'Unknown errors',
description: 'Unknown errors message',
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/FileUpload/ActionCell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const ActionCell = ({
/>
)}
<IconButton
src={Preview}
src={Delete}
alt={formatMessage(messages.previewButtonAltText)}
iconAs={Icon}
disabled={disabled}
Expand Down
59 changes: 59 additions & 0 deletions src/components/FileUpload/FileDownload.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from '@edx/frontend-platform/i18n';

import { StatefulButton, Icon } from '@edx/paragon';

import { useDownloadFiles } from 'data/services/lms/hooks/actions';
import { MutationStatus } from 'data/services/lms/constants';

import messages from './messages';
import { useParams } from 'react-router';
import { useFileDownloadHooks } from './hooks';

/**
* <FileDownload />
*/
export const FileDownload = ({ files }) => {
const { xblockId } = useParams();
const { downloadFiles, status } = useFileDownloadHooks({
files,
zipFileName: xblockId,
});
return (
<StatefulButton
state={status}
disabledStates={[MutationStatus.loading, MutationStatus.success]}
onClick={downloadFiles}
icons={{
[MutationStatus.idle]: <Icon className='fa fa-download' />,
[MutationStatus.loading]: <Icon className='fa fa-spinner fa-spin' />,
[MutationStatus.success]: <Icon className='fa fa-check' />,
[MutationStatus.error]: <Icon className='fa fa-refresh' />,
}}
labels={{
[MutationStatus.idle]: <FormattedMessage {...messages.downloadFiles} />,
[MutationStatus.loading]: (
<FormattedMessage {...messages.downloading} />
),
[MutationStatus.success]: <FormattedMessage {...messages.downloaded} />,
[MutationStatus.error]: (
<FormattedMessage {...messages.retryDownload} />
),
}}
/>
);
};

FileDownload.defaultProps = {};
FileDownload.propTypes = {
files: PropTypes.arrayOf(
PropTypes.shape({
fileUrl: PropTypes.string.isRequired,
fileName: PropTypes.string.isRequired,
fileDescription: PropTypes.string,
})
).isRequired,
};

export default FileDownload;
2 changes: 1 addition & 1 deletion src/components/FileUpload/UploadConfirmModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const UploadConfirmModal = ({
/>
{shouldShowError && (
<Form.Control.Feedback type="invalid">
formatMessage(messages.fileDescriptionMissingError)
{formatMessage(messages.fileDescriptionMissingError)}
</Form.Control.Feedback>
)}
</Form.Group>
Expand Down
49 changes: 38 additions & 11 deletions src/components/FileUpload/hooks.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import { useCallback } from 'react';

import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils';
import { useDownloadFiles } from 'data/services/lms/hooks/actions';

export const stateKeys = StrictDict({
shouldShowError: 'shouldShowError',
isModalOpen: 'isModalOpen',
uploadArgs: 'uploadArgs',
description: 'description',
});

export const useUploadConfirmModalHooks = ({
file, closeHandler, uploadHandler,
file,
closeHandler,
uploadHandler,
}) => {
const [description, setDescription] = useKeyedState(stateKeys.description, '');
const [shouldShowError, setShouldShowError] = useKeyedState(stateKeys.shouldShowError, false);
const [description, setDescription] = useKeyedState(
stateKeys.description,
''
);
const [shouldShowError, setShouldShowError] = useKeyedState(
stateKeys.shouldShowError,
false
);

const confirmUploadClickHandler = () => {
if (description !== '') {
Expand Down Expand Up @@ -40,11 +50,12 @@ export const useUploadConfirmModalHooks = ({
};
};

export const useFileUploadHooks = ({
onFileUploaded,
}) => {
export const useFileUploadHooks = ({ onFileUploaded }) => {
const [uploadArgs, setUploadArgs] = useKeyedState(stateKeys.uploadArgs, {});
const [isModalOpen, setIsModalOpen] = useKeyedState(stateKeys.isModalOpen, false);
const [isModalOpen, setIsModalOpen] = useKeyedState(
stateKeys.isModalOpen,
false
);

const confirmUpload = useCallback(async () => {
setIsModalOpen(false);
Expand All @@ -59,10 +70,13 @@ export const useFileUploadHooks = ({
setUploadArgs({});
}, [setIsModalOpen, setUploadArgs]);

const onProcessUpload = useCallback(({ fileData, handleError, requestConfig }) => {
setIsModalOpen(true);
setUploadArgs({ fileData, handleError, requestConfig });
}, [setIsModalOpen, setUploadArgs]);
const onProcessUpload = useCallback(
({ fileData, handleError, requestConfig }) => {
setIsModalOpen(true);
setUploadArgs({ fileData, handleError, requestConfig });
},
[setIsModalOpen, setUploadArgs]
);

return {
isModalOpen,
Expand All @@ -73,6 +87,19 @@ export const useFileUploadHooks = ({
};
};

export const useFileDownloadHooks = ({ files, zipFileName }) => {
const downloadFileMation = useDownloadFiles();
const downloadFiles = () =>
downloadFileMation.mutate({
files,
zipFileName,
});
return {
downloadFiles,
status: downloadFileMation.status,
};
};

export default {
useUploadConfirmModalHooks,
useFileUploadHooks,
Expand Down
4 changes: 4 additions & 0 deletions src/components/FileUpload/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ActionCell from './ActionCell';
import { useFileUploadHooks } from './hooks';
import messages from './messages';
import FilePreview from 'components/FilePreview';
import FileDownload from './FileDownload';

import './styles.scss';

Expand Down Expand Up @@ -50,6 +51,9 @@ const FileUpload = ({
...file,
size: typeof file.size === 'number' ? filesize(file.size) : 'Unknown',
}))}
tableActions={[
<FileDownload files={uploadedFiles} />,
]}
columns={[
{
Header: formatMessage(messages.fileNameTitle),
Expand Down
Loading

0 comments on commit 3f613f7

Please sign in to comment.