diff --git a/src/App.js b/src/App.js
index bd66eae..519a403 100644
--- a/src/App.js
+++ b/src/App.js
@@ -6,6 +6,7 @@ import LoggedInHome from "./LoggedInHome";
import Login from "./Login";
import SetPage from "./SetPage";
import GroupPage from "./GroupPage";
+import GroupStats from "./GroupStats";
import UserGroups from "./UserGroups";
import Settings from "./Settings";
import Progress from "./Progress";
@@ -299,6 +300,9 @@ class App extends React.Component {
+
+
+
@@ -371,7 +375,6 @@ class App extends React.Component {
>
- {/*
*/}
diff --git a/src/GroupPage.js b/src/GroupPage.js
index 362ae1d..1446c39 100644
--- a/src/GroupPage.js
+++ b/src/GroupPage.js
@@ -1,9 +1,11 @@
import React, { Component } from 'react';
import { withRouter, Link } from "react-router-dom";
-import { HomeRounded as HomeRoundedIcon, EditRounded as EditRoundedIcon, ArrowForwardRounded as ArrowForwardRoundedIcon, DeleteRounded as DeleteRoundedIcon } from "@material-ui/icons";
+import { TimelineRounded as TimelineRoundedIcon, HomeRounded as HomeRoundedIcon, EditRounded as EditRoundedIcon, ArrowForwardRounded as ArrowForwardRoundedIcon, DeleteRounded as DeleteRoundedIcon } from "@material-ui/icons";
import NavBar from "./NavBar";
import Button from "./Button";
+import LinkButton from "./LinkButton";
import Footer from "./Footer";
+import Error404 from "./Error404";
import "./css/GroupPage.css";
import "./css/ConfirmationDialog.css";
@@ -55,70 +57,91 @@ export default withRouter(class GroupPage extends Component {
if (this.isMounted) super.setState(state, callback);
}
- componentDidMount() {
- this.state.db
- .collection("users")
- .doc(this.state.user.uid)
- .collection("groups")
- .doc(this.props.match.params.groupId)
- .get()
- .then((userGroupDoc) => {
- this.state.db
- .collection("groups")
- .doc(this.props.match.params.groupId)
- .get()
- .then(async (groupDoc) => {
- document.title = `${groupDoc.data().display_name} | Parandum`;
+ async componentDidMount() {
+ let promises = [];
+ let newState = {
+ sets: {},
+ };
- let newState = {
- role: userGroupDoc.data().role,
- groupName: groupDoc.data().display_name,
- originalGroupName: groupDoc.data().display_name,
- sets: {},
- memberCount: Object.keys(groupDoc.data().users).length + (Object.keys(groupDoc.data().users).includes(this.state.user.uid) ? 0 : 1),
- joinCode: userGroupDoc.data().role === "owner" ? groupDoc.data().join_code : "",
- };
+ promises.push(
+ this.state.db
+ .collection("users")
+ .doc(this.state.user.uid)
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .get()
+ .then((userGroupDoc) => userGroupDoc.data())
+ .catch((error) => {
+ console.log(`Can't access user group: ${error}`);
+ return {
+ role: "none",
+ };
+ })
+ );
- await Promise.all(groupDoc.data().sets.map((setId) => {
- return this.state.db.collection("sets")
- .doc(setId)
- .get()
- .then((doc) => {
- newState.sets[setId] = {
- displayName: doc.data().title,
- loading: false,
- };
- });
- }));
+ promises.push(
+ this.state.db
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .get()
+ .then(async (groupDoc) => {
+ await Promise.all(groupDoc.data().sets.map((setId) => {
+ return this.state.db.collection("sets")
+ .doc(setId)
+ .get()
+ .then((doc) => {
+ newState.sets[setId] = {
+ displayName: doc.data().title,
+ loading: false,
+ };
+ });
+ }));
- if (newState.role === "owner") {
- const getGroupMembers = () => {
- return this.state.functions.getGroupMembers({ groupId: this.props.match.params.groupId })
- .catch((error) => {
- return {
- data: {
- owners: [
- {
- displayName: this.state.user.displayName,
- uid: this.state.user.uid,
- }
- ],
- contributors: [],
- members: [],
- }
- }
- });
- }
+ return groupDoc.data();
+ }).catch((error) => {
+ console.log(`Can't access group: ${error}`);
+ return {
+ display_name: "",
+ users: {},
+ join_code: "",
+ };
+ })
+ );
- const groupUsers = await getGroupMembers();
- newState.groupUsers = groupUsers.data;
+ if (newState.role === "owner") {
+ promises.push(
+ this.state.functions.getGroupMembers({ groupId: this.props.match.params.groupId })
+ .then((response) => {
+ newState.groupUsers = response.data;
+ })
+ .catch((error) => {
+ newState.groupUsers = {
+ owners: [
+ {
+ displayName: this.state.user.displayName,
+ uid: this.state.user.uid,
+ }
+ ],
+ contributors: [],
+ members: [],
}
+ })
+ )
+ }
- this.setState(newState);
- this.props.page.load();
- });
- });
+ const completedPromises = await Promise.all(promises);
+
+ document.title = `${completedPromises[1].display_name} | Parandum`;
+
+ newState.role = completedPromises[0].role;
+ newState.groupName = completedPromises[1].display_name;
+ newState.originalGroupName = completedPromises[1].display_name;
+ newState.memberCount = Object.keys(completedPromises[1].users).length + (Object.keys(completedPromises[1].users).includes(this.state.user.uid) ? 0 : 1);
+ newState.joinCode = completedPromises[0].role === "owner" ? completedPromises[1].join_code : "";
+
+ this.setState(newState);
+ this.props.page.load();
this.props.logEvent("select_content", {
content_type: "group",
@@ -336,6 +359,9 @@ export default withRouter(class GroupPage extends Component {
render() {
return (
+ (this.state.role === "none") ?
+
+ :
@@ -375,12 +401,20 @@ export default withRouter(class GroupPage extends Component {
}
{
this.state.role === "owner" &&
- }
- className="button--round"
- title="Delete group"
- >
+
+ }
+ className="button--round"
+ title="Group progress"
+ >
+ }
+ className="button--round"
+ title="Delete group"
+ >
+
}
{
diff --git a/src/GroupStats.js b/src/GroupStats.js
new file mode 100644
index 0000000..3fe9b75
--- /dev/null
+++ b/src/GroupStats.js
@@ -0,0 +1,237 @@
+import React, { Component } from 'react';
+import { GroupRounded as GroupRoundedIcon, HomeRounded as HomeRoundedIcon } from "@material-ui/icons";
+import { withRouter } from 'react-router-dom';
+import NavBar from "./NavBar";
+import Footer from "./Footer";
+import Error404 from "./Error404";
+import "./css/History.css";
+import "./css/MistakesHistory.css";
+
+export default withRouter(class GroupStats extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ user: props.user,
+ db: props.db,
+ navbarItems: [
+ {
+ type: "link",
+ link: `/groups/${this.props.match.params.groupId}`,
+ icon: ,
+ hideTextMobile: true,
+ },
+ {
+ type: "link",
+ link: "/",
+ icon: ,
+ hideTextMobile: true,
+ }
+ ],
+ role: null,
+ groupName: "",
+ };
+
+ let isMounted = true;
+ Object.defineProperty(this, "isMounted", {
+ get: () => isMounted,
+ set: (value) => isMounted = value,
+ });
+ }
+
+ setState = (state, callback = null) => {
+ if (this.isMounted) super.setState(state, callback);
+ }
+
+ async componentDidMount() {
+ let promises = [];
+ let newState = {};
+
+ await this.state.db
+ .collection("users")
+ .doc(this.state.user.uid)
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .get()
+ .then((userGroupDoc) => {
+ newState.role = userGroupDoc.data().role;
+ })
+ .catch((error) => {
+ console.log(`Can't access user group: ${error}`);
+ newState.role = "none";
+ });
+
+ if (newState.role === "owner") {
+ promises.push(
+ this.state.db
+ .collection("groups")
+ .doc(this.props.match.params.groupId)
+ .get()
+ .then(async (groupDoc) => {
+ // await Promise.all(groupDoc.data().sets.map((setId) => {
+ // return this.state.db.collection("sets")
+ // .doc(setId)
+ // .get()
+ // .then((doc) => {
+ // newState.sets[setId] = {
+ // displayName: doc.data().title,
+ // loading: false,
+ // };
+ // });
+ // }));
+
+ document.title = `Stats | ${groupDoc.data().display_name} | Parandum`;
+ newState.groupName = groupDoc.data().display_name;
+ }).catch((error) => {
+ console.log(`Can't access group: ${error}`);
+ newState.groupName = "";
+ document.title = "Stats | Parandum";
+ })
+ );
+
+ promises.push(
+ this.state.db.collection("incorrect_answers")
+ .where("groups", "array-contains", this.props.match.params.groupId)
+ .orderBy("term", "asc")
+ .get()
+ .then((querySnapshot) => {
+ let incorrectAnswers = [];
+ querySnapshot.docs.map((doc, index, array) => {
+ if (index === 0 || doc.data().term !== array[index - 1].data().term || doc.data().definition !== array[index - 1].data().definition) {
+ incorrectAnswers.push({
+ term: doc.data().term,
+ definition: doc.data().definition,
+ answers: [{
+ answer: doc.data().answer,
+ switchLanguage: doc.data().switch_language,
+ }],
+ count: doc.data().switch_language ? 0 : 1,
+ switchedCount: doc.data().switch_language ? 1 : 0,
+ });
+ } else {
+ incorrectAnswers[incorrectAnswers.length - 1].answers.push({
+ answer: doc.data().answer,
+ switchLanguage: doc.data().switch_language,
+ });
+ if (doc.data().switch_language) {
+ incorrectAnswers[incorrectAnswers.length - 1].switchedCount++;
+ } else {
+ incorrectAnswers[incorrectAnswers.length - 1].count++;
+ }
+ }
+ return true;
+ });
+ newState.incorrectAnswers = incorrectAnswers.sort((a, b) => b.count + b.switchedCount - a.count - a.switchedCount);
+ newState.totalIncorrect = querySnapshot.docs.length;
+ })
+ .catch((error) => {
+ newState.incorrectAnswers = [];
+ newState.totalIncorrect = 0;
+ console.log(`Couldn't get group progress: ${error}`);
+ })
+ )
+
+ await Promise.all(promises);
+ }
+
+ this.setState(newState);
+ this.props.page.load();
+
+ this.props.logEvent("select_content", {
+ content_type: "group_stats",
+ item_id: this.props.match.params.groupId,
+ });
+ }
+
+ componentWillUnmount() {
+ this.isMounted = false;
+ this.props.page.unload();
+ }
+
+ render() {
+ return (
+ this.state.role !== null ?
+ (this.state.role === "owner"
+ ?
+
+
+
+ Group Stats: {this.state.groupName}
+
+
+
+
{this.state.totalIncorrect}
+
mistakes
+
+ {
+ this.state.incorrectAnswers.length > 0 &&
+
+
{this.state.incorrectAnswers[0].term}
+
meaning
+
{this.state.incorrectAnswers[0].definition}
+
is the most common
+
+ }
+
+
+ {
+ this.state.incorrectAnswers.map((vocabItem, index) => (
+
+
+
{vocabItem.term}
+
{vocabItem.switchedCount} mistake{vocabItem.switchedCount !== 1 && "s"}{vocabItem.switchedCount > 0 && ":"}
+ {
+ vocabItem.switchedCount > 0 &&
+
+ {
+ vocabItem.answers.sort((a, b) => {
+ if (a.answer < b.answer) {
+ return -1;
+ }
+ if (a.answer > b.answer) {
+ return 1;
+ }
+ return 0;
+ }).map((answerItem, index) => answerItem.switchLanguage && (
+
{answerItem.answer === "" ? skipped : answerItem.answer}
+ ))
+ }
+
+ }
+
+
+
{vocabItem.definition}
+
{vocabItem.count} mistake{vocabItem.count !== 1 && "s"}{vocabItem.count > 0 && ":"}
+ {
+ vocabItem.count > 0 &&
+
+ {
+ vocabItem.answers.sort((a, b) => {
+ if (a.answer < b.answer) {
+ return -1;
+ }
+ if (a.answer > b.answer) {
+ return 1;
+ }
+ return 0;
+ }).map((answerItem, index) => !answerItem.switchLanguage && (
+
{answerItem.answer === "" ? skipped : answerItem.answer}
+ ))
+ }
+
+ }
+
+
+ ))
+ }
+
+
+
+
+
+ :
+ )
+ :
+ null
+ )
+ }
+})