Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Rubric actions #75

Merged
merged 5 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,835 changes: 209 additions & 1,626 deletions package-lock.json

Large diffs are not rendered by default.

54 changes: 33 additions & 21 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Routes, Route } from 'react-router-dom';
import { ErrorPage } from '@edx/frontend-platform/react';
import {
PageWrap,

Check failure on line 3 in src/App.jsx

View workflow job for this annotation

GitHub Actions / test

'PageWrap' is defined but never used
AuthenticatedPageRoute,
ErrorPage,
} from '@edx/frontend-platform/react';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Spinner } from '@edx/paragon';

import { useIsORAConfigLoaded, useIsPageDataLoaded } from 'data/services/lms/hooks/selectors';

import PeerAssessmentView from 'views/PeerAssessmentView';
import SelfAssessmentView from 'views/SelfAssessmentView';
import StudentTrainingView from 'views/StudentTrainingView';
import PeerAssessmentView from 'views/AssessmentView/PeerAssessmentView';
import SelfAssessmentView from 'views/AssessmentView/SelfAssessmentView';
import StudentTrainingView from 'views/AssessmentView/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';
import PageDataProvider from 'components/PageDataProvider';

import messages from './messages';
import routes from './routes';
Expand All @@ -24,48 +24,60 @@
const appRoute = (route, Component) => (
<Route
path={route}
key={route}
element={(
<AppContainer>
<Component />
</AppContainer>
<AuthenticatedPageRoute>
<AppContainer>
<Component />
</AppContainer>
</AuthenticatedPageRoute>
)}
/>
);
const modalRoute = (route, Component, title) => (
<Route
key={route}
path={route}
element={(
<AppContainer>
<ModalContainer title={title}>
<Component />
</ModalContainer>
</AppContainer>
<AuthenticatedPageRoute>
<AppContainer>
<ModalContainer title={title}>
<Component />
</ModalContainer>
</AppContainer>
</AuthenticatedPageRoute>
)}
/>
);

/*
const embeddedRoutes = [
<Route path={routes.xblockEmbed} element={<XBlockView />} />,
<Route key="embedXblock" path={routes.xblockEmbed} element={<XBlockView />} />,
modalRoute(routes.peerAssessmentEmbed, PeerAssessmentView, 'ORA Peer Assessment'),
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)} />} />,
modaleoute(routes.gradedEmbed, GradeView, 'My Grade'),
<Route
key="embedError"
path={routes.rootEmbed}
element={<ErrorPage message={formatMessage(messages.error404Message)} />}
/>,
];
*/
const baseRoutes = [
appRoute(routes.xblock, XBlockView),
modalRoute(routes.peerAssessment, PeerAssessmentView, 'Assess your peers'),
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)} />} />,
<Route key="error" path={routes.root} element={<ErrorPage message={formatMessage(messages.error404Message)} />} />,
];

return (
<Routes>
{embeddedRoutes}
{/* embeddedRoutes */}
{baseRoutes}
</Routes>
);
Expand Down
1 change: 0 additions & 1 deletion src/components/Assessment/Assessment.scss
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@

.assessment-footer {
box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.3) !important;
display: flex;
justify-content: center;
padding: map-get($spacers, 3);
}
Expand Down
47 changes: 47 additions & 0 deletions src/components/Assessment/EditableAssessment/AssessmentActions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';

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

Check failure on line 4 in src/components/Assessment/EditableAssessment/AssessmentActions.jsx

View workflow job for this annotation

GitHub Actions / test

'Card' is defined but never used
import { useIntl } from '@edx/frontend-platform/i18n';

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

import messages from '../messages';

/**
* <Rubric />
*/
const AssessmentActions = ({
onSubmit,
submitStatus,
}) => {
const closeModal = useCloseModal();
const { formatMessage } = useIntl();
return (
<div className="assessment-footer">
<Button className="w-100" onClick={closeModal} variant="outlint-primary">
{formatMessage(messages.finishLater)}
</Button>
<StatefulButton
className="w-100"
onClick={onSubmit}
state={submitStatus}
_disabledStates={[MutationStatus.loading, MutationStatus.success]}
disabledStates={[MutationStatus.loading]}
labels={{
[MutationStatus.idle]: formatMessage(messages.submitGrade),
[MutationStatus.loading]: formatMessage(messages.submittingGrade),
[MutationStatus.success]: formatMessage(messages.gradeSubmitted),
}}
/>
</div>
);
};

AssessmentActions.propTypes = {
onSubmit: PropTypes.func.isRequired,
submitStatus: PropTypes.string.isRequired,
};

export default AssessmentActions;
Original file line number Diff line number Diff line change
@@ -1,29 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';

import { Form } from '@edx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';

import { useViewStep } from 'hooks';
import InfoPopover from 'components/InfoPopover';

import messages from 'components/Assessment/messages';
import { useOverallFeedbackFormFields } from 'context/AssessmentContext/hooks';
import { stepNames } from 'data/services/lms/constants';

/**
* <OverallFeedback />
*/
const OverallFeedback = ({
prompt,
value,
isDisabled,
isInvalid,
onChange,
}) => {
const OverallFeedback = () => {
const { formatMessage } = useIntl();

const inputLabel = formatMessage(
!isDisabled ? messages.addComments : messages.comments,
);

const { prompt, value, onChange } = useOverallFeedbackFormFields();
const step = useViewStep();
if (step === stepNames.studentTraining) {
return null;
}
return (
<Form.Group>
<Form.Label className="criteria-label">
Expand All @@ -37,32 +32,12 @@ const OverallFeedback = ({
<Form.Control
as="textarea"
className="rubric-feedback feedback-input"
floatingLabel={inputLabel}
floatingLabel={formatMessage(messages.addComments)}
value={value}
onChange={onChange}
disabled={isDisabled}
/>
{isInvalid && (
<Form.Control.Feedback type="invalid" className="feedback-error-msg">
{formatMessage(messages.overallFeedbackError)}
</Form.Control.Feedback>
)}
</Form.Group>
);
};

OverallFeedback.defaultProps = {
value: '',
isDisabled: false,
isInvalid: false,
};

OverallFeedback.propTypes = {
prompt: PropTypes.string.isRequired,
value: PropTypes.string,
isDisabled: PropTypes.bool,
onChange: PropTypes.func.isRequired,
isInvalid: PropTypes.bool,
};

export default OverallFeedback;
38 changes: 0 additions & 38 deletions src/components/Assessment/EditableAssessment/hooks.js

This file was deleted.

62 changes: 22 additions & 40 deletions src/components/Assessment/EditableAssessment/index.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React from 'react';

import { Card, StatefulButton } from '@edx/paragon';
import { Card } from '@edx/paragon';
import { useIntl } from '@edx/frontend-platform/i18n';

import { MutationStatus } from 'data/services/lms/constants';
import { useViewStep } from 'hooks';
import { stepNames } from 'data/services/lms/constants';

Check failure on line 7 in src/components/Assessment/EditableAssessment/index.jsx

View workflow job for this annotation

GitHub Actions / test

'stepNames' is defined but never used

import CriterionContainer from 'components/CriterionContainer';
import RadioCriterion from 'components/CriterionContainer/RadioCriterion';
import CriterionFeedback from 'components/CriterionContainer/CriterionFeedback';
import { AssessmentContext } from 'context/AssessmentContext';

import OverallFeedback from './OverallFeedback';
import AssessmentActions from './AssessmentActions';

import useEditableAssessmentData from './hooks';
import messages from '../messages';

/**
Expand All @@ -18,57 +22,35 @@
const EditableAssessment = () => {
const {
criteria,
formFields,
onSubmit,
submitStatus,
overallFeedbackPrompt,
} = useEditableAssessmentData();

} = React.useContext(AssessmentContext);
const { formatMessage } = useIntl();
const step = useViewStep();

Check failure on line 30 in src/components/Assessment/EditableAssessment/index.jsx

View workflow job for this annotation

GitHub Actions / test

'step' is assigned a value but never used
return (
<Card className="rubric-card">
<Card.Section className="rubric-body">
<Card className="assessment-card">
<Card.Section className="assessment-body">
<h3>{formatMessage(messages.rubric)}</h3>
<hr className="m-2.5" />
{criteria.map((criterion) => (
<CriterionContainer
key={criterion.name}
criterion={{ ...criterion }}
input={(
<RadioCriterion
criterion={criterion}
formFields={formFields.criteria[criterion.name].options}
/>
)}
feedback={(
<CriterionFeedback
criterion={criterion}
formFields={formFields.criteria[criterion.name].feedback}
/>
)}
/>
))}
{criteria.map((criterion, criterionIndex) => {
const args = {
key: criterion.name,
criterion,
input: (<RadioCriterion {...{ criterion, criterionIndex }} />),
feedback: (<CriterionFeedback {...{ criterion, criterionIndex }} />),
};
return (<CriterionContainer {...args} />);
})}
<hr />
<OverallFeedback prompt={overallFeedbackPrompt} {...formFields.overallFeedback} />
<OverallFeedback prompt={overallFeedbackPrompt} />
</Card.Section>
<div className="rubric-footer">
<StatefulButton
onClick={onSubmit}
state={submitStatus}
disabledStates={[MutationStatus.loading, MutationStatus.success]}
labels={{
[MutationStatus.idle]: formatMessage(messages.submitGrade),
[MutationStatus.loading]: formatMessage(messages.submittingGrade),
[MutationStatus.success]: formatMessage(messages.gradeSubmitted),
}}
/>
</div>
<AssessmentActions {...{ onSubmit, submitStatus }} />
</Card>
);
};

EditableAssessment.propTypes = {

};

export default EditableAssessment;
Loading
Loading