Skip to content

Commit

Permalink
Merge pull request #440 from concord-consortium/187021252-display-rub…
Browse files Browse the repository at this point in the history
…ric-score

feat: Flesh out score with rubric [PT-187021252]
  • Loading branch information
dougmartin authored Mar 5, 2024
2 parents 0ba6525 + 060b191 commit db7129e
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 50 deletions.
13 changes: 13 additions & 0 deletions css/portal-dashboard/feedback/activity-feedback-score.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@import "../variables";

.activityFeedbackScore {
display: flex;
flex-direction: column;
gap: 10px;
align-items: flex-end;

.scoreLabel {
color: @cc-charcoal;
font-weight: bold;
}
}
53 changes: 18 additions & 35 deletions css/portal-dashboard/feedback/feedback-rows.less
Original file line number Diff line number Diff line change
Expand Up @@ -68,45 +68,28 @@
margin-top: 7.5px;
}

.textAndScore {
display: flex;
gap: 35px;

textarea {
border: solid 1.5px @cc-charcoal-light2;
border-radius: 8px;
box-sizing: border-box;
font: 16px lato, arial, helvetica, sans-serif;
height: auto;
min-height: 50px;
outline: none;
padding: 5px 10px 13px;
resize: none;
width: 100%;
min-height: 80px;

&:focus {
border-color: @cc-charcoal-light1;
}
}
textarea {
border: solid 1.5px @cc-charcoal-light2;
border-radius: 8px;
box-sizing: border-box;
font: 16px lato, arial, helvetica, sans-serif;
height: auto;
min-height: 50px;
outline: none;
padding: 5px 10px 13px;
resize: none;
width: 100%;
min-height: 80px;

.score {
display: flex;
flex-direction: column;
gap: 10px;
align-items: flex-end;

&>div {
color: @cc-charcoal;
font-weight: bold;
}

input {
width: 40px;
}
&:focus {
border-color: @cc-charcoal-light1;
}
}

.textAndScore {
display: flex;
gap: 35px;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { TrackEventFunction } from "../../../actions";
import { ScoreInput } from "./score-input";
import { ScoringSettings } from "../../../util/scoring";
import { AUTOMATIC_SCORE, MANUAL_SCORE, NO_SCORE } from "../../../util/scoring-constants";
import { Rubric } from "./rubric-utils";

import css from "../../../../css/portal-dashboard/feedback/activity-feedback-score.less";

interface IProps {
activityId: string | null;
Expand All @@ -14,12 +17,13 @@ interface IProps {
studentId: string;
updateActivityFeedback?: (activityId: string, activityIndex: number, platformStudentId: string, feedback: any) => void;
trackEvent: TrackEventFunction;
className: string;
scoringSettings: ScoringSettings;
rubricFeedback: any;
rubric: Rubric;
}

export const ActivityFeedbackScore: React.FC<IProps> = (props) => {
const { activityId, activityIndex, activityStarted, score, studentId, updateActivityFeedback, trackEvent, className, scoringSettings } = props;
const { activityId, activityIndex, activityStarted, score, studentId, updateActivityFeedback, trackEvent, scoringSettings, rubricFeedback, rubric } = props;
const scoreType = scoringSettings.scoreType ?? NO_SCORE;
const [ scoreChanged, setScoreChanged ] = useState(false);

Expand Down Expand Up @@ -54,21 +58,28 @@ export const ActivityFeedbackScore: React.FC<IProps> = (props) => {
score={score}
minScore={0}
disabled={false}
className={className}
className={css.activityFeedbackScore}
onChange={handleScoreChange}
onBlur={scoreChanged ? updateScoreLogged : undefined}
>
<div>Score</div>
<div className={css.scoreLabel}>Score</div>
</ScoreInput>
);
}

const displayScore = "TBD"; // TBD: compute this in PT #187021252
let displayScore = "N/A";
if (rubricFeedback) {
const scoredValues = Object.values(rubricFeedback).filter((v: any) => v.score > 0);
if (scoredValues.length === rubric.criteria.length) {
const totalScore = scoredValues.reduce((acc, cur: any) => acc + cur.score, 0);
displayScore = String(totalScore);
}
}

return (
<div>
<div>Score</div>
<div style={{marginTop: 5}}>{displayScore}</div>
<div className={css.activityFeedbackScore}>
<div className={css.scoreLabel}>Score</div>
<div>{displayScore}</div>
</div>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const ActivityLevelFeedbackStudentRows: React.FC<IProps> = (props) => {
rubricFeedback={rubricFeedback}
setFeedbackSortRefreshEnabled={setFeedbackSortRefreshEnabled}
updateActivityFeedback={updateActivityFeedback}
scoringSettings={scoringSettings}
/>
}
<div className={css.textAndScore} data-cy="feedback-text-and-score">
Expand All @@ -94,8 +95,9 @@ export const ActivityLevelFeedbackStudentRows: React.FC<IProps> = (props) => {
setFeedbackSortRefreshEnabled={setFeedbackSortRefreshEnabled}
updateActivityFeedback={updateActivityFeedback}
trackEvent={trackEvent}
className={css.score}
scoringSettings={scoringSettings}
rubricFeedback={rubricFeedback}
rubric={rubric}
/>
</div>
</div>
Expand Down
12 changes: 8 additions & 4 deletions js/components/portal-dashboard/feedback/rubric-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import Markdown from "markdown-to-jsx";
import LaunchIcon from "../../../../img/svg-icons/launch-icon.svg";
import { hasRubricFeedback } from "../../../util/activity-feedback-helper";
import { Rubric, getFeedbackColor } from "./rubric-utils";
import { ScoringSettings } from "../../../util/scoring";
import { RUBRIC_SCORE } from "../../../util/scoring-constants";

import css from "../../../../css/portal-dashboard/feedback/rubric-table.less";

Expand All @@ -15,15 +17,16 @@ interface IProps {
activityIndex: number;
setFeedbackSortRefreshEnabled: (value: boolean) => void;
updateActivityFeedback: (activityId: string, activityIndex: number, platformStudentId: string, feedback: any) => void;
scoringSettings: ScoringSettings;
}
export class RubricTableContainer extends React.PureComponent<IProps> {
render() {
const { rubric } = this.props;
const { rubric, scoringSettings } = this.props;
const { criteria } = rubric;

return (
<div className={css.rubricContainer} data-cy="rubric-table">
{this.renderColumnHeaders(rubric)}
{this.renderColumnHeaders(rubric, scoringSettings)}
<div className={css.rubricTable}>
{criteria.map((crit: any) =>
<div className={css.rubricTableRow} key={crit.id} id={crit.id}>
Expand All @@ -38,8 +41,9 @@ export class RubricTableContainer extends React.PureComponent<IProps> {
);
}

private renderColumnHeaders = (rubric: Rubric) => {
private renderColumnHeaders = (rubric: Rubric, scoringSettings: ScoringSettings) => {
const { referenceURL } = rubric;
const showScore = scoringSettings.scoreType === RUBRIC_SCORE;
return (
<div className={css.columnHeaders}>
<div className={css.rubricDescriptionHeader}>
Expand All @@ -54,7 +58,7 @@ export class RubricTableContainer extends React.PureComponent<IProps> {
{rubric.ratings.map((rating: any) =>
<div className={css.rubricScoreHeader} key={rating.id}>
<div className={css.rubricScoreLevel}>{rating.label}</div>
{rubric.scoreUsingPoints && <div className={css.rubricScoreNumber}>({rating.score})</div>}
{rubric.scoreUsingPoints && showScore && <div className={css.rubricScoreNumber}>({rating.score})</div>}
</div>
)}
</div>
Expand Down
6 changes: 4 additions & 2 deletions js/components/portal-dashboard/feedback/score-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ interface IProps {
onBlur?: (score: number) => void;
}

const maxScore = 999;

export class ScoreInput extends PureComponent<IProps> {

render() {
Expand All @@ -21,7 +23,7 @@ export class ScoreInput extends PureComponent<IProps> {
return (
<div className={classNames(css.scoreInput, className, {[css.disabled]: disabled})}>
{children}
<input type="number" disabled={disabled} value={score} min={minScore} onChange={this.handleChange} onKeyDown={this.handleKeyDown} onBlur={this.handleBlur} />
<input type="number" disabled={disabled} value={score} min={minScore} max={maxScore} onChange={this.handleChange} onKeyDown={this.handleKeyDown} onBlur={this.handleBlur} />
</div>
);
}
Expand All @@ -35,7 +37,7 @@ export class ScoreInput extends PureComponent<IProps> {
private handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const {minScore, onChange} = this.props;
const score = parseInt(e.target.value, 10);
if (score >= minScore) {
if ((score >= minScore) && (score <= maxScore)) {
onChange(score);
}
}
Expand Down

0 comments on commit db7129e

Please sign in to comment.