Skip to content

Commit

Permalink
feat: implement grade route
Browse files Browse the repository at this point in the history
  • Loading branch information
leangseu-edx committed Oct 24, 2023
1 parent b1ffbbb commit b18d722
Show file tree
Hide file tree
Showing 21 changed files with 416 additions and 54 deletions.
3 changes: 3 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SelfAssessmentView from 'views/SelfAssessmentView';
import StudentTrainingView from 'views/StudentTrainingView';
import SubmissionView from 'views/SubmissionView';
import XBlockView from 'views/XBlockView';
import GradeView from 'views/GradeView';

import AppContainer from 'components/AppContainer';
import ModalContainer from 'components/ModalContainer';
Expand Down Expand Up @@ -49,6 +50,7 @@ const RouterRoot = () => {
modalRoute(routes.selfAssessmentEmbed, SelfAssessmentView, 'ORA Self Assessment'),
modalRoute(routes.studentTrainingEmbed, StudentTrainingView, 'ORA Student Training'),
modalRoute(routes.submissionEmbed, SubmissionView, 'ORA Submission'),
modalRoute(routes.gradedEmbed, GradeView, 'My Grade'),
<Route path={routes.rootEmbed} element={<ErrorPage message={formatMessage(messages.error404Message)} />} />,
];
const baseRoutes = [
Expand All @@ -57,6 +59,7 @@ const RouterRoot = () => {
modalRoute(routes.selfAssessment, SelfAssessmentView, 'Assess yourself'),
modalRoute(routes.studentTraining, StudentTrainingView, 'Practice grading'),
modalRoute(routes.submission, SubmissionView, 'Your response'),
modalRoute(routes.graded, GradeView, 'My Grade'),
<Route path={routes.root} element={<ErrorPage message={formatMessage(messages.error404Message)} />} />,
];

Expand Down
53 changes: 53 additions & 0 deletions src/components/CollapsibleFeedback/Feedback.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import PropTypes from 'prop-types';

import { Collapsible, Icon } from '@edx/paragon';
import { ExpandMore, ExpandLess } from '@edx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import messages from './messages';

const Feedback = ({ criterion, selectedOption, selectedPoints, commentHeader, commentBody, defaultOpen }) => {
const [isExpanded, setIsExpanded] = React.useState(defaultOpen);
const { formatMessage } = useIntl();

return (
<>
<div className='mt-2'>
<h5>{criterion.name}</h5>
{selectedOption && <p>{selectedOption} -- {selectedPoints} points</p>}
</div>
<div className='bg-gray-100 p-3'>
<Collapsible.Advanced
open={isExpanded}
onToggle={() => setIsExpanded(!isExpanded)}
>
<Collapsible.Trigger className='d-flex justify-content-between'>
<h5 className='mb-0'>{commentHeader} Comment</h5>
{isExpanded ? (
<div className='d-flex mb-0 small'>
<span>{formatMessage(messages.readLess)}</span>
<Icon src={ExpandLess} />
</div>
) : (
<div className='d-flex mb-0 small'>
<span>{formatMessage(messages.readMore)}</span>
<Icon src={ExpandMore} />
</div>
)}
</Collapsible.Trigger>
<Collapsible.Body className='pt-2'>
<p>{commentBody}</p>
</Collapsible.Body>
</Collapsible.Advanced>
</div>
</>
);
};
Feedback.defaultProps = {
defaultOpen: false,
};
Feedback.propTypes = {
defaultOpen: PropTypes.bool,
};

export default Feedback;
52 changes: 52 additions & 0 deletions src/components/CollapsibleFeedback/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import PropTypes from 'prop-types';

import { Collapsible } from '@edx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';
import Feedback from './Feedback';
import messages from './messages';

const CollapsibleFeedback = ({ assessment, stepScore, stepName }) => {
const assessmentCriterions = assessment.assessmentCriterions;
const { formatMessage } = useIntl();

return (
<Collapsible
title={
<h3>
{formatMessage(messages.grade, {
stepName,
})}
{stepScore && formatMessage(messages.gradePoints, stepScore)}
</h3>
}
>
{assessmentCriterions.map((criterion) => {
return (
<Feedback
key={criterion.name}
criterion={criterion.name}
selectedOption={criterion.selectedOption}
selectedPoints={criterion.selectedPoints}
commentHeader={stepName}
commentBody={criterion.feedback}
/>
);
})}
<Feedback
criterion={{ name: 'Overall Feedback' }}
commentHeader={stepName}
commentBody={assessment.overallFeedback}
/>
</Collapsible>
);
};
CollapsibleFeedback.defaultProps = {};
CollapsibleFeedback.propTypes = {
// assessment: PropTypes.shape({
// overallFeedback: PropTypes.string,
// }),
stepName: PropTypes.string.isRequired,
};

export default CollapsibleFeedback;
31 changes: 31 additions & 0 deletions src/components/CollapsibleFeedback/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
readMore: {
id: 'ora-collapsible-comment.readMore',
defaultMessage: 'Read more',
description: 'Read more button text',
},
readLess: {
id: 'ora-collapsible-comment.readLess',
defaultMessage: 'Read less',
description: 'Read less button text',
},
grade: {
id: 'ora-collapsible-comment.grade',
defaultMessage: '{stepName} Grade:',
description: 'Grade button text',
},
gradePoints: {
id: 'ora-collapsible-comment.gradePoints',
defaultMessage: '{earned} / {possible}',
description: 'Grade points button text',
},
notWeightedGradeLabel: {
id: 'ora-collapsible-comment.notWeightedGradeLabel',
defaultMessage: '(Not weighted toward final grade))',
description: 'Not weighted grade label',
},
});

export default messages;
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import './FileCard.scss';
/**
* <FileCard />
*/
const FileCard = ({ file, children }) => (
const FileCard = ({ file, children, defaultOpen }) => (
<Card className="file-card" key={file.fileName}>
<Collapsible
className="file-collapsible"
defaultOpen
defaultOpen={defaultOpen}
title={<h3 className="file-card-title">{file.fileName}</h3>}
>
<div className="preview-panel">
Expand All @@ -24,6 +24,7 @@ const FileCard = ({ file, children }) => (
FileCard.propTypes = {
file: PropTypes.shape({ fileName: PropTypes.string.isRequired }).isRequired,
children: PropTypes.node.isRequired,
defaultOpen: PropTypes.bool.isRequired,
};

export default FileCard;
9 changes: 6 additions & 3 deletions src/components/FilePreview/components/FileRenderer/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useRenderData } from './hooks';
/**
* <FileRenderer />
*/
export const FileRenderer = ({ file }) => {
export const FileRenderer = ({ file, defaultOpen }) => {
const { formatMessage } = useIntl();
const {
Renderer,
Expand All @@ -21,7 +21,7 @@ export const FileRenderer = ({ file }) => {
} = useRenderData({ file, formatMessage });

return (
<FileCard key={file.fileUrl} file={file}>
<FileCard defaultOpen={defaultOpen} file={file}>
{isLoading && <LoadingBanner />}
{errorStatus ? (
<ErrorBanner {...error} />
Expand All @@ -32,12 +32,15 @@ export const FileRenderer = ({ file }) => {
);
};

FileRenderer.defaultProps = {};
FileRenderer.defaultProps = {
defaultOpen: true,
};
FileRenderer.propTypes = {
file: PropTypes.shape({
fileName: PropTypes.string,
fileUrl: PropTypes.string,
}).isRequired,
defaultOpen: PropTypes.bool,
// injected
// intl: intlShape.isRequired,
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/FilePreview/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import React from 'react';
import { useResponseData } from 'data/services/lms/hooks/selectors';
import { FileRenderer, isSupported } from './components';

const FilePreview = () => {
const FilePreview = ({ defaultCollapsePreview }) => {
const { uploadedFiles } = useResponseData();
return (
<div>
{uploadedFiles.filter(isSupported).map((file) => (
<FileRenderer key={file.name} file={file} />
<FileRenderer key={file.name} file={file} defaultOpen={!defaultCollapsePreview} />
))}
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/FileUpload/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const FileUpload = ({
uploadedFiles,
onFileUploaded,
onDeletedFile,
defaultCollapsePreview,
}) => {
const { formatMessage } = useIntl();

Expand All @@ -39,7 +40,7 @@ const FileUpload = ({
return (
<div>
<h3>File Upload</h3>
{isReadOnly && <FilePreview />}
{isReadOnly && <FilePreview defaultCollapsePreview={defaultCollapsePreview}/>}
{uploadedFiles.length > 0 && (
<>
<b>Uploaded Files</b>
Expand Down Expand Up @@ -91,6 +92,7 @@ FileUpload.defaultProps = {
uploadedFiles: [],
onFileUploaded: nullMethod,
onDeletedFile: nullMethod,
defaultCollapsePreview: false,
};
FileUpload.propTypes = {
isReadOnly: PropTypes.bool,
Expand All @@ -103,6 +105,7 @@ FileUpload.propTypes = {
),
onFileUploaded: PropTypes.func,
onDeletedFile: PropTypes.func,
defaultCollapsePreview: PropTypes.bool,
};

export default FileUpload;
4 changes: 2 additions & 2 deletions src/components/Prompt/hooks.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from 'react';

const usePromptHooks = () => {
const [open, setOpen] = useState(true);
const usePromptHooks = ({ defaultOpen }) => {
const [open, setOpen] = useState(defaultOpen);

const toggleOpen = () => setOpen(!open);

Expand Down
9 changes: 7 additions & 2 deletions src/components/Prompt/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ import { Collapsible } from '@edx/paragon';

import usePromptHooks from './hooks';

const Prompt = ({ prompt }) => {
const { open, toggleOpen } = usePromptHooks();
const Prompt = ({ prompt, defaultOpen }) => {
const { open, toggleOpen } = usePromptHooks({ defaultOpen });
return (
<Collapsible title={open ? '' : 'Review the prompt'} open={open} onToggle={toggleOpen}>
<div dangerouslySetInnerHTML={{ __html: prompt }} />
</Collapsible>
);
};

Prompt.defaultProps = {
defaultOpen: true,
};

Prompt.propTypes = {
defaultOpen: PropTypes.bool,
prompt: PropTypes.string.isRequired,
};

Expand Down
2 changes: 1 addition & 1 deletion src/data/services/lms/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const routeSteps = StrictDict({
peer_assessment: stepNames.peer,
self_assessment: stepNames.self,
student_training: stepNames.studentTraining,
my_grades: stepNames.done,
graded: stepNames.done,
});

export const stepRoutes = StrictDict(Object.keys(routeSteps).reduce(
Expand Down
2 changes: 1 addition & 1 deletion src/data/services/lms/fakeData/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const viewKeys = StrictDict({
studentTraining: 'student_training',
self: 'self_assessment',
peer: 'peer_assessment',
done: 'my_grades',
done: 'graded',
});

export const progressKeys = StrictDict({
Expand Down
38 changes: 14 additions & 24 deletions src/data/services/lms/fakeData/pageData/assessments.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,20 @@ import { stepNames } from 'data/services/lms/constants';
import { progressKeys } from '../constants';

export const createAssessmentState = ({
options_selected = [],
criterion_feedback,
assessment_criterions = [],
overall_feedback = '',
}) => ({
options_selected,
criterion_feedback,
assessment_criterions,
overall_feedback,
});

export const emptySelections = {
'Criterion 1 name': null,
'Criterion 2 name': null,
'Criterion 3 name': null,
'Criterion 4 name': null,
};
export const filledSelections = {
'Criterion 1 name': 'Option 4 name',
'Criterion 2 name': 'Option 3 name',
'Criterion 3 name': 'Option 2 name',
'Criterion 4 name': 'Option 1 name',
};

const gradedState = createAssessmentState({
options_selected: filledSelections,
criterion_feedback: {
'Criterion 1 name': 'feedback 1',
'Criterion 2 name': 'feedback 2',
'Criterion 3 name': 'feedback 3',
'Criterion 4 name': 'feedback 4',
},
assessment_criterions: new Array(4).fill(0).map((_, i) => ({
name: `Criterion ${i + 1} name`,
selectedOption: `Option ${i + 1} name`,
selectedPoints: i,
feedback: `feedback ${i + 1}`,
})),
overall_feedback: 'nice job',
});

Expand Down Expand Up @@ -66,6 +50,12 @@ export const getAssessmentState = ({ progressKey, stepConfig }) => {
],
};
}
if (stepConfig.includes(stepNames.self)) {
out.self = {
stepScore: { earned: 10, possible: 10 },
assessment: gradedState,
};
}
return out;
};

Expand Down
Loading

0 comments on commit b18d722

Please sign in to comment.