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: Add confirmation on max score setting [PT-187021265] #445

Merged
merged 1 commit into from
Mar 7, 2024
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
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 @@
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 @@
</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 @@
}

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 @@
};
}

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
Loading