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

Assessments: Overview table - calculate not answered value #22156

Merged
merged 21 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 13 additions & 3 deletions apps/src/templates/sectionAssessments/MultipleChoiceAnswerCell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const styles = {
color: color.level_perfect,
float: 'left',
width: 20,
fontSize: 25,
},
text: {
color: color.charcoal,
Expand All @@ -25,12 +24,13 @@ const styles = {
float: 'left',
paddingRight: 40,
width: 20,
textAlign: 'center',
},
};

class MultipleChoiceAnswerCell extends Component {
static propTypes = {
percentValue: PropTypes.string.isRequired,
percentValue: PropTypes.number.isRequired,
isCorrectAnswer: PropTypes.bool,
};

Expand All @@ -39,7 +39,12 @@ class MultipleChoiceAnswerCell extends Component {
return (
<div>
<div>
{percentValue}
{(percentValue >= 0) &&
<span>{`${percentValue}%`}</span>
}
{(percentValue < 0 ) &&
<span>{'-'}</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you said Poorva likes it without -?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poorva also likes it with the dash and she is open to either option. I ran a mini survey with Maddie and Erin and the 'dash' option is preferred.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great!

}
</div>
<div>
{isCorrectAnswer &&
Expand All @@ -51,4 +56,9 @@ class MultipleChoiceAnswerCell extends Component {
}
}


MultipleChoiceAnswerCell.defaultProps = {
percentValue: -1
};

export default MultipleChoiceAnswerCell;
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,34 @@ export const COLUMNS = {
QUESTION: 0,
};

const alphabetMapper = [
commonMsg.answerOptionA(),
commonMsg.answerOptionB(),
commonMsg.answerOptionC(),
commonMsg.answerOptionD(),
commonMsg.answerOptionE(),
commonMsg.answerOptionF(),
commonMsg.answerOptionG(),
];
const NOT_ANSWERED = 'notAnswered';

const calculateNotAnswered = (multipleChoiceDataArr) => {
let total = 0;
multipleChoiceDataArr.forEach (studentsAnswersObj => {
if (studentsAnswersObj.percentAnswered) {
total += studentsAnswersObj.percentAnswered;
}
});

return (100 - total);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked "Do we have any multiple choice questions where students can select multiple answers, like a "select all that apply..." ?" in Slack because, if that's the case, you could run into a situation where calculateNotAnswered returns a negative number. For example, let's say there are only two answer choices: "A" and "B" and students are allowed to select: only "A", only "B", none, or "A" AND "B". If 100% of the students selected "A" AND "B", total in this function is 200, and you'd return -100. Let's confirm the requirements with Poorva.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Since this is an overview table of all the students' assessments, I do not think this will be an issue. For the individual student tables, this will be applicable (a good test :-) to check). Thoughts!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If students can select multiple answer options, I'm still concerned about calculateNotAnswered for this overview table. For example we could have a scenario like:
img_0564
In this case we would want the % not answered to be 25% because 1 out of 4 students did not answer the question; however the function as written would return 0%.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a great unit test case!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur!! Tests will be covered in the next PR.

};

const answerColumnsFormatter = (percentAnswered, {rowData, columnIndex, rowIndex, property}) => {
const cell = rowData.answers[columnIndex - 1];

let percentValue = 0;

if (property === NOT_ANSWERED) {
percentValue = calculateNotAnswered(rowData.answers);
} else {
percentValue = (cell && cell.percentAnswered);
}

return (
<MultipleChoiceAnswerCell
id={rowData.id}
percentValue={(cell && `${cell.percentAnswered}%`) || '-'}
percentValue={percentValue}
isCorrectAnswer={cell && cell.isCorrectAnswer}
/>
);
Expand All @@ -36,7 +48,6 @@ const questionAnswerDataPropType = PropTypes.shape({
question: PropTypes.string,
percentAnswered: PropTypes.string,
isCorrectAnswer: PropTypes.bool,
notAnswered: PropTypes.string,
});

class MultipleChoiceOverviewTable extends Component {
Expand Down Expand Up @@ -72,22 +83,23 @@ class MultipleChoiceOverviewTable extends Component {

getNotAnsweredColumn = () => (
{
property: 'notAnswered',
property: NOT_ANSWERED,
header: {
label: commonMsg.notAnswered(),
props: {style: tableLayoutStyles.headerCell},
},
cell: {
format: answerColumnsFormatter,
props: {style: tableLayoutStyles.cell},
}
}
);

getAnswerColumn = (index) => (
getAnswerColumn = (columnLabel) => (
{
property: 'percentAnswered',
header: {
label: alphabetMapper[index],
label: columnLabel,
props: {style: tableLayoutStyles.headerCell},
},
cell: {
Expand All @@ -112,18 +124,20 @@ class MultipleChoiceOverviewTable extends Component {
);

getColumns = (sortable) => {
const maxAnswerChoicesLength = this.props.questionAnswerData.reduce((answersTotal, currentAnswerCount) => {
return Math.max(answersTotal, currentAnswerCount.answers.length);
}, 0);

let dataColumns = [];
dataColumns.push(this.getQuestionColumn(sortable));
for (let i = 0; i < maxAnswerChoicesLength; i++) {
dataColumns.push(this.getAnswerColumn(i));
}
dataColumns.push(this.getNotAnsweredColumn());
const maxOptionsQuestion = [...this.props.questionAnswerData].sort((question1, question2) => (
question1.answers.length - question2.answers.length
)).pop();

let columnLabelNames = maxOptionsQuestion.answers.map((answer) => {
return this.getAnswerColumn(answer.multipleChoiceOption);
});

return [
this.getQuestionColumn(sortable),
...columnLabelNames,
this.getNotAnsweredColumn(),
];

return dataColumns;
};

render() {
Expand Down Expand Up @@ -151,3 +165,4 @@ class MultipleChoiceOverviewTable extends Component {
}

export default MultipleChoiceOverviewTable;

Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
import React from 'react';
import MultipleChoiceOverviewTable from './MultipleChoiceOverviewTable';
import commonMsg from '@cdo/locale';

const multipleChoiceData = [
{
id: 1,
question: '1. What is a variable?',
answers: [{percentAnswered: 40, isCorrectAnswer: true},
{percentAnswered: 20, isCorrectAnswer: false},
{percentAnswered: 20, isCorrectAnswer: false},
{percentAnswered: 20, isCorrectAnswer: false},
answers: [{multipleChoiceOption: commonMsg.answerOptionA(), percentAnswered: 40, isCorrectAnswer: true},
{multipleChoiceOption: commonMsg.answerOptionB(), percentAnswered: 20, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionC(), percentAnswered: 20, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionD(), percentAnswered: 20, isCorrectAnswer: false},
],
Copy link
Contributor

@Erin007 Erin007 May 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe I'm confused, but I'm a little concerned that we're relying on order to match percentAnswered to specific answer options (eg. "A"). What if we had something like {multipleChoiceOption: "A", percentAnswered: 40, isCorrectAnswer: true}? Then all of the relevant data gets bundled together.

Copy link
Contributor

@Erin007 Erin007 May 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want the translatable string, I think you could do:
{multipleChoiceOption: {i18n.answerOptionA()}, percentAnswered: 40, isCorrectAnswer: true}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Erin007 This is a valid point! After our in-person discussion, there is a tremendous payoff being able to identify which percentAnswered is associated with the answer choice. Additionally, debugging is easier. Thanks!

},
{
id: 2,
question: '2. What is a 4-bit number for the decimal number Ten(10)?',
answers: [{percentAnswered: 30, isCorrectAnswer: false},
{percentAnswered: 10, isCorrectAnswer: true},
{percentAnswered: 10, isCorrectAnswer: false},
{percentAnswered: 10, isCorrectAnswer: false},
{percentAnswered: 20, isCorrectAnswer: false},
{percentAnswered: 10, isCorrectAnswer: false},
answers: [{multipleChoiceOption: commonMsg.answerOptionA(), percentAnswered: 30, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionB(), percentAnswered: 10, isCorrectAnswer: true},
{multipleChoiceOption: commonMsg.answerOptionC(), percentAnswered: 10, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionD(), percentAnswered: 10, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionE(), percentAnswered: 20, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionF(), percentAnswered: 10, isCorrectAnswer: false},
],
},
{
id: 3,
question: '3. What is the minimum number of bits you will need to encode the 26 letters of the alphabet?',
answers: [{percentAnswered: 50, isCorrectAnswer: false},
{percentAnswered: 15, isCorrectAnswer: false},
{percentAnswered: 20, isCorrectAnswer: true},
{percentAnswered: 5, isCorrectAnswer: false},
{percentAnswered: 5, isCorrectAnswer: false},
answers: [{multipleChoiceOption: commonMsg.answerOptionA(), percentAnswered: 50, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionB(), percentAnswered: 15, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionC(), percentAnswered: 20, isCorrectAnswer: true},
{multipleChoiceOption: commonMsg.answerOptionD(), percentAnswered: 5, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionE(), percentAnswered: 5, isCorrectAnswer: false},
],
},
{
id: 4,
question: '4. What is a function?',
answers: [{percentAnswered: 15, isCorrectAnswer: false},
{percentAnswered: 18, isCorrectAnswer: false},
{percentAnswered: 10, isCorrectAnswer: false},
{percentAnswered: 9, isCorrectAnswer: false},
{percentAnswered: 5, isCorrectAnswer: false},
{percentAnswered: 45, isCorrectAnswer: true},
{percentAnswered: 5, isCorrectAnswer: false},
answers: [{multipleChoiceOption: commonMsg.answerOptionA(), percentAnswered: 15, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionB(), percentAnswered: 18, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionC(), percentAnswered: 10, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionD(), percentAnswered: 9, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionE(), percentAnswered: 5, isCorrectAnswer: false},
{multipleChoiceOption: commonMsg.answerOptionF(), percentAnswered: 32, isCorrectAnswer: true},
{multipleChoiceOption: commonMsg.answerOptionG(), percentAnswered: 5, isCorrectAnswer: false},
],
},
];
Expand Down