From 96f810d3ff1a1faa463eb5a7892926953d73c2d0 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sun, 27 Mar 2022 11:14:28 -0400 Subject: [PATCH 01/53] create selectable participantList skeleton --- package-lock.json | 769 ++++++++++++++++++++++++++++- package.json | 3 + src/components/ParticipantList.tsx | 40 ++ src/components/Participants.tsx | 12 +- src/pages/Schedule.tsx | 7 +- yarn.lock | 214 +++++++- 6 files changed, 1007 insertions(+), 38 deletions(-) create mode 100644 src/components/ParticipantList.tsx diff --git a/package-lock.json b/package-lock.json index d0cbd1e..ce72e3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,11 @@ "name": "freethyme", "version": "0.1.0", "dependencies": { + "@emotion/react": "^11.8.2", + "@emotion/styled": "^11.8.1", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", + "@mui/material": "^5.5.2", "@reduxjs/toolkit": "^1.8.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", @@ -1988,6 +1991,86 @@ "postcss": "^8.3" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz", + "integrity": "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/runtime": "^7.13.10", + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.5", + "@emotion/serialize": "^1.0.2", + "babel-plugin-macros": "^2.6.1", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/serialize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", + "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", + "dependencies": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "node_modules/@emotion/babel-plugin/node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@emotion/cache": { "version": "10.0.29", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", @@ -2043,6 +2126,66 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, + "node_modules/@emotion/react": { + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.8.2.tgz", + "integrity": "sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/cache": "^11.7.1", + "@emotion/serialize": "^1.0.2", + "@emotion/utils": "^1.1.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/react/node_modules/@emotion/cache": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", + "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", + "dependencies": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "node_modules/@emotion/react/node_modules/@emotion/serialize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", + "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", + "dependencies": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/react/node_modules/@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "node_modules/@emotion/react/node_modules/@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, "node_modules/@emotion/serialize": { "version": "0.11.16", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", @@ -2066,16 +2209,28 @@ "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" }, "node_modules/@emotion/styled": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", - "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "version": "11.8.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.8.1.tgz", + "integrity": "sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ==", "dependencies": { - "@emotion/styled-base": "^10.3.0", - "babel-plugin-emotion": "^10.0.27" + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/is-prop-valid": "^1.1.2", + "@emotion/serialize": "^1.0.2", + "@emotion/utils": "^1.1.0" }, "peerDependencies": { - "@emotion/core": "^10.0.27", - "react": ">=16.3.0" + "@babel/core": "^7.0.0", + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/react": { + "optional": true + } } }, "node_modules/@emotion/styled-base": { @@ -2093,6 +2248,31 @@ "react": ">=16.3.0" } }, + "node_modules/@emotion/styled/node_modules/@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "dependencies": { + "@emotion/memoize": "^0.7.4" + } + }, + "node_modules/@emotion/styled/node_modules/@emotion/serialize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz", + "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==", + "dependencies": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/styled/node_modules/@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, "node_modules/@emotion/stylis": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", @@ -3043,6 +3223,241 @@ "react-dom": "^16.8.0 || ^17.0.0" } }, + "node_modules/@mui/base": { + "version": "5.0.0-alpha.73", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.73.tgz", + "integrity": "sha512-TEUCIIEAWrngAqpIa+dY3nofGSNj70LC3KC9WcCzyXPK3M4AG2GNi7ndd/g/0DtC55kbxrudzlV8TG3vrB2Vjw==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@emotion/is-prop-valid": "^1.1.2", + "@mui/utils": "^5.4.4", + "@popperjs/core": "^2.11.4", + "clsx": "^1.1.1", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^17.0.0", + "react-dom": "^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "dependencies": { + "@emotion/memoize": "^0.7.4" + } + }, + "node_modules/@mui/material": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.5.2.tgz", + "integrity": "sha512-r4p1u9eDlSqW3TS/Iq9yolifWHpuW6e0BSeqEJW3EEIcKfPVVk4WNUNJ+s8DtN7dBoDcveXxcQVVjYXTIv1d9g==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@mui/base": "5.0.0-alpha.73", + "@mui/system": "^5.5.2", + "@mui/types": "^7.1.3", + "@mui/utils": "^5.4.4", + "@types/react-transition-group": "^4.4.4", + "clsx": "^1.1.1", + "csstype": "^3.0.11", + "hoist-non-react-statics": "^3.3.2", + "prop-types": "^15.7.2", + "react-is": "^17.0.2", + "react-transition-group": "^4.4.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^17.0.0", + "react-dom": "^17.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.4.4.tgz", + "integrity": "sha512-V/gxttr6736yJoU9q+4xxXsa0K/w9Hn9pg99zsOHt7i/O904w2CX5NHh5WqDXtoUzVcayLF0RB17yr6l79CE+A==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@mui/utils": "^5.4.4", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.5.2.tgz", + "integrity": "sha512-jkz5AHHbA43akBo5L3y1X1/X0f+RvXvCp3eXKt+iOf3qnKSAausbtlVz7gBbC4xIWDnP1Jb/6T+t/0/7gObRYA==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@emotion/cache": "^11.7.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine/node_modules/@emotion/cache": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", + "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", + "dependencies": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "node_modules/@mui/styled-engine/node_modules/@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "node_modules/@mui/styled-engine/node_modules/@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "node_modules/@mui/system": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.5.2.tgz", + "integrity": "sha512-OATYFI36nliud8xh0u+ZNqDo0jWjxpO0vZLlzqNB+ZtkR5Q/+1X3GgboA9ruiB8Rq+udnJlMBQNGW0qqjvAOHQ==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@mui/private-theming": "^5.4.4", + "@mui/styled-engine": "^5.5.2", + "@mui/types": "^7.1.3", + "@mui/utils": "^5.4.4", + "clsx": "^1.1.1", + "csstype": "^3.0.11", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^17.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.1.3.tgz", + "integrity": "sha512-DDF0UhMBo4Uezlk+6QxrlDbchF79XG6Zs0zIewlR4c0Dt6GKVFfUtzPtHCH1tTbcSlq/L2bGEdiaoHBJ9Y1gSA==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.4.4.tgz", + "integrity": "sha512-hfYIXEuhc2mXMGN5nUPis8beH6uE/zl3uMWJcyHX0/LN/+QxO9zhYuV6l8AsAaphHFyS/fBv0SW3Nid7jw5hKQ==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "@types/prop-types": "^15.7.4", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui" + }, + "peerDependencies": { + "react": "^17.0.0" + } + }, "node_modules/@node-redis/bloom": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", @@ -4368,6 +4783,14 @@ "@types/react": "^16" } }, + "node_modules/@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-redux": { "version": "7.1.23", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.23.tgz", @@ -6915,9 +7338,9 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, "node_modules/csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -14515,6 +14938,19 @@ "styled-components": ">=5.0" } }, + "node_modules/react-schedule-selector/node_modules/@emotion/styled": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", + "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "dependencies": { + "@emotion/styled-base": "^10.3.0", + "babel-plugin-emotion": "^10.0.27" + }, + "peerDependencies": { + "@emotion/core": "^10.0.27", + "react": ">=16.3.0" + } + }, "node_modules/react-schedule-selector/node_modules/@jest/types": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", @@ -15961,6 +16397,11 @@ "postcss": "^8.2.15" } }, + "node_modules/stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -19010,6 +19451,76 @@ "postcss-value-parser": "^4.2.0" } }, + "@emotion/babel-plugin": { + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz", + "integrity": "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==", + "requires": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/runtime": "^7.13.10", + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.5", + "@emotion/serialize": "^1.0.2", + "babel-plugin-macros": "^2.6.1", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "@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" + } + }, + "@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, + "cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + } + } + }, "@emotion/cache": { "version": "10.0.29", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", @@ -19062,6 +19573,56 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, + "@emotion/react": { + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.8.2.tgz", + "integrity": "sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA==", + "requires": { + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/cache": "^11.7.1", + "@emotion/serialize": "^1.0.2", + "@emotion/utils": "^1.1.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + }, + "dependencies": { + "@emotion/cache": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", + "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", + "requires": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "@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" + } + }, + "@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + } + } + }, "@emotion/serialize": { "version": "0.11.16", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", @@ -19087,12 +19648,42 @@ "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" }, "@emotion/styled": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", - "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "version": "11.8.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.8.1.tgz", + "integrity": "sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ==", "requires": { - "@emotion/styled-base": "^10.3.0", - "babel-plugin-emotion": "^10.0.27" + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/is-prop-valid": "^1.1.2", + "@emotion/serialize": "^1.0.2", + "@emotion/utils": "^1.1.0" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "requires": { + "@emotion/memoize": "^0.7.4" + } + }, + "@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" + } + }, + "@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + } } }, "@emotion/styled-base": { @@ -19779,6 +20370,126 @@ "react-is": "^16.8.0 || ^17.0.0" } }, + "@mui/base": { + "version": "5.0.0-alpha.73", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.73.tgz", + "integrity": "sha512-TEUCIIEAWrngAqpIa+dY3nofGSNj70LC3KC9WcCzyXPK3M4AG2GNi7ndd/g/0DtC55kbxrudzlV8TG3vrB2Vjw==", + "requires": { + "@babel/runtime": "^7.17.2", + "@emotion/is-prop-valid": "^1.1.2", + "@mui/utils": "^5.4.4", + "@popperjs/core": "^2.11.4", + "clsx": "^1.1.1", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "requires": { + "@emotion/memoize": "^0.7.4" + } + } + } + }, + "@mui/material": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.5.2.tgz", + "integrity": "sha512-r4p1u9eDlSqW3TS/Iq9yolifWHpuW6e0BSeqEJW3EEIcKfPVVk4WNUNJ+s8DtN7dBoDcveXxcQVVjYXTIv1d9g==", + "requires": { + "@babel/runtime": "^7.17.2", + "@mui/base": "5.0.0-alpha.73", + "@mui/system": "^5.5.2", + "@mui/types": "^7.1.3", + "@mui/utils": "^5.4.4", + "@types/react-transition-group": "^4.4.4", + "clsx": "^1.1.1", + "csstype": "^3.0.11", + "hoist-non-react-statics": "^3.3.2", + "prop-types": "^15.7.2", + "react-is": "^17.0.2", + "react-transition-group": "^4.4.2" + } + }, + "@mui/private-theming": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.4.4.tgz", + "integrity": "sha512-V/gxttr6736yJoU9q+4xxXsa0K/w9Hn9pg99zsOHt7i/O904w2CX5NHh5WqDXtoUzVcayLF0RB17yr6l79CE+A==", + "requires": { + "@babel/runtime": "^7.17.2", + "@mui/utils": "^5.4.4", + "prop-types": "^15.7.2" + } + }, + "@mui/styled-engine": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.5.2.tgz", + "integrity": "sha512-jkz5AHHbA43akBo5L3y1X1/X0f+RvXvCp3eXKt+iOf3qnKSAausbtlVz7gBbC4xIWDnP1Jb/6T+t/0/7gObRYA==", + "requires": { + "@babel/runtime": "^7.17.2", + "@emotion/cache": "^11.7.1", + "prop-types": "^15.7.2" + }, + "dependencies": { + "@emotion/cache": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", + "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", + "requires": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + } + } + }, + "@mui/system": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.5.2.tgz", + "integrity": "sha512-OATYFI36nliud8xh0u+ZNqDo0jWjxpO0vZLlzqNB+ZtkR5Q/+1X3GgboA9ruiB8Rq+udnJlMBQNGW0qqjvAOHQ==", + "requires": { + "@babel/runtime": "^7.17.2", + "@mui/private-theming": "^5.4.4", + "@mui/styled-engine": "^5.5.2", + "@mui/types": "^7.1.3", + "@mui/utils": "^5.4.4", + "clsx": "^1.1.1", + "csstype": "^3.0.11", + "prop-types": "^15.7.2" + } + }, + "@mui/types": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.1.3.tgz", + "integrity": "sha512-DDF0UhMBo4Uezlk+6QxrlDbchF79XG6Zs0zIewlR4c0Dt6GKVFfUtzPtHCH1tTbcSlq/L2bGEdiaoHBJ9Y1gSA==", + "requires": {} + }, + "@mui/utils": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.4.4.tgz", + "integrity": "sha512-hfYIXEuhc2mXMGN5nUPis8beH6uE/zl3uMWJcyHX0/LN/+QxO9zhYuV6l8AsAaphHFyS/fBv0SW3Nid7jw5hKQ==", + "requires": { + "@babel/runtime": "^7.17.2", + "@types/prop-types": "^15.7.4", + "@types/react-is": "^16.7.1 || ^17.0.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + } + }, "@node-redis/bloom": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz", @@ -20785,6 +21496,14 @@ "@types/react": "^16" } }, + "@types/react-is": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", + "requires": { + "@types/react": "*" + } + }, "@types/react-redux": { "version": "7.1.23", "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.23.tgz", @@ -22701,9 +23420,9 @@ } }, "csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" }, "damerau-levenshtein": { "version": "1.0.8", @@ -28112,6 +28831,15 @@ "src": "^1.1.2" }, "dependencies": { + "@emotion/styled": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", + "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "requires": { + "@emotion/styled-base": "^10.3.0", + "babel-plugin-emotion": "^10.0.27" + } + }, "@jest/types": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", @@ -29196,6 +29924,11 @@ "postcss-selector-parser": "^6.0.4" } }, + "stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/package.json b/package.json index e8cdc83..065b222 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "0.1.0", "private": true, "dependencies": { + "@emotion/react": "^11.8.2", + "@emotion/styled": "^11.8.1", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", + "@mui/material": "^5.5.2", "@reduxjs/toolkit": "^1.8.0", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", diff --git a/src/components/ParticipantList.tsx b/src/components/ParticipantList.tsx new file mode 100644 index 0000000..8394ef3 --- /dev/null +++ b/src/components/ParticipantList.tsx @@ -0,0 +1,40 @@ +import Participants, { ParticipantType } from './Participants'; +import { Box, List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; +import { ListItemButton } from '@mui/material'; +import { AccountCircle } from '@material-ui/icons'; +import { useState } from 'react'; + + + + +function ParticipantList() { + const [selected, setSelected] = useState([]); + + const handleSelection = ( + event: React.MouseEvent, + index: ParticipantType, + ) => { + setSelected([index, ...selected]); + }; + + return ( + + + + + + + + + + + + + + + ); + +} + + +export default ParticipantList; \ No newline at end of file diff --git a/src/components/Participants.tsx b/src/components/Participants.tsx index 2a09a91..70586d8 100644 --- a/src/components/Participants.tsx +++ b/src/components/Participants.tsx @@ -1,8 +1,8 @@ import React, { useState } from "react" const Participants = () => { - // participantData has key-value pairs in the format participant_name: selected_time_slots - const [participantData, setParticipantData] = useState({}) + const [name, setName] = useState(""); + const [selectedTimeSlots, setSelectedTimeSlots] = useState([]); return (
@@ -11,4 +11,10 @@ const Participants = () => { ) } -export default Participants; \ No newline at end of file +export default Participants; + +export interface ParticipantType { + name: string; + selectedTimeSlots: string[]; + id: number +}; \ No newline at end of file diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index ca68156..d1d39bd 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -4,13 +4,14 @@ import Calendar from '../components/Calendar'; import Participants from '../components/Participants'; import Header from '../components/Header'; +import ParticipantList from '../components/ParticipantList'; function Schedule() { return( <> -
- - + {/*
*/} + {/* */} + ); } diff --git a/yarn.lock b/yarn.lock index 2f9488b..cc30103 100644 --- a/yarn.lock +++ b/yarn.lock @@ -515,7 +515,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.16.7": +"@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.16.7": "integrity" "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==" "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz" "version" "7.16.7" @@ -1024,7 +1024,7 @@ "core-js-pure" "^3.20.2" "regenerator-runtime" "^0.13.4" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.16", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.16", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.17.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": "integrity" "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==" "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz" "version" "7.17.2" @@ -1133,6 +1133,24 @@ dependencies: "postcss-value-parser" "^4.2.0" +"@emotion/babel-plugin@^11.7.1": + "integrity" "sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==" + "resolved" "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz" + "version" "11.7.2" + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + "babel-plugin-macros" "^2.6.1" + "convert-source-map" "^1.5.0" + "escape-string-regexp" "^4.0.0" + "find-root" "^1.1.0" + "source-map" "^0.5.7" + "stylis" "4.0.13" + "@emotion/cache@^10.0.27": "integrity" "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==" "resolved" "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz" @@ -1143,6 +1161,17 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" +"@emotion/cache@^11.7.1": + "integrity" "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==" + "resolved" "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz" + "version" "11.7.1" + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + "stylis" "4.0.13" + "@emotion/core@^10.0.27", "@emotion/core@^10.0.28": "integrity" "sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==" "resolved" "https://registry.npmjs.org/@emotion/core/-/core-10.3.1.tgz" @@ -1176,11 +1205,36 @@ dependencies: "@emotion/memoize" "0.7.4" -"@emotion/memoize@0.7.4": +"@emotion/is-prop-valid@^1.1.2": + "integrity" "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==" + "resolved" "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz" + "version" "1.1.2" + dependencies: + "@emotion/memoize" "^0.7.4" + +"@emotion/memoize@^0.7.4", "@emotion/memoize@0.7.4": "integrity" "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" "version" "0.7.4" +"@emotion/memoize@^0.7.5": + "integrity" "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + "resolved" "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz" + "version" "0.7.5" + +"@emotion/react@^11.0.0-rc.0", "@emotion/react@^11.4.1", "@emotion/react@^11.5.0", "@emotion/react@^11.8.2": + "integrity" "sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA==" + "resolved" "https://registry.npmjs.org/@emotion/react/-/react-11.8.2.tgz" + "version" "11.8.2" + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.7.1" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.1.0" + "@emotion/weak-memoize" "^0.2.5" + "hoist-non-react-statics" "^3.3.1" + "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": "integrity" "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==" "resolved" "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz" @@ -1192,6 +1246,22 @@ "@emotion/utils" "0.11.3" "csstype" "^2.5.7" +"@emotion/serialize@^1.0.2": + "integrity" "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==" + "resolved" "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz" + "version" "1.0.2" + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + "csstype" "^3.0.2" + +"@emotion/sheet@^1.1.0": + "integrity" "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + "resolved" "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz" + "version" "1.1.0" + "@emotion/sheet@0.9.4": "integrity" "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" "resolved" "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz" @@ -1215,22 +1285,38 @@ "@emotion/styled-base" "^10.3.0" "babel-plugin-emotion" "^10.0.27" +"@emotion/styled@^11.3.0", "@emotion/styled@^11.8.1": + "integrity" "sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ==" + "resolved" "https://registry.npmjs.org/@emotion/styled/-/styled-11.8.1.tgz" + "version" "11.8.1" + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/is-prop-valid" "^1.1.2" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.1.0" + "@emotion/stylis@^0.8.4", "@emotion/stylis@0.8.5": "integrity" "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" "resolved" "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz" "version" "0.8.5" -"@emotion/unitless@^0.7.4", "@emotion/unitless@0.7.5": +"@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5", "@emotion/unitless@0.7.5": "integrity" "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" "resolved" "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" "version" "0.7.5" +"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": + "integrity" "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + "resolved" "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz" + "version" "1.1.0" + "@emotion/utils@0.11.3": "integrity" "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" "resolved" "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz" "version" "0.11.3" -"@emotion/weak-memoize@0.2.5": +"@emotion/weak-memoize@^0.2.5", "@emotion/weak-memoize@0.2.5": "integrity" "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" "resolved" "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz" "version" "0.2.5" @@ -1568,6 +1654,85 @@ "prop-types" "^15.7.2" "react-is" "^16.8.0 || ^17.0.0" +"@mui/base@5.0.0-alpha.73": + "integrity" "sha512-TEUCIIEAWrngAqpIa+dY3nofGSNj70LC3KC9WcCzyXPK3M4AG2GNi7ndd/g/0DtC55kbxrudzlV8TG3vrB2Vjw==" + "resolved" "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.73.tgz" + "version" "5.0.0-alpha.73" + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/is-prop-valid" "^1.1.2" + "@mui/utils" "^5.4.4" + "@popperjs/core" "^2.11.4" + "clsx" "^1.1.1" + "prop-types" "^15.7.2" + "react-is" "^17.0.2" + +"@mui/material@^5.5.2": + "integrity" "sha512-r4p1u9eDlSqW3TS/Iq9yolifWHpuW6e0BSeqEJW3EEIcKfPVVk4WNUNJ+s8DtN7dBoDcveXxcQVVjYXTIv1d9g==" + "resolved" "https://registry.npmjs.org/@mui/material/-/material-5.5.2.tgz" + "version" "5.5.2" + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/base" "5.0.0-alpha.73" + "@mui/system" "^5.5.2" + "@mui/types" "^7.1.3" + "@mui/utils" "^5.4.4" + "@types/react-transition-group" "^4.4.4" + "clsx" "^1.1.1" + "csstype" "^3.0.11" + "hoist-non-react-statics" "^3.3.2" + "prop-types" "^15.7.2" + "react-is" "^17.0.2" + "react-transition-group" "^4.4.2" + +"@mui/private-theming@^5.4.4": + "integrity" "sha512-V/gxttr6736yJoU9q+4xxXsa0K/w9Hn9pg99zsOHt7i/O904w2CX5NHh5WqDXtoUzVcayLF0RB17yr6l79CE+A==" + "resolved" "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.4.4.tgz" + "version" "5.4.4" + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/utils" "^5.4.4" + "prop-types" "^15.7.2" + +"@mui/styled-engine@^5.5.2": + "integrity" "sha512-jkz5AHHbA43akBo5L3y1X1/X0f+RvXvCp3eXKt+iOf3qnKSAausbtlVz7gBbC4xIWDnP1Jb/6T+t/0/7gObRYA==" + "resolved" "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.5.2.tgz" + "version" "5.5.2" + dependencies: + "@babel/runtime" "^7.17.2" + "@emotion/cache" "^11.7.1" + "prop-types" "^15.7.2" + +"@mui/system@^5.5.2": + "integrity" "sha512-OATYFI36nliud8xh0u+ZNqDo0jWjxpO0vZLlzqNB+ZtkR5Q/+1X3GgboA9ruiB8Rq+udnJlMBQNGW0qqjvAOHQ==" + "resolved" "https://registry.npmjs.org/@mui/system/-/system-5.5.2.tgz" + "version" "5.5.2" + dependencies: + "@babel/runtime" "^7.17.2" + "@mui/private-theming" "^5.4.4" + "@mui/styled-engine" "^5.5.2" + "@mui/types" "^7.1.3" + "@mui/utils" "^5.4.4" + "clsx" "^1.1.1" + "csstype" "^3.0.11" + "prop-types" "^15.7.2" + +"@mui/types@^7.1.3": + "integrity" "sha512-DDF0UhMBo4Uezlk+6QxrlDbchF79XG6Zs0zIewlR4c0Dt6GKVFfUtzPtHCH1tTbcSlq/L2bGEdiaoHBJ9Y1gSA==" + "resolved" "https://registry.npmjs.org/@mui/types/-/types-7.1.3.tgz" + "version" "7.1.3" + +"@mui/utils@^5.4.4": + "integrity" "sha512-hfYIXEuhc2mXMGN5nUPis8beH6uE/zl3uMWJcyHX0/LN/+QxO9zhYuV6l8AsAaphHFyS/fBv0SW3Nid7jw5hKQ==" + "resolved" "https://registry.npmjs.org/@mui/utils/-/utils-5.4.4.tgz" + "version" "5.4.4" + dependencies: + "@babel/runtime" "^7.17.2" + "@types/prop-types" "^15.7.4" + "@types/react-is" "^16.7.1 || ^17.0.0" + "prop-types" "^15.7.2" + "react-is" "^17.0.2" + "@node-redis/bloom@1.0.1": "integrity" "sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw==" "resolved" "https://registry.npmjs.org/@node-redis/bloom/-/bloom-1.0.1.tgz" @@ -1639,7 +1804,7 @@ "schema-utils" "^3.0.0" "source-map" "^0.7.3" -"@popperjs/core@^2.10.1", "@popperjs/core@^2.10.2": +"@popperjs/core@^2.10.1", "@popperjs/core@^2.10.2", "@popperjs/core@^2.11.4": "integrity" "sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg==" "resolved" "https://registry.npmjs.org/@popperjs/core/-/core-2.11.4.tgz" "version" "2.11.4" @@ -2168,6 +2333,13 @@ dependencies: "@types/react" "^16" +"@types/react-is@^16.7.1 || ^17.0.0": + "integrity" "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==" + "resolved" "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz" + "version" "17.0.3" + dependencies: + "@types/react" "*" + "@types/react-redux@^7.1.20", "@types/react-redux@^7.1.23": "integrity" "sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw==" "resolved" "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.23.tgz" @@ -2940,6 +3112,15 @@ "cosmiconfig" "^6.0.0" "resolve" "^1.12.0" +"babel-plugin-macros@^2.6.1": + "integrity" "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==" + "resolved" "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz" + "version" "2.8.0" + dependencies: + "@babel/runtime" "^7.7.2" + "cosmiconfig" "^6.0.0" + "resolve" "^1.12.0" + "babel-plugin-macros@^3.1.0": "integrity" "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==" "resolved" "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz" @@ -3366,7 +3547,7 @@ "strip-ansi" "^6.0.0" "wrap-ansi" "^7.0.0" -"clsx@^1.0.4": +"clsx@^1.0.4", "clsx@^1.1.1": "integrity" "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" "resolved" "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz" "version" "1.1.1" @@ -3831,10 +4012,10 @@ "resolved" "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz" "version" "2.6.20" -"csstype@^3.0.2": - "integrity" "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" - "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz" - "version" "3.0.10" +"csstype@^3.0.11", "csstype@^3.0.2": + "integrity" "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz" + "version" "3.0.11" "damerau-levenshtein@^1.0.7": "integrity" "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" @@ -5145,7 +5326,7 @@ dependencies: "@babel/runtime" "^7.7.6" -"hoist-non-react-statics@^3.0.0", "hoist-non-react-statics@^3.3.0", "hoist-non-react-statics@^3.3.2": +"hoist-non-react-statics@^3.0.0", "hoist-non-react-statics@^3.3.0", "hoist-non-react-statics@^3.3.1", "hoist-non-react-statics@^3.3.2": "integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==" "resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" "version" "3.3.2" @@ -7900,7 +8081,7 @@ "strip-ansi" "^6.0.1" "text-table" "^0.2.0" -"react-dom@*", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16.14.0", "react-dom@>=16.6.0", "react-dom@>=16.8": +"react-dom@*", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^17.0.0", "react-dom@^17.0.2", "react-dom@>= 16.8.0", "react-dom@>=16.14.0", "react-dom@>=16.6.0", "react-dom@>=16.8": "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==" "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" "version" "17.0.2" @@ -8052,7 +8233,7 @@ "loose-envify" "^1.4.0" "prop-types" "^15.6.2" -"react@*", "react@^16.8.0 || ^17.0.0", "react@^16.8.0 || ^17.0.0-rc.1", "react@^16.8.3 || ^17", "react@^16.9.0 || ^17.0.0 || 18.0.0-beta", "react@^17.0.2", "react@>= 16", "react@>= 16.8.0", "react@>=0.14.0", "react@>=15.0.0", "react@>=16.0", "react@>=16.14.0", "react@>=16.3.0", "react@>=16.6.0", "react@>=16.8", "react@>=16.8.0", "react@17.0.2": +"react@*", "react@^16.8.0 || ^17.0.0", "react@^16.8.0 || ^17.0.0-rc.1", "react@^16.8.3 || ^17", "react@^16.9.0 || ^17.0.0 || 18.0.0-beta", "react@^17.0.0", "react@^17.0.2", "react@>= 16", "react@>= 16.8.0", "react@>=0.14.0", "react@>=15.0.0", "react@>=16.0", "react@>=16.14.0", "react@>=16.3.0", "react@>=16.6.0", "react@>=16.8", "react@>=16.8.0", "react@17.0.2": "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==" "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz" "version" "17.0.2" @@ -8928,6 +9109,11 @@ "browserslist" "^4.16.6" "postcss-selector-parser" "^6.0.4" +"stylis@4.0.13": + "integrity" "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + "resolved" "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" + "version" "4.0.13" + "supports-color@^5.3.0", "supports-color@^5.5.0": "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" From 8d4ce188f811bffa54bfc62a9a1787e5ed2d7272 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sun, 27 Mar 2022 11:19:25 -0400 Subject: [PATCH 02/53] modify typeof Participant --- src/components/Participants.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Participants.tsx b/src/components/Participants.tsx index 70586d8..9ff7fc7 100644 --- a/src/components/Participants.tsx +++ b/src/components/Participants.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react" const Participants = () => { const [name, setName] = useState(""); - const [selectedTimeSlots, setSelectedTimeSlots] = useState([]); + const [timeSlots, setTimeSlots] = useState([]); return (
@@ -14,7 +14,7 @@ const Participants = () => { export default Participants; export interface ParticipantType { - name: string; - selectedTimeSlots: string[]; id: number + name: string; + timeSlots: string[]; }; \ No newline at end of file From d86655e7985a076240f1b4d079339720e620b4c5 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sun, 27 Mar 2022 13:46:11 -0400 Subject: [PATCH 03/53] create TimeSlot interface --- src/components/Participants.tsx | 2 +- src/components/TimeSlot.tsx | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/components/TimeSlot.tsx diff --git a/src/components/Participants.tsx b/src/components/Participants.tsx index 9ff7fc7..7efb6c9 100644 --- a/src/components/Participants.tsx +++ b/src/components/Participants.tsx @@ -14,7 +14,7 @@ const Participants = () => { export default Participants; export interface ParticipantType { - id: number + id: number; name: string; timeSlots: string[]; }; \ No newline at end of file diff --git a/src/components/TimeSlot.tsx b/src/components/TimeSlot.tsx new file mode 100644 index 0000000..ffbe2cf --- /dev/null +++ b/src/components/TimeSlot.tsx @@ -0,0 +1,14 @@ +function TimeSlot() { + +} + + +export interface TimeSlotType { + id: number; + memberId: number; + day: string; + timeStart: string; + timeEnd: string; +} + +export default TimeSlot; \ No newline at end of file From a170249e7f7fda3b0ff05daf96da97ade4268609 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sun, 27 Mar 2022 13:51:18 -0400 Subject: [PATCH 04/53] fix naming inconsistency --- src/components/{Participants.tsx => Member.tsx} | 9 +++++---- src/components/{ParticipantList.tsx => MemberList.tsx} | 10 +++++----- 2 files changed, 10 insertions(+), 9 deletions(-) rename src/components/{Participants.tsx => Member.tsx} (63%) rename src/components/{ParticipantList.tsx => MemberList.tsx} (78%) diff --git a/src/components/Participants.tsx b/src/components/Member.tsx similarity index 63% rename from src/components/Participants.tsx rename to src/components/Member.tsx index 7efb6c9..f3739c0 100644 --- a/src/components/Participants.tsx +++ b/src/components/Member.tsx @@ -1,8 +1,9 @@ import React, { useState } from "react" +import { TimeSlotType } from "./TimeSlot"; -const Participants = () => { +const Member = () => { const [name, setName] = useState(""); - const [timeSlots, setTimeSlots] = useState([]); + const [timeSlots, setTimeSlots] = useState([]); return (
@@ -11,9 +12,9 @@ const Participants = () => { ) } -export default Participants; +export default Member; -export interface ParticipantType { +export interface MemberType { id: number; name: string; timeSlots: string[]; diff --git a/src/components/ParticipantList.tsx b/src/components/MemberList.tsx similarity index 78% rename from src/components/ParticipantList.tsx rename to src/components/MemberList.tsx index 8394ef3..f96d5c3 100644 --- a/src/components/ParticipantList.tsx +++ b/src/components/MemberList.tsx @@ -1,4 +1,4 @@ -import Participants, { ParticipantType } from './Participants'; +import Member, { MemberType } from './Member'; import { Box, List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; import { ListItemButton } from '@mui/material'; import { AccountCircle } from '@material-ui/icons'; @@ -7,12 +7,12 @@ import { useState } from 'react'; -function ParticipantList() { - const [selected, setSelected] = useState([]); +function MemberList() { + const [selected, setSelected] = useState([]); const handleSelection = ( event: React.MouseEvent, - index: ParticipantType, + index: MemberType, ) => { setSelected([index, ...selected]); }; @@ -37,4 +37,4 @@ function ParticipantList() { } -export default ParticipantList; \ No newline at end of file +export default MemberList; \ No newline at end of file From da82365c5bc9bdeac987be93dc0a0d9f70464473 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sun, 27 Mar 2022 14:42:50 -0400 Subject: [PATCH 05/53] select multiple members, record ids to show choice --- src/components/MemberList.tsx | 49 +++++++++++++++++++++-------------- src/pages/Schedule.tsx | 11 +++++--- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index f96d5c3..80db289 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -1,34 +1,45 @@ -import Member, { MemberType } from './Member'; -import { Box, List, ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; -import { ListItemButton } from '@mui/material'; +import Member from './Member'; +import { Box, List, ListItem, ListItemIcon, ListItemText, Checkbox } from '@material-ui/core'; import { AccountCircle } from '@material-ui/icons'; import { useState } from 'react'; +function MemberList({ members }) { + const [selected, setSelected] = useState([]); + console.log(selected); -function MemberList() { - const [selected, setSelected] = useState([]); + const handleSelection = (id: number) => () => { + const current = selected.indexOf(id); + const newSelected = [...selected]; - const handleSelection = ( - event: React.MouseEvent, - index: MemberType, - ) => { - setSelected([index, ...selected]); + if (current === -1) { + newSelected.push(id); + } else { + newSelected.splice(current, 1); + } + setSelected(newSelected); }; return ( - + - - - - - - - - + {members.map((member)=>{ + return ( + + + + + + + + ) + })} diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index d1d39bd..3be4a5e 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -2,16 +2,21 @@ // where users create/edit the schedule import Calendar from '../components/Calendar'; -import Participants from '../components/Participants'; import Header from '../components/Header'; -import ParticipantList from '../components/ParticipantList'; +import MemberList from '../components/MemberList'; function Schedule() { return( <> {/*
*/} {/* */} - + ); } From f597b13504461d340e28f16f8a26a69be4f16baa Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 27 Mar 2022 17:07:31 -0400 Subject: [PATCH 06/53] Store members in Meeting & make naming consistent --- src/app/store.ts | 4 ++-- src/components/CreateMeeting.tsx | 4 ++-- src/components/Header.tsx | 2 +- src/pages/meetingNameSlice.tsx | 27 --------------------------- src/pages/meetingSlice.tsx | 31 +++++++++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 32 deletions(-) delete mode 100644 src/pages/meetingNameSlice.tsx create mode 100644 src/pages/meetingSlice.tsx diff --git a/src/app/store.ts b/src/app/store.ts index 5207999..fa72714 100644 --- a/src/app/store.ts +++ b/src/app/store.ts @@ -1,10 +1,10 @@ import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'; -import meetingNameReducer from '../pages/meetingNameSlice'; +import meetingReducer from '../pages/meetingSlice'; export const store = configureStore({ reducer: { - meetingName: meetingNameReducer + meeting: meetingReducer }, }); diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 5e92ba8..908d54b 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from "react"; import { Grid, FormControl, TextField} from '@material-ui/core' import { useAppDispatch } from '../app/hooks' -import { createMeeting } from "../pages/meetingNameSlice"; +import { createMeeting } from "../pages/meetingSlice"; import { useNavigate } from 'react-router-dom' import '../styles/button.css' import axios from 'axios' @@ -24,7 +24,7 @@ const CreateMeeting = () => { axios.post("http://localhost:4000/api/calendars/", { name }) .then((response)=>{ id = response.data.id; - dispatch(createMeeting({ id, name })); + dispatch(createMeeting({ id, name})); navigate("/create"); }) .catch((error)=>{ diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c8a8322..80837a6 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -5,7 +5,7 @@ import Add from "./Add"; import { useAppSelector } from "../app/hooks"; const Header = ({name}) => { - const meetingName = useAppSelector(state=> state.meetingName.meetingName); + const meetingName = useAppSelector(state=> state.meeting.name); const [Header, setHeader] = useState({meetingName:meetingName, userName:"", selectedTimes: false}); diff --git a/src/pages/meetingNameSlice.tsx b/src/pages/meetingNameSlice.tsx deleted file mode 100644 index 2905ef0..0000000 --- a/src/pages/meetingNameSlice.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import type { RootState } from '../app/store' -interface MeetingNameState { - id: number - meetingName: string -} - -const initialState: MeetingNameState = { - id: NaN, - meetingName: "" -} - -export const meetingNameSlice = createSlice({ - name: "meeting", - initialState, - reducers: { - createMeeting: (state, action: PayloadAction)=>{ - state.id = action.payload["id"]; - state.meetingName = action.payload["name"]; - console.log(state.id, state.meetingName); - } - } -}) - -export const { createMeeting } = meetingNameSlice.actions; -export const selectMeetingName = (state: RootState) => state.meetingName.meetingName -export default meetingNameSlice.reducer diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx new file mode 100644 index 0000000..8710a54 --- /dev/null +++ b/src/pages/meetingSlice.tsx @@ -0,0 +1,31 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import type { RootState } from '../app/store' +import type { MemberType } from '../components/Member' + +interface MeetingState { + id: number + name: string + members: MemberType[] +} + +const initialState: MeetingState = { + id: NaN, + name: "", + members: [] +} + +export const meetingSlice = createSlice({ + name: "meeting", + initialState, + reducers: { + createMeeting: (state, action: PayloadAction)=>{ + state.id = action.payload["id"]; + state.name = action.payload["name"]; + console.log(state.id, state.name); + } + } +}) + +export const { createMeeting } = meetingSlice.actions; +export const selectMeetingName = (state: RootState) => state.meeting.name +export default meetingSlice.reducer From b609be5f0c9a956494c70f41a87fc89df8254045 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sun, 27 Mar 2022 18:19:17 -0400 Subject: [PATCH 07/53] copy url to clipboard on clicking share button --- package-lock.json | 21 +++++++++++++++++++++ package.json | 3 +++ src/components/CreateMeeting.tsx | 10 +++++----- src/components/Header.tsx | 12 +++++++----- src/components/Share.tsx | 14 ++++++++++++-- src/pages/Schedule.tsx | 2 +- yarn.lock | 7 +++++++ 7 files changed, 56 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index ce72e3f..c3d9810 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,9 @@ "styled-components": "^5.3.3", "typescript": "~4.1.5", "uuid": "^8.3.2" + }, + "devDependencies": { + "@types/react-copy-to-clipboard": "^5.0.2" } }, "node_modules/@ampproject/remapping": { @@ -4775,6 +4778,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-copy-to-clipboard": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.2.tgz", + "integrity": "sha512-O29AThfxrkUFRsZXjfSWR2yaWo0ppB1yLEnHA+Oh24oNetjBAwTDu1PmolIqdJKzsZiO4J1jn6R6TmO96uBvGg==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-dom": { "version": "16.9.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.14.tgz", @@ -21488,6 +21500,15 @@ "csstype": "^3.0.2" } }, + "@types/react-copy-to-clipboard": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.2.tgz", + "integrity": "sha512-O29AThfxrkUFRsZXjfSWR2yaWo0ppB1yLEnHA+Oh24oNetjBAwTDu1PmolIqdJKzsZiO4J1jn6R6TmO96uBvGg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-dom": { "version": "16.9.14", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.14.tgz", diff --git a/package.json b/package.json index 065b222..1620747 100644 --- a/package.json +++ b/package.json @@ -52,5 +52,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/react-copy-to-clipboard": "^5.0.2" } } diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 908d54b..eaff9da 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -1,10 +1,10 @@ -import React, { useState, useEffect } from "react"; +import React, { useState } from "react"; import { Grid, FormControl, TextField} from '@material-ui/core' import { useAppDispatch } from '../app/hooks' import { createMeeting } from "../pages/meetingSlice"; -import { useNavigate } from 'react-router-dom' -import '../styles/button.css' -import axios from 'axios' +import { useNavigate } from 'react-router-dom'; +import '../styles/button.css'; +import axios from 'axios'; const styles = { display: "flex", @@ -24,7 +24,7 @@ const CreateMeeting = () => { axios.post("http://localhost:4000/api/calendars/", { name }) .then((response)=>{ id = response.data.id; - dispatch(createMeeting({ id, name})); + dispatch(createMeeting({ id, name })); navigate("/create"); }) .catch((error)=>{ diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 80837a6..64a9414 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -18,11 +18,13 @@ const Header = ({name}) => {

{name}

- -
- {/* if user has already selected time then let them edit*/} - {Header.selectedTimes? : } -
+ + { + //
+ // {/* if user has already selected time then let them edit*/} + // {Header.selectedTimes? : } + //
+ }
diff --git a/src/components/Share.tsx b/src/components/Share.tsx index 0e76640..9841065 100644 --- a/src/components/Share.tsx +++ b/src/components/Share.tsx @@ -1,9 +1,19 @@ -import React from "react" +import React, { useState } from 'react'; const Share = () => { + const [ copied, setCopied ] = useState(false); + return (
- + + {copied ? Link copied. : null}
) } diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index 3be4a5e..739c281 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -8,7 +8,7 @@ import MemberList from '../components/MemberList'; function Schedule() { return( <> - {/*
*/} +
{/* */} Date: Sun, 27 Mar 2022 19:33:31 -0400 Subject: [PATCH 08/53] adding style to memberList --- src/components/Add.tsx | 6 +++++- src/components/CreateMeeting.tsx | 2 +- src/components/Header.tsx | 13 +++++-------- src/components/MemberList.tsx | 8 +++++--- src/styles/button.css | 11 ++++++++--- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 5b4aa70..d4ae0ca 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -3,7 +3,11 @@ import React from "react" const Add = () => { return (
- +
) } diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index eaff9da..a63d2b9 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -56,7 +56,7 @@ const CreateMeeting = () => { diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 64a9414..796ac3f 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -7,8 +7,6 @@ import { useAppSelector } from "../app/hooks"; const Header = ({name}) => { const meetingName = useAppSelector(state=> state.meeting.name); - const [Header, setHeader] = useState({meetingName:meetingName, userName:"", selectedTimes: false}); - return (
@@ -19,12 +17,11 @@ const Header = ({name}) => {

{name}

- { - //
- // {/* if user has already selected time then let them edit*/} - // {Header.selectedTimes? : } - //
- } + +
+ +
+
diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index 80db289..95688a4 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -1,5 +1,5 @@ import Member from './Member'; -import { Box, List, ListItem, ListItemIcon, ListItemText, Checkbox } from '@material-ui/core'; +import { Box, List, ListItem, ListItemIcon, ListItemText, Checkbox, Divider } from '@material-ui/core'; import { AccountCircle } from '@material-ui/icons'; import { useState } from 'react'; @@ -22,16 +22,17 @@ function MemberList({ members }) { }; return ( - + + {members.map((member)=>{ return ( - + ) })} + diff --git a/src/styles/button.css b/src/styles/button.css index 77ea99e..9c23d80 100644 --- a/src/styles/button.css +++ b/src/styles/button.css @@ -18,19 +18,24 @@ body { box-shadow: 0px 2px 3px 2px rgba(0, 0, 0, 0.2); } -.btn--add { +.btn--create { border: 1px solid #fd7473; background-color: #fd7473; } +.btn--add { + border: 1px solid #0aa98a; + background-color: #0aa98a; +} + .btn--edit { border: 1px solid #d29842; background-color: #d29842; } .btn--share { - border: 1px solid #143b63; - background-color: #143b63; + border: 1px solid #52b7d9; + background-color: #52b7d9; } .btn__text { From dc047dc2240a3c7fc088cb99320b607363404592 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 27 Mar 2022 20:30:03 -0400 Subject: [PATCH 09/53] Add unique URL routes for each meeting --- src/App.tsx | 6 ++++-- src/components/CreateMeeting.tsx | 4 ++-- src/pages/Schedule.tsx | 21 ++++++++++++++++++++- src/pages/meetingSlice.tsx | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index dc4149d..e2e01eb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -9,8 +9,10 @@ function App() { <> - } /> - } /> + } /> + }> + + diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 908d54b..1793eea 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -24,8 +24,8 @@ const CreateMeeting = () => { axios.post("http://localhost:4000/api/calendars/", { name }) .then((response)=>{ id = response.data.id; - dispatch(createMeeting({ id, name})); - navigate("/create"); + dispatch(createMeeting({ id, name })); + navigate("/" + id); }) .catch((error)=>{ console.log(error); diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index 3be4a5e..3d7e1c8 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -4,11 +4,30 @@ import Calendar from '../components/Calendar'; import Header from '../components/Header'; import MemberList from '../components/MemberList'; +import { useParams } from 'react-router-dom'; +import axios from 'axios' +import { useState } from 'react'; +import { useEffect } from 'react'; function Schedule() { + let id = useParams().id; + let [name, setName] = useState("") + + useEffect(() => { + axios.get("http://localhost:4000/api/calendars/"+id) + .then(function (response) { + console.log(response.data) + setName(response.data.name) + }) + .catch((error)=>{ + console.log(error); + }); + }, []) + + return( <> - {/*
*/} + {
} {/* */} )=>{ state.id = action.payload["id"]; state.name = action.payload["name"]; - console.log(state.id, state.name); + console.log(`Meeting created with id: ${state.id}, name: ${state.name}`); } } }) From e1bf234dbdefadf9ed50b9946b3f434367f2059b Mon Sep 17 00:00:00 2001 From: Rosa Date: Mon, 28 Mar 2022 12:01:24 -0400 Subject: [PATCH 10/53] style landingPage w/ flexbox, add css file --- src/components/CreateMeeting.tsx | 41 ++++++++++++++------------------ src/styles/landingPage.css | 18 ++++++++++++++ 2 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 src/styles/landingPage.css diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index a63d2b9..c59bd04 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -4,14 +4,9 @@ import { useAppDispatch } from '../app/hooks' import { createMeeting } from "../pages/meetingSlice"; import { useNavigate } from 'react-router-dom'; import '../styles/button.css'; +import '../styles/landingPage.css'; import axios from 'axios'; -const styles = { - display: "flex", - justifyContent: "center", - alignItems: "center", -} - const CreateMeeting = () => { const dispatch = useAppDispatch(); @@ -38,29 +33,29 @@ const CreateMeeting = () => { }; return ( - - - - + <> +
+
+ + + +
+
- +
+
+ + ) } diff --git a/src/styles/landingPage.css b/src/styles/landingPage.css new file mode 100644 index 0000000..4d37dd1 --- /dev/null +++ b/src/styles/landingPage.css @@ -0,0 +1,18 @@ +.flexbox-container { + height: 700px; + width: 100vw; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 30px; +} + +.flexbox-item-1 { + min-width: 80%; +} + +.flexbox-item-2 { + width: 80%; +} + From f04d8e147f78c8a24a82cdd818a74e4aad447547 Mon Sep 17 00:00:00 2001 From: Rosa Date: Mon, 28 Mar 2022 12:02:47 -0400 Subject: [PATCH 11/53] fix merge conflicts --- src/pages/Schedule.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index db3ffb4..3d7e1c8 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -27,11 +27,7 @@ function Schedule() { return( <> -<<<<<<< HEAD {
} -======= -
->>>>>>> edfb3e8cc30f01e1d392b81ee4742c135491a1a8 {/* */} Date: Mon, 28 Mar 2022 13:02:30 -0400 Subject: [PATCH 12/53] styling schedule page w/ grid, add css --- src/components/CreateMeeting.tsx | 2 +- src/components/Header.tsx | 9 +++---- src/pages/Schedule.tsx | 44 ++++++++++++++++++++++++-------- src/styles/button.css | 7 ++++- src/styles/schedule.css | 25 ++++++++++++++++++ 5 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 src/styles/schedule.css diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 2c314ee..6f6e84b 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { Grid, FormControl, TextField} from '@material-ui/core' +import { FormControl, TextField} from '@material-ui/core' import { useAppDispatch } from '../app/hooks' import { createMeeting } from "../pages/meetingSlice"; import { useNavigate } from 'react-router-dom'; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 796ac3f..e2e5de0 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,4 +1,3 @@ -import React, { useState } from "react" import Share from "./Share"; import Edit from "./Edit"; import Add from "./Add"; @@ -9,21 +8,21 @@ const Header = ({name}) => { return (
-
+

{meetingName}

-
+

{name}

-
+
-
+
diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index 3d7e1c8..97d031e 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -8,6 +8,7 @@ import { useParams } from 'react-router-dom'; import axios from 'axios' import { useState } from 'react'; import { useEffect } from 'react'; +import '../styles/schedule.css'; function Schedule() { let id = useParams().id; @@ -26,17 +27,38 @@ function Schedule() { return( - <> - {
} - {/* */} - - + +
+
+
+
+
+ +
+
+ +
+ + +
+ +
+ ); } diff --git a/src/styles/button.css b/src/styles/button.css index 77ea99e..7e4cbb9 100644 --- a/src/styles/button.css +++ b/src/styles/button.css @@ -18,11 +18,16 @@ body { box-shadow: 0px 2px 3px 2px rgba(0, 0, 0, 0.2); } -.btn--add { +.btn--create { border: 1px solid #fd7473; background-color: #fd7473; } +.btn--add { + border: 1px solid #35bbe4; + background-color: #35bbe4; +} + .btn--edit { border: 1px solid #d29842; background-color: #d29842; diff --git a/src/styles/schedule.css b/src/styles/schedule.css new file mode 100644 index 0000000..77d8945 --- /dev/null +++ b/src/styles/schedule.css @@ -0,0 +1,25 @@ +.item-header { + grid-area: header; + grid-column: 1.5 / span 2.5; +} +.item-calendar { + grid-area: calendar; +} +.item-list { + grid-area: list; +} +.item-footer { + grid-area: footer; +} + +.schedule-container { + display: grid; + grid-template-columns: repeat(4, 25%); + grid-template-rows: 2fr 7fr 3fr; + grid-template-areas: + "header header header header" + "calendar calendar calendar list" + "footer footer footer footer"; + column-gap:20px; + row-gap: 20px; +} \ No newline at end of file From 590e6879e138ea44905d08d2aba726610bbcc29a Mon Sep 17 00:00:00 2001 From: Kiron Date: Mon, 28 Mar 2022 21:37:49 -0400 Subject: [PATCH 13/53] Add reducers to update state once meeting is fetched --- src/components/Header.tsx | 4 ++-- src/pages/Schedule.tsx | 12 ++++++++---- src/pages/meetingSlice.tsx | 10 +++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/components/Header.tsx b/src/components/Header.tsx index e2e5de0..23c8742 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -3,7 +3,7 @@ import Edit from "./Edit"; import Add from "./Add"; import { useAppSelector } from "../app/hooks"; -const Header = ({name}) => { +const Header = () => { const meetingName = useAppSelector(state=> state.meeting.name); return ( @@ -13,7 +13,7 @@ const Header = ({name}) => {
-

{name}

+

{}

diff --git a/src/pages/Schedule.tsx b/src/pages/Schedule.tsx index 97d031e..e253d94 100644 --- a/src/pages/Schedule.tsx +++ b/src/pages/Schedule.tsx @@ -9,16 +9,20 @@ import axios from 'axios' import { useState } from 'react'; import { useEffect } from 'react'; import '../styles/schedule.css'; +import { updateMembers, updateName } from './meetingSlice'; +import { useAppDispatch } from '../app/hooks'; function Schedule() { + const dispatch = useAppDispatch(); + // meeting id let id = useParams().id; - let [name, setName] = useState("") useEffect(() => { axios.get("http://localhost:4000/api/calendars/"+id) .then(function (response) { - console.log(response.data) - setName(response.data.name) + console.log(response.data); + dispatch(updateName(response.data.name)); + dispatch(updateMembers(response.data.members)); }) .catch((error)=>{ console.log(error); @@ -30,7 +34,7 @@ function Schedule() {
-
+
diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index e991785..3d7b2f5 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -22,10 +22,18 @@ export const meetingSlice = createSlice({ state.id = action.payload["id"]; state.name = action.payload["name"]; console.log(`Meeting created with id: ${state.id}, name: ${state.name}`); + }, + updateName: (state, action: PayloadAction)=>{ + state.name = action.payload; + console.log(action.payload) + }, + updateMembers: (state, action: PayloadAction)=>{ + state.members = action.payload; } + } }) -export const { createMeeting } = meetingSlice.actions; +export const { createMeeting, updateName, updateMembers } = meetingSlice.actions; export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer From 14e35c5ed51fe923ff86b39841acb8f22d06e968 Mon Sep 17 00:00:00 2001 From: Kiron Date: Mon, 28 Mar 2022 22:31:47 -0400 Subject: [PATCH 14/53] Rename Schedule to Meeting --- src/App.tsx | 4 ++-- src/pages/{Schedule.tsx => Meeting.tsx} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/pages/{Schedule.tsx => Meeting.tsx} (100%) diff --git a/src/App.tsx b/src/App.tsx index e2e01eb..8065499 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import Landing from './pages/Landing'; -import Schedule from './pages/Schedule'; +import Meeting from './pages/Meeting'; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; function App() { @@ -10,7 +10,7 @@ function App() { } /> - }> + }> diff --git a/src/pages/Schedule.tsx b/src/pages/Meeting.tsx similarity index 100% rename from src/pages/Schedule.tsx rename to src/pages/Meeting.tsx From c258542c8e0d99bc9ad6092cbd2031f1e15c9b76 Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 29 Mar 2022 00:25:52 -0400 Subject: [PATCH 15/53] Add reducers to update id and members --- src/pages/Meeting.tsx | 4 ++-- src/pages/meetingSlice.tsx | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index e253d94..c298b34 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -9,9 +9,8 @@ import axios from 'axios' import { useState } from 'react'; import { useEffect } from 'react'; import '../styles/schedule.css'; -import { updateMembers, updateName } from './meetingSlice'; +import { updateId, updateMembers, updateName } from './meetingSlice'; import { useAppDispatch } from '../app/hooks'; - function Schedule() { const dispatch = useAppDispatch(); // meeting id @@ -21,6 +20,7 @@ function Schedule() { axios.get("http://localhost:4000/api/calendars/"+id) .then(function (response) { console.log(response.data); + dispatch(updateId(response.data.id)); dispatch(updateName(response.data.name)); dispatch(updateMembers(response.data.members)); }) diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 3d7b2f5..c8d0bd9 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -23,17 +23,21 @@ export const meetingSlice = createSlice({ state.name = action.payload["name"]; console.log(`Meeting created with id: ${state.id}, name: ${state.name}`); }, + updateId: (state, action: PayloadAction)=>{ + state.id = action.payload; + }, updateName: (state, action: PayloadAction)=>{ state.name = action.payload; - console.log(action.payload) }, updateMembers: (state, action: PayloadAction)=>{ - state.members = action.payload; + state.members = [...action.payload]; + }, + addMember: (state, action: PayloadAction)=>{ + state.members = [action.payload, ...state.members]; } - } }) -export const { createMeeting, updateName, updateMembers } = meetingSlice.actions; +export const { createMeeting, updateId, updateName, updateMembers, addMember } = meetingSlice.actions; export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer From dcaa3565fcb858adf7d86d476f27d9c9c40ba019 Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 29 Mar 2022 00:27:12 -0400 Subject: [PATCH 16/53] Correct MemberType interface --- src/components/Member.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Member.tsx b/src/components/Member.tsx index f3739c0..6d3fd4f 100644 --- a/src/components/Member.tsx +++ b/src/components/Member.tsx @@ -17,5 +17,5 @@ export default Member; export interface MemberType { id: number; name: string; - timeSlots: string[]; + timeSlots: TimeSlotType[]; }; \ No newline at end of file From d0e4ae983469b157486643a0012146e94f65e0b2 Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 29 Mar 2022 00:29:29 -0400 Subject: [PATCH 17/53] Add and store new member --- src/components/Add.tsx | 50 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index d4ae0ca..1782509 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,13 +1,51 @@ import React from "react" +import axios from "axios"; +import { addMember } from "../pages/meetingSlice"; +import { useAppDispatch } from "../app/hooks"; +import { useAppSelector } from "../app/hooks"; +import { useState } from "react"; +import { FormControl, TextField} from '@material-ui/core' const Add = () => { + const dispatch = useAppDispatch(); + const [memberName, setMemberName] = useState(""); + const meetingId = useAppSelector(state => state.meeting.id) + + const updateMemberName = (event) => { + setMemberName(event.target.value); + }; + + const handleSubmit = (event) => { + event.preventDefault(); + console.log(memberName) + console.log(meetingId) + axios.post(`http://localhost:4000//api/calendars/${meetingId}/members/`, { "name": memberName }) + .then((response)=>{ + dispatch(addMember({ id: response.data.id, name: response.data.name, timeSlots: response.data.timeSlots })); + }) + .catch((error)=>{ + console.log(error); + }); + }; + return ( -
- +
+
+ +
+
+ +
) } From c2db3975f9fc06b548c8add67b4a7b79b6565c80 Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 29 Mar 2022 00:47:11 -0400 Subject: [PATCH 18/53] Make MemberList dynamic --- src/components/MemberList.tsx | 5 +++-- src/pages/Meeting.tsx | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index 95688a4..d1ba9cf 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -2,10 +2,11 @@ import Member from './Member'; import { Box, List, ListItem, ListItemIcon, ListItemText, Checkbox, Divider } from '@material-ui/core'; import { AccountCircle } from '@material-ui/icons'; import { useState } from 'react'; +import { useAppSelector } from '../app/hooks'; - -function MemberList({ members }) { +function MemberList() { + const members = useAppSelector(state => state.meeting.members) const [selected, setSelected] = useState([]); console.log(selected); diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index c298b34..5603cde 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -40,7 +40,8 @@ function Schedule() {
- + {/* + ]}/> */}
From 30baadef0f882fa66aa6c554c9ebf459bf32c3bc Mon Sep 17 00:00:00 2001 From: Rosa Date: Sat, 2 Apr 2022 09:38:55 -0400 Subject: [PATCH 19/53] sync changes --- src/components/Add.tsx | 5 +--- src/components/Calendar.tsx | 23 +++++++++--------- src/components/MemberList.tsx | 1 + src/pages/Meeting.tsx | 30 +++++------------------- src/styles/{schedule.css => meeting.css} | 2 +- 5 files changed, 20 insertions(+), 41 deletions(-) rename src/styles/{schedule.css => meeting.css} (95%) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 1782509..14c6c8d 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,10 +1,9 @@ -import React from "react" import axios from "axios"; import { addMember } from "../pages/meetingSlice"; import { useAppDispatch } from "../app/hooks"; import { useAppSelector } from "../app/hooks"; import { useState } from "react"; -import { FormControl, TextField} from '@material-ui/core' +import { TextField } from '@material-ui/core'; const Add = () => { const dispatch = useAppDispatch(); @@ -17,8 +16,6 @@ const Add = () => { const handleSubmit = (event) => { event.preventDefault(); - console.log(memberName) - console.log(meetingId) axios.post(`http://localhost:4000//api/calendars/${meetingId}/members/`, { "name": memberName }) .then((response)=>{ dispatch(addMember({ id: response.data.id, name: response.data.name, timeSlots: response.data.timeSlots })); diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 275e170..032570c 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,23 +1,22 @@ -import React, { useState } from "react" +import { useState } from "react" import ScheduleSelector from 'react-schedule-selector' const Calendar = () => { const [timeSlots, setTimeSlots] = useState([]); - console.log(timeSlots); return (
+ selection={timeSlots} + numDays={7} + minTime={7} + maxTime={20} + // two slots per hour + hourlyChunks={2} + dateFormat = "dddd" + timeFormat = "h:mm" + // pass function that takes in new slots and updates existing state + onChange={setTimeSlots}/>
) diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index d1ba9cf..f22bfb9 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -7,6 +7,7 @@ import { useAppSelector } from '../app/hooks'; function MemberList() { const members = useAppSelector(state => state.meeting.members) + console.log(members); const [selected, setSelected] = useState([]); console.log(selected); diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index 5603cde..f6a3406 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -1,23 +1,21 @@ -// figma second & third pages -// where users create/edit the schedule - import Calendar from '../components/Calendar'; import Header from '../components/Header'; import MemberList from '../components/MemberList'; import { useParams } from 'react-router-dom'; import axios from 'axios' -import { useState } from 'react'; import { useEffect } from 'react'; -import '../styles/schedule.css'; +import '../styles/meeting.css'; import { updateId, updateMembers, updateName } from './meetingSlice'; import { useAppDispatch } from '../app/hooks'; + + function Schedule() { const dispatch = useAppDispatch(); // meeting id let id = useParams().id; useEffect(() => { - axios.get("http://localhost:4000/api/calendars/"+id) + axios.get("http://localhost:4000/api/calendars/" + id) .then(function (response) { console.log(response.data); dispatch(updateId(response.data.id)); @@ -32,7 +30,7 @@ function Schedule() { return( -
+
@@ -40,23 +38,7 @@ function Schedule() {
- - {/* */} +
diff --git a/src/styles/schedule.css b/src/styles/meeting.css similarity index 95% rename from src/styles/schedule.css rename to src/styles/meeting.css index 77d8945..eb0698f 100644 --- a/src/styles/schedule.css +++ b/src/styles/meeting.css @@ -12,7 +12,7 @@ grid-area: footer; } -.schedule-container { +.meeting-container { display: grid; grid-template-columns: repeat(4, 25%); grid-template-rows: 2fr 7fr 3fr; From 55ac9fdb039fad795e450b1d9f24ea9ec0d4a15f Mon Sep 17 00:00:00 2001 From: Rosa Date: Sat, 2 Apr 2022 19:55:39 -0400 Subject: [PATCH 20/53] add & organize API related function for global use --- src/App.tsx | 2 + src/api/api.js | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/api/api.js diff --git a/src/App.tsx b/src/App.tsx index 8065499..8b6f2f6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,8 @@ import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; function App() { + + return ( <> diff --git a/src/api/api.js b/src/api/api.js new file mode 100644 index 0000000..2a2ce9d --- /dev/null +++ b/src/api/api.js @@ -0,0 +1,104 @@ +import axios from "axios"; + +const axiosInstance = axios.create({ + baseURL: "http://localhost:4000", +}); + +async function createMeeting(meetingName) { + try { + const response = await axiosInstance.post(`/api/calendars`, {name: meetingName}); + return response.data; + // { + // "id": integer, + // "name": string, + // "members": [] + // } + } catch(err) { + console.log(err); + } +} + +async function getMeeting(meetingId) { + try{ + const response = await axiosInstance.get(`/api/calendars/${meetingId}`); + return response.data; + // { + // "id": integer, (meetingId) + // "name": string, + // "members": list[Member] + // } + } catch(err){ + console.log(err) + } +} + +async function renameMeeting(meetingId, newName) { + try{ + const response = await axiosInstance.patch(`/api/calendars/${meetingId}`, {name:newName}); + return response.data; + // { + // "id": integer, (meetingId) + // "name": string, + // "members": list[Member] + // } + } catch(err){ + console.log(err) + } +} + +async function addNewMember(meetingId, memberName) { + try { + const response = await axiosInstance.post(`/api/calendars/${meetingId}/members/`, {name: memberName}); + return response.data; + // { + // "id": integer, + // "name": string, + // "timeSlots": [] + // } + } catch(err) { + console.log(err); + } +} + +async function setAvail(meetingId, memberId, timeSlots) { + try { + const response = await axiosInstance.put(`/api/calendars/${meetingId}/members/${memberId}`, { timeSlots }); + return response.data; + // { + // "id": integer + // "name": string + // "timeSlots": list[TimeSlot] + // } + } catch(err) { + console.log(err); + } +} + +async function renameMember(meetingId, memberId, newName) { + try{ + const response = await axiosInstance.patch(`/api/calendars/${meetingId}/members/${memberId}`, {name:newName}); + return response.data; + // { + // "id": integer, + // "name": string, + // "timeSlots": list[TimeSlot] + // } + } catch(err){ + console.log(err) + } +} + + +async function removeMember(meetingId, memberId) { + try{ + await axiosInstance.delete(`/api/calendars/${meetingId}/members/${memberId}`); + } catch(err) { + console.log(err); + } + +} + +export { createMeeting, getMeeting, removeMember, renameMeeting, renameMember, addNewMember, setAvail }; + + +createMeeting("new"); \ No newline at end of file From 30db6302e6795f7aab8ff6cd188d2e9b8fa1b9b3 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sat, 2 Apr 2022 19:58:50 -0400 Subject: [PATCH 21/53] save memberId to store, among others (may delete) --- src/components/Add.tsx | 22 ++++++++---------- src/components/CreateMeeting.tsx | 22 +++++++----------- src/pages/Meeting.tsx | 39 ++++++++++++++++---------------- src/pages/meetingSlice.tsx | 19 ++++++++++++---- 4 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 14c6c8d..a39b399 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,7 +1,6 @@ -import axios from "axios"; -import { addMember } from "../pages/meetingSlice"; -import { useAppDispatch } from "../app/hooks"; -import { useAppSelector } from "../app/hooks"; +import { addMember, setCurMemberId, setCurMemberName } from "../pages/meetingSlice"; +import { useAppDispatch, useAppSelector } from "../app/hooks"; +import * as API from "../api/api"; import { useState } from "react"; import { TextField } from '@material-ui/core'; @@ -14,16 +13,13 @@ const Add = () => { setMemberName(event.target.value); }; - const handleSubmit = (event) => { + const handleSubmit = async (event) => { event.preventDefault(); - axios.post(`http://localhost:4000//api/calendars/${meetingId}/members/`, { "name": memberName }) - .then((response)=>{ - dispatch(addMember({ id: response.data.id, name: response.data.name, timeSlots: response.data.timeSlots })); - }) - .catch((error)=>{ - console.log(error); - }); - }; + const data = await API.addNewMember(meetingId, memberName); + dispatch(setCurMemberId(data.id)); + dispatch(setCurMemberName(data.name)); + dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots })); + }; return (
diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 6f6e84b..8cb70a8 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -5,26 +5,20 @@ import { createMeeting } from "../pages/meetingSlice"; import { useNavigate } from 'react-router-dom'; import '../styles/button.css'; import '../styles/landingPage.css'; -import axios from 'axios'; +import * as API from "../api/api"; const CreateMeeting = () => { const dispatch = useAppDispatch(); const navigate = useNavigate(); - const [name, setName] = useState(""); + const [name, setName] = useState("Unnamed Meeting"); - const handleSubmit = (event) => { + const handleSubmit = async (event) => { event.preventDefault(); - let id: number; - axios.post("http://localhost:4000/api/calendars/", { name }) - .then((response)=>{ - id = response.data.id; - dispatch(createMeeting({ id, name })); - navigate("/" + id); - }) - .catch((error)=>{ - console.log(error); - }); + const data = await API.createMeeting(name); + const id = data.id; + dispatch(createMeeting({ id, name })); + navigate("/" + id); }; // Update name every time user changes text in text field @@ -40,7 +34,7 @@ const CreateMeeting = () => { diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index f6a3406..1c5e518 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -1,31 +1,30 @@ import Calendar from '../components/Calendar'; import Header from '../components/Header'; import MemberList from '../components/MemberList'; -import { useParams } from 'react-router-dom'; -import axios from 'axios' -import { useEffect } from 'react'; +import * as API from "../api/api"; +import { useEffect } from "react"; import '../styles/meeting.css'; -import { updateId, updateMembers, updateName } from './meetingSlice'; -import { useAppDispatch } from '../app/hooks'; +import { updateMeetingId, updateMembers, updateMeetingName } from './meetingSlice'; +import { useAppDispatch, useAppSelector } from '../app/hooks'; -function Schedule() { +function Meeting(props) { const dispatch = useAppDispatch(); - // meeting id - let id = useParams().id; + let meetingId = useAppSelector(state=>state.meeting.id); + useEffect(() => { - axios.get("http://localhost:4000/api/calendars/" + id) - .then(function (response) { - console.log(response.data); - dispatch(updateId(response.data.id)); - dispatch(updateName(response.data.name)); - dispatch(updateMembers(response.data.members)); - }) - .catch((error)=>{ - console.log(error); - }); - }, []) + const loadData = async () =>{ + const data = await API.getMeeting(meetingId); + dispatch(updateMeetingId(data.id)); + dispatch(updateMeetingName(data.name)); + dispatch(updateMembers(data.members)); + } + if (meetingId) { + loadData().catch(err=>console.log(err)); + } + + }, [meetingId, dispatch]); return( @@ -49,4 +48,4 @@ function Schedule() { ); } -export default Schedule; \ No newline at end of file +export default Meeting; \ No newline at end of file diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index c8d0bd9..4dfe829 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -6,12 +6,16 @@ interface MeetingState { id: number name: string members: MemberType[] + curMemberName: string + curMemberId: number } const initialState: MeetingState = { id: NaN, name: "", - members: [] + members: [], + curMemberName: "", + curMemberId: NaN, } export const meetingSlice = createSlice({ @@ -21,12 +25,11 @@ export const meetingSlice = createSlice({ createMeeting: (state, action: PayloadAction)=>{ state.id = action.payload["id"]; state.name = action.payload["name"]; - console.log(`Meeting created with id: ${state.id}, name: ${state.name}`); }, - updateId: (state, action: PayloadAction)=>{ + updateMeetingId: (state, action: PayloadAction)=>{ state.id = action.payload; }, - updateName: (state, action: PayloadAction)=>{ + updateMeetingName: (state, action: PayloadAction)=>{ state.name = action.payload; }, updateMembers: (state, action: PayloadAction)=>{ @@ -34,10 +37,16 @@ export const meetingSlice = createSlice({ }, addMember: (state, action: PayloadAction)=>{ state.members = [action.payload, ...state.members]; + }, + setCurMemberName: (state, action: PayloadAction)=>{ + state.curMemberName = action.payload; + }, + setCurMemberId: (state, action: PayloadAction)=>{ + state.curMemberId = action.payload; } } }) -export const { createMeeting, updateId, updateName, updateMembers, addMember } = meetingSlice.actions; +export const { createMeeting, updateMeetingId, updateMeetingName, updateMembers, addMember, setCurMemberName, setCurMemberId } = meetingSlice.actions; export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer From 7b3544996c4476ea9d20d6c6d018d89cb10a1702 Mon Sep 17 00:00:00 2001 From: Rosa Date: Sat, 2 Apr 2022 20:00:38 -0400 Subject: [PATCH 22/53] calculate, format, & PUT timeslots to backend --- src/components/AddAvail.tsx | 28 ++++++++++++++++++++++++++++ src/components/Calendar.tsx | 23 +++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 src/components/AddAvail.tsx diff --git a/src/components/AddAvail.tsx b/src/components/AddAvail.tsx new file mode 100644 index 0000000..bdf8760 --- /dev/null +++ b/src/components/AddAvail.tsx @@ -0,0 +1,28 @@ +import * as API from "../api/api"; + +async function addAvail(meetingId, memberId, timeSlots) { + + const timeData = timeSlots.map((timeSlot)=>{ + const date = new Date(timeSlot); + const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); + // "Saturday 23:30" + const [day, time] = formattedDate.split(" "); + const [hour, minute] = time.split(":"); + const timeStart = parseInt(hour) * 60 + parseInt(minute); + const timeEnd = timeStart + 30; + const data = { + id : meetingId, + memberId, + day, + timeStart, + timeEnd + }; + return data; + }); + + await API.setAvail(meetingId, memberId, timeData); + console.log("set member availability succeeded"); + +} + +export { addAvail }; \ No newline at end of file diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 032570c..26616d1 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,21 +1,28 @@ -import { useState } from "react" -import ScheduleSelector from 'react-schedule-selector' +import { useEffect, useState } from "react" +import ScheduleSelector from "react-schedule-selector"; +import { addAvail } from "./AddAvail"; +import { useAppSelector } from "../app/hooks"; const Calendar = () => { + const meetingId = useAppSelector(state => state.meeting.id); + const memberId = useAppSelector(state => state.meeting.curMemberId); + const [timeSlots, setTimeSlots] = useState([]); + useEffect(()=>{ + addAvail(meetingId, memberId, timeSlots); + }, [meetingId, memberId, timeSlots]); + return (
From 02888c4c0936ef862656e05b21d7044dd912b5cf Mon Sep 17 00:00:00 2001 From: Rosa Date: Sat, 2 Apr 2022 20:04:48 -0400 Subject: [PATCH 23/53] may use ref and HOC to display diff cell colors --- src/components/Calendar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 26616d1..e7e4e3c 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -16,6 +16,7 @@ const Calendar = () => { return (
Date: Sat, 2 Apr 2022 20:38:33 -0400 Subject: [PATCH 24/53] fix merge conflicts --- package-lock.json | 44 ++++++++++++++++++++++--------------- package.json | 2 +- src/components/Add.tsx | 11 ++++++---- src/components/AddAvail.tsx | 4 ++-- src/components/Calendar.tsx | 6 +++-- src/pages/meetingSlice.tsx | 2 +- 6 files changed, 41 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b291ec..79a42bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "react-schedule-selector": "^3.0.0", "react-scripts": "5.0.0", "sass": "^1.49.9", - "styled-components": "^5.3.3", + "styled-components": "^5.3.5", "typescript": "~4.1.5", "uuid": "^8.3.2" }, @@ -16361,13 +16361,14 @@ } }, "node_modules/styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz", + "integrity": "sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==", + "hasInstallScript": true, "dependencies": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", + "@emotion/is-prop-valid": "^1.1.0", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", "babel-plugin-styled-components": ">= 1.12.0", @@ -16389,6 +16390,14 @@ "react-is": ">= 16.8.0" } }, + "node_modules/styled-components/node_modules/@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "dependencies": { + "@emotion/memoize": "^0.7.4" + } + }, "node_modules/styled-components/node_modules/shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", @@ -22683,7 +22692,6 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, -<<<<<<< HEAD "boostrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/boostrap/-/boostrap-2.0.0.tgz", @@ -22695,8 +22703,6 @@ "integrity": "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q==", "requires": {} }, -======= ->>>>>>> d33b06cdc4352969a07e70b0790904f0794343af "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -22918,7 +22924,6 @@ "wrap-ansi": "^7.0.0" } }, -<<<<<<< HEAD "clsx": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", @@ -22929,8 +22934,6 @@ "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" }, -======= ->>>>>>> d33b06cdc4352969a07e70b0790904f0794343af "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -29028,7 +29031,6 @@ "workbox-webpack-plugin": "^6.4.1" } }, -<<<<<<< HEAD "react-transition-group": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", @@ -29040,8 +29042,6 @@ "prop-types": "^15.6.2" } }, -======= ->>>>>>> d33b06cdc4352969a07e70b0790904f0794343af "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -29922,13 +29922,13 @@ "requires": {} }, "styled-components": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", - "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz", + "integrity": "sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==", "requires": { "@babel/helper-module-imports": "^7.0.0", "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^0.8.8", + "@emotion/is-prop-valid": "^1.1.0", "@emotion/stylis": "^0.8.4", "@emotion/unitless": "^0.7.4", "babel-plugin-styled-components": ">= 1.12.0", @@ -29938,6 +29938,14 @@ "supports-color": "^5.5.0" }, "dependencies": { + "@emotion/is-prop-valid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz", + "integrity": "sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ==", + "requires": { + "@emotion/memoize": "^0.7.4" + } + }, "shallowequal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", diff --git a/package.json b/package.json index 1620747..f4781cf 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "react-schedule-selector": "^3.0.0", "react-scripts": "5.0.0", "sass": "^1.49.9", - "styled-components": "^5.3.3", + "styled-components": "^5.3.5", "typescript": "~4.1.5", "uuid": "^8.3.2" }, diff --git a/src/components/Add.tsx b/src/components/Add.tsx index a39b399..1c03dd2 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -9,11 +9,14 @@ const Add = () => { const [memberName, setMemberName] = useState(""); const meetingId = useAppSelector(state => state.meeting.id) - const updateMemberName = (event) => { - setMemberName(event.target.value); + // the fix ?????? + const updateMemberName = (event: { target: { value: string; }; }) => { + const name = event.target.value; + setMemberName(name); }; - - const handleSubmit = async (event) => { + + // and this ?????? + const handleSubmit = async (event: { preventDefault: () => void; }) => { event.preventDefault(); const data = await API.addNewMember(meetingId, memberName); dispatch(setCurMemberId(data.id)); diff --git a/src/components/AddAvail.tsx b/src/components/AddAvail.tsx index bdf8760..cfe1b2d 100644 --- a/src/components/AddAvail.tsx +++ b/src/components/AddAvail.tsx @@ -1,8 +1,8 @@ import * as API from "../api/api"; -async function addAvail(meetingId, memberId, timeSlots) { +async function addAvail(meetingId: number, memberId: number, timeSlots: Array) { - const timeData = timeSlots.map((timeSlot)=>{ + const timeData = timeSlots.map((timeSlot: string)=>{ const date = new Date(timeSlot); const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); // "Saturday 23:30" diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index e7e4e3c..82a74fc 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,7 +1,9 @@ -import { useEffect, useState } from "react" -import ScheduleSelector from "react-schedule-selector"; +import { useEffect, useState } from "react"; import { addAvail } from "./AddAvail"; import { useAppSelector } from "../app/hooks"; +// @ts-ignore +import ScheduleSelector from "react-schedule-selector"; + const Calendar = () => { const meetingId = useAppSelector(state => state.meeting.id); diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 4dfe829..ec3f8fe 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -22,7 +22,7 @@ export const meetingSlice = createSlice({ name: "meeting", initialState, reducers: { - createMeeting: (state, action: PayloadAction)=>{ + createMeeting: (state, action)=>{ state.id = action.payload["id"]; state.name = action.payload["name"]; }, From f3a32153f7f8a5fc674d1819aa8ce87c2717952d Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 7 Apr 2022 23:00:01 -0400 Subject: [PATCH 25/53] add event type --- src/components/Add.tsx | 18 ++++++++---------- src/pages/Meeting.tsx | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 1c03dd2..a5b853a 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,7 +1,7 @@ import { addMember, setCurMemberId, setCurMemberName } from "../pages/meetingSlice"; import { useAppDispatch, useAppSelector } from "../app/hooks"; import * as API from "../api/api"; -import { useState } from "react"; +import { FormEvent, useState } from "react"; import { TextField } from '@material-ui/core'; const Add = () => { @@ -9,16 +9,14 @@ const Add = () => { const [memberName, setMemberName] = useState(""); const meetingId = useAppSelector(state => state.meeting.id) - // the fix ?????? - const updateMemberName = (event: { target: { value: string; }; }) => { - const name = event.target.value; - setMemberName(name); + const updateMemberName = (event: FormEvent) => { + const element = event.currentTarget as HTMLInputElement; + setMemberName(element.value); }; - // and this ?????? - const handleSubmit = async (event: { preventDefault: () => void; }) => { + const handleSubmit = async (event: MouseEvent) => { event.preventDefault(); - const data = await API.addNewMember(meetingId, memberName); + let data = await API.addNewMember(meetingId, memberName); dispatch(setCurMemberId(data.id)); dispatch(setCurMemberName(data.name)); dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots })); @@ -30,14 +28,14 @@ const Add = () => { updateMemberName} />
diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index 1c5e518..7ee5034 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -8,7 +8,7 @@ import { updateMeetingId, updateMembers, updateMeetingName } from './meetingSlic import { useAppDispatch, useAppSelector } from '../app/hooks'; -function Meeting(props) { +function Meeting() { const dispatch = useAppDispatch(); let meetingId = useAppSelector(state=>state.meeting.id); From a0a159f193cd6ab85f046ecb89f91c06446ea65b Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 7 Apr 2022 23:16:31 -0400 Subject: [PATCH 26/53] fix event type --- src/components/CreateMeeting.tsx | 13 ++-- src/components/Header.tsx | 1 - src/features/counter/Counter.module.css | 79 ---------------------- src/features/counter/Counter.tsx | 68 ------------------- src/features/counter/counterAPI.ts | 6 -- src/features/counter/counterSlice.spec.ts | 34 ---------- src/features/counter/counterSlice.ts | 82 ----------------------- 7 files changed, 7 insertions(+), 276 deletions(-) delete mode 100644 src/features/counter/Counter.module.css delete mode 100644 src/features/counter/Counter.tsx delete mode 100644 src/features/counter/counterAPI.ts delete mode 100644 src/features/counter/counterSlice.spec.ts delete mode 100644 src/features/counter/counterSlice.ts diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 8cb70a8..826be4f 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { FormEvent, useState } from "react"; import { FormControl, TextField} from '@material-ui/core' import { useAppDispatch } from '../app/hooks' import { createMeeting } from "../pages/meetingSlice"; @@ -13,7 +13,7 @@ const CreateMeeting = () => { const navigate = useNavigate(); const [name, setName] = useState("Unnamed Meeting"); - const handleSubmit = async (event) => { + const handleSubmit = async (event: MouseEvent) => { event.preventDefault(); const data = await API.createMeeting(name); const id = data.id; @@ -22,8 +22,9 @@ const CreateMeeting = () => { }; // Update name every time user changes text in text field - const updateName = (event) => { - setName(event.target.value); + const updateName = (event: FormEvent) => { + const element = event.currentTarget as HTMLInputElement; + setName(element.value); }; return ( @@ -35,7 +36,7 @@ const CreateMeeting = () => { placeholder="Name the Meeting:" aria-label="Name the Meeting:" value={name === "Unnamed Meeting" ? "" : name} - onChange={updateName} + onChange={()=>updateName} />
@@ -43,7 +44,7 @@ const CreateMeeting = () => { diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 23c8742..7ca5209 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,5 +1,4 @@ import Share from "./Share"; -import Edit from "./Edit"; import Add from "./Add"; import { useAppSelector } from "../app/hooks"; diff --git a/src/features/counter/Counter.module.css b/src/features/counter/Counter.module.css deleted file mode 100644 index 025bb72..0000000 --- a/src/features/counter/Counter.module.css +++ /dev/null @@ -1,79 +0,0 @@ -.row { - display: flex; - align-items: center; - justify-content: center; -} - -.row > button { - margin-left: 4px; - margin-right: 8px; -} - -.row:not(:last-child) { - margin-bottom: 16px; -} - -.value { - font-size: 78px; - padding-left: 16px; - padding-right: 16px; - margin-top: 2px; - font-family: 'Courier New', Courier, monospace; -} - -.button { - appearance: none; - background: none; - font-size: 32px; - padding-left: 12px; - padding-right: 12px; - outline: none; - border: 2px solid transparent; - color: rgb(112, 76, 182); - padding-bottom: 4px; - cursor: pointer; - background-color: rgba(112, 76, 182, 0.1); - border-radius: 2px; - transition: all 0.15s; -} - -.textbox { - font-size: 32px; - padding: 2px; - width: 64px; - text-align: center; - margin-right: 4px; -} - -.button:hover, -.button:focus { - border: 2px solid rgba(112, 76, 182, 0.4); -} - -.button:active { - background-color: rgba(112, 76, 182, 0.2); -} - -.asyncButton { - composes: button; - position: relative; -} - -.asyncButton:after { - content: ''; - background-color: rgba(112, 76, 182, 0.15); - display: block; - position: absolute; - width: 100%; - height: 100%; - left: 0; - top: 0; - opacity: 0; - transition: width 1s linear, opacity 0.5s ease 1s; -} - -.asyncButton:active:after { - width: 0%; - opacity: 1; - transition: 0s; -} diff --git a/src/features/counter/Counter.tsx b/src/features/counter/Counter.tsx deleted file mode 100644 index ece5191..0000000 --- a/src/features/counter/Counter.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { useState } from 'react'; - -import { useAppSelector, useAppDispatch } from '../../app/hooks'; -import { - decrement, - increment, - incrementByAmount, - incrementAsync, - incrementIfOdd, - selectCount, -} from './counterSlice'; -import styles from './Counter.module.css'; - -export function Counter() { - const count = useAppSelector(selectCount); - const dispatch = useAppDispatch(); - const [incrementAmount, setIncrementAmount] = useState('2'); - - const incrementValue = Number(incrementAmount) || 0; - - return ( -
-
- - {count} - -
-
- setIncrementAmount(e.target.value)} - /> - - - -
-
- ); -} diff --git a/src/features/counter/counterAPI.ts b/src/features/counter/counterAPI.ts deleted file mode 100644 index 0a9cdd3..0000000 --- a/src/features/counter/counterAPI.ts +++ /dev/null @@ -1,6 +0,0 @@ -// A mock function to mimic making an async request for data -export function fetchCount(amount = 1) { - return new Promise<{ data: number }>((resolve) => - setTimeout(() => resolve({ data: amount }), 500) - ); -} diff --git a/src/features/counter/counterSlice.spec.ts b/src/features/counter/counterSlice.spec.ts deleted file mode 100644 index 098163b..0000000 --- a/src/features/counter/counterSlice.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import counterReducer, { - CounterState, - increment, - decrement, - incrementByAmount, -} from './counterSlice'; - -describe('counter reducer', () => { - const initialState: CounterState = { - value: 3, - status: 'idle', - }; - it('should handle initial state', () => { - expect(counterReducer(undefined, { type: 'unknown' })).toEqual({ - value: 0, - status: 'idle', - }); - }); - - it('should handle increment', () => { - const actual = counterReducer(initialState, increment()); - expect(actual.value).toEqual(4); - }); - - it('should handle decrement', () => { - const actual = counterReducer(initialState, decrement()); - expect(actual.value).toEqual(2); - }); - - it('should handle incrementByAmount', () => { - const actual = counterReducer(initialState, incrementByAmount(2)); - expect(actual.value).toEqual(5); - }); -}); diff --git a/src/features/counter/counterSlice.ts b/src/features/counter/counterSlice.ts deleted file mode 100644 index 0010332..0000000 --- a/src/features/counter/counterSlice.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { RootState, AppThunk } from '../../app/store'; -import { fetchCount } from './counterAPI'; - -export interface CounterState { - value: number; - status: 'idle' | 'loading' | 'failed'; -} - -const initialState: CounterState = { - value: 0, - status: 'idle', -}; - -// The function below is called a thunk and allows us to perform async logic. It -// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This -// will call the thunk with the `dispatch` function as the first argument. Async -// code can then be executed and other actions can be dispatched. Thunks are -// typically used to make async requests. -export const incrementAsync = createAsyncThunk( - 'counter/fetchCount', - async (amount: number) => { - const response = await fetchCount(amount); - // The value we return becomes the `fulfilled` action payload - return response.data; - } -); - -export const counterSlice = createSlice({ - name: 'counter', - initialState, - // The `reducers` field lets us define reducers and generate associated actions - reducers: { - increment: (state) => { - // Redux Toolkit allows us to write "mutating" logic in reducers. It - // doesn't actually mutate the state because it uses the Immer library, - // which detects changes to a "draft state" and produces a brand new - // immutable state based off those changes - state.value += 1; - }, - decrement: (state) => { - state.value -= 1; - }, - // Use the PayloadAction type to declare the contents of `action.payload` - incrementByAmount: (state, action: PayloadAction) => { - state.value += action.payload; - }, - }, - // The `extraReducers` field lets the slice handle actions defined elsewhere, - // including actions generated by createAsyncThunk or in other slices. - extraReducers: (builder) => { - builder - .addCase(incrementAsync.pending, (state) => { - state.status = 'loading'; - }) - .addCase(incrementAsync.fulfilled, (state, action) => { - state.status = 'idle'; - state.value += action.payload; - }); - }, -}); - -export const { increment, decrement, incrementByAmount } = counterSlice.actions; - -// The function below is called a selector and allows us to select a value from -// the state. Selectors can also be defined inline where they're used instead of -// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)` -export const selectCount = (state: RootState) => state.counter.value; - -// We can also write thunks by hand, which may contain both sync and async logic. -// Here's an example of conditionally dispatching actions based on current state. -export const incrementIfOdd = (amount: number): AppThunk => ( - dispatch, - getState -) => { - const currentValue = selectCount(getState()); - if (currentValue % 2 === 1) { - dispatch(incrementByAmount(amount)); - } -}; - -export default counterSlice.reducer; From 7d8757564cdb1e21d388f54a15adb3a1076a6a9f Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 7 Apr 2022 23:30:58 -0400 Subject: [PATCH 27/53] add module file for schedule selector --- src/schedule-selector.d.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/schedule-selector.d.ts diff --git a/src/schedule-selector.d.ts b/src/schedule-selector.d.ts new file mode 100644 index 0000000..76c44c9 --- /dev/null +++ b/src/schedule-selector.d.ts @@ -0,0 +1 @@ +declare module 'react-schedule-selector'; \ No newline at end of file From 8d6f7f6dae89d51d174800cd36577ff1ac95e61a Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 12 Apr 2022 14:48:48 -0400 Subject: [PATCH 28/53] fix event type issue --- src/components/Add.tsx | 8 ++++---- src/components/CreateMeeting.tsx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index a5b853a..2b55d37 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -9,12 +9,12 @@ const Add = () => { const [memberName, setMemberName] = useState(""); const meetingId = useAppSelector(state => state.meeting.id) - const updateMemberName = (event: FormEvent) => { + const updateMemberName = (event: any) => { const element = event.currentTarget as HTMLInputElement; setMemberName(element.value); }; - const handleSubmit = async (event: MouseEvent) => { + const handleSubmit = async (event: any) => { event.preventDefault(); let data = await API.addNewMember(meetingId, memberName); dispatch(setCurMemberId(data.id)); @@ -28,14 +28,14 @@ const Add = () => { updateMemberName} + onChange={updateMemberName} />
diff --git a/src/components/CreateMeeting.tsx b/src/components/CreateMeeting.tsx index 826be4f..c7a46ab 100644 --- a/src/components/CreateMeeting.tsx +++ b/src/components/CreateMeeting.tsx @@ -13,7 +13,7 @@ const CreateMeeting = () => { const navigate = useNavigate(); const [name, setName] = useState("Unnamed Meeting"); - const handleSubmit = async (event: MouseEvent) => { + const handleSubmit = async (event: any) => { event.preventDefault(); const data = await API.createMeeting(name); const id = data.id; @@ -22,7 +22,7 @@ const CreateMeeting = () => { }; // Update name every time user changes text in text field - const updateName = (event: FormEvent) => { + const updateName = (event: any) => { const element = event.currentTarget as HTMLInputElement; setName(element.value); }; @@ -36,7 +36,7 @@ const CreateMeeting = () => { placeholder="Name the Meeting:" aria-label="Name the Meeting:" value={name === "Unnamed Meeting" ? "" : name} - onChange={()=>updateName} + onChange={updateName} />
@@ -44,7 +44,7 @@ const CreateMeeting = () => { From b06ec40df4994249eefb9d62137776581b78e8ea Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 12 Apr 2022 14:56:07 -0400 Subject: [PATCH 29/53] fix meeting not fetched if page refreshed --- src/pages/Meeting.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index 7ee5034..fb96c2a 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -6,25 +6,27 @@ import { useEffect } from "react"; import '../styles/meeting.css'; import { updateMeetingId, updateMembers, updateMeetingName } from './meetingSlice'; import { useAppDispatch, useAppSelector } from '../app/hooks'; - +import { useParams } from 'react-router-dom'; function Meeting() { + let {id} = useParams(); const dispatch = useAppDispatch(); let meetingId = useAppSelector(state=>state.meeting.id); useEffect(() => { const loadData = async () =>{ - const data = await API.getMeeting(meetingId); + //const data = await API.getMeeting(meetingId); + const data = await API.getMeeting(id); dispatch(updateMeetingId(data.id)); dispatch(updateMeetingName(data.name)); dispatch(updateMembers(data.members)); } - if (meetingId) { + if (id) { loadData().catch(err=>console.log(err)); } - }, [meetingId, dispatch]); + }, [id, dispatch]); return( From fd8475ba3b29cb7610c3be130f7f74ec3ebea20b Mon Sep 17 00:00:00 2001 From: Kiron Date: Tue, 12 Apr 2022 15:30:19 -0400 Subject: [PATCH 30/53] get id from url and update store meetingId --- src/pages/Meeting.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index fb96c2a..fbbc71d 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -9,24 +9,24 @@ import { useAppDispatch, useAppSelector } from '../app/hooks'; import { useParams } from 'react-router-dom'; function Meeting() { - let {id} = useParams(); + let id = useParams().id as string; const dispatch = useAppDispatch(); + dispatch(updateMeetingId(parseInt(id))) let meetingId = useAppSelector(state=>state.meeting.id); useEffect(() => { const loadData = async () =>{ - //const data = await API.getMeeting(meetingId); - const data = await API.getMeeting(id); + const data = await API.getMeeting(meetingId); dispatch(updateMeetingId(data.id)); dispatch(updateMeetingName(data.name)); dispatch(updateMembers(data.members)); } - if (id) { + if (meetingId) { loadData().catch(err=>console.log(err)); } - }, [id, dispatch]); + }, [meetingId, dispatch]); return( From ab19828c626918d817300908e9edb12d7fbdad05 Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 14 Apr 2022 14:52:35 -0400 Subject: [PATCH 31/53] check whether new or returning member --- src/api/api.js | 3 +-- src/components/Add.tsx | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/api/api.js b/src/api/api.js index 2a2ce9d..698b4c4 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -74,6 +74,7 @@ async function setAvail(meetingId, memberId, timeSlots) { } } +// don't use, member name unique async function renameMember(meetingId, memberId, newName) { try{ const response = await axiosInstance.patch(`/api/calendars/${meetingId}/members/${memberId}`, {name:newName}); @@ -100,5 +101,3 @@ async function removeMember(meetingId, memberId) { export { createMeeting, getMeeting, removeMember, renameMeeting, renameMember, addNewMember, setAvail }; - -createMeeting("new"); \ No newline at end of file diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 2b55d37..27469aa 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,25 +1,40 @@ import { addMember, setCurMemberId, setCurMemberName } from "../pages/meetingSlice"; import { useAppDispatch, useAppSelector } from "../app/hooks"; import * as API from "../api/api"; -import { FormEvent, useState } from "react"; +import { useState } from "react"; import { TextField } from '@material-ui/core'; const Add = () => { const dispatch = useAppDispatch(); const [memberName, setMemberName] = useState(""); - const meetingId = useAppSelector(state => state.meeting.id) + const meetingId = useAppSelector(state => state.meeting.id); + const curMembers = useAppSelector(state => state.meeting.members); - const updateMemberName = (event: any) => { + const addMemberName = (event: any) => { const element = event.currentTarget as HTMLInputElement; setMemberName(element.value); }; const handleSubmit = async (event: any) => { event.preventDefault(); - let data = await API.addNewMember(meetingId, memberName); - dispatch(setCurMemberId(data.id)); - dispatch(setCurMemberName(data.name)); - dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots })); + let isNewMember = true; + curMembers.forEach((member)=>{ + // Pre: member name unique + // returning member, set as current user + if (member.name === memberName) { + dispatch(setCurMemberId(member.id)); + dispatch(setCurMemberName(member.name)); + isNewMember = false; + } + }); + // new member + if (isNewMember){ + let data = await API.addNewMember(meetingId, memberName); + console.log("create new member") + dispatch(setCurMemberId(data.id)); + dispatch(setCurMemberName(data.name)); + dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots })); + } }; return ( @@ -28,7 +43,7 @@ const Add = () => {
From 4504cc8bfb0aae6192d3f04394cf88aafa3a2669 Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 14 Apr 2022 14:53:33 -0400 Subject: [PATCH 32/53] dispatch selected members to show their timeSlots --- src/components/AddAvail.tsx | 43 ++++++++++++++++++----------------- src/components/MemberList.tsx | 9 +++++--- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/components/AddAvail.tsx b/src/components/AddAvail.tsx index cfe1b2d..9bdae39 100644 --- a/src/components/AddAvail.tsx +++ b/src/components/AddAvail.tsx @@ -1,27 +1,28 @@ import * as API from "../api/api"; -async function addAvail(meetingId: number, memberId: number, timeSlots: Array) { - - const timeData = timeSlots.map((timeSlot: string)=>{ - const date = new Date(timeSlot); - const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); - // "Saturday 23:30" - const [day, time] = formattedDate.split(" "); - const [hour, minute] = time.split(":"); - const timeStart = parseInt(hour) * 60 + parseInt(minute); - const timeEnd = timeStart + 30; - const data = { - id : meetingId, - memberId, - day, - timeStart, - timeEnd - }; - return data; - }); - await API.setAvail(meetingId, memberId, timeData); - console.log("set member availability succeeded"); +async function addAvail(meetingId: number, memberId: number, timeSlots: Array) { + + if (meetingId && memberId && timeSlots.length !== 0) { + const timeData = timeSlots.map((date: Date)=>{ + const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); + // "Saturday 23:30" + const [day, time] = formattedDate.split(" "); + const [hour, minute] = time.split(":"); + const timeStart = parseInt(hour) * 60 + parseInt(minute); + const timeEnd = timeStart + 30; + const data = { + id : meetingId, + memberId, + day, + timeStart, + timeEnd + }; + return data; + }); + await API.setAvail(meetingId, memberId, timeData); + console.log("set member availability succeeded"); + } } diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index f22bfb9..6210c46 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -1,12 +1,14 @@ -import Member from './Member'; import { Box, List, ListItem, ListItemIcon, ListItemText, Checkbox, Divider } from '@material-ui/core'; import { AccountCircle } from '@material-ui/icons'; import { useState } from 'react'; -import { useAppSelector } from '../app/hooks'; +import { useAppSelector, useAppDispatch} from '../app/hooks'; +import { selectMembers } from '../pages/meetingSlice'; function MemberList() { - const members = useAppSelector(state => state.meeting.members) + const dispatch = useAppDispatch(); + const members = useAppSelector(state => state.meeting.members); + console.log(members); const [selected, setSelected] = useState([]); console.log(selected); @@ -21,6 +23,7 @@ function MemberList() { newSelected.splice(current, 1); } setSelected(newSelected); + dispatch(selectMembers(newSelected)); }; return ( From 8e7db90f1725ec1936c456671e976d25200f55b1 Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 14 Apr 2022 14:56:19 -0400 Subject: [PATCH 33/53] display red/green/gray for diff cell status --- src/components/Calendar.tsx | 67 ++++++++++++++++++++++++++++++-- src/components/CreateMeeting.tsx | 2 +- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 82a74fc..ff28028 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,24 +1,83 @@ import { useEffect, useState } from "react"; +import { setCurMemberSlots } from "../pages/meetingSlice"; import { addAvail } from "./AddAvail"; -import { useAppSelector } from "../app/hooks"; +import { useAppSelector, useAppDispatch } from "../app/hooks"; // @ts-ignore import ScheduleSelector from "react-schedule-selector"; const Calendar = () => { + const dispatch = useAppDispatch(); const meetingId = useAppSelector(state => state.meeting.id); const memberId = useAppSelector(state => state.meeting.curMemberId); + const members = useAppSelector(state => state.meeting.members); + const curMemberId = useAppSelector(state => state.meeting.curMemberId); + const curMemberSlots = useAppSelector(state => state.meeting.curMemberSlots); + const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); + + + const [timeSlots, setTimeSlots] = useState([]); + console.log(timeSlots); + + + + + + const renderDateCell = (date: Date, selected: boolean, refSetter: (dateCell: HTMLElement | null) => void) => { + const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); + // "Saturday 23:30" + const [day, time] = formattedDate.split(" "); + const [hour, minute] = time.split(":"); + const timeStart = parseInt(hour) * 60 + parseInt(minute); + const timeEnd = timeStart + 30; + + // default cell color, unselected + let backColor = "gray"; + + // red: show avaliabilities of selected members + members.forEach((member)=>{ + if (selectedMembers.includes(member.id)) { + const slots = member.timeSlots; + slots.forEach((slot)=>{ + if (slot.day === day + && slot.timeStart === timeStart + && slot.timeEnd === timeEnd) { + backColor = "red"; + } + }); + } + }); + + + if (selected) { + backColor = "green"; + } + + return ( + + ); + + } - const [timeSlots, setTimeSlots] = useState([]); useEffect(()=>{ + const modified = timeSlots.map(slot => slot.toTimeString()); + dispatch(setCurMemberSlots([...curMemberSlots, ...modified])); addAvail(meetingId, memberId, timeSlots); - }, [meetingId, memberId, timeSlots]); + }, [curMemberSlots, dispatch, meetingId, memberId, timeSlots]); return (
Date: Thu, 14 Apr 2022 14:57:18 -0400 Subject: [PATCH 34/53] add more to state for easy info sharing --- src/components/TimeSlot.tsx | 11 ++--------- src/pages/meetingSlice.tsx | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/components/TimeSlot.tsx b/src/components/TimeSlot.tsx index ffbe2cf..25b2318 100644 --- a/src/components/TimeSlot.tsx +++ b/src/components/TimeSlot.tsx @@ -1,14 +1,7 @@ -function TimeSlot() { - -} - - export interface TimeSlotType { id: number; memberId: number; day: string; - timeStart: string; - timeEnd: string; + timeStart: number; + timeEnd: number; } - -export default TimeSlot; \ No newline at end of file diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index ec3f8fe..98cc1b0 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -7,7 +7,9 @@ interface MeetingState { name: string members: MemberType[] curMemberName: string - curMemberId: number + curMemberId: number, + curMemberSlots: string[], + selectedMembers: number[], } const initialState: MeetingState = { @@ -16,6 +18,8 @@ const initialState: MeetingState = { members: [], curMemberName: "", curMemberId: NaN, + curMemberSlots: [], + selectedMembers: [], } export const meetingSlice = createSlice({ @@ -43,10 +47,25 @@ export const meetingSlice = createSlice({ }, setCurMemberId: (state, action: PayloadAction)=>{ state.curMemberId = action.payload; + }, + setCurMemberSlots: (state, action: PayloadAction)=>{ // date string + state.curMemberSlots = action.payload; + }, + selectMembers: (state, action: PayloadAction )=>{ // for display chosen members' times + state.selectedMembers = action.payload; } } }) -export const { createMeeting, updateMeetingId, updateMeetingName, updateMembers, addMember, setCurMemberName, setCurMemberId } = meetingSlice.actions; +export const { createMeeting, + updateMeetingId, + updateMeetingName, + updateMembers, + addMember, + setCurMemberName, + setCurMemberId, + setCurMemberSlots, + selectMembers } = meetingSlice.actions; + export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer From f63b38829b7b3385a1a45d4cde5abf438655d79e Mon Sep 17 00:00:00 2001 From: Rosa Date: Thu, 14 Apr 2022 15:00:04 -0400 Subject: [PATCH 35/53] fix infinite rendering in Calendar useEffect --- src/components/Calendar.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index ff28028..accfbd8 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -68,11 +68,9 @@ const Calendar = () => { } - useEffect(()=>{ - const modified = timeSlots.map(slot => slot.toTimeString()); - dispatch(setCurMemberSlots([...curMemberSlots, ...modified])); + useEffect(()=>{ addAvail(meetingId, memberId, timeSlots); - }, [curMemberSlots, dispatch, meetingId, memberId, timeSlots]); + }, [meetingId, memberId, timeSlots]); return (
From 97aa67858e5bf2fa69b2c540f488e1593873016c Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 16 Apr 2022 12:28:30 -0400 Subject: [PATCH 36/53] Show different shades based on number of members --- src/components/Calendar.tsx | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index accfbd8..dfa3a73 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -35,6 +35,7 @@ const Calendar = () => { let backColor = "gray"; // red: show avaliabilities of selected members + let membersInSlot = 0; members.forEach((member)=>{ if (selectedMembers.includes(member.id)) { const slots = member.timeSlots; @@ -42,15 +43,32 @@ const Calendar = () => { if (slot.day === day && slot.timeStart === timeStart && slot.timeEnd === timeEnd) { - backColor = "red"; + //backColor = "red"; + membersInSlot++; } }); } }); - - + // if (membersInSlot > 0) { + // console.log("intersections: " + membersInSlot); + // } if (selected) { backColor = "green"; + } else { + // backColor = "#" + (membersInSlot * 34444).toString() + // console.log(backColor) + if (membersInSlot === 1) { + backColor = "#FFFFFF" + } else if (membersInSlot === 2) { + backColor = "#BBBBBB" + } else if (membersInSlot === 3) { + backColor = "#888888" + } else if (membersInSlot === 4) { + backColor = "#555555" + } + else{ + backColor = "darkseagreen" + } } return ( @@ -62,7 +80,7 @@ const Calendar = () => { background: backColor, borderRadius: "3px", }} - > + > {membersInSlot} ); } From b9ee5ea5d3ca06dab0c9dc185c38d231ea461d7f Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 16 Apr 2022 18:54:06 -0400 Subject: [PATCH 37/53] Change slot opacity based on number of members --- src/components/Calendar.tsx | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index dfa3a73..4c7f01f 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -33,7 +33,8 @@ const Calendar = () => { // default cell color, unselected let backColor = "gray"; - + let opacity = 1; + // red: show avaliabilities of selected members let membersInSlot = 0; members.forEach((member)=>{ @@ -49,26 +50,14 @@ const Calendar = () => { }); } }); - // if (membersInSlot > 0) { - // console.log("intersections: " + membersInSlot); - // } + if (selected) { backColor = "green"; } else { - // backColor = "#" + (membersInSlot * 34444).toString() - // console.log(backColor) - if (membersInSlot === 1) { - backColor = "#FFFFFF" - } else if (membersInSlot === 2) { - backColor = "#BBBBBB" - } else if (membersInSlot === 3) { - backColor = "#888888" - } else if (membersInSlot === 4) { - backColor = "#555555" - } - else{ - backColor = "darkseagreen" - } + if (membersInSlot !== 0) { + backColor = "blue" + opacity = membersInSlot/members.length + } } return ( @@ -78,9 +67,10 @@ const Calendar = () => { width: "100%", height: "100%", background: backColor, + opacity: opacity, borderRadius: "3px", }} - > {membersInSlot} + > ); } From b1483b1cf9a25df0db59d3d590372986f6f31082 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 16 Apr 2022 21:34:52 -0400 Subject: [PATCH 38/53] Link copied prompt disappears after a delay --- src/components/Share.tsx | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/Share.tsx b/src/components/Share.tsx index 9841065..8683c04 100644 --- a/src/components/Share.tsx +++ b/src/components/Share.tsx @@ -1,19 +1,27 @@ -import React, { useState } from 'react'; +import { $CombinedState } from '@reduxjs/toolkit'; +import React from 'react'; const Share = () => { - const [ copied, setCopied ] = useState(false); + const handleClick = () => { + navigator.clipboard.writeText(window.location.href); + + let prompt = document.getElementById("1") as HTMLElement + prompt.style.display = ""; + + const hidePrompt = () => { + prompt.style.display = "none" + } + setTimeout(hidePrompt, 1500) + } return (
- {copied ? Link copied. : null} + Link copied.
) } From e2b776b34dced05ce6d6e0613d6cbea9838fb71c Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 01:57:38 -0400 Subject: [PATCH 39/53] Delete member functionality --- src/components/Delete.tsx | 27 +++++++++++++++++++++++++++ src/components/Header.tsx | 4 ++++ src/pages/meetingSlice.tsx | 7 ++++++- src/styles/button.css | 9 +++++++-- 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/components/Delete.tsx diff --git a/src/components/Delete.tsx b/src/components/Delete.tsx new file mode 100644 index 0000000..f010e3b --- /dev/null +++ b/src/components/Delete.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { useAppDispatch, useAppSelector } from '../app/hooks'; +import { removeMember } from '../pages/meetingSlice'; +import * as API from "../api/api"; +const Delete = () => { + const dispatch = useAppDispatch() + const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); + const meetingId = useAppSelector(state => state.meeting.id) + const handleClick = () => { + selectedMembers.forEach((memberId) => { + API.removeMember(meetingId, memberId) + dispatch(removeMember(memberId)) + }) + + } + return ( +
+ +
+ ) +} + +export default Delete; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 7ca5209..0a6e650 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,5 +1,6 @@ import Share from "./Share"; import Add from "./Add"; +import Delete from "./Delete"; import { useAppSelector } from "../app/hooks"; const Header = () => { @@ -20,6 +21,9 @@ const Header = () => {
+
+ +
diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 98cc1b0..0f6233a 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -42,6 +42,9 @@ export const meetingSlice = createSlice({ addMember: (state, action: PayloadAction)=>{ state.members = [action.payload, ...state.members]; }, + removeMember: (state, action: PayloadAction)=>{ + state.members = [...state.members.filter(member => member.id !== action.payload)]; + }, setCurMemberName: (state, action: PayloadAction)=>{ state.curMemberName = action.payload; }, @@ -51,6 +54,7 @@ export const meetingSlice = createSlice({ setCurMemberSlots: (state, action: PayloadAction)=>{ // date string state.curMemberSlots = action.payload; }, + // store member id's selectMembers: (state, action: PayloadAction )=>{ // for display chosen members' times state.selectedMembers = action.payload; } @@ -61,7 +65,8 @@ export const { createMeeting, updateMeetingId, updateMeetingName, updateMembers, - addMember, + addMember, + removeMember, setCurMemberName, setCurMemberId, setCurMemberSlots, diff --git a/src/styles/button.css b/src/styles/button.css index 7e4cbb9..98d5e12 100644 --- a/src/styles/button.css +++ b/src/styles/button.css @@ -24,8 +24,13 @@ body { } .btn--add { - border: 1px solid #35bbe4; - background-color: #35bbe4; + border: 1px solid #35e46f; + background-color: #35e46f; +} + +.btn--delete { + border: 1px solid #e43535; + background-color: #e43535; } .btn--edit { From e44e2981435129419a6f64715f8b485996bbeb3b Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 02:16:50 -0400 Subject: [PATCH 40/53] Validation for blank member name --- src/components/Add.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 27469aa..c0e8da2 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -17,11 +17,16 @@ const Add = () => { const handleSubmit = async (event: any) => { event.preventDefault(); + // treat "A" the same as "A " + const trimmedName = memberName.trim() + if (trimmedName === "") { + alert("Name can't be blank!") + } let isNewMember = true; curMembers.forEach((member)=>{ // Pre: member name unique // returning member, set as current user - if (member.name === memberName) { + if (member.name === trimmedName) { dispatch(setCurMemberId(member.id)); dispatch(setCurMemberName(member.name)); isNewMember = false; @@ -29,7 +34,7 @@ const Add = () => { }); // new member if (isNewMember){ - let data = await API.addNewMember(meetingId, memberName); + let data = await API.addNewMember(meetingId, trimmedName); console.log("create new member") dispatch(setCurMemberId(data.id)); dispatch(setCurMemberName(data.name)); From f75552df69df8166ada51cd9bfd429b1fbb4964b Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 02:45:32 -0400 Subject: [PATCH 41/53] Delete button validation --- src/components/Delete.tsx | 12 ++++++++---- src/pages/meetingSlice.tsx | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/Delete.tsx b/src/components/Delete.tsx index f010e3b..c15f004 100644 --- a/src/components/Delete.tsx +++ b/src/components/Delete.tsx @@ -3,13 +3,17 @@ import { useAppDispatch, useAppSelector } from '../app/hooks'; import { removeMember } from '../pages/meetingSlice'; import * as API from "../api/api"; const Delete = () => { - const dispatch = useAppDispatch() + const dispatch = useAppDispatch(); const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); - const meetingId = useAppSelector(state => state.meeting.id) + const meetingId = useAppSelector(state => state.meeting.id); const handleClick = () => { + if (selectedMembers.length === 0) { + alert("No members selected!"); + return; + } selectedMembers.forEach((memberId) => { - API.removeMember(meetingId, memberId) - dispatch(removeMember(memberId)) + API.removeMember(meetingId, memberId); + dispatch(removeMember(memberId)); }) } diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 0f6233a..3060279 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -44,6 +44,7 @@ export const meetingSlice = createSlice({ }, removeMember: (state, action: PayloadAction)=>{ state.members = [...state.members.filter(member => member.id !== action.payload)]; + state.selectedMembers = [...state.selectedMembers.filter(memberId => memberId !== action.payload)] }, setCurMemberName: (state, action: PayloadAction)=>{ state.curMemberName = action.payload; From 1d5527af0952e2b0bfd62d1dda36686314e1ffb0 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 02:46:06 -0400 Subject: [PATCH 42/53] Enhance meeting name styling --- src/components/Header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 0a6e650..abb7143 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -9,7 +9,7 @@ const Header = () => { return (
-

{meetingName}

+

{meetingName}

From 78fdd194c75c605d11c0fff09bef70c2be65bb3c Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 02:46:36 -0400 Subject: [PATCH 43/53] Stop execution if blank name --- src/components/Add.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index c0e8da2..b154daa 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -20,7 +20,8 @@ const Add = () => { // treat "A" the same as "A " const trimmedName = memberName.trim() if (trimmedName === "") { - alert("Name can't be blank!") + alert("Name can't be blank!"); + return; } let isNewMember = true; curMembers.forEach((member)=>{ From 765f8119cf617765e0d32174aa3a4ca42e8c1db1 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 12:04:52 -0400 Subject: [PATCH 44/53] Show members in slot on hover --- src/components/Available.tsx | 13 +++++++++++++ src/components/Calendar.tsx | 21 +++++++++++---------- src/components/Header.tsx | 5 +++-- src/components/Share.tsx | 1 - src/pages/meetingSlice.tsx | 10 ++++++++-- 5 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 src/components/Available.tsx diff --git a/src/components/Available.tsx b/src/components/Available.tsx new file mode 100644 index 0000000..8ca94f1 --- /dev/null +++ b/src/components/Available.tsx @@ -0,0 +1,13 @@ +import React from 'react'; +import { useAppSelector } from '../app/hooks'; +const Available = () => { + const members = useAppSelector(state => state.meeting.hoveredMembers) + + return ( +
+ Available members: {members.join(", ")} +
+ ) +} + +export default Available; \ No newline at end of file diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 4c7f01f..78e7c8f 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { setCurMemberSlots } from "../pages/meetingSlice"; +import { updateHoveredMembers } from "../pages/meetingSlice"; import { addAvail } from "./AddAvail"; import { useAppSelector, useAppDispatch } from "../app/hooks"; // @ts-ignore @@ -19,9 +19,6 @@ const Calendar = () => { const [timeSlots, setTimeSlots] = useState([]); console.log(timeSlots); - - - const renderDateCell = (date: Date, selected: boolean, refSetter: (dateCell: HTMLElement | null) => void) => { const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); @@ -35,8 +32,8 @@ const Calendar = () => { let backColor = "gray"; let opacity = 1; - // red: show avaliabilities of selected members - let membersInSlot = 0; + let membersInSlot = [] as string[]; + let numMembersInSlot = 0; members.forEach((member)=>{ if (selectedMembers.includes(member.id)) { const slots = member.timeSlots; @@ -44,8 +41,8 @@ const Calendar = () => { if (slot.day === day && slot.timeStart === timeStart && slot.timeEnd === timeEnd) { - //backColor = "red"; - membersInSlot++; + numMembersInSlot++; + membersInSlot.push(member.name); } }); } @@ -54,9 +51,9 @@ const Calendar = () => { if (selected) { backColor = "green"; } else { - if (membersInSlot !== 0) { + if (numMembersInSlot !== 0) { backColor = "blue" - opacity = membersInSlot/members.length + opacity = numMembersInSlot/members.length } } @@ -70,6 +67,10 @@ const Calendar = () => { opacity: opacity, borderRadius: "3px", }} + onMouseOver = { () => { + dispatch(updateHoveredMembers(membersInSlot)) + } + } > ); diff --git a/src/components/Header.tsx b/src/components/Header.tsx index abb7143..53d4fb9 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,6 +1,7 @@ import Share from "./Share"; import Add from "./Add"; import Delete from "./Delete"; +import Available from "./Available"; import { useAppSelector } from "../app/hooks"; const Header = () => { @@ -9,11 +10,11 @@ const Header = () => { return (
-

{meetingName}

+

{meetingName}

-

{}

+
diff --git a/src/components/Share.tsx b/src/components/Share.tsx index 8683c04..02aaab7 100644 --- a/src/components/Share.tsx +++ b/src/components/Share.tsx @@ -1,4 +1,3 @@ -import { $CombinedState } from '@reduxjs/toolkit'; import React from 'react'; const Share = () => { diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 3060279..717396d 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -10,6 +10,7 @@ interface MeetingState { curMemberId: number, curMemberSlots: string[], selectedMembers: number[], + hoveredMembers: string[] } const initialState: MeetingState = { @@ -20,6 +21,7 @@ const initialState: MeetingState = { curMemberId: NaN, curMemberSlots: [], selectedMembers: [], + hoveredMembers: [] } export const meetingSlice = createSlice({ @@ -58,7 +60,10 @@ export const meetingSlice = createSlice({ // store member id's selectMembers: (state, action: PayloadAction )=>{ // for display chosen members' times state.selectedMembers = action.payload; - } + }, + updateHoveredMembers: (state, action: PayloadAction)=>{ + state.hoveredMembers = [...action.payload]; + }, } }) @@ -71,7 +76,8 @@ export const { createMeeting, setCurMemberName, setCurMemberId, setCurMemberSlots, - selectMembers } = meetingSlice.actions; + selectMembers, +updateHoveredMembers } = meetingSlice.actions; export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer From cbe211d882a92bf6bbcaa34e3ad33013c500e8bc Mon Sep 17 00:00:00 2001 From: Kiron Date: Sat, 23 Apr 2022 12:32:03 -0400 Subject: [PATCH 45/53] Add select all members button --- src/components/MemberList.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index 6210c46..f371521 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -26,10 +26,26 @@ function MemberList() { dispatch(selectMembers(newSelected)); }; + const handleClick = () => { + const allSelected = members.map(member => member.id) + setSelected(allSelected) + dispatch(selectMembers(allSelected)) + } + return ( - +
+
+ +
+
+ +
+
+ {members.map((member)=>{ return ( From 7e2514a757a1330a5756611be70a9cb2eb18f401 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 24 Apr 2022 02:01:41 -0400 Subject: [PATCH 46/53] Add edit functionality and further validation --- src/api/dateFormateConverter.ts | 44 ++++++++++++++++++++++++ src/components/Add.tsx | 8 ++++- src/components/Available.tsx | 2 +- src/components/Calendar.tsx | 59 +++++++++++++++++++++++++++------ src/components/Confirm.tsx | 30 +++++++++++++++++ src/components/Header.tsx | 7 ++-- src/components/MemberList.tsx | 2 -- src/pages/Meeting.tsx | 4 +-- src/pages/meetingSlice.tsx | 18 +++++++--- src/styles/button.css | 5 +++ 10 files changed, 156 insertions(+), 23 deletions(-) create mode 100644 src/api/dateFormateConverter.ts create mode 100644 src/components/Confirm.tsx diff --git a/src/api/dateFormateConverter.ts b/src/api/dateFormateConverter.ts new file mode 100644 index 0000000..3f07da6 --- /dev/null +++ b/src/api/dateFormateConverter.ts @@ -0,0 +1,44 @@ +import { TimeSlotType } from "../components/TimeSlot" + +export function convertTStoDate(slots: TimeSlotType[]){ + const dayMap : any = {"Sunday":0, "Monday":1, "Tuesday":2, "Wednesday":3, "Thursday":4, "Friday":5, "Saturday":6} as Object + const present = new Date(); + const currYear = present.getFullYear(); + let currDayOfMonth = present.getDate(); + let currWeekday = present.getDay(); + const currMonth = present.getMonth() + let converted = [] as Date[] + // need to extract hours from no of mins + slots.forEach(slot => { + let daysToAdd; + let slotDay = dayMap[slot.day] as number + daysToAdd = slotDay - currWeekday + // 1410 becomes 23.5 + let hourFloat = slot.timeStart/60 + let hour = Math.floor(hourFloat) + let minutes = 60 * (hourFloat % 1) // 30 or 0 + converted.push(new Date(currYear, currMonth, currDayOfMonth + daysToAdd, hour, minutes)) + }); + return converted +} + +export function convertDatetoTS(dates: Date[], meetingId:number, memberId:number ) { + const timeData = dates.map((date: Date)=>{ + const formattedDate = new Intl.DateTimeFormat('en-GB', { weekday: 'long', hour: 'numeric', minute: 'numeric' }).format(date); + // "Saturday 23:30" + const [day, time] = formattedDate.split(" "); + const [hour, minute] = time.split(":"); + const timeStart = parseInt(hour) * 60 + parseInt(minute); + const timeEnd = timeStart + 30; + const data = { + id : meetingId, + memberId, + day, + timeStart, + timeEnd + }; + return data; + }); + return timeData +} + diff --git a/src/components/Add.tsx b/src/components/Add.tsx index b154daa..116c968 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,4 +1,4 @@ -import { addMember, setCurMemberId, setCurMemberName } from "../pages/meetingSlice"; +import { addMember, selectMembers, setCurMemberId, setCurMemberName } from "../pages/meetingSlice"; import { useAppDispatch, useAppSelector } from "../app/hooks"; import * as API from "../api/api"; import { useState } from "react"; @@ -9,6 +9,8 @@ const Add = () => { const [memberName, setMemberName] = useState(""); const meetingId = useAppSelector(state => state.meeting.id); const curMembers = useAppSelector(state => state.meeting.members); + const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); + const addMemberName = (event: any) => { const element = event.currentTarget as HTMLInputElement; @@ -23,6 +25,10 @@ const Add = () => { alert("Name can't be blank!"); return; } + if (selectedMembers.length !== 0) { + alert("Unselect all members to add new availability!") + return; + } let isNewMember = true; curMembers.forEach((member)=>{ // Pre: member name unique diff --git a/src/components/Available.tsx b/src/components/Available.tsx index 8ca94f1..c37984d 100644 --- a/src/components/Available.tsx +++ b/src/components/Available.tsx @@ -4,7 +4,7 @@ const Available = () => { const members = useAppSelector(state => state.meeting.hoveredMembers) return ( -
+
Available members: {members.join(", ")}
) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 78e7c8f..ebec121 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -1,23 +1,58 @@ import { useEffect, useState } from "react"; -import { updateHoveredMembers } from "../pages/meetingSlice"; +import { setCurMemberId, setCurMemberSlots, updateHoveredMembers } from "../pages/meetingSlice"; import { addAvail } from "./AddAvail"; import { useAppSelector, useAppDispatch } from "../app/hooks"; // @ts-ignore import ScheduleSelector from "react-schedule-selector"; - +import { convertTStoDate, convertDatetoTS } from "../api/dateFormateConverter"; +import { updateChangedAlready } from "../pages/meetingSlice"; const Calendar = () => { const dispatch = useAppDispatch(); const meetingId = useAppSelector(state => state.meeting.id); const memberId = useAppSelector(state => state.meeting.curMemberId); const members = useAppSelector(state => state.meeting.members); - const curMemberId = useAppSelector(state => state.meeting.curMemberId); const curMemberSlots = useAppSelector(state => state.meeting.curMemberSlots); const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); - + const changedAlready = useAppSelector(state => state.meeting.changedAlready); const [timeSlots, setTimeSlots] = useState([]); - console.log(timeSlots); + + const handleChange = (event:any) => { + console.log(changedAlready) + // don't change time slots if we already fetched them + if (changedAlready === true) { + // if (selectedMembers.length === 0) { + // setTimeSlots([]) + // return; + // } + setTimeSlots(event) + dispatch(setCurMemberId(selectedMembers[0])) + dispatch(setCurMemberSlots(convertDatetoTS(timeSlots, meetingId, selectedMembers[0]))) + } + } + + if (selectedMembers.length === 1 && changedAlready === false) { + for (let i = 0; i < members.length; i++) { + if (members[i].id === selectedMembers[0]) { + let convertedDates = convertTStoDate(members[i].timeSlots) + dispatch(updateChangedAlready(true)) + setTimeSlots(convertedDates) + console.log("BEEP") + console.log(members[i].timeSlots) + console.log(convertedDates) + break; + } + } + } else if (selectedMembers.length === 0 && changedAlready === false) { + dispatch(updateChangedAlready(true)) + setTimeSlots([]) + } + + if (selectedMembers.length > 1) { + dispatch(updateChangedAlready(false)) + } + const renderDateCell = (date: Date, selected: boolean, refSetter: (dateCell: HTMLElement | null) => void) => { @@ -34,6 +69,7 @@ const Calendar = () => { let membersInSlot = [] as string[]; let numMembersInSlot = 0; + members.forEach((member)=>{ if (selectedMembers.includes(member.id)) { const slots = member.timeSlots; @@ -47,10 +83,13 @@ const Calendar = () => { }); } }); - - if (selected) { - backColor = "green"; - } else { + + if (selectedMembers.length <= 1) { + if (selected) { + backColor = "green" + } + } + else { if (numMembersInSlot !== 0) { backColor = "blue" opacity = numMembersInSlot/members.length @@ -92,7 +131,7 @@ const Calendar = () => { hourlyChunks={2} dateFormat = "ddd" timeFormat = "h:mm A" - onChange={setTimeSlots}/> + onChange={handleChange}/>
) diff --git a/src/components/Confirm.tsx b/src/components/Confirm.tsx new file mode 100644 index 0000000..8949d0f --- /dev/null +++ b/src/components/Confirm.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import * as API from "../api/api"; +import { useAppSelector } from '../app/hooks'; + +const Confirm = () => { + const meetingId = useAppSelector(state => state.meeting.id); + const memberId = useAppSelector(state => state.meeting.curMemberId); + const curMemberSlots = useAppSelector(state => state.meeting.curMemberSlots); + const selectedMembers = useAppSelector(state => state.meeting.selectedMembers) + + const handleClick = () => { + if (selectedMembers.length !== 1) { + alert("Select one member to update their availability!"); + return; + } + API.setAvail(meetingId, memberId, curMemberSlots) + } + return ( +
+ + +
+ ) +} + +export default Confirm; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 53d4fb9..6d98d36 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,7 +1,7 @@ import Share from "./Share"; import Add from "./Add"; import Delete from "./Delete"; -import Available from "./Available"; +import Confirm from "./Confirm"; import { useAppSelector } from "../app/hooks"; const Header = () => { @@ -14,7 +14,6 @@ const Header = () => {
-
@@ -26,6 +25,10 @@ const Header = () => {
+
+ +
+
diff --git a/src/components/MemberList.tsx b/src/components/MemberList.tsx index f371521..3292356 100644 --- a/src/components/MemberList.tsx +++ b/src/components/MemberList.tsx @@ -9,9 +9,7 @@ function MemberList() { const dispatch = useAppDispatch(); const members = useAppSelector(state => state.meeting.members); - console.log(members); const [selected, setSelected] = useState([]); - console.log(selected); const handleSelection = (id: number) => () => { const current = selected.indexOf(id); diff --git a/src/pages/Meeting.tsx b/src/pages/Meeting.tsx index fbbc71d..5813a1c 100644 --- a/src/pages/Meeting.tsx +++ b/src/pages/Meeting.tsx @@ -1,6 +1,7 @@ import Calendar from '../components/Calendar'; import Header from '../components/Header'; import MemberList from '../components/MemberList'; +import Available from "../components/Available"; import * as API from "../api/api"; import { useEffect } from "react"; import '../styles/meeting.css'; @@ -42,9 +43,8 @@ function Meeting() {
-
- +
); diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 717396d..2ecc547 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -1,6 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import type { RootState } from '../app/store' import type { MemberType } from '../components/Member' +import { TimeSlotType } from '../components/TimeSlot' interface MeetingState { id: number @@ -8,9 +9,10 @@ interface MeetingState { members: MemberType[] curMemberName: string curMemberId: number, - curMemberSlots: string[], + curMemberSlots: TimeSlotType[], selectedMembers: number[], - hoveredMembers: string[] + hoveredMembers: string[], + changedAlready: boolean } const initialState: MeetingState = { @@ -21,7 +23,8 @@ const initialState: MeetingState = { curMemberId: NaN, curMemberSlots: [], selectedMembers: [], - hoveredMembers: [] + hoveredMembers: [], + changedAlready: false } export const meetingSlice = createSlice({ @@ -54,7 +57,8 @@ export const meetingSlice = createSlice({ setCurMemberId: (state, action: PayloadAction)=>{ state.curMemberId = action.payload; }, - setCurMemberSlots: (state, action: PayloadAction)=>{ // date string + setCurMemberSlots: (state, action: PayloadAction)=>{ // date string + console.log(action.payload) state.curMemberSlots = action.payload; }, // store member id's @@ -64,6 +68,9 @@ export const meetingSlice = createSlice({ updateHoveredMembers: (state, action: PayloadAction)=>{ state.hoveredMembers = [...action.payload]; }, + updateChangedAlready: (state, action: PayloadAction)=>{ + state.changedAlready = action.payload; + }, } }) @@ -77,7 +84,8 @@ export const { createMeeting, setCurMemberId, setCurMemberSlots, selectMembers, -updateHoveredMembers } = meetingSlice.actions; +updateHoveredMembers, +updateChangedAlready } = meetingSlice.actions; export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer diff --git a/src/styles/button.css b/src/styles/button.css index 98d5e12..0ea9ae8 100644 --- a/src/styles/button.css +++ b/src/styles/button.css @@ -33,6 +33,11 @@ body { background-color: #e43535; } +.btn--confirm { + border: 1px solid #e4d235; + background-color: #e4d235; +} + .btn--edit { border: 1px solid #d29842; background-color: #d29842; From 10e1a108fa90623eee237d66bfc0b14de1c00723 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 24 Apr 2022 02:22:33 -0400 Subject: [PATCH 47/53] Fix bug so times get updated correctly --- src/components/Calendar.tsx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index ebec121..c0a1731 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -22,10 +22,7 @@ const Calendar = () => { console.log(changedAlready) // don't change time slots if we already fetched them if (changedAlready === true) { - // if (selectedMembers.length === 0) { - // setTimeSlots([]) - // return; - // } + setTimeSlots(event) dispatch(setCurMemberId(selectedMembers[0])) dispatch(setCurMemberSlots(convertDatetoTS(timeSlots, meetingId, selectedMembers[0]))) @@ -44,12 +41,9 @@ const Calendar = () => { break; } } - } else if (selectedMembers.length === 0 && changedAlready === false) { - dispatch(updateChangedAlready(true)) - setTimeSlots([]) - } + } - if (selectedMembers.length > 1) { + if (selectedMembers.length !== 1) { dispatch(updateChangedAlready(false)) } From c267a62c6c8d9924c1a9067bc84ae9c6ebbd9f81 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 24 Apr 2022 13:42:06 -0400 Subject: [PATCH 48/53] guard against duplicate names --- src/components/Add.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 116c968..f9641ee 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -8,7 +8,7 @@ const Add = () => { const dispatch = useAppDispatch(); const [memberName, setMemberName] = useState(""); const meetingId = useAppSelector(state => state.meeting.id); - const curMembers = useAppSelector(state => state.meeting.members); + const members = useAppSelector(state => state.meeting.members); const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); @@ -29,8 +29,14 @@ const Add = () => { alert("Unselect all members to add new availability!") return; } + for (let i = 0; i < members.length; i++) { + if (members[i].name === trimmedName) { + alert("Member with this name already exists!"); + return; + } + } let isNewMember = true; - curMembers.forEach((member)=>{ + members.forEach((member)=>{ // Pre: member name unique // returning member, set as current user if (member.name === trimmedName) { From 34a0eb5690881423bafa63d70928ac3c3f62edc5 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 24 Apr 2022 13:43:22 -0400 Subject: [PATCH 49/53] clear grid when 0 members selected --- src/components/Calendar.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index c0a1731..6b40ec0 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -20,7 +20,12 @@ const Calendar = () => { const handleChange = (event:any) => { console.log(changedAlready) - // don't change time slots if we already fetched them + + if (selectedMembers.length === 0) { + setTimeSlots(event) + return; + } + // let user select slots only after their previous slots have been fetched if (changedAlready === true) { setTimeSlots(event) @@ -43,10 +48,16 @@ const Calendar = () => { } } - if (selectedMembers.length !== 1) { + // make sure that changedAlready is false when we go back to 1 selected member + if (selectedMembers.length > 1) { dispatch(updateChangedAlready(false)) + } + // changedAlready is always true when we first reach 0 selected members + else if (selectedMembers.length === 0 && changedAlready === true) { + dispatch(updateChangedAlready(false)) + setTimeSlots([]) } - + const renderDateCell = (date: Date, selected: boolean, refSetter: (dateCell: HTMLElement | null) => void) => { From 2c8655e94fbacee12bb010a8be796c8ebbc952e0 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 24 Apr 2022 17:58:19 -0400 Subject: [PATCH 50/53] Fix bugs so new members can be added --- src/api/api.js | 1 + src/components/Add.tsx | 38 +++++++++++++++++++------------------ src/components/Calendar.tsx | 9 +-------- src/pages/meetingSlice.tsx | 1 - 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/api/api.js b/src/api/api.js index 698b4c4..0150ab6 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -62,6 +62,7 @@ async function addNewMember(meetingId, memberName) { async function setAvail(meetingId, memberId, timeSlots) { try { + console.log(timeSlots) const response = await axiosInstance.put(`/api/calendars/${meetingId}/members/${memberId}`, { timeSlots }); return response.data; // { diff --git a/src/components/Add.tsx b/src/components/Add.tsx index f9641ee..61909b3 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -1,14 +1,16 @@ -import { addMember, selectMembers, setCurMemberId, setCurMemberName } from "../pages/meetingSlice"; +import { addMember, selectMembers, setCurMemberId, setCurMemberName, setCurMemberSlots } from "../pages/meetingSlice"; import { useAppDispatch, useAppSelector } from "../app/hooks"; import * as API from "../api/api"; import { useState } from "react"; import { TextField } from '@material-ui/core'; +import { TimeSlotType } from "./TimeSlot"; const Add = () => { const dispatch = useAppDispatch(); const [memberName, setMemberName] = useState(""); const meetingId = useAppSelector(state => state.meeting.id); const members = useAppSelector(state => state.meeting.members); + const memberSlots = useAppSelector(state => state.meeting.curMemberSlots); const selectedMembers = useAppSelector(state => state.meeting.selectedMembers); @@ -35,24 +37,24 @@ const Add = () => { return; } } - let isNewMember = true; - members.forEach((member)=>{ - // Pre: member name unique - // returning member, set as current user - if (member.name === trimmedName) { - dispatch(setCurMemberId(member.id)); - dispatch(setCurMemberName(member.name)); - isNewMember = false; - } - }); + // new member - if (isNewMember){ - let data = await API.addNewMember(meetingId, trimmedName); - console.log("create new member") - dispatch(setCurMemberId(data.id)); - dispatch(setCurMemberName(data.name)); - dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots })); - } + + let data = await API.addNewMember(meetingId, trimmedName); + console.log("create new member") + dispatch(setCurMemberId(data.id)); + dispatch(setCurMemberName(data.name)); + dispatch(addMember({ id: data.id, name: data.name, timeSlots: data.timeSlots })); + + // memberId is undefined in slots at this point + const memberSlotsWithId = memberSlots.map((slot: TimeSlotType) => { + return {...slot, memberId: data.id} + }) + dispatch(setCurMemberSlots(memberSlotsWithId)) + + console.log(memberSlotsWithId) + API.setAvail(meetingId, data.id, memberSlotsWithId) + }; return ( diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index 6b40ec0..f5316d3 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -19,10 +19,10 @@ const Calendar = () => { const [timeSlots, setTimeSlots] = useState([]); const handleChange = (event:any) => { - console.log(changedAlready) if (selectedMembers.length === 0) { setTimeSlots(event) + dispatch(setCurMemberSlots(convertDatetoTS(timeSlots, meetingId, selectedMembers[0]))) return; } // let user select slots only after their previous slots have been fetched @@ -40,9 +40,6 @@ const Calendar = () => { let convertedDates = convertTStoDate(members[i].timeSlots) dispatch(updateChangedAlready(true)) setTimeSlots(convertedDates) - console.log("BEEP") - console.log(members[i].timeSlots) - console.log(convertedDates) break; } } @@ -121,10 +118,6 @@ const Calendar = () => { } - useEffect(()=>{ - addAvail(meetingId, memberId, timeSlots); - }, [meetingId, memberId, timeSlots]); - return (
)=>{ // date string - console.log(action.payload) state.curMemberSlots = action.payload; }, // store member id's From 541875dacf3bc4ec1855ea58c53e16b0260d8cd0 Mon Sep 17 00:00:00 2001 From: Kiron Date: Sun, 24 Apr 2022 18:30:21 -0400 Subject: [PATCH 51/53] Show updated times without page refresh --- src/api/api.js | 5 ++++- src/components/Add.tsx | 2 -- src/pages/meetingSlice.tsx | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/api/api.js b/src/api/api.js index 0150ab6..c6eb5fa 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -1,4 +1,6 @@ import axios from "axios"; +import { store } from "../app/store"; +import { setCurMemberSlots, updateMemberSlots } from "../pages/meetingSlice"; const axiosInstance = axios.create({ baseURL: "http://localhost:4000", @@ -62,8 +64,9 @@ async function addNewMember(meetingId, memberName) { async function setAvail(meetingId, memberId, timeSlots) { try { - console.log(timeSlots) + store.dispatch(setCurMemberSlots(timeSlots)) const response = await axiosInstance.put(`/api/calendars/${meetingId}/members/${memberId}`, { timeSlots }); + store.dispatch(updateMemberSlots({id: memberId, name: response.data.name, timeSlots: timeSlots })) return response.data; // { // "id": integer diff --git a/src/components/Add.tsx b/src/components/Add.tsx index 61909b3..09dacb9 100644 --- a/src/components/Add.tsx +++ b/src/components/Add.tsx @@ -50,9 +50,7 @@ const Add = () => { const memberSlotsWithId = memberSlots.map((slot: TimeSlotType) => { return {...slot, memberId: data.id} }) - dispatch(setCurMemberSlots(memberSlotsWithId)) - console.log(memberSlotsWithId) API.setAvail(meetingId, data.id, memberSlotsWithId) }; diff --git a/src/pages/meetingSlice.tsx b/src/pages/meetingSlice.tsx index 58e8b67..25c099d 100644 --- a/src/pages/meetingSlice.tsx +++ b/src/pages/meetingSlice.tsx @@ -47,6 +47,13 @@ export const meetingSlice = createSlice({ addMember: (state, action: PayloadAction)=>{ state.members = [action.payload, ...state.members]; }, + updateMemberSlots: (state, action: PayloadAction)=>{ + for (let i = 0; i < state.members.length; i++) { + if (state.members[i].id === action.payload.id) { + state.members[i].timeSlots = action.payload.timeSlots + } + } + }, removeMember: (state, action: PayloadAction)=>{ state.members = [...state.members.filter(member => member.id !== action.payload)]; state.selectedMembers = [...state.selectedMembers.filter(memberId => memberId !== action.payload)] @@ -84,7 +91,8 @@ export const { createMeeting, setCurMemberSlots, selectMembers, updateHoveredMembers, -updateChangedAlready } = meetingSlice.actions; +updateChangedAlready, +updateMemberSlots } = meetingSlice.actions; export const selectMeetingName = (state: RootState) => state.meeting.name export default meetingSlice.reducer From 3e922083dfb3650b1e0216710d4c12fa55297832 Mon Sep 17 00:00:00 2001 From: Rosa Date: Tue, 26 Apr 2022 15:34:33 -0400 Subject: [PATCH 52/53] fix concurrent rendering --- src/components/Calendar.tsx | 42 ++++++++++++++++++++----------------- src/components/Confirm.tsx | 1 + src/components/Header.tsx | 3 +-- src/components/Share.tsx | 1 + 4 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/components/Calendar.tsx b/src/components/Calendar.tsx index f5316d3..afa6801 100644 --- a/src/components/Calendar.tsx +++ b/src/components/Calendar.tsx @@ -27,33 +27,37 @@ const Calendar = () => { } // let user select slots only after their previous slots have been fetched if (changedAlready === true) { - setTimeSlots(event) dispatch(setCurMemberId(selectedMembers[0])) dispatch(setCurMemberSlots(convertDatetoTS(timeSlots, meetingId, selectedMembers[0]))) } } - if (selectedMembers.length === 1 && changedAlready === false) { - for (let i = 0; i < members.length; i++) { - if (members[i].id === selectedMembers[0]) { - let convertedDates = convertTStoDate(members[i].timeSlots) - dispatch(updateChangedAlready(true)) - setTimeSlots(convertedDates) - break; + useEffect(()=>{ + + if (selectedMembers.length === 1 && changedAlready === false) { + for (let i = 0; i < members.length; i++) { + if (members[i].id === selectedMembers[0]) { + let convertedDates = convertTStoDate(members[i].timeSlots) + dispatch(updateChangedAlready(true)) + setTimeSlots(convertedDates) + break; + } } + } + + // make sure that changedAlready is false when we go back to 1 selected member + if (selectedMembers.length > 1) { + dispatch(updateChangedAlready(false)) + } + // changedAlready is always true when we first reach 0 selected members + else if (selectedMembers.length === 0 && changedAlready === true) { + dispatch(updateChangedAlready(false)) + setTimeSlots([]) } - } - - // make sure that changedAlready is false when we go back to 1 selected member - if (selectedMembers.length > 1) { - dispatch(updateChangedAlready(false)) - } - // changedAlready is always true when we first reach 0 selected members - else if (selectedMembers.length === 0 && changedAlready === true) { - dispatch(updateChangedAlready(false)) - setTimeSlots([]) - } + + }, [changedAlready, dispatch, members, selectedMembers]) + diff --git a/src/components/Confirm.tsx b/src/components/Confirm.tsx index 8949d0f..23b3592 100644 --- a/src/components/Confirm.tsx +++ b/src/components/Confirm.tsx @@ -15,6 +15,7 @@ const Confirm = () => { } API.setAvail(meetingId, memberId, curMemberSlots) } + return (