Skip to content

Commit

Permalink
feat: Add confirmation on max score setting [PT-187021265]
Browse files Browse the repository at this point in the history
This adds a confirmation dialog if the max score is set to be less than existing student scores.
  • Loading branch information
dougmartin committed Mar 7, 2024
1 parent 0e665b3 commit df9ea5b
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const FeedbackLegend: React.FC<IProps> = (props) => {
{feedbackLevel === "Activity" &&
<div className={css.feedbackBadgeLegend__rubric}>
<div className={css.feedbackBadgeLegend__rubric_settings}>
<FeedbackSettingsToggle activity={activity} scoringSettings={scoringSettings} />
<FeedbackSettingsToggle activity={activity} scoringSettings={scoringSettings} feedbacks={feedbacks} />
</div>
<div className={css.feedbackBadgeLegend__rubric_score}>
{showAvgScore && <div className={css.feedbackBadgeLegend__rubric_score_avg}>
Expand Down
167 changes: 109 additions & 58 deletions js/components/portal-dashboard/feedback/feedback-settings-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,30 @@ interface IProps {
scoringSettings: ScoringSettings;
updateActivityFeedbackSettings: (activityId: string, activityIndex: number, feedbackFlags: any) => void;
rubric?: Rubric;
feedbacks: any;
}

interface IState {
scoreType: string;
maxScore: number;
confirmMaxScore: boolean;
}

class FeedbackSettingsModal extends PureComponent<IProps, IState> {
private initialSettings: IState;

constructor(props: IProps) {
super(props);
this.initialSettings = props.scoringSettings;
this.state = {...props.scoringSettings};
this.initialSettings = {

Check warning on line 38 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L38

Added line #L38 was not covered by tests
...props.scoringSettings,
confirmMaxScore: false,
};
this.state = {...this.initialSettings};

Check warning on line 42 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L42

Added line #L42 was not covered by tests
}

render() {
const { scoreType, maxScore } = this.state;
const { show, rubric } = this.props;
const maxScoreDisabled = scoreType !== MANUAL_SCORE;
const hasScoredQuestions = getScoredQuestions(this.props.activity).size > 0;
const { confirmMaxScore } = this.state;
const { show } = this.props;

Check warning on line 47 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L46-L47

Added lines #L46 - L47 were not covered by tests

return (
<Modal animation={false} centered dialogClassName={css.lightbox} onHide={this.handleCancel} show={show} data-cy="feedback-settings-modal">
Expand All @@ -52,58 +55,92 @@ class FeedbackSettingsModal extends PureComponent<IProps, IState> {
</Modal.Header>
<Modal.Body className={css.lightboxBody}>
<div className={css.contentArea} data-cy="feedback-settings-modal-content-area">
<div className={css.modalOption} data-cy="feedback-settings-modal-option">
<FeedbackSettingsModalButton selected={scoreType === NO_SCORE} value={NO_SCORE} onClick={this.handleScoreTypeChange} label="No score" />
</div>
<div className={css.modalOption} data-cy="feedback-settings-modal-option">
<FeedbackSettingsModalButton selected={scoreType === MANUAL_SCORE} value={MANUAL_SCORE} onClick={this.handleScoreTypeChange} label="Manual score">
<ScoreInput score={maxScore} minScore={1} disabled={maxScoreDisabled} className={css.maxScore} onChange={this.handleMaxScoreChange}>
<div>Max score</div>
</ScoreInput>
</FeedbackSettingsModalButton>
<div className={css.modalOptionInfo}>
<p>
All activities within this assignment can be scored up to your specified max score.
</p>
<p>
You may also choose <strong>not to score</strong> any student’s activities by not entering values in the entry fields.
</p>
</div>
</div>
{rubric && (
<div className={css.modalOption} data-cy="feedback-settings-modal-option">
<FeedbackSettingsModalButton selected={scoreType === RUBRIC_SCORE} value={RUBRIC_SCORE} onClick={this.handleScoreTypeChange} label="Use score from rubric" />
<div className={css.modalOptionInfo}>
<p>
All activities within this assignment will receive a score based on the activity-level rubric scores you’ve selected.
</p>
</div>
</div>
)}
{hasScoredQuestions && (
<div className={css.modalOption} data-cy="feedback-settings-modal-option">
<FeedbackSettingsModalButton selected={scoreType === AUTOMATIC_SCORE} value={AUTOMATIC_SCORE} onClick={this.handleScoreTypeChange} label="Use score from autoscored multiple-choice questions" alignTop={true} />
<div className={css.modalOptionInfo}>
<p>
All activities within this assignment will receive a score based on the total score of autoscored multiple-choice questions.
</p>
</div>
</div>
)}
<div className={css.buttonContainer}>
<div className={css.closeButton} onClick={this.handleCancel} data-cy="feedback-settings-modal-close-button">
Cancel
</div>
<div className={classNames(css.closeButton, {[css.disabled]: this.saveDisabled})} onClick={this.handleSave} data-cy="feedback-settings-modal-close-button">
Save
</div>
</div>
{!confirmMaxScore && this.renderOptions()}
{confirmMaxScore && this.renderConfirmMaxScore()}
</div>
</Modal.Body>
</Modal>
);
}

renderOptions() {
const { scoreType, maxScore } = this.state;
const { rubric } = this.props;
const maxScoreDisabled = scoreType !== MANUAL_SCORE;
const hasScoredQuestions = getScoredQuestions(this.props.activity).size > 0;

Check warning on line 70 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L67-L70

Added lines #L67 - L70 were not covered by tests

return (

Check warning on line 72 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L72

Added line #L72 was not covered by tests
<>
<div className={css.modalOption} data-cy="feedback-settings-modal-option">
<FeedbackSettingsModalButton selected={scoreType === NO_SCORE} value={NO_SCORE} onClick={this.handleScoreTypeChange} label="No score" />
</div>
<div className={css.modalOption} data-cy="feedback-settings-modal-option">
<FeedbackSettingsModalButton selected={scoreType === MANUAL_SCORE} value={MANUAL_SCORE} onClick={this.handleScoreTypeChange} label="Manual score">
<ScoreInput score={maxScore} minScore={1} disabled={maxScoreDisabled} className={css.maxScore} onChange={this.handleMaxScoreChange}>
<div>Max score</div>
</ScoreInput>
</FeedbackSettingsModalButton>
<div className={css.modalOptionInfo}>
<p>
All activities within this assignment can be scored up to your specified max score.
</p>
<p>
You may also choose <strong>not to score</strong> any student’s activities by not entering values in the entry fields.
</p>
</div>
</div>
{rubric && (
<div className={css.modalOption} data-cy="feedback-settings-modal-option">

Check warning on line 93 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L93

Added line #L93 was not covered by tests
<FeedbackSettingsModalButton selected={scoreType === RUBRIC_SCORE} value={RUBRIC_SCORE} onClick={this.handleScoreTypeChange} label="Use score from rubric" />
<div className={css.modalOptionInfo}>
<p>
All activities within this assignment will receive a score based on the activity-level rubric scores you’ve selected.
</p>
</div>
</div>
)}
{hasScoredQuestions && (
<div className={css.modalOption} data-cy="feedback-settings-modal-option">

Check warning on line 103 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L103

Added line #L103 was not covered by tests
<FeedbackSettingsModalButton selected={scoreType === AUTOMATIC_SCORE} value={AUTOMATIC_SCORE} onClick={this.handleScoreTypeChange} label="Use score from autoscored multiple-choice questions" alignTop={true} />
<div className={css.modalOptionInfo}>
<p>
All activities within this assignment will receive a score based on the total score of autoscored multiple-choice questions.
</p>
</div>
</div>
)}
<div className={css.buttonContainer}>
<div className={css.closeButton} onClick={this.handleCancel} data-cy="feedback-settings-modal-close-button">
Cancel
</div>
<div className={classNames(css.closeButton, {[css.disabled]: this.saveDisabled})} onClick={this.handleSave} data-cy="feedback-settings-modal-close-button">
Save
</div>
</div>
</>
);
}

renderConfirmMaxScore() {
const { maxScore } = this.state;

Check warning on line 125 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L125

Added line #L125 was not covered by tests

return (

Check warning on line 127 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L127

Added line #L127 was not covered by tests
<>
<p>
Some of the current student scores will be above the new max score of {maxScore}.
</p>
<div className={css.buttonContainer}>
<div className={css.closeButton} onClick={this.handleCancel} data-cy="feedback-settings-modal-close-button">
Cancel
</div>
<div className={classNames(css.closeButton)} onClick={this.handleSave} data-cy="feedback-settings-modal-close-button">
Continue
</div>
</div>
</>
);
}

private handleScoreTypeChange = (scoreType: ScoreType) => {
this.setState({ scoreType });
}
Expand All @@ -113,20 +150,34 @@ class FeedbackSettingsModal extends PureComponent<IProps, IState> {
}

private handleCancel = () => {
// restore initial settings
this.setState(this.initialSettings);
this.close();
if (this.state.confirmMaxScore) {
this.setState({ confirmMaxScore: false });

Check warning on line 154 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L154

Added line #L154 was not covered by tests
} else {
// restore initial settings
this.setState(this.initialSettings);
this.close();

Check warning on line 158 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L157-L158

Added lines #L157 - L158 were not covered by tests
}
}

private handleSave = () => {
const {scoreType, maxScore} = this.state;
const {updateActivityFeedbackSettings, activityId, activityIndex} = this.props;
const {scoreType, maxScore, confirmMaxScore} = this.state;
const {updateActivityFeedbackSettings, activityId, activityIndex, feedbacks} = this.props;

Check warning on line 164 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L163-L164

Added lines #L163 - L164 were not covered by tests
if (!this.saveDisabled) {
const updates: any = { scoreType };
if (maxScore !== undefined) {
// check if scores above max score and confirm if they are
const scoresAboveMax = feedbacks.scores.reduce((acc: boolean, cur: number) => {

Check warning on line 169 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L169

Added line #L169 was not covered by tests
return acc || cur > maxScore;
}, false);
if (scoresAboveMax && !confirmMaxScore) {
this.setState({ confirmMaxScore: true });
return;

Check warning on line 174 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L173-L174

Added lines #L173 - L174 were not covered by tests
}

updates.maxScore = maxScore;
}
updateActivityFeedbackSettings(activityId, activityIndex, updates);
this.setState({ confirmMaxScore: false });

Check warning on line 180 in js/components/portal-dashboard/feedback/feedback-settings-modal.tsx

View check run for this annotation

Codecov / codecov/patch

js/components/portal-dashboard/feedback/feedback-settings-modal.tsx#L180

Added line #L180 was not covered by tests
this.close();
}
}
Expand Down Expand Up @@ -157,7 +208,7 @@ function mapStateToProps() {
};
}

const mapDispatchToProps = (dispatch: any, ownProps: any): Partial<IProps> => {
const mapDispatchToProps = (dispatch: any): Partial<IProps> => {
return {
updateActivityFeedbackSettings: (activityId, activityIndex, feedbackFlags) => dispatch(updateActivityFeedbackSettings(activityId, activityIndex, feedbackFlags)),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import css from "../../../../css/portal-dashboard/feedback/feedback-settings-tog
interface IProps {
activity: Map<any, any>;
scoringSettings: ScoringSettings;
feedbacks: any;
}

export const FeedbackSettingsToggle: React.FC<IProps> = (props) => {
const { activity, scoringSettings } = props;
const { activity, scoringSettings, feedbacks } = props;
const [modalOpen, setModalOpen] = useState(false);
const [buttonActive, setButtonActive] = useState(false);

Expand All @@ -33,6 +34,7 @@ export const FeedbackSettingsToggle: React.FC<IProps> = (props) => {
onHide={handleShowModal(false)}
show={true}
scoringSettings={scoringSettings}
feedbacks={feedbacks}
/>}
</div>
);
Expand Down

0 comments on commit df9ea5b

Please sign in to comment.