Add set-specific history tracking for group owners
This commit is contained in:
162
package-lock.json
generated
162
package-lock.json
generated
@@ -1370,6 +1370,18 @@
|
|||||||
"kuler": "^2.0.0"
|
"kuler": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@emotion/cache": {
|
||||||
|
"version": "11.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.5.0.tgz",
|
||||||
|
"integrity": "sha512-mAZ5QRpLriBtaj/k2qyrXwck6yeoz1V5lMt/jfj6igWU35yYlNKs2LziXVgvH81gnJZ+9QQNGelSsnuoAy6uIw==",
|
||||||
|
"requires": {
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/sheet": "^1.0.3",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"stylis": "^4.0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@emotion/hash": {
|
"@emotion/hash": {
|
||||||
"version": "0.8.0",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
|
||||||
@@ -1388,6 +1400,44 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
|
||||||
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
|
||||||
},
|
},
|
||||||
|
"@emotion/react": {
|
||||||
|
"version": "11.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.5.0.tgz",
|
||||||
|
"integrity": "sha512-MYq/bzp3rYbee4EMBORCn4duPQfgpiEB5XzrZEBnUZAL80Qdfr7CEv/T80jwaTl/dnZmt9SnTa8NkTrwFNpLlw==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.13.10",
|
||||||
|
"@emotion/cache": "^11.5.0",
|
||||||
|
"@emotion/serialize": "^1.0.2",
|
||||||
|
"@emotion/sheet": "^1.0.3",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"@emotion/weak-memoize": "^0.2.5",
|
||||||
|
"hoist-non-react-statics": "^3.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@emotion/serialize": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==",
|
||||||
|
"requires": {
|
||||||
|
"@emotion/hash": "^0.8.0",
|
||||||
|
"@emotion/memoize": "^0.7.4",
|
||||||
|
"@emotion/unitless": "^0.7.5",
|
||||||
|
"@emotion/utils": "^1.0.0",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"csstype": {
|
||||||
|
"version": "3.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz",
|
||||||
|
"integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@emotion/sheet": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-YoX5GyQ4db7LpbmXHMuc8kebtBGP6nZfRC5Z13OKJMixBEwdZrJ914D6yJv/P+ZH/YY3F5s89NYX2hlZAf3SRQ=="
|
||||||
|
},
|
||||||
"@emotion/stylis": {
|
"@emotion/stylis": {
|
||||||
"version": "0.8.5",
|
"version": "0.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
|
||||||
@@ -1398,6 +1448,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
|
||||||
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
|
"integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
|
||||||
},
|
},
|
||||||
|
"@emotion/utils": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
|
||||||
|
},
|
||||||
|
"@emotion/weak-memoize": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
|
||||||
|
"integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
|
||||||
|
},
|
||||||
"@eslint/eslintrc": {
|
"@eslint/eslintrc": {
|
||||||
"version": "0.4.3",
|
"version": "0.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
|
||||||
@@ -13928,6 +13988,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||||
},
|
},
|
||||||
|
"memoize-one": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
|
||||||
|
},
|
||||||
"memoizee": {
|
"memoizee": {
|
||||||
"version": "0.4.15",
|
"version": "0.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz",
|
||||||
@@ -14351,6 +14416,12 @@
|
|||||||
"yargs-unparser": "2.0.0"
|
"yargs-unparser": "2.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
@@ -14465,6 +14536,12 @@
|
|||||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"js-yaml": {
|
"js-yaml": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
|
||||||
@@ -14522,6 +14599,25 @@
|
|||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"is-fullwidth-code-point": "^2.0.0",
|
||||||
|
"strip-ansi": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"strip-json-comments": {
|
"strip-json-comments": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||||
@@ -14546,6 +14642,15 @@
|
|||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wide-align": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"string-width": "^1.0.2 || 2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"yargs-parser": {
|
"yargs-parser": {
|
||||||
"version": "20.2.4",
|
"version": "20.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
|
||||||
@@ -17596,6 +17701,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-select": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-select/-/react-select-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-SkEBD1AYsSXrIdNj5HBt7+Ehe+jxdiB448J0atJqR6lE3l/GcFlRf4JYB3NlHe/02jrW4AnIQLo1t0IqWrxXOw==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.12.0",
|
||||||
|
"@emotion/cache": "^11.4.0",
|
||||||
|
"@emotion/react": "^11.1.1",
|
||||||
|
"@types/react-transition-group": "^4.4.0",
|
||||||
|
"memoize-one": "^5.0.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-transition-group": "^4.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-shallow-renderer": {
|
"react-shallow-renderer": {
|
||||||
"version": "16.14.1",
|
"version": "16.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz",
|
||||||
@@ -19560,6 +19679,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"stylis": {
|
||||||
|
"version": "4.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.10.tgz",
|
||||||
|
"integrity": "sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg=="
|
||||||
|
},
|
||||||
"superstatic": {
|
"superstatic": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/superstatic/-/superstatic-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/superstatic/-/superstatic-7.1.0.tgz",
|
||||||
@@ -22192,40 +22316,12 @@
|
|||||||
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
|
||||||
},
|
},
|
||||||
"wide-align": {
|
"wide-align": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
|
||||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"string-width": "^1.0.2 || 2"
|
"string-width": "^1.0.2 || 2 || 3 || 4"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-regex": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
|
||||||
},
|
|
||||||
"is-fullwidth-code-point": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
|
||||||
},
|
|
||||||
"string-width": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
|
||||||
"requires": {
|
|
||||||
"is-fullwidth-code-point": "^2.0.0",
|
|
||||||
"strip-ansi": "^4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-ansi": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
|
||||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
|
||||||
"requires": {
|
|
||||||
"ansi-regex": "^3.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"widest-line": {
|
"widest-line": {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"react-firebaseui": "^5.0.2",
|
"react-firebaseui": "^5.0.2",
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^5.3.0",
|
||||||
"react-scripts": "^4.0.3",
|
"react-scripts": "^4.0.3",
|
||||||
|
"react-select": "^5.1.0",
|
||||||
"react-xarrows": "^2.0.2",
|
"react-xarrows": "^2.0.2",
|
||||||
"styled-components": "^5.3.1",
|
"styled-components": "^5.3.1",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ class App extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.page = {
|
this.page = {
|
||||||
loaded: !this.state.pageLoading,
|
loaded: () => !this.state.pageLoading,
|
||||||
load: () => {
|
load: () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
pageLoading: false,
|
pageLoading: false,
|
||||||
|
|||||||
@@ -232,6 +232,10 @@ export default withRouter(class GroupPage extends Component {
|
|||||||
};
|
};
|
||||||
delete newState.sets[setId];
|
delete newState.sets[setId];
|
||||||
this.setState(newState);
|
this.setState(newState);
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(`Can't remove set from group: ${error}`);
|
||||||
|
newLoadingState.sets[setId].loading = false;
|
||||||
|
this.setState(newLoadingState);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,26 +447,36 @@ export default withRouter(class GroupPage extends Component {
|
|||||||
?
|
?
|
||||||
<div className="group-links-container">
|
<div className="group-links-container">
|
||||||
{
|
{
|
||||||
Object.keys(this.state.sets).map((setId) =>
|
Object.keys(this.state.sets)
|
||||||
<div key={setId} className="group-set-link">
|
.sort((a, b) => {
|
||||||
<Link
|
if (this.state.sets[a].displayName < this.state.sets[b].displayName) {
|
||||||
to={`/sets/${setId}`}
|
return -1;
|
||||||
>
|
|
||||||
{this.state.sets[setId].displayName}
|
|
||||||
</Link>
|
|
||||||
{
|
|
||||||
this.state.role === "owner" &&
|
|
||||||
<Button
|
|
||||||
className="button--no-background"
|
|
||||||
onClick={() => this.removeSet(setId)}
|
|
||||||
icon={<DeleteRoundedIcon />}
|
|
||||||
loading={this.state.sets[setId].loading}
|
|
||||||
disabled={this.state.sets[setId].loading}
|
|
||||||
title="Remove set"
|
|
||||||
></Button>
|
|
||||||
}
|
}
|
||||||
</div>
|
if (this.state.sets[a].displayName > this.state.sets[b].displayName) {
|
||||||
)
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
.map((setId) =>
|
||||||
|
<div key={setId} className="group-set-link">
|
||||||
|
<Link
|
||||||
|
to={`/sets/${setId}`}
|
||||||
|
>
|
||||||
|
{this.state.sets[setId].displayName}
|
||||||
|
</Link>
|
||||||
|
{
|
||||||
|
this.state.role === "owner" &&
|
||||||
|
<Button
|
||||||
|
className="button--no-background"
|
||||||
|
onClick={() => this.removeSet(setId)}
|
||||||
|
icon={<DeleteRoundedIcon />}
|
||||||
|
loading={this.state.sets[setId].loading}
|
||||||
|
disabled={this.state.sets[setId].loading}
|
||||||
|
title="Remove set"
|
||||||
|
></Button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { ArrowDropDownRounded as ArrowDropDownRoundedIcon, GroupRounded as GroupRoundedIcon, HomeRounded as HomeRoundedIcon } from "@material-ui/icons";
|
import { ArrowDropDownRounded as ArrowDropDownRoundedIcon, GroupRounded as GroupRoundedIcon, HomeRounded as HomeRoundedIcon } from "@material-ui/icons";
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
|
import Select from "react-select";
|
||||||
import NavBar from "./NavBar";
|
import NavBar from "./NavBar";
|
||||||
import Footer from "./Footer";
|
import Footer from "./Footer";
|
||||||
import Error404 from "./Error404";
|
import Error404 from "./Error404";
|
||||||
@@ -8,6 +9,7 @@ import "./css/History.css";
|
|||||||
import "./css/MistakesHistory.css";
|
import "./css/MistakesHistory.css";
|
||||||
|
|
||||||
import Collapsible from "react-collapsible";
|
import Collapsible from "react-collapsible";
|
||||||
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
|
|
||||||
export default withRouter(class GroupStats extends Component {
|
export default withRouter(class GroupStats extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -31,6 +33,15 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
],
|
],
|
||||||
role: null,
|
role: null,
|
||||||
groupName: "",
|
groupName: "",
|
||||||
|
sets: {},
|
||||||
|
selectedSet: {
|
||||||
|
value: "all_sets",
|
||||||
|
label: "All sets",
|
||||||
|
},
|
||||||
|
includeCompoundTests: true,
|
||||||
|
incorrectAnswers: [],
|
||||||
|
filteredIncorrectAnswers: [],
|
||||||
|
setsWithHistory: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
let isMounted = true;
|
let isMounted = true;
|
||||||
@@ -46,7 +57,10 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
let newState = {};
|
let newState = {
|
||||||
|
sets: {},
|
||||||
|
setsWithHistory: {},
|
||||||
|
};
|
||||||
|
|
||||||
await this.state.db
|
await this.state.db
|
||||||
.collection("users")
|
.collection("users")
|
||||||
@@ -69,20 +83,19 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
.doc(this.props.match.params.groupId)
|
.doc(this.props.match.params.groupId)
|
||||||
.get()
|
.get()
|
||||||
.then(async (groupDoc) => {
|
.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`;
|
document.title = `Stats | ${groupDoc.data().display_name} | Parandum`;
|
||||||
newState.groupName = groupDoc.data().display_name;
|
newState.groupName = groupDoc.data().display_name;
|
||||||
|
|
||||||
|
return Promise.all(groupDoc.data().sets.map((setId) => {
|
||||||
|
return this.state.db.collection("sets")
|
||||||
|
.doc(setId)
|
||||||
|
.get()
|
||||||
|
.then((doc) => {
|
||||||
|
newState.sets[setId] = {
|
||||||
|
title: doc.data().title,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}));
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.log(`Can't access group: ${error}`);
|
console.log(`Can't access group: ${error}`);
|
||||||
newState.groupName = "";
|
newState.groupName = "";
|
||||||
@@ -105,14 +118,22 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
answers: [{
|
answers: [{
|
||||||
answer: doc.data().answer,
|
answer: doc.data().answer,
|
||||||
switchLanguage: doc.data().switch_language,
|
switchLanguage: doc.data().switch_language,
|
||||||
|
setIds: doc.data().setIds,
|
||||||
}],
|
}],
|
||||||
count: doc.data().switch_language ? 0 : 1,
|
count: doc.data().switch_language ? 0 : 1,
|
||||||
switchedCount: doc.data().switch_language ? 1 : 0,
|
switchedCount: doc.data().switch_language ? 1 : 0,
|
||||||
|
setIds: [doc.data().setIds],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
incorrectAnswers[incorrectAnswers.length - 1].answers.push({
|
incorrectAnswers[incorrectAnswers.length - 1].answers.push({
|
||||||
answer: doc.data().answer,
|
answer: doc.data().answer,
|
||||||
switchLanguage: doc.data().switch_language,
|
switchLanguage: doc.data().switch_language,
|
||||||
|
setIds: doc.data().setIds,
|
||||||
|
});
|
||||||
|
doc.data().setIds.map((setId) => {
|
||||||
|
if (!incorrectAnswers[incorrectAnswers.length - 1].setIds.includes(setId))
|
||||||
|
return incorrectAnswers[incorrectAnswers.length - 1].setIds.push(setId);
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
if (doc.data().switch_language) {
|
if (doc.data().switch_language) {
|
||||||
incorrectAnswers[incorrectAnswers.length - 1].switchedCount++;
|
incorrectAnswers[incorrectAnswers.length - 1].switchedCount++;
|
||||||
@@ -120,9 +141,13 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
incorrectAnswers[incorrectAnswers.length - 1].count++;
|
incorrectAnswers[incorrectAnswers.length - 1].count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
doc.data().setIds.map((setId) => newState.setsWithHistory[setId] = true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
newState.incorrectAnswers = incorrectAnswers.sort((a, b) => b.count + b.switchedCount - a.count - a.switchedCount);
|
newState.incorrectAnswers = incorrectAnswers.sort((a, b) => b.count + b.switchedCount - a.count - a.switchedCount);
|
||||||
|
newState.filteredIncorrectAnswers = newState.incorrectAnswers;
|
||||||
newState.totalIncorrect = querySnapshot.docs.length;
|
newState.totalIncorrect = querySnapshot.docs.length;
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -149,6 +174,64 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
this.props.page.unload();
|
this.props.page.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arraysHaveSameMembers = (arr1, arr2) => {
|
||||||
|
const set1 = new Set(arr1);
|
||||||
|
const set2 = new Set(arr2);
|
||||||
|
return arr1.every(item => set2.has(item)) &&
|
||||||
|
arr2.every(item => set1.has(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSetSelectionChange = (selectedSet = this.state.selectedSet) => {
|
||||||
|
let totalIncorrect = 0;
|
||||||
|
const filteredIncorrectAnswers = (selectedSet.value === "all_sets" ?
|
||||||
|
JSON.parse(JSON.stringify(this.state.incorrectAnswers))
|
||||||
|
:
|
||||||
|
JSON.parse(JSON.stringify(this.state.incorrectAnswers))
|
||||||
|
.filter((vocabItem) =>
|
||||||
|
vocabItem.setIds.includes(selectedSet.value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map((vocabItem) => {
|
||||||
|
let newVocabItem = vocabItem;
|
||||||
|
if (selectedSet.value === "all_sets") {
|
||||||
|
if (this.state.includeCompoundTests) {
|
||||||
|
newVocabItem.answers = vocabItem.answers;
|
||||||
|
} else {
|
||||||
|
newVocabItem.answers = vocabItem.answers
|
||||||
|
.filter((answer) =>
|
||||||
|
answer.setIds.length === 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newVocabItem.answers = vocabItem.answers
|
||||||
|
.filter((answer) =>
|
||||||
|
this.arraysHaveSameMembers(answer.setIds, [selectedSet.value]) ||
|
||||||
|
(
|
||||||
|
this.state.includeCompoundTests &&
|
||||||
|
answer.setIds.includes(this.state.selectedSet.value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
newVocabItem.switchedCount = newVocabItem.answers.filter((answer) => answer.switchLanguage).length;
|
||||||
|
newVocabItem.count = newVocabItem.answers.length - newVocabItem.switchedCount;
|
||||||
|
|
||||||
|
totalIncorrect += newVocabItem.answers.length;
|
||||||
|
|
||||||
|
return newVocabItem;
|
||||||
|
});
|
||||||
|
this.setState({
|
||||||
|
filteredIncorrectAnswers: filteredIncorrectAnswers,
|
||||||
|
selectedSet: selectedSet,
|
||||||
|
totalIncorrect: totalIncorrect,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleIncludeCompoundTestsChange = (event) => {
|
||||||
|
this.setState({
|
||||||
|
includeCompoundTests: event.target.checked,
|
||||||
|
}, () => this.handleSetSelectionChange());
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
this.state.role !== null ?
|
this.state.role !== null ?
|
||||||
@@ -159,85 +242,171 @@ export default withRouter(class GroupStats extends Component {
|
|||||||
<main>
|
<main>
|
||||||
<h1>Group Stats: {this.state.groupName}</h1>
|
<h1>Group Stats: {this.state.groupName}</h1>
|
||||||
<div className="history-sections">
|
<div className="history-sections">
|
||||||
|
<Select
|
||||||
|
className="set-select-container"
|
||||||
|
value={this.state.selectedSet}
|
||||||
|
onChange={this.handleSetSelectionChange}
|
||||||
|
defaultValue={"all_sets"}
|
||||||
|
options={
|
||||||
|
[
|
||||||
|
{
|
||||||
|
value: "all_sets",
|
||||||
|
label: "All sets",
|
||||||
|
}
|
||||||
|
].concat(Object.keys(this.state.sets)
|
||||||
|
.filter((setId) => this.state.setsWithHistory[setId] === true)
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (this.state.sets[a].title < this.state.sets[b].title) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (this.state.sets[a].title > this.state.sets[b].title) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
.map((setId) => {
|
||||||
|
return {
|
||||||
|
value: setId,
|
||||||
|
label: this.state.sets[setId].title
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
theme={theme => {
|
||||||
|
const overlayColor = getComputedStyle(
|
||||||
|
document.querySelector("#root > div")
|
||||||
|
).getPropertyValue("--background-color-light")
|
||||||
|
.trim();
|
||||||
|
const textColor = getComputedStyle(
|
||||||
|
document.querySelector("#root > div")
|
||||||
|
).getPropertyValue("--text-color")
|
||||||
|
.trim();
|
||||||
|
const textColorTinted = getComputedStyle(
|
||||||
|
document.querySelector("#root > div")
|
||||||
|
).getPropertyValue("--text-color-tinted")
|
||||||
|
.trim();
|
||||||
|
const primaryColor = getComputedStyle(
|
||||||
|
document.querySelector("#root > div")
|
||||||
|
).getPropertyValue("--primary-color")
|
||||||
|
.trim();
|
||||||
|
const primaryColorDark = getComputedStyle(
|
||||||
|
document.querySelector("#root > div")
|
||||||
|
).getPropertyValue("--primary-color-dark")
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...theme,
|
||||||
|
borderRadius: 6,
|
||||||
|
colors: {
|
||||||
|
...theme.colors,
|
||||||
|
primary: primaryColor,
|
||||||
|
primary25: primaryColorDark,
|
||||||
|
neutral0: overlayColor,
|
||||||
|
neutral5: overlayColor,
|
||||||
|
neutral10: overlayColor,
|
||||||
|
neutral20: textColorTinted,
|
||||||
|
neutral30: textColor,
|
||||||
|
neutral40: textColor,
|
||||||
|
neutral50: textColor,
|
||||||
|
neutral60: textColorTinted,
|
||||||
|
neutral70: textColor,
|
||||||
|
neutral80: textColor,
|
||||||
|
neutral90: textColor,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<label>
|
||||||
|
<Checkbox
|
||||||
|
checked={this.state.includeCompoundTests}
|
||||||
|
onChange={this.handleIncludeCompoundTestsChange}
|
||||||
|
inputProps={{ 'aria-label': 'checkbox' }}
|
||||||
|
/>
|
||||||
|
<span>Include compound tests</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
<div className="historical-user-stats-container">
|
<div className="historical-user-stats-container">
|
||||||
<div className="stat-row stat-row--inline">
|
<div className="stat-row stat-row--inline">
|
||||||
<h1>{this.state.totalIncorrect}</h1>
|
<h1>{this.state.totalIncorrect}</h1>
|
||||||
<p>mistakes</p>
|
<p>mistakes</p>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
this.state.incorrectAnswers.length > 0 &&
|
this.state.filteredIncorrectAnswers.length > 0 &&
|
||||||
<div className="stat-row stat-row--inline">
|
<div className="stat-row stat-row--inline">
|
||||||
<h1>{this.state.incorrectAnswers[0].term}</h1>
|
{/* <h1>{this.state.incorrectAnswers[0].term}</h1> */}
|
||||||
|
<h1>{this.state.filteredIncorrectAnswers[0].term}</h1>
|
||||||
<p>meaning</p>
|
<p>meaning</p>
|
||||||
<h1>{this.state.incorrectAnswers[0].definition}</h1>
|
{/* <h1>{this.state.incorrectAnswers[0].definition}</h1> */}
|
||||||
|
<h1>{this.state.filteredIncorrectAnswers[0].definition}</h1>
|
||||||
<p>is the most common</p>
|
<p>is the most common</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mistakes-history-container">
|
<div className="mistakes-history-container">
|
||||||
{
|
{
|
||||||
this.state.incorrectAnswers.map((vocabItem, index) => (
|
this.state.filteredIncorrectAnswers
|
||||||
<React.Fragment key={index}>
|
.map((vocabItem, index) => {
|
||||||
<div>
|
const sortedAnswers = vocabItem.answers
|
||||||
<h2>{vocabItem.term}</h2>
|
.sort((a, b) => {
|
||||||
{
|
if (a.answer < b.answer) {
|
||||||
vocabItem.switchedCount > 0
|
return -1;
|
||||||
?
|
}
|
||||||
<Collapsible transitionTime={300} trigger={<><b>{vocabItem.switchedCount} mistake{vocabItem.switchedCount !== 1 && "s"}</b><ArrowDropDownRoundedIcon /></>}>
|
if (a.answer > b.answer) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<div>
|
||||||
|
<h2>{vocabItem.term}</h2>
|
||||||
{
|
{
|
||||||
vocabItem.switchedCount > 0 &&
|
vocabItem.switchedCount > 0
|
||||||
<div>
|
?
|
||||||
|
<Collapsible transitionTime={300} trigger={<><b>{vocabItem.switchedCount} mistake{vocabItem.switchedCount !== 1 && "s"}</b><ArrowDropDownRoundedIcon /></>}>
|
||||||
{
|
{
|
||||||
vocabItem.answers.sort((a, b) => {
|
vocabItem.switchedCount > 0 &&
|
||||||
if (a.answer < b.answer) {
|
<div>
|
||||||
return -1;
|
{
|
||||||
|
sortedAnswers
|
||||||
|
.map((answerItem, index) => answerItem.switchLanguage && (
|
||||||
|
<p key={index}>{answerItem.answer === "" ? <i>skipped</i> : answerItem.answer}</p>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
if (a.answer > b.answer) {
|
</div>
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}).map((answerItem, index) => answerItem.switchLanguage && (
|
|
||||||
<p key={index}>{answerItem.answer === "" ? <i>skipped</i> : answerItem.answer}</p>
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
</div>
|
</Collapsible>
|
||||||
|
:
|
||||||
|
<b>0 mistakes</b>
|
||||||
}
|
}
|
||||||
</Collapsible>
|
</div>
|
||||||
:
|
<div>
|
||||||
<b>{vocabItem.switchedCount} mistake{vocabItem.switchedCount !== 1 && "s"}</b>
|
<h2>{vocabItem.definition}</h2>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>{vocabItem.definition}</h2>
|
|
||||||
{
|
|
||||||
vocabItem.count > 0
|
|
||||||
?
|
|
||||||
<Collapsible transitionTime={300} trigger={<><b>{vocabItem.count} mistake{vocabItem.count !== 1 && "s"}</b><ArrowDropDownRoundedIcon /></>}>
|
|
||||||
{
|
{
|
||||||
vocabItem.count > 0 &&
|
vocabItem.count > 0
|
||||||
<div>
|
?
|
||||||
|
<Collapsible transitionTime={300} trigger={<><b>{vocabItem.count} mistake{vocabItem.count !== 1 && "s"}</b><ArrowDropDownRoundedIcon /></>}>
|
||||||
{
|
{
|
||||||
vocabItem.answers.sort((a, b) => {
|
vocabItem.count > 0 &&
|
||||||
if (a.answer < b.answer) {
|
<div>
|
||||||
return -1;
|
{
|
||||||
|
sortedAnswers
|
||||||
|
.map((answerItem, index) => !answerItem.switchLanguage && (
|
||||||
|
<p key={index}>{answerItem.answer === "" ? <i>skipped</i> : answerItem.answer}</p>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
if (a.answer > b.answer) {
|
</div>
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}).map((answerItem, index) => !answerItem.switchLanguage && (
|
|
||||||
<p key={index}>{answerItem.answer === "" ? <i>skipped</i> : answerItem.answer}</p>
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
</div>
|
</Collapsible>
|
||||||
|
:
|
||||||
|
<b>0 mistakes</b>
|
||||||
}
|
}
|
||||||
</Collapsible>
|
</div>
|
||||||
:
|
</React.Fragment>
|
||||||
<b>{vocabItem.switchedCount} mistake{vocabItem.switchedCount !== 1 && "s"}</b>
|
)
|
||||||
}
|
})
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ export default withRouter(class LoggedInHome extends React.Component {
|
|||||||
Groups
|
Groups
|
||||||
</LinkButton>
|
</LinkButton>
|
||||||
{
|
{
|
||||||
this.state.userSets && this.state.userSets.length > 0 &&
|
(!this.props.page.loaded() || (this.state.userSets && this.state.userSets.length > 0)) &&
|
||||||
<LinkButton
|
<LinkButton
|
||||||
to="/my-sets"
|
to="/my-sets"
|
||||||
>
|
>
|
||||||
@@ -523,7 +523,8 @@ export default withRouter(class LoggedInHome extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{this.state.userGroupSets && this.state.userGroupSets.length > 0 && this.state.userGroupSets.map(data =>
|
{this.state.userGroupSets && this.state.userGroupSets.length > 0 && this.state.userGroupSets
|
||||||
|
.map(data =>
|
||||||
data.sets && data.sets.length > 0 &&
|
data.sets && data.sets.length > 0 &&
|
||||||
<div key={data.group.id} className="checkbox-list-container">
|
<div key={data.group.id} className="checkbox-list-container">
|
||||||
<Link to={`/groups/${data.group.id}`}>
|
<Link to={`/groups/${data.group.id}`}>
|
||||||
@@ -531,7 +532,49 @@ export default withRouter(class LoggedInHome extends React.Component {
|
|||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="checkbox-list">
|
<div className="checkbox-list">
|
||||||
{data.sets.map(set =>
|
{data.sets
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.data().title < b.data().title) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.data().title > b.data().title) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
})
|
||||||
|
.map(set =>
|
||||||
|
<div key={set.id}>
|
||||||
|
<label>
|
||||||
|
<Checkbox
|
||||||
|
name={set.id}
|
||||||
|
checked={this.state.selections[set.id]}
|
||||||
|
onChange={this.handleSetSelectionChange}
|
||||||
|
inputProps={{ 'aria-label': 'checkbox' }}
|
||||||
|
/>
|
||||||
|
<Link to={`/sets/${set.id}`}>
|
||||||
|
{set.data().title}
|
||||||
|
</Link>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{this.state.publicSets && this.state.publicSets.length > 0 &&
|
||||||
|
<div className="checkbox-list-container">
|
||||||
|
<h3><PublicRoundedIcon /> Public Sets</h3>
|
||||||
|
<div className="checkbox-list">
|
||||||
|
{this.state.publicSets
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.data().title < b.data().title) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (a.data().title > b.data().title) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}).map(set =>
|
||||||
<div key={set.id}>
|
<div key={set.id}>
|
||||||
<label>
|
<label>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@@ -545,29 +588,8 @@ export default withRouter(class LoggedInHome extends React.Component {
|
|||||||
</Link>
|
</Link>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)
|
||||||
</div>
|
}
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{this.state.publicSets && this.state.publicSets.length > 0 &&
|
|
||||||
<div className="checkbox-list-container">
|
|
||||||
<h3><PublicRoundedIcon /> Public Sets</h3>
|
|
||||||
<div className="checkbox-list">
|
|
||||||
{this.state.publicSets.map(set =>
|
|
||||||
<div key={set.id}>
|
|
||||||
<label>
|
|
||||||
<Checkbox
|
|
||||||
name={set.id}
|
|
||||||
checked={this.state.selections[set.id]}
|
|
||||||
onChange={this.handleSetSelectionChange}
|
|
||||||
inputProps={{ 'aria-label': 'checkbox' }}
|
|
||||||
/>
|
|
||||||
<Link to={`/sets/${set.id}`}>
|
|
||||||
{set.data().title}
|
|
||||||
</Link>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ html {
|
|||||||
--text-color-tinted: #cccccc;
|
--text-color-tinted: #cccccc;
|
||||||
--background-color: #111111;
|
--background-color: #111111;
|
||||||
--background-color-dark: #000000;
|
--background-color-dark: #000000;
|
||||||
|
--background-color-light: #222222;
|
||||||
--overlay-color: #333333;
|
--overlay-color: #333333;
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -25,3 +25,7 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.set-select-container {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user