Add average mark to progress page & fix loader

This commit is contained in:
2021-10-03 18:56:22 +01:00
parent 31ebbc2d65
commit dd3b9c88cd
4 changed files with 62 additions and 4 deletions

View File

@@ -222,5 +222,9 @@ service cloud.firestore {
match /join_codes/{joinCode} { match /join_codes/{joinCode} {
allow get: if isSignedIn(); allow get: if isSignedIn();
} }
match /completed_progress/{setIds} {
allow get: if isSignedIn();
}
} }
} }

View File

@@ -386,6 +386,7 @@ function cleanseVocabString(item) {
* @param {object} data The data passed to the function. * @param {object} data The data passed to the function.
* @param {string} data.progressId The ID of the progress document to update. * @param {string} data.progressId The ID of the progress document to update.
* @param {string} data.answer The answer given by the user to the current prompt. * @param {string} data.answer The answer given by the user to the current prompt.
* @return {string} averagePercentage The average percentage mark for the current collection of sets. Only returned when the test is complete.
* @return {boolean} correct Whether the provided answer was correct. * @return {boolean} correct Whether the provided answer was correct.
* @return {array} correctAnswers An array of correct answers for the question just answered. If not all correct * @return {array} correctAnswers An array of correct answers for the question just answered. If not all correct
* answers have yet been given, and the current answer is correct, this only contains the correct * answers have yet been given, and the current answer is correct, this only contains the correct
@@ -551,8 +552,27 @@ exports.processAnswer = functions.https.onCall((data, context) => {
if (mode === "lives" && docData.lives <= 0) docData.questions.length = returnData.totalQuestions = docData.progress; if (mode === "lives" && docData.lives <= 0) docData.questions.length = returnData.totalQuestions = docData.progress;
const completedProgressDocId = db.collection("completed_progress").doc(progressDoc.data().setIds.sort().join("__"));
return transaction.get(completedProgressDocId).then((completedProgressDoc) => {
const totalPercentage = completedProgressDoc.data().total_percentage + (docData.correct.length / docData.questions.length * 100);
const attempts = completedProgressDoc.data().attempts + 1;
transaction.set(completedProgressDocId, {
attempts: attempts,
total_percentage: totalPercentage,
});
returnData.averagePercentage = (totalPercentage / attempts).toFixed(2);
transaction.set(progressDocId, docData);
return returnData;
}).catch((error) => {
const totalPercentage = docData.correct.length / docData.questions.length * 100;
transaction.set(completedProgressDocId, {
attempts: 1,
total_percentage: totalPercentage,
});
returnData.averagePercentage = totalPercentage.toFixed(2);
transaction.set(progressDocId, docData); transaction.set(progressDocId, docData);
return returnData; return returnData;
});
} else { } else {
const nextVocabId = docData.questions[docData.progress]; const nextVocabId = docData.questions[docData.progress];
const nextSetOwner = nextVocabId.split("__")[0]; const nextSetOwner = nextVocabId.split("__")[0];

View File

@@ -70,6 +70,8 @@ export default withRouter(class Progress extends React.Component {
lives: 1, lives: 1,
startLives: null, startLives: null,
setComplete: false, setComplete: false,
averagePercentage: null,
pageLoaded: false,
}; };
let isMounted = true; let isMounted = true;
@@ -87,7 +89,7 @@ export default withRouter(class Progress extends React.Component {
const progressId = this.props.match.params.progressId; const progressId = this.props.match.params.progressId;
const progressRef = this.state.db.collection("progress").doc(progressId); const progressRef = this.state.db.collection("progress").doc(progressId);
let [ newState, setDone, incorrectAnswers, duration ] = await progressRef.get().then((doc) => { let [ newState, setDone, incorrectAnswers, duration, setIds ] = await progressRef.get().then((doc) => {
const data = doc.data(); const data = doc.data();
document.title = `Study | ${data.set_title} | Parandum`; document.title = `Study | ${data.set_title} | Parandum`;
@@ -107,6 +109,7 @@ export default withRouter(class Progress extends React.Component {
setIds: data.setIds, setIds: data.setIds,
originalTotalQuestions: [...new Set(data.questions)].length, originalTotalQuestions: [...new Set(data.questions)].length,
setComplete: data.duration !== null, setComplete: data.duration !== null,
pageLoaded: true,
}; };
if (data.lives) { if (data.lives) {
@@ -114,7 +117,7 @@ export default withRouter(class Progress extends React.Component {
newState.startLives = data.start_lives; newState.startLives = data.start_lives;
} }
return [ newState, data.duration !== null, data.incorrect, data.duration ]; return [ newState, data.duration !== null, data.incorrect, data.duration, data.setIds ];
}).catch((error) => { }).catch((error) => {
console.log(`Progress data inaccessible: ${error}`); console.log(`Progress data inaccessible: ${error}`);
return [ return [
@@ -166,6 +169,16 @@ export default withRouter(class Progress extends React.Component {
})); }));
})); }));
promises.push(this.state.db.collection("completed_progress")
.doc(setIds.sort().join("__"))
.get()
.then((completedProgressDoc) => {
newState.averagePercentage = (completedProgressDoc.data().total_percentage / completedProgressDoc.data().attempts).toFixed(2);
}).catch((error) => {
console.log(`Couldn't get average percentage: ${error}`);
newState.averagePercentage = null;
}));
if (incorrectAnswers.length > 0) { if (incorrectAnswers.length > 0) {
newState.incorrectAnswers = {}; newState.incorrectAnswers = {};
@@ -363,6 +376,7 @@ export default withRouter(class Progress extends React.Component {
if (data.duration) { if (data.duration) {
// test done // test done
newState.duration = data.duration; newState.duration = data.duration;
newState.averagePercentage = data.averagePercentage;
this.props.logEvent("test_complete", { this.props.logEvent("test_complete", {
progress_id: this.props.match.params.progressId, progress_id: this.props.match.params.progressId,
@@ -491,7 +505,8 @@ export default withRouter(class Progress extends React.Component {
return ( return (
<div> <div>
{ {
this.state.progressInaccessible this.state.pageLoaded &&
(this.state.progressInaccessible
? ?
<Error404 /> <Error404 />
: :
@@ -570,6 +585,13 @@ export default withRouter(class Progress extends React.Component {
<p>You got</p> <p>You got</p>
<h1>{`${(this.state.correct / this.state.totalQuestions * 100).toFixed(2)}%`}</h1> <h1>{`${(this.state.correct / this.state.totalQuestions * 100).toFixed(2)}%`}</h1>
</div> </div>
{
this.state.averagePercentage !== null &&
<div className="stat-row stat-row--inline">
<p>The average is</p>
<h1>{`${this.state.averagePercentage}%`}</h1>
</div>
}
<div className="stat-row stat-row--inline"> <div className="stat-row stat-row--inline">
<h1>{`${this.state.correct} of ${this.state.totalQuestions}`}</h1> <h1>{`${this.state.correct} of ${this.state.totalQuestions}`}</h1>
<p>marks</p> <p>marks</p>
@@ -739,7 +761,7 @@ export default withRouter(class Progress extends React.Component {
</div> </div>
</> </>
} }
</> </>)
} }
</div> </div>
) )

View File

@@ -820,4 +820,16 @@ describe("Parandum Firestore database", () => {
const testDoc = db.collection("join_codes").doc(joinCodeOne); const testDoc = db.collection("join_codes").doc(joinCodeOne);
await firebase.assertFails(testDoc.get()); await firebase.assertFails(testDoc.get());
}); });
it("Can read completed progress docs when signed in", async () => {
const db = getFirestore(myAuth);
const testDoc = db.collection("completed_progress").doc(setOne);
await firebase.assertSucceeds(testDoc.get());
});
it("Can't read completed progress docs when not signed in", async () => {
const db = getFirestore(null);
const testDoc = db.collection("completed_progress").doc(setOne);
await firebase.assertFails(testDoc.get());
});
}); });