@@ -24,43 +28,20 @@ const AssessmentContent = ({
{formatMessage(messages.instructions)}:
{formatMessage(messages.instructionsText)}
- {oraConfigData.prompts.map((prompt, index) => (
+ {prompts.map((prompt, index) => (
// eslint-disable-next-line react/no-array-index-key
))}
-
+
);
};
-AssessmentContent.propTypes = {
- submission: PropTypes.shape({
- response: PropTypes.shape({
- textResponses: PropTypes.arrayOf(PropTypes.string),
- uploadedFiles: PropTypes.arrayOf(
- PropTypes.shape({
- fileDescription: PropTypes.string,
- fileName: PropTypes.string,
- fileSize: PropTypes.number,
- }),
- ),
- }),
- }).isRequired,
- oraConfigData: PropTypes.shape({
- prompts: PropTypes.arrayOf(PropTypes.string),
- // eslint-disable-next-line react/forbid-prop-types
- submissionConfig: PropTypes.any,
- }).isRequired,
-};
-
export default AssessmentContent;
diff --git a/src/views/SelfAssessmentView/index.jsx b/src/views/SelfAssessmentView/index.jsx
index 04d5f23d..5b9b14f7 100644
--- a/src/views/SelfAssessmentView/index.jsx
+++ b/src/views/SelfAssessmentView/index.jsx
@@ -1,21 +1,20 @@
import React from 'react';
-import ProgressBar from 'components/ProgressBar';
+import { Button } from '@edx/paragon';
+import { useIsORAConfigLoaded } from 'data/services/lms/hooks/selectors';
+import BaseAssessmentView from 'components/BaseAssessmentView';
+import AssessmentContent from './Content';
-import AssessmentContentLayout from './AssessmentContentLayout';
-import useAssessmentViewHooks from './hooks';
+export const SelfAssessmentView = () => useIsORAConfigLoaded() && (
+
Cancel,
+ ,
+ ]}
+ submitAssessment={() => {}}
+ >
+
+
+);
-export const AssessmentView = () => {
- const { submission, oraConfigData } = useAssessmentViewHooks();
- return (
- <>
-
-
- >
- );
-};
-
-export default AssessmentView;
+export default SelfAssessmentView;
diff --git a/src/views/SubmissionView/SubmissionContent.jsx b/src/views/SubmissionView/SubmissionContent.jsx
index 035c8f06..27badadf 100644
--- a/src/views/SubmissionView/SubmissionContent.jsx
+++ b/src/views/SubmissionView/SubmissionContent.jsx
@@ -5,6 +5,8 @@ import { Icon } from '@edx/paragon';
import { CheckCircle } from '@edx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
+import { usePrompts, useSubmissionConfig } from 'data/services/lms/hooks/selectors';
+
import Prompt from 'components/Prompt';
import TextResponseEditor from 'components/TextResponseEditor';
import FileUpload from 'components/FileUpload';
@@ -12,20 +14,18 @@ import FileUpload from 'components/FileUpload';
import messages from './messages';
const SubmissionContent = ({
- submission,
- oraConfigData,
- onTextResponseChange,
- onFileUploaded,
- onDeletedFile,
- draftSaved,
+ textResponses,
+ uploadedFiles,
}) => {
+ const submissionConfig = useSubmissionConfig();
+ const prompts = usePrompts();
const { formatMessage } = useIntl();
return (
{formatMessage(messages.yourResponse)}
- {draftSaved && (
+ {textResponses.draftSaved && (
{formatMessage(messages.draftSaved)}
@@ -36,48 +36,41 @@ const SubmissionContent = ({
{formatMessage(messages.instructions)}:
{formatMessage(messages.instructionsText)}
- {oraConfigData.prompts.map((prompt, index) => (
+ {prompts.map((prompt, index) => (
// eslint-disable-next-line react/no-array-index-key
))}
);
};
SubmissionContent.propTypes = {
- submission: PropTypes.shape({
- response: PropTypes.shape({
- textResponses: PropTypes.arrayOf(PropTypes.string),
- uploadedFiles: PropTypes.arrayOf(
- PropTypes.shape({
- fileDescription: PropTypes.string,
- fileName: PropTypes.string,
- fileSize: PropTypes.number,
- }),
- ),
- }),
+ textResponses: PropTypes.shape({
+ value: PropTypes.arrayOf(PropTypes.string).isRequired,
+ onChange: PropTypes.func.isRequired,
+ draftSaved: PropTypes.bool.isRequired,
}).isRequired,
- oraConfigData: PropTypes.shape({
- prompts: PropTypes.arrayOf(PropTypes.string),
- // eslint-disable-next-line react/forbid-prop-types
- submissionConfig: PropTypes.any,
+ uploadedFiles: PropTypes.shape({
+ value: PropTypes.shape({
+ fileDescription: PropTypes.string,
+ fileName: PropTypes.string,
+ fileSize: PropTypes.number,
+ }),
+ onDeletedFile: PropTypes.func.isRequired,
+ onFileUploaded: PropTypes.func.isRequired,
}).isRequired,
- onTextResponseChange: PropTypes.func.isRequired,
- onFileUploaded: PropTypes.func.isRequired,
- onDeletedFile: PropTypes.func.isRequired,
- draftSaved: PropTypes.bool.isRequired,
};
export default SubmissionContent;
diff --git a/src/views/SubmissionView/SubmissionContent.test.jsx b/src/views/SubmissionView/SubmissionContent.test.jsx
index b30f9c76..62c6e153 100644
--- a/src/views/SubmissionView/SubmissionContent.test.jsx
+++ b/src/views/SubmissionView/SubmissionContent.test.jsx
@@ -25,9 +25,8 @@ describe.skip('
', () => {
maxFileSize: 100,
},
},
- onTextResponseChange: () => jest.fn().mockName('onTextResponseChange'),
+ onTextResponseChange: jest.fn().mockName('onTextResponseChange'),
onFileUploaded: jest.fn().mockName('onFileUploaded'),
- onDeletedFile: jest.fn().mockName('onDeletedFile'),
draftSaved: true,
};
diff --git a/src/views/SubmissionView/__snapshots__/SubmissionContent.test.jsx.snap b/src/views/SubmissionView/__snapshots__/SubmissionContent.test.jsx.snap
index 642b7975..7b07e027 100644
--- a/src/views/SubmissionView/__snapshots__/SubmissionContent.test.jsx.snap
+++ b/src/views/SubmissionView/__snapshots__/SubmissionContent.test.jsx.snap
@@ -36,7 +36,7 @@ exports[`
render default 1`] = `
prompt="
test
"
/>
render default 1`] = `
/>
render no prompts 1`] = `
it.
renders 1`] = `
-
-
+
+
`;
diff --git a/src/views/SubmissionView/hooks.js b/src/views/SubmissionView/hooks.js
index acd4d812..69568e69 100644
--- a/src/views/SubmissionView/hooks.js
+++ b/src/views/SubmissionView/hooks.js
@@ -1,73 +1,113 @@
-import { useEffect, useReducer } from 'react';
+import { useCallback, useEffect } from 'react';
-import { useORAConfigData, usePageData } from 'data/services/lms/hooks/selectors';
+import { StrictDict, useKeyedState } from '@edx/react-unit-test-utils';
+import {
+ usePageData,
+ usePrompts,
+ useRubricConfig,
+} from 'data/services/lms/hooks/selectors';
import {
- submitResponse, saveResponse, uploadFiles, deleteFile,
+ useSubmitResponse, useSaveResponse, useUploadFiles, useDeleteFile,
} from 'data/services/lms/hooks/actions';
import { MutationStatus } from 'data/services/lms/constants';
-const useSubmissionViewHooks = () => {
- const submitResponseMutation = submitResponse();
- const saveResponseMutation = saveResponse();
- const uploadFilesMutation = uploadFiles();
- const deleteFileMutation = deleteFile();
- const pageData = usePageData();
- const oraConfigData = useORAConfigData();
-
- const [submission, dispatchSubmission] = useReducer(
- (state, payload) => ({ ...state, isDirty: true, ...payload }),
- { ...pageData?.submission, isDirty: false },
+export const stateKeys = StrictDict({
+ textResponses: 'textResponses',
+ uploadedFiles: 'uploadedFiles',
+ isDirty: 'isDirty',
+});
+
+export const useTextResponses = () => {
+ const { response } = usePageData().submission;
+ const prompts = usePrompts();
+
+ const [isDirty, setIsDirty] = useKeyedState(stateKeys.isDirty, false);
+ const [value, setValue] = useKeyedState(
+ stateKeys.textResponses,
+ response ? response.textResponses : prompts.map(() => ''),
);
- useEffect(() => {
- // a workaround to update the submission state when the pageData changes
- if (pageData?.submission) {
- dispatchSubmission({ ...pageData.submission, isDirty: false });
- }
- }, [pageData?.submission]);
-
- const onTextResponseChange = (index) => (textResponse) => {
- dispatchSubmission({
- response: {
- ...submission.response,
- textResponses: [
- ...submission.response.textResponses.slice(0, index),
- textResponse,
- ...submission.response.textResponses.slice(index + 1),
- ],
- },
+ const saveResponseMutation = useSaveResponse();
+
+ const saveResponseHandler = useCallback(() => {
+ setIsDirty(false);
+ saveResponseMutation.mutate({ textResponses: value });
+ }, [setIsDirty, saveResponseMutation, value]);
+
+ const onChange = useCallback((index) => (textResponse) => {
+ setValue(oldResponses => {
+ const out = [...oldResponses];
+ out[index] = textResponse;
+ return out;
});
+ setIsDirty(true);
+ }, [setValue, setIsDirty]);
+
+ return {
+ formProps: {
+ value,
+ onChange,
+ draftSaved: saveResponseMutation.status === MutationStatus.success && !isDirty,
+ },
+ saveResponse: {
+ handler: saveResponseHandler,
+ status: saveResponseMutation.status,
+ },
};
+};
- const onFileUploaded = uploadFilesMutation.mutate;
+export const useUploadedFiles = () => {
+ const deleteFileMutation = useDeleteFile();
+ const uploadFilesMutation = useUploadFiles();
- const onDeletedFile = deleteFileMutation.mutate;
+ const { response } = usePageData().submission;
- const submitResponseHandler = () => {
- dispatchSubmission({ isDirty: false });
- submitResponseMutation.mutate(submission);
- };
+ const [value, setValue] = useKeyedState(
+ stateKeys.uploadedFiles,
+ response ? response.uploadedFiles : [],
+ );
- const saveResponseHandler = () => {
- dispatchSubmission({ isDirty: false });
- saveResponseMutation.mutate(submission);
- };
+ const onFileUploaded = useCallback(async (data) => {
+ const { fileData, queryClient } = data;
+ const uploadResponse = await uploadFilesMutation.mutateAsync(data);
+ if (uploadResponse) {
+ setValue((oldFiles) => [...oldFiles, uploadResponse.uploadedFiles[0]]);
+ }
+ }, [uploadFilesMutation, setValue]);
+
+ const onDeletedFile = deleteFileMutation.mutateAsync;
+
+ return { value, onFileUploaded, onDeletedFile };
+};
+
+const useSubmissionViewData = () => {
+ const submitResponseMutation = useSubmitResponse();
+ const textResponses = useTextResponses();
+ const uploadedFiles = useUploadedFiles();
+ const { showDuringResponse } = useRubricConfig();
+
+ const submitResponseHandler = useCallback(() => {
+ submitResponseMutation.mutate({
+ textResponses: textResponses.formProps.value,
+ uploadedFiles: uploadedFiles.value,
+ });
+ }, [submitResponseMutation, textResponses, uploadedFiles]);
return {
- submitResponseHandler,
- submitResponseStatus: submitResponseMutation.status,
- saveResponseHandler,
- saveResponseStatus: saveResponseMutation.status,
- draftSaved: saveResponseMutation.status === MutationStatus.success && !submission.isDirty,
- pageData,
- oraConfigData,
- submission,
- dispatchSubmission,
- onTextResponseChange,
- onFileUploaded,
- onDeletedFile,
+ actionsProps: {
+ submitResponse: {
+ handler: submitResponseHandler,
+ status: submitResponseMutation.status,
+ },
+ saveResponse: textResponses.saveResponse,
+ },
+ formProps: {
+ textResponses: textResponses.formProps,
+ uploadedFiles,
+ },
+ showRubric: showDuringResponse,
};
};
-export default useSubmissionViewHooks;
+export default useSubmissionViewData;
diff --git a/src/views/SubmissionView/index.jsx b/src/views/SubmissionView/index.jsx
index 5239589e..52de0395 100644
--- a/src/views/SubmissionView/index.jsx
+++ b/src/views/SubmissionView/index.jsx
@@ -1,40 +1,37 @@
import React from 'react';
+import PropTypes from 'prop-types';
+import { Col, Row } from '@edx/paragon';
+
+import Rubric from 'components/Rubric';
import ProgressBar from 'components/ProgressBar';
-import SubmissionContentLayout from './SubmissionContentLayout';
+import { useIsPageDataLoaded } from 'data/services/lms/hooks/selectors';
+
+import SubmissionContent from './SubmissionContent';
import SubmissionActions from './SubmissionActions';
-import useSubmissionViewHooks from './hooks';
+import useSubmissionViewData from './hooks';
+
+import './index.scss';
export const SubmissionView = () => {
- const {
- submission,
- oraConfigData,
- onFileUploaded,
- onTextResponseChange,
- submitResponseHandler,
- submitResponseStatus,
- saveResponseHandler,
- saveResponseStatus,
- draftSaved,
- onDeletedFile,
- } = useSubmissionViewHooks();
+ const { actionsProps, formProps, showRubric } = useSubmissionViewData();
+ if (!useIsPageDataLoaded()) {
+ return null;
+ }
return (
<>
-
-
+
+
+
+
+
+
+ {showRubric && }
+
+
+
+
>
);
};
diff --git a/src/views/SubmissionView/index.test.jsx b/src/views/SubmissionView/index.test.jsx
index 1d233c9a..8311e215 100644
--- a/src/views/SubmissionView/index.test.jsx
+++ b/src/views/SubmissionView/index.test.jsx
@@ -10,7 +10,6 @@ jest.mock('./hooks', () => jest.fn().mockReturnValue({
submission: 'submission',
oraConfigData: 'oraConfigData',
onFileUploaded: jest.fn().mockName('onFileUploaded'),
- onDeletedFile: jest.fn().mockName('onDeletedFile'),
onTextResponseChange: jest.fn().mockName('onTextResponseChange'),
submitResponseHandler: jest.fn().mockName('submitResponseHandler'),
submitResponseStatus: 'submitResponseStatus',