diff --git a/package-lock.json b/package-lock.json
index c1f606e..7e662b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,8 +12,13 @@
"@emotion/styled": "^11.8.1",
"@mui/icons-material": "^5.4.2",
"@mui/material": "^5.4.3",
+ "@reduxjs/toolkit": "^1.8.0",
+ "@types/react-big-calendar": "^0.36.2",
+ "moment": "^2.29.1",
"react": "^17.0.2",
+ "react-big-calendar": "^0.39.3",
"react-dom": "^17.0.2",
+ "react-redux": "^7.2.6",
"react-router-dom": "^6.2.1"
},
"devDependencies": {
@@ -2205,6 +2210,40 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.0.tgz",
+ "integrity": "sha512-cdfHWfcvLyhBUDicoFwG1u32JqvwKDxLxDd7zSmSoFw/RhYLOygIRtmaMjPRUUHmVmmAGAvquLLsKKU/677kSQ==",
+ "dependencies": {
+ "immer": "^9.0.7",
+ "redux": "^4.1.2",
+ "redux-thunk": "^2.4.1",
+ "reselect": "^4.1.5"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || 18.0.0-beta",
+ "react-redux": "^7.2.1 || ^8.0.0-beta"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@restart/hooks": {
+ "version": "0.3.27",
+ "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.27.tgz",
+ "integrity": "sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw==",
+ "dependencies": {
+ "dequal": "^2.0.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"node_modules/@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
@@ -2560,6 +2599,15 @@
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
"dev": true
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"node_modules/@types/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -2637,6 +2685,15 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/@types/react-big-calendar": {
+ "version": "0.36.2",
+ "resolved": "https://registry.npmjs.org/@types/react-big-calendar/-/react-big-calendar-0.36.2.tgz",
+ "integrity": "sha512-grXQJgeHWXhgcipRB28NnUwIhD6aAKFs7IacGwy2+33hC8yAcR62nsW73aa25K3qxU8RxoLflKSCrsm4QCQpuQ==",
+ "dependencies": {
+ "@types/prop-types": "*",
+ "@types/react": "*"
+ }
+ },
"node_modules/@types/react-dom": {
"version": "17.0.11",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
@@ -2654,6 +2711,17 @@
"@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",
+ "integrity": "sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw==",
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.3.0",
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0",
+ "redux": "^4.0.0"
+ }
+ },
"node_modules/@types/react-router": {
"version": "5.1.18",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz",
@@ -2722,6 +2790,11 @@
"@types/node": "*"
}
},
+ "node_modules/@types/warning": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
+ },
"node_modules/@types/webpack": {
"version": "5.28.0",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz",
@@ -5153,6 +5226,11 @@
"url": "https://github.com/imagemin/cwebp-bin?sponsor=1"
}
},
+ "node_modules/date-arithmetic": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
+ "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
+ },
"node_modules/debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
@@ -5498,6 +5576,14 @@
"node": ">= 0.6"
}
},
+ "node_modules/dequal": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
+ "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
@@ -7458,20 +7544,6 @@
"node": ">=12"
}
},
- "node_modules/html-minifier-terser/node_modules/acorn": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
- "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
- "dev": true,
- "optional": true,
- "peer": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/html-minifier-terser/node_modules/source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@@ -8163,6 +8235,15 @@
"node": ">=8"
}
},
+ "node_modules/immer": {
+ "version": "9.0.12",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
+ "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -8285,6 +8366,14 @@
"node": ">=4"
}
},
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
@@ -8962,8 +9051,12 @@
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
@@ -9073,6 +9166,11 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/memoize-one": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
+ },
"node_modules/memory-fs": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
@@ -9216,6 +9314,14 @@
"mkdirp": "bin/cmd.js"
}
},
+ "node_modules/moment": {
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/mozjpeg": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-7.1.1.tgz",
@@ -10452,6 +10558,28 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-big-calendar": {
+ "version": "0.39.3",
+ "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.39.3.tgz",
+ "integrity": "sha512-RLymspfoBeYNBMvKnpMSpHtUAsJhv1Cbp1sE6aE7huQ92xT0mgnFDxUSoWc//C5J8WbYWLtlld521eisNJSjNw==",
+ "dependencies": {
+ "@babel/runtime": "^7.1.5",
+ "clsx": "^1.0.4",
+ "date-arithmetic": "^4.1.0",
+ "dom-helpers": "^5.1.0",
+ "invariant": "^2.2.4",
+ "lodash": "^4.17.11",
+ "lodash-es": "^4.17.11",
+ "memoize-one": "^5.1.1",
+ "prop-types": "^15.7.2",
+ "react-overlays": "^4.1.1",
+ "uncontrollable": "^7.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.6.1 || ^17",
+ "react-dom": "^16.6.1 || ^17"
+ }
+ },
"node_modules/react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@@ -10470,6 +10598,59 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "node_modules/react-overlays": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
+ "integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.1",
+ "@popperjs/core": "^2.5.3",
+ "@restart/hooks": "^0.3.25",
+ "@types/warning": "^3.0.0",
+ "dom-helpers": "^5.2.0",
+ "prop-types": "^15.7.2",
+ "uncontrollable": "^7.0.0",
+ "warning": "^4.0.3"
+ },
+ "peerDependencies": {
+ "react": ">=16.3.0",
+ "react-dom": ">=16.3.0"
+ }
+ },
+ "node_modules/react-redux": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
+ "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.15.4",
+ "@types/react-redux": "^7.1.20",
+ "hoist-non-react-statics": "^3.3.2",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2"
+ },
+ "peerDependencies": {
+ "react": "^16.8.3 || ^17"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-redux/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ },
"node_modules/react-router": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
@@ -10548,6 +10729,22 @@
"node": ">= 0.10"
}
},
+ "node_modules/redux": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
+ "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
+ "dependencies": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "node_modules/redux-thunk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
+ "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
+ "peerDependencies": {
+ "redux": "^4"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -10698,6 +10895,11 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
+ "node_modules/reselect": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz",
+ "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
+ },
"node_modules/resolve": {
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
@@ -11808,20 +12010,6 @@
}
}
},
- "node_modules/terser-webpack-plugin/node_modules/acorn": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
- "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
- "dev": true,
- "optional": true,
- "peer": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/terser-webpack-plugin/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -12214,6 +12402,20 @@
"through": "^2.3.8"
}
},
+ "node_modules/uncontrollable": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
+ "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.6.3",
+ "@types/react": ">=16.9.11",
+ "invariant": "^2.2.4",
+ "react-lifecycles-compat": "^3.0.4"
+ },
+ "peerDependencies": {
+ "react": ">=15.0.0"
+ }
+ },
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@@ -12361,6 +12563,14 @@
"node": ">= 0.8"
}
},
+ "node_modules/warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/watchpack": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
@@ -14247,6 +14457,25 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
"integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA=="
},
+ "@reduxjs/toolkit": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.0.tgz",
+ "integrity": "sha512-cdfHWfcvLyhBUDicoFwG1u32JqvwKDxLxDd7zSmSoFw/RhYLOygIRtmaMjPRUUHmVmmAGAvquLLsKKU/677kSQ==",
+ "requires": {
+ "immer": "^9.0.7",
+ "redux": "^4.1.2",
+ "redux-thunk": "^2.4.1",
+ "reselect": "^4.1.5"
+ }
+ },
+ "@restart/hooks": {
+ "version": "0.3.27",
+ "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.27.tgz",
+ "integrity": "sha512-s984xV/EapUIfkjlf8wz9weP2O9TNKR96C68FfMEy2bE69+H4cNv3RD4Mf97lW7Htt7PjZrYTjSC8f3SB9VCXw==",
+ "requires": {
+ "dequal": "^2.0.2"
+ }
+ },
"@sindresorhus/is": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
@@ -14498,6 +14727,15 @@
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
"dev": true
},
+ "@types/hoist-non-react-statics": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+ "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+ "requires": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"@types/html-minifier-terser": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz",
@@ -14575,6 +14813,15 @@
"csstype": "^3.0.2"
}
},
+ "@types/react-big-calendar": {
+ "version": "0.36.2",
+ "resolved": "https://registry.npmjs.org/@types/react-big-calendar/-/react-big-calendar-0.36.2.tgz",
+ "integrity": "sha512-grXQJgeHWXhgcipRB28NnUwIhD6aAKFs7IacGwy2+33hC8yAcR62nsW73aa25K3qxU8RxoLflKSCrsm4QCQpuQ==",
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/react": "*"
+ }
+ },
"@types/react-dom": {
"version": "17.0.11",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
@@ -14592,6 +14839,17 @@
"@types/react": "*"
}
},
+ "@types/react-redux": {
+ "version": "7.1.23",
+ "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.23.tgz",
+ "integrity": "sha512-D02o3FPfqQlfu2WeEYwh3x2otYd2Dk1o8wAfsA0B1C2AJEFxE663Ozu7JzuWbznGgW248NaOF6wsqCGNq9d3qw==",
+ "requires": {
+ "@types/hoist-non-react-statics": "^3.3.0",
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0",
+ "redux": "^4.0.0"
+ }
+ },
"@types/react-router": {
"version": "5.1.18",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.18.tgz",
@@ -14660,6 +14918,11 @@
"@types/node": "*"
}
},
+ "@types/warning": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
+ "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
+ },
"@types/webpack": {
"version": "5.28.0",
"resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-5.28.0.tgz",
@@ -16529,6 +16792,11 @@
"bin-wrapper": "^4.0.1"
}
},
+ "date-arithmetic": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
+ "integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
+ },
"debug": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
@@ -16797,6 +17065,11 @@
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
"dev": true
},
+ "dequal": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.2.tgz",
+ "integrity": "sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug=="
+ },
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
@@ -18309,14 +18582,6 @@
"terser": "^5.10.0"
},
"dependencies": {
- "acorn": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
- "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
- "dev": true,
- "optional": true,
- "peer": true
- },
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@@ -18827,6 +19092,11 @@
"is-cwebp-readable": "^3.0.0"
}
},
+ "immer": {
+ "version": "9.0.12",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
+ "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
+ },
"import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -18916,6 +19186,14 @@
"p-is-promise": "^1.1.0"
}
},
+ "invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
@@ -19401,8 +19679,12 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"lodash.debounce": {
"version": "4.0.8",
@@ -19491,6 +19773,11 @@
"fs-monkey": "1.0.3"
}
},
+ "memoize-one": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
+ "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
+ },
"memory-fs": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
@@ -19598,6 +19885,11 @@
"minimist": "^1.2.5"
}
},
+ "moment": {
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+ },
"mozjpeg": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-7.1.1.tgz",
@@ -20506,6 +20798,24 @@
"object-assign": "^4.1.1"
}
},
+ "react-big-calendar": {
+ "version": "0.39.3",
+ "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.39.3.tgz",
+ "integrity": "sha512-RLymspfoBeYNBMvKnpMSpHtUAsJhv1Cbp1sE6aE7huQ92xT0mgnFDxUSoWc//C5J8WbYWLtlld521eisNJSjNw==",
+ "requires": {
+ "@babel/runtime": "^7.1.5",
+ "clsx": "^1.0.4",
+ "date-arithmetic": "^4.1.0",
+ "dom-helpers": "^5.1.0",
+ "invariant": "^2.2.4",
+ "lodash": "^4.17.11",
+ "lodash-es": "^4.17.11",
+ "memoize-one": "^5.1.1",
+ "prop-types": "^15.7.2",
+ "react-overlays": "^4.1.1",
+ "uncontrollable": "^7.0.0"
+ }
+ },
"react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@@ -20521,6 +20831,46 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "react-overlays": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
+ "integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
+ "requires": {
+ "@babel/runtime": "^7.12.1",
+ "@popperjs/core": "^2.5.3",
+ "@restart/hooks": "^0.3.25",
+ "@types/warning": "^3.0.0",
+ "dom-helpers": "^5.2.0",
+ "prop-types": "^15.7.2",
+ "uncontrollable": "^7.0.0",
+ "warning": "^4.0.3"
+ }
+ },
+ "react-redux": {
+ "version": "7.2.6",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
+ "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==",
+ "requires": {
+ "@babel/runtime": "^7.15.4",
+ "@types/react-redux": "^7.1.20",
+ "hoist-non-react-statics": "^3.3.2",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.7.2",
+ "react-is": "^17.0.2"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ }
+ }
+ },
"react-router": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
@@ -20582,6 +20932,20 @@
"resolve": "^1.9.0"
}
},
+ "redux": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
+ "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
+ "requires": {
+ "@babel/runtime": "^7.9.2"
+ }
+ },
+ "redux-thunk": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
+ "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==",
+ "requires": {}
+ },
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -20701,6 +21065,11 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
"dev": true
},
+ "reselect": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz",
+ "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
+ },
"resolve": {
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
@@ -21583,14 +21952,6 @@
"terser": "^5.7.2"
},
"dependencies": {
- "acorn": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
- "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
- "dev": true,
- "optional": true,
- "peer": true
- },
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -21872,6 +22233,17 @@
"through": "^2.3.8"
}
},
+ "uncontrollable": {
+ "version": "7.2.1",
+ "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
+ "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
+ "requires": {
+ "@babel/runtime": "^7.6.3",
+ "@types/react": ">=16.9.11",
+ "invariant": "^2.2.4",
+ "react-lifecycles-compat": "^3.0.4"
+ }
+ },
"unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@@ -21986,6 +22358,14 @@
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
"dev": true
},
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"watchpack": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
diff --git a/package.json b/package.json
index 2884ba1..75a49c7 100644
--- a/package.json
+++ b/package.json
@@ -12,8 +12,13 @@
"@emotion/styled": "^11.8.1",
"@mui/icons-material": "^5.4.2",
"@mui/material": "^5.4.3",
+ "@reduxjs/toolkit": "^1.8.0",
+ "@types/react-big-calendar": "^0.36.2",
+ "moment": "^2.29.1",
"react": "^17.0.2",
+ "react-big-calendar": "^0.39.3",
"react-dom": "^17.0.2",
+ "react-redux": "^7.2.6",
"react-router-dom": "^6.2.1"
},
"scripts": {
diff --git a/src/App.tsx b/src/App.tsx
index 8f8e4e6..05975c4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,11 +1,11 @@
-import React, { useState } from "react";
+import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./styles.css";
import Login from "./components/login/Login";
import Home from "./components/home/Home";
import Contacts from "./components/contacts/Contacts";
-import Calendar from "./components/calendar/Calendar";
+import CalendarPage from "./components/calendar/CalendarPage";
import { ThemeProvider } from "@emotion/react";
import ProtectedRoute from "./ProtectedRoute";
import MeetingDetails from "./components/meeting-details/MeetingDetails";
@@ -15,8 +15,6 @@ import Theme from "./Theme";
import "./style/App.css";
const App: React.FC = () => {
- const [meetingInfoOpen, setMeetingInfoOpen] = useState(false);
-
return (
@@ -24,15 +22,12 @@ const App: React.FC = () => {
} />
}>
} />
- }
- />
- } />
+ } />
+ } />
-
+
);
};
diff --git a/src/ProtectedRoute.tsx b/src/ProtectedRoute.tsx
index e3a9edd..72167dd 100644
--- a/src/ProtectedRoute.tsx
+++ b/src/ProtectedRoute.tsx
@@ -1,19 +1,18 @@
-import {useLocation, Outlet, Navigate, Routes, Route} from "react-router-dom";
+import {useLocation, Outlet, Navigate} from "react-router-dom";
import useAuth from "./hooks/useAuth";
import Navbar from "./components/navbar/Navbar";
import Sidebar from "./components/sidebar/Sidebar";
-import React, {useState} from "react";
+import React, { useState } from "react";
import {
MeetingStatus,
SidebarUserObj,
} from "./components/sidebar/SidebarUser";
-import {Box} from "@mui/material";
+import { Box } from "@mui/material";
const ProtectedRoute = () => {
- const { auth }: any = useAuth();
+ const auth= useAuth();
const location = useLocation();
- const [meetingInfoOpen, setMeetingInfoOpen] = useState(false);
/* Temporary data */
const [sidebarUsers] = useState([
{ id: 0, name: "Jincheng L.", meetingStatus: MeetingStatus.ONLINE },
@@ -38,22 +37,21 @@ const ProtectedRoute = () => {
{ id: 19, name: "Bob Q.", meetingStatus: MeetingStatus.ONLINE },
{ id: 20, name: "Bob R.", meetingStatus: MeetingStatus.ONLINE },
]);
- return (
- auth?.isLoggedIn
- ?
- <>
-
-
-
-
-
-
-
-
+ return auth?.isLoggedIn ? (
+ <>
+
+
+
+
- >
- :
+
+
+
+
+ >
+ ) : (
+
);
};
-export default ProtectedRoute;
\ No newline at end of file
+export default ProtectedRoute;
diff --git a/src/api-bodies/MockData.tsx b/src/api-bodies/MockData.tsx
new file mode 100644
index 0000000..5b1ab73
--- /dev/null
+++ b/src/api-bodies/MockData.tsx
@@ -0,0 +1,86 @@
+const people = [
+ {
+ uuid: "0",
+ emailAddress: "cth0604@gmail.com",
+ name: "Taehee Choi",
+ role: "Front-end Dev",
+ },
+ {
+ uuid: "1",
+ emailAddress: "cth0604@gmail.com",
+ name: "Arthur Marques",
+ role: "Team Lead",
+ },
+ {
+ uuid: "2",
+ emailAddress: "cth0604@gmail.com",
+ name: "Mathew Balsdon",
+ role: "Front-end Dev",
+ },
+ {
+ uuid: "3",
+ emailAddress: "cth0604@gmail.com",
+ name: "Benson Lin",
+ role: "Back-end Dev",
+ },
+ {
+ uuid: "4",
+ emailAddress: "cth0604@gmail.com",
+ name: "Jincheng Lu",
+ role: "Front-end Dev",
+ },
+ {
+ uuid: "5",
+ emailAddress: "cth0604@gmail.com",
+ name: "Esteban Margaron",
+ role: "Back-end Dev",
+ },
+ {
+ uuid: "6",
+ emailAddress: "cth0604@gmail.com",
+ name: "Leanna Resurreccion",
+ role: "Back-end Dev",
+ },
+];
+
+const meetings = [
+ {
+ meetingId: "0",
+ liveParticipantIds: [],
+ registrantIds: ["0", "1", "2", "3", "4", "5", "6"],
+ start: "2022-03-13T17:00:00",
+ duration: 15,
+ timezone: "",
+ joinUrl: "",
+ topic: "Daily Scrum Meeting",
+ },
+ {
+ meetingId: "1",
+ liveParticipantIds: [],
+ registrantIds: ["0", "2", "4"],
+ start: "2022-03-13T17:30:00",
+ duration: 30,
+ timezone: "",
+ joinUrl: "",
+ topic: "Front-end Meeting",
+ },
+ {
+ meetingId: "2",
+ liveParticipantIds: [],
+ registrantIds: ["3", "5", "6"],
+ start: "2022-03-13T17:30:00",
+ duration: 30,
+ timezone: "",
+ joinUrl: "",
+ topic: "Back-end Meeting",
+ },
+];
+
+const team = {
+ user: "0",
+ manager: "1",
+ sameManager: ["2", "3", "4", "5", "6"],
+ directReports: [],
+};
+
+export { people, meetings, team };
diff --git a/src/components/calendar/Calendar.tsx b/src/components/calendar/Calendar.tsx
deleted file mode 100644
index 300488f..0000000
--- a/src/components/calendar/Calendar.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-const Calendar: React.FC = () => {
- return Calendar;
-};
-
-export default Calendar;
diff --git a/src/components/calendar/CalendarPage.tsx b/src/components/calendar/CalendarPage.tsx
new file mode 100644
index 0000000..340e0fe
--- /dev/null
+++ b/src/components/calendar/CalendarPage.tsx
@@ -0,0 +1,14 @@
+import { Toolbar } from "@mui/material";
+import UserCalendar from "./UserCalendar";
+
+const CalendarPage: React.FC = () => {
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default CalendarPage;
diff --git a/src/components/calendar/Events.tsx b/src/components/calendar/Events.tsx
new file mode 100644
index 0000000..6b62d47
--- /dev/null
+++ b/src/components/calendar/Events.tsx
@@ -0,0 +1,185 @@
+/*
+Test data from
+https://github.com/jquense/react-big-calendar/blob/master/examples/events.js
+*/
+
+const now = new Date();
+
+export default [
+ {
+ id: 0,
+ title: "All Day Event very long title",
+ allDay: true,
+ start: new Date(2022, 2, 0),
+ end: new Date(2022, 2, 1),
+ },
+ {
+ id: 1,
+ title: "Long Event",
+ start: new Date(2022, 2, 7),
+ end: new Date(2022, 2, 10),
+ },
+
+ {
+ id: 2,
+ title: "DTS STARTS",
+ start: new Date(2022, 1, 13, 0, 0, 0),
+ end: new Date(2022, 1, 20, 0, 0, 0),
+ },
+
+ {
+ id: 3,
+ title: "DTS ENDS",
+ start: new Date(2022, 9, 6, 0, 0, 0),
+ end: new Date(2022, 9, 13, 0, 0, 0),
+ },
+
+ {
+ id: 4,
+ title: "Some Event",
+ start: new Date(2022, 2, 9, 0, 0, 0),
+ end: new Date(2022, 2, 10, 0, 0, 0),
+ },
+ {
+ id: 5,
+ title: "Conference",
+ start: new Date(2022, 2, 11),
+ end: new Date(2022, 2, 13),
+ desc: "Big conference for important people",
+ },
+ {
+ id: 6,
+ title: "Meeting",
+ start: new Date(2022, 2, 12, 10, 30, 0, 0),
+ end: new Date(2022, 2, 12, 12, 30, 0, 0),
+ desc: "Pre-meeting meeting, to prepare for the meeting",
+ },
+ {
+ id: 7,
+ title: "Lunch",
+ start: new Date(2022, 2, 12, 12, 0, 0, 0),
+ end: new Date(2022, 2, 12, 13, 0, 0, 0),
+ desc: "Power lunch",
+ },
+ {
+ id: 8,
+ title: "Meeting",
+ start: new Date(2022, 2, 12, 14, 0, 0, 0),
+ end: new Date(2022, 2, 12, 15, 0, 0, 0),
+ },
+ {
+ id: 9,
+ title: "Happy Hour",
+ start: new Date(2022, 2, 12, 17, 0, 0, 0),
+ end: new Date(2022, 2, 12, 17, 30, 0, 0),
+ desc: "Most important meal of the day",
+ },
+ {
+ id: 10,
+ title: "Dinner",
+ start: new Date(2022, 2, 12, 20, 0, 0, 0),
+ end: new Date(2022, 2, 12, 21, 0, 0, 0),
+ },
+ {
+ id: 11,
+ title: "Planning Meeting with Paige",
+ start: new Date(2022, 2, 13, 8, 0, 0),
+ end: new Date(2022, 2, 13, 10, 30, 0),
+ },
+ {
+ id: 11.1,
+ title: "Inconvenient multi-day Conference Call",
+ start: new Date(2022, 2, 13, 9, 30, 0),
+ end: new Date(2022, 2, 14, 1, 0, 0),
+ },
+ {
+ id: 11.2,
+ title: "Project Kickoff - Lou's Shoes",
+ start: new Date(2022, 2, 13, 11, 30, 0),
+ end: new Date(2022, 2, 13, 14, 0, 0),
+ },
+ {
+ id: 11.3,
+ title: "Quote Follow-up - Tea by Tina",
+ start: new Date(2022, 2, 13, 15, 30, 0),
+ end: new Date(2022, 2, 13, 16, 0, 0),
+ },
+ {
+ id: 12,
+ title: "Late Night Event",
+ start: new Date(2022, 2, 17, 19, 30, 0),
+ end: new Date(2022, 2, 18, 2, 0, 0),
+ },
+ {
+ id: 12.5,
+ title: "Late Same Night Event",
+ start: new Date(2022, 2, 17, 19, 30, 0),
+ end: new Date(2022, 2, 17, 23, 30, 0),
+ },
+ {
+ id: 13,
+ title: "Multi-day Event",
+ start: new Date(2022, 2, 20, 19, 30, 0),
+ end: new Date(2022, 2, 22, 2, 0, 0),
+ },
+ {
+ id: 14,
+ title: "Today",
+ start: new Date(new Date().setHours(new Date().getHours() - 3)),
+ end: new Date(new Date().setHours(new Date().getHours() + 3)),
+ },
+ {
+ id: 15,
+ title: "Point in Time Event",
+ start: now,
+ end: now,
+ },
+ {
+ id: 16,
+ title: "Video Record",
+ start: new Date(2022, 2, 14, 15, 30, 0),
+ end: new Date(2022, 2, 14, 19, 0, 0),
+ },
+ {
+ id: 17,
+ title: "Dutch Song Producing",
+ start: new Date(2022, 2, 14, 16, 30, 0),
+ end: new Date(2022, 2, 14, 20, 0, 0),
+ },
+ {
+ id: 18,
+ title: "Itaewon Halloween Meeting",
+ start: new Date(2022, 2, 14, 16, 30, 0),
+ end: new Date(2022, 2, 14, 17, 30, 0),
+ },
+ {
+ id: 19,
+ title: "Online Coding Test",
+ start: new Date(2022, 2, 14, 17, 30, 0),
+ end: new Date(2022, 2, 14, 20, 30, 0),
+ },
+ {
+ id: 20,
+ title: "An overlapped Event",
+ start: new Date(2022, 2, 14, 17, 0, 0),
+ end: new Date(2022, 2, 14, 18, 30, 0),
+ },
+ {
+ id: 21,
+ title: "Phone Interview",
+ start: new Date(2022, 2, 14, 17, 0, 0),
+ end: new Date(2022, 2, 14, 18, 30, 0),
+ },
+ {
+ id: 22,
+ title: "Cooking Class",
+ start: new Date(2022, 2, 14, 17, 30, 0),
+ end: new Date(2022, 2, 14, 19, 0, 0),
+ },
+ {
+ id: 23,
+ title: "Go to the gym",
+ start: new Date(2022, 2, 14, 18, 30, 0),
+ end: new Date(2022, 2, 14, 20, 0, 0),
+ },
+];
\ No newline at end of file
diff --git a/src/components/calendar/UserCalendar.tsx b/src/components/calendar/UserCalendar.tsx
new file mode 100644
index 0000000..d6a7797
--- /dev/null
+++ b/src/components/calendar/UserCalendar.tsx
@@ -0,0 +1,23 @@
+import { Calendar, momentLocalizer } from "react-big-calendar";
+import moment from "moment";
+import testEvents from "./Events";
+
+import "react-big-calendar/lib/css/react-big-calendar.css";
+
+const localizer = momentLocalizer(moment);
+
+const UserCalendar: React.FC = () => {
+
+ return (
+
+ );
+};
+
+export default UserCalendar;
\ No newline at end of file
diff --git a/src/components/contacts/ContactInfo.tsx b/src/components/contacts/ContactInfo.tsx
deleted file mode 100644
index 27646b6..0000000
--- a/src/components/contacts/ContactInfo.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import Status from "./Status";
-
-interface ContactInfo {
- name: string;
- status: Status;
-}
-
-export default ContactInfo;
diff --git a/src/components/contacts/Contacts.tsx b/src/components/contacts/Contacts.tsx
index c95afe8..e533db4 100644
--- a/src/components/contacts/Contacts.tsx
+++ b/src/components/contacts/Contacts.tsx
@@ -2,25 +2,19 @@ import { Box } from "@mui/material";
import React from "react";
import Body from "./contacts-components/Body";
-import ContactInfo from "./ContactInfo";
import Sidebar from "./contacts-components/Sidebar";
+import UserLite from "../../api-bodies/UserLite";
-interface Props {
- setMeetingInfoOpen: (open: boolean) => void;
-}
-
-const Contacts: React.FC = (props) => {
- const [contactSelected, setContactSelected] =
- React.useState(null);
+const Contacts: React.FC = () => {
+ const [contactSelected, setContactSelected] = React.useState(
+ null
+ );
return (
{contactSelected !== null ? (
-
+
) : null}
);
diff --git a/src/components/contacts/Utils.tsx b/src/components/contacts/Utils.tsx
index e5424d8..bedc302 100644
--- a/src/components/contacts/Utils.tsx
+++ b/src/components/contacts/Utils.tsx
@@ -1,3 +1,4 @@
+import DetailedMeeting from "../../api-bodies/DetailedMeeting";
import Status from "./Status";
const returnStatusColor = (
@@ -15,4 +16,10 @@ const returnStatusColor = (
}
};
-export { returnStatusColor };
+const getMeetingDuration = (meeting: DetailedMeeting) => {
+ const startDate = new Date(meeting.start);
+ const endDate = new Date(startDate.getTime() + meeting.duration * 60000);
+ return `${startDate.toTimeString()} - ${endDate.toTimeString()}`;
+};
+
+export { returnStatusColor, getMeetingDuration };
diff --git a/src/components/contacts/contacts-components/Body.tsx b/src/components/contacts/contacts-components/Body.tsx
index fd4de4a..bb9f5ce 100644
--- a/src/components/contacts/contacts-components/Body.tsx
+++ b/src/components/contacts/contacts-components/Body.tsx
@@ -2,11 +2,10 @@ import { Box, Toolbar } from "@mui/material";
import React from "react";
import UpperBody from "./body-components/UpperBody";
import LowerBody from "./body-components/LowerBody";
-import ContactInfo from "../ContactInfo";
+import UserLite from "../../../api-bodies/UserLite";
interface Props {
- contactSelected: ContactInfo;
- setMeetingInfoOpen: (open: boolean) => void;
+ contactSelected: UserLite;
}
const Body: React.FC = (props) => {
@@ -21,10 +20,7 @@ const Body: React.FC = (props) => {
>
-
+
);
};
diff --git a/src/components/contacts/contacts-components/Sidebar.tsx b/src/components/contacts/contacts-components/Sidebar.tsx
index f4007f4..eecf63c 100644
--- a/src/components/contacts/contacts-components/Sidebar.tsx
+++ b/src/components/contacts/contacts-components/Sidebar.tsx
@@ -9,19 +9,17 @@ import {
} from "@mui/material";
import React from "react";
import { ExpandLess, ExpandMore } from "@mui/icons-material";
-import ContactInfo from "../ContactInfo";
-import Status from "../Status";
import ContactItem from "./sidebar-components/ContactItem";
-
-const contacts: ContactInfo[] = [
- { name: "Taehee ...", status: Status.Online },
- { name: "Jincheng ...", status: Status.Offline },
- { name: "Mathew ...", status: Status.InMeeting },
- { name: "Esteban ...", status: Status.Away },
-];
+import { useAppSelector } from "../../../redux/hooks";
+import {
+ selectFavoritesJSON,
+ selectTeamJSON,
+} from "../../../redux/slices/peopleSlice";
+import { selectFavorites } from "../../../redux/slices/favoritesSlice";
+import UserLite from "../../../api-bodies/UserLite";
interface Props {
- setContactSelected: (contactInfo: ContactInfo) => void;
+ setContactSelected: (contactInfo: UserLite) => void;
}
const sidebarWidth = 240;
@@ -30,6 +28,12 @@ const Sidebar: React.FC = (props) => {
const [favoritesOpen, setFavoritesOpen] = React.useState(true);
const [teamOpen, setTeamOpen] = React.useState(false);
+ const favorites = useAppSelector(selectFavorites);
+ const favoritesJSON = useAppSelector((state) =>
+ selectFavoritesJSON(state, favorites)
+ );
+ const teamJSON = useAppSelector(selectTeamJSON);
+
return (
= (props) => {
setFavoritesOpen(!favoritesOpen)}>
{favoritesOpen ? : }
-
+
- {contacts.map((contact, i) => (
+ {favoritesJSON.map((favorite, i) => (
@@ -65,13 +72,13 @@ const Sidebar: React.FC = (props) => {
setTeamOpen(!teamOpen)}>
{teamOpen ? : }
-
+
- {contacts.map((contact, i) => (
+ {teamJSON.map((member, i) => (
diff --git a/src/components/contacts/contacts-components/body-components/LowerBody.tsx b/src/components/contacts/contacts-components/body-components/LowerBody.tsx
index a43d74f..824c7a6 100644
--- a/src/components/contacts/contacts-components/body-components/LowerBody.tsx
+++ b/src/components/contacts/contacts-components/body-components/LowerBody.tsx
@@ -1,21 +1,22 @@
import { Box, Button, List, Typography } from "@mui/material";
import React from "react";
-import ContactInfo from "../../ContactInfo";
-
-const meetings: { name: string; duration: string }[] = [
- { name: "Kanban Meeting", duration: "10:45 am - 11:45 am" },
- { name: "Design Meeting", duration: "10:45 am - 11:45 am" },
- { name: "Customer Meeting", duration: "10:45 am - 11:45 am" },
- { name: "Some kind of Meeting", duration: "10:45 am - 11:45 am" },
- { name: "Some kind of Meeting", duration: "10:45 am - 11:45 am" },
-];
+import UserLite from "../../../../api-bodies/UserLite";
+import { useAppSelector, useAppDispatch } from "../../../../redux/hooks";
+import { open } from "../../../../redux/slices/meetingDetailsOpenSlice";
+import { selectUserUpcomingMeetings } from "../../../../redux/slices/meetingsSlice";
+import { getMeetingDuration } from "../../Utils";
interface Props {
- contactInfo: ContactInfo;
- setMeetingInfoOpen: (open: boolean) => void;
+ contactInfo: UserLite;
}
const LowerBody: React.FC = (props) => {
+ const dispatch = useAppDispatch();
+
+ const meetings = useAppSelector((state) =>
+ selectUserUpcomingMeetings(state, props.contactInfo.uuid)
+ );
+
return (
= (props) => {
- {meeting.duration}
+
+ {getMeetingDuration(meeting)}
+
))}
diff --git a/src/components/contacts/contacts-components/body-components/UpperBody.tsx b/src/components/contacts/contacts-components/body-components/UpperBody.tsx
index 18ead7a..39ad22f 100644
--- a/src/components/contacts/contacts-components/body-components/UpperBody.tsx
+++ b/src/components/contacts/contacts-components/body-components/UpperBody.tsx
@@ -3,11 +3,12 @@ import React from "react";
import PhoneIcon from "@mui/icons-material/Phone";
import VideocamIcon from "@mui/icons-material/Videocam";
import GroupsIcon from "@mui/icons-material/Groups";
-import ContactInfo from "../../ContactInfo";
import AddIcon from "@mui/icons-material/Add";
+import Status from "../../Status";
+import UserLite from "../../../../api-bodies/UserLite";
interface Props {
- contactInfo: ContactInfo;
+ contactInfo: UserLite;
}
const UpperBody: React.FC = (props) => {
@@ -63,9 +64,7 @@ const UpperBody: React.FC = (props) => {
-
- {props.contactInfo.status}
-
+ {Status.Online}
MeetingName-1372
diff --git a/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx b/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx
index c8d9e48..2b78288 100644
--- a/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx
+++ b/src/components/contacts/contacts-components/sidebar-components/ContactItem.tsx
@@ -2,12 +2,13 @@ import { ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
import React from "react";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import CircleIcon from "@mui/icons-material/Circle";
-import ContactInfo from "../../ContactInfo";
import { returnStatusColor } from "../../Utils";
+import UserLite from "../../../../api-bodies/UserLite";
+import Status from "../../Status";
interface Props {
- contactInfo: ContactInfo;
- setContactSelected: (contactInfo: ContactInfo) => void;
+ contactInfo: UserLite;
+ setContactSelected: (contactInfo: UserLite) => void;
}
const ContactItem: React.FC = (props) => {
@@ -22,10 +23,10 @@ const ContactItem: React.FC = (props) => {
-
+
);
};
diff --git a/src/components/home/CallFavouritesDialog.tsx b/src/components/home/CallFavouritesDialog.tsx
new file mode 100644
index 0000000..61c97ee
--- /dev/null
+++ b/src/components/home/CallFavouritesDialog.tsx
@@ -0,0 +1,44 @@
+import { Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, FormGroup, Typography } from "@mui/material";
+import { SidebarUserObj } from "../sidebar/SidebarUser";
+
+interface Props {
+ open: boolean;
+ selectedValue: SidebarUserObj;
+ onClose: (value: SidebarUserObj) => void;
+ users: SidebarUserObj[];
+}
+
+const CallFavouritesDialog: React.FC = ({ open, selectedValue, onClose, users }: Props) => {
+ const handleClose = () => {
+ onClose(selectedValue);
+ };
+
+ return (
+
+ );
+};
+
+export default CallFavouritesDialog;
\ No newline at end of file
diff --git a/src/components/home/Home.tsx b/src/components/home/Home.tsx
index c50a231..43829b6 100644
--- a/src/components/home/Home.tsx
+++ b/src/components/home/Home.tsx
@@ -2,8 +2,22 @@ import MeetingsPanel from "./MeetingsPanel";
import ShortCuts from "./ShortCuts";
import Container from "@mui/material/Container";
import Grid from "@mui/material/Grid";
+import { MeetingStatus, SidebarUserObj } from "../sidebar/SidebarUser";
+import { useState } from "react";
const Home: React.FC = () => {
+
+ /* Temporary data - this is the same as what's in ProtectedRoute.tsx so it should not
+ be duplicated like this in the future (Route components were being weird when I tried
+ to pass it down from App.tsx) */
+ const [mockUsers] = useState([
+ { id: 0, name: "Jincheng L.", meetingStatus: MeetingStatus.ONLINE },
+ { id: 1, name: "Matt B.", meetingStatus: MeetingStatus.IN_MEETING },
+ { id: 2, name: "Taehee C.", meetingStatus: MeetingStatus.OFFLINE },
+ { id: 3, name: "Bob A.", meetingStatus: MeetingStatus.AWAY }
+ ]);
+
+
return (
@@ -11,7 +25,7 @@ const Home: React.FC = () => {
-
+
diff --git a/src/components/home/ShortCuts.tsx b/src/components/home/ShortCuts.tsx
index 9a0bb09..b631d4c 100644
--- a/src/components/home/ShortCuts.tsx
+++ b/src/components/home/ShortCuts.tsx
@@ -5,8 +5,27 @@ import CircleIcon from "@mui/icons-material/Circle";
import Button from "@mui/material/Button";
import Grid from "@mui/material/Grid";
import Typography from "@mui/material/Typography";
+import { SidebarUserObj } from "../sidebar/SidebarUser";
+import CallFavouritesDialog from "./CallFavouritesDialog";
+import { useState } from "react";
+
+interface Props {
+ users: SidebarUserObj[];
+}
+
+const ShortCuts: React.FC = ({ users }: Props) => {
+ const [open, setOpen] = useState(false);
+ const [selectedValue, setSelectedValue] = useState(users[0]);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = (value: SidebarUserObj) => {
+ setOpen(false);
+ setSelectedValue(value);
+ };
-const ShortCuts: React.FC = () => {
return (
@@ -25,9 +44,14 @@ const ShortCuts: React.FC = () => {
-
diff --git a/src/components/login/Login.tsx b/src/components/login/Login.tsx
index 8a0f4db..ca9563d 100644
--- a/src/components/login/Login.tsx
+++ b/src/components/login/Login.tsx
@@ -1,6 +1,6 @@
-import { useRef, useState, useEffect, useContext } from "react";
-import { useLocation, Link, useNavigate } from "react-router-dom";
-import { Stack } from "@mui/material";
+import { useState } from "react";
+import { useLocation, useNavigate } from "react-router-dom";
+import { Stack, Typography } from "@mui/material";
import Container from "@mui/material/Container";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
@@ -9,13 +9,16 @@ import zoomLogo from "../../assets/zoom.png";
import LoginIcon from "@mui/icons-material/Login";
import useAuth from "../../hooks/useAuth";
+interface LocationState {
+ from: { pathname: string };
+}
const Login: React.FC = () => {
-
- const { setAuth }: any = useAuth();
+ const setAuth = useAuth();
const navigate = useNavigate();
- const location: any = useLocation();
- const from = location.state?.from?.pathname || "/";
+ const location = useLocation();
+ const state = location.state as LocationState;
+ const from = state?.from?.pathname || "/";
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
@@ -34,8 +37,10 @@ const Login: React.FC = () => {
const handleLogin = () => {
if (username === "" && password === "") {
- setAuth({username: username, isLoggedIn: true});
- navigate(from, {replace: true});
+ // setAuth({username: username, isLoggedIn: true});
+ setAuth["username"] = username;
+ setAuth["isLoggedIn"] = true;
+ navigate(from, { replace: true });
}
setUsername("");
setPassword("");
@@ -44,23 +49,52 @@ const Login: React.FC = () => {
return (
-
+
{/* {errMsg}
*/}
- {setUsername(event.target.value)}}/>
- {setPassword(event.target.value)}}/>
+ {
+ setUsername(event.target.value);
+ }}
+ />
+ {
+ setPassword(event.target.value);
+ }}
+ />
- Forgotten Your Password?
- } className="login-btn" variant="contained" type="submit" onClick={handleLogin}>Login
+
+ Forgot your password?
+
+ }
+ className="login-btn"
+ variant="contained"
+ type="submit"
+ onClick={handleLogin}
+ >
+ Login
+
-
+ Login with
-
+
);
};
-
-export default Login;
\ No newline at end of file
+
+export default Login;
diff --git a/src/components/meeting-details/MeetingDetails.tsx b/src/components/meeting-details/MeetingDetails.tsx
index dcca058..0703c24 100644
--- a/src/components/meeting-details/MeetingDetails.tsx
+++ b/src/components/meeting-details/MeetingDetails.tsx
@@ -2,17 +2,24 @@ import { Dialog } from "@mui/material";
import React from "react";
import Body from "./meeting-details-components/Body";
import Header from "./meeting-details-components/Header";
+import { useAppSelector, useAppDispatch } from "../../redux/hooks";
+import {
+ close,
+ selectMeetingDetailsOpen,
+} from "../../redux/slices/meetingDetailsOpenSlice";
-interface Props {
- open: boolean;
- setOpen: (open: boolean) => void;
-}
+const MeetingDetails: React.FC = () => {
+ const meetingDetailsOpen = useAppSelector(selectMeetingDetailsOpen);
+ const dispatch = useAppDispatch();
-const MeetingDetails: React.FC = (props) => {
return (
-
+
);
};
diff --git a/src/components/meeting-details/meeting-details-components/Body.tsx b/src/components/meeting-details/meeting-details-components/Body.tsx
index 632ac39..e253b82 100644
--- a/src/components/meeting-details/meeting-details-components/Body.tsx
+++ b/src/components/meeting-details/meeting-details-components/Body.tsx
@@ -8,8 +8,13 @@ import {
} from "@mui/material";
import React from "react";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
+import DetailedMeeting from "../../../api-bodies/DetailedMeeting";
-const Body: React.FC = () => {
+interface Props {
+ meeting: DetailedMeeting | null;
+}
+
+const Body: React.FC = () => {
return (
void;
+ meeting: DetailedMeeting | null;
}
const Header: React.FC = (props) => {
+ const dispatch = useAppDispatch();
+
return (
- Kanban Meeting
+ {props.meeting !== null ? props.meeting.topic : null}
Join
@@ -23,7 +28,7 @@ const Header: React.FC = (props) => {
edge="start"
color="inherit"
aria-label="close"
- onClick={() => props.setOpen(false)}
+ onClick={() => dispatch(close())}
sx={{ ml: 1 }}
>
diff --git a/src/context/AuthProvider.tsx b/src/context/AuthProvider.tsx
index cb661da..7f1fbd6 100644
--- a/src/context/AuthProvider.tsx
+++ b/src/context/AuthProvider.tsx
@@ -1,15 +1,19 @@
import { createContext, useState } from "react";
-const AuthContext = createContext({});
-
-export const AuthProvider = ({ children }: {children: any}) => {
- const [auth, setAuth] = useState({});
-
- return (
-
- {children}
-
- )
+interface loginInfo {
+ username: string;
+ isLoggedIn: boolean;
}
-export default AuthContext;
\ No newline at end of file
+const AuthContext = createContext({
+ username: "",
+ isLoggedIn: false,
+});
+
+export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
+ const [auth] = useState({ username: "", isLoggedIn: false });
+
+ return {children};
+};
+
+export default AuthContext;
diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx
index d1fb072..ebe7cc6 100644
--- a/src/hooks/useAuth.tsx
+++ b/src/hooks/useAuth.tsx
@@ -1,8 +1,13 @@
import { useContext } from "react";
import AuthContext from "../context/AuthProvider";
-const useAuth = () => {
- return useContext(AuthContext);
+interface loginInfo {
+ username: string;
+ isLoggedIn: boolean;
}
+const useAuth = () => {
+ return useContext(AuthContext);
+};
+
export default useAuth;
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
index d8f9587..cb69700 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,12 +1,25 @@
import ReactDOM from "react-dom";
import App from "./App";
import "./style/App.css";
-import { AuthProvider } from './context/AuthProvider';
+import { AuthProvider } from "./context/AuthProvider";
+import { Provider } from "react-redux";
+import { store } from "./redux/store";
+import { fetchFavorites } from "./redux/slices/favoritesSlice";
+import { fetchTeam } from "./redux/slices/teamSlice";
+import { fetchMeetings } from "./redux/slices/meetingsSlice";
+import { fetchPeople } from "./redux/slices/peopleSlice";
-const Index:React.FC = () => {
+store.dispatch(fetchPeople(""));
+store.dispatch(fetchFavorites(""));
+store.dispatch(fetchTeam(""));
+store.dispatch(fetchMeetings(""));
+
+const Index: React.FC = () => {
return (
-
+
+
+
);
};
diff --git a/src/redux/hooks.tsx b/src/redux/hooks.tsx
new file mode 100644
index 0000000..36b5ea2
--- /dev/null
+++ b/src/redux/hooks.tsx
@@ -0,0 +1,6 @@
+import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
+import type { RootState, AppDispatch } from "./store";
+
+// Use throughout your app instead of plain `useDispatch` and `useSelector`
+export const useAppDispatch = () => useDispatch();
+export const useAppSelector: TypedUseSelectorHook = useSelector;
diff --git a/src/redux/slices/favoritesSlice.tsx b/src/redux/slices/favoritesSlice.tsx
new file mode 100644
index 0000000..5ac5d36
--- /dev/null
+++ b/src/redux/slices/favoritesSlice.tsx
@@ -0,0 +1,55 @@
+import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
+import { RootState } from "../store";
+
+interface FavoritesState {
+ favorites: string[];
+}
+
+const initialState: FavoritesState = {
+ favorites: [],
+};
+
+export const favoritesSlice = createSlice({
+ name: "favorites",
+ initialState,
+ reducers: {},
+ extraReducers(builder) {
+ builder
+ .addCase(fetchFavorites.fulfilled, (state, action) => {
+ state.favorites = action.payload;
+ })
+ .addCase(addFavorite.fulfilled, (state, action) => {
+ state.favorites.push(action.payload);
+ })
+ .addCase(removeFavorite.fulfilled, (state, action) => {
+ const index = state.favorites.indexOf(action.payload);
+ state.favorites.splice(index, 1);
+ });
+ },
+});
+
+export const fetchFavorites = createAsyncThunk(
+ "favorites/fetchFavorites",
+ async (uuid: string) => {
+ // const response = await client.post("/fakeApi/posts", initialPost);
+ // !!!
+ console.log(uuid);
+ return ["2", "4"];
+ }
+);
+export const addFavorite = createAsyncThunk(
+ "favorites/addFavorite",
+ async (uuid: string) => {
+ // const response = await client.post("/fakeApi/posts", initialPost);
+ return uuid;
+ }
+);
+export const removeFavorite = createAsyncThunk(
+ "favorites/removeFavorite",
+ async (uuid: string) => {
+ // const response = await client.post("/fakeApi/posts", initialPost);
+ return uuid;
+ }
+);
+export const selectFavorites = (state: RootState) => state.favorites.favorites;
+export default favoritesSlice.reducer;
diff --git a/src/redux/slices/meetingDetailsOpenSlice.tsx b/src/redux/slices/meetingDetailsOpenSlice.tsx
new file mode 100644
index 0000000..7b6e6ca
--- /dev/null
+++ b/src/redux/slices/meetingDetailsOpenSlice.tsx
@@ -0,0 +1,33 @@
+import { createSlice } from "@reduxjs/toolkit";
+import DetailedMeeting from "../../api-bodies/DetailedMeeting";
+import { RootState } from "../store";
+
+interface MeetingDetailsOpenState {
+ open: boolean;
+ meeting: DetailedMeeting | null;
+}
+
+const initialState: MeetingDetailsOpenState = {
+ open: false,
+ meeting: null,
+};
+
+export const meetingDetailsOpenSlice = createSlice({
+ name: "meetingDetailsOpen",
+ initialState,
+ reducers: {
+ open: (state, action) => {
+ state.open = true;
+ state.meeting = action.payload;
+ },
+ close: (state) => {
+ state.open = false;
+ state.meeting = null;
+ },
+ },
+});
+
+export const { open, close } = meetingDetailsOpenSlice.actions;
+export const selectMeetingDetailsOpen = (state: RootState) =>
+ state.meetingDetailsOpen;
+export default meetingDetailsOpenSlice.reducer;
diff --git a/src/redux/slices/meetingsSlice.tsx b/src/redux/slices/meetingsSlice.tsx
new file mode 100644
index 0000000..272e764
--- /dev/null
+++ b/src/redux/slices/meetingsSlice.tsx
@@ -0,0 +1,41 @@
+import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
+import DetailedMeeting from "../../api-bodies/DetailedMeeting";
+import { RootState } from "../store";
+import { meetings } from "../../api-bodies/MockData";
+
+interface MeetingsState {
+ meetings: DetailedMeeting[];
+}
+
+const initialState: MeetingsState = {
+ meetings: [],
+};
+
+export const meetingsSlice = createSlice({
+ name: "meetings",
+ initialState,
+ reducers: {},
+ extraReducers(builder) {
+ builder.addCase(fetchMeetings.fulfilled, (state, action) => {
+ return action.payload;
+ });
+ },
+});
+
+export const fetchMeetings = createAsyncThunk(
+ "meetings/fetchMeetings",
+ async (uuid: string) => {
+ // const response = await client.post("/fakeApi/posts", initialPost);
+ // !!!
+ console.log(uuid);
+ return { meetings: meetings };
+ }
+);
+
+export const selectMeetings = (state: RootState) => state.meetings.meetings;
+export const selectUserUpcomingMeetings = (state: RootState, uuid: string) => {
+ return state.meetings.meetings.filter((meeting) =>
+ meeting.registrantIds.includes(uuid)
+ );
+};
+export default meetingsSlice.reducer;
diff --git a/src/redux/slices/peopleSlice.tsx b/src/redux/slices/peopleSlice.tsx
new file mode 100644
index 0000000..ef76f52
--- /dev/null
+++ b/src/redux/slices/peopleSlice.tsx
@@ -0,0 +1,40 @@
+import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
+import UserLite from "../../api-bodies/UserLite";
+import { RootState } from "../store";
+import { people } from "../../api-bodies/MockData";
+
+interface PeopleState {
+ people: UserLite[];
+}
+
+const initialState: PeopleState = {
+ people: [],
+};
+
+export const peopleSlice = createSlice({
+ name: "people",
+ initialState,
+ reducers: {},
+ extraReducers(builder) {
+ builder.addCase(fetchPeople.fulfilled, (state, action) => {
+ console.log(action.payload);
+ state.people = action.payload;
+ });
+ },
+});
+
+export const fetchPeople = createAsyncThunk(
+ "people/fetchPeople",
+ async (uuid: string) => {
+ // const response = await client.post("/fakeApi/posts", initialPost);
+ // !!!
+ console.log(uuid);
+ return people;
+ }
+);
+
+export const selectFavoritesJSON = (state: RootState, favorites: string[]) => {
+ return state.people.people.filter((p) => favorites.includes(p.uuid));
+};
+export const selectTeamJSON = (state: RootState) => state.people.people;
+export default peopleSlice.reducer;
diff --git a/src/redux/slices/teamSlice.tsx b/src/redux/slices/teamSlice.tsx
new file mode 100644
index 0000000..c6e7fe2
--- /dev/null
+++ b/src/redux/slices/teamSlice.tsx
@@ -0,0 +1,41 @@
+import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
+import { RootState } from "../store";
+import { team } from "../../api-bodies/MockData";
+
+interface TeamState {
+ user: string | null;
+ manager: string | null;
+ sameManager: string[];
+ directReports: string[];
+}
+
+const initialState: TeamState = {
+ user: null,
+ manager: null,
+ sameManager: [],
+ directReports: [],
+};
+
+export const teamSlice = createSlice({
+ name: "team",
+ initialState,
+ reducers: {},
+ extraReducers(builder) {
+ builder.addCase(fetchTeam.fulfilled, (state, action) => {
+ return action.payload;
+ });
+ },
+});
+
+export const fetchTeam = createAsyncThunk(
+ "team/fetchTeam",
+ async (uuid: string) => {
+ // const response = await client.post("/fakeApi/posts", initialPost);
+ // !!!
+ console.log(uuid);
+ return team;
+ }
+);
+
+export const selectTeam = (state: RootState) => state.team;
+export default teamSlice.reducer;
diff --git a/src/redux/store.tsx b/src/redux/store.tsx
new file mode 100644
index 0000000..23d0ab2
--- /dev/null
+++ b/src/redux/store.tsx
@@ -0,0 +1,19 @@
+import { configureStore } from "@reduxjs/toolkit";
+import meetingDetailsOpenReducer from "./slices/meetingDetailsOpenSlice";
+import favoritesReducer from "./slices/favoritesSlice";
+import teamReducer from "./slices/teamSlice";
+import meetingsReducer from "./slices/meetingsSlice";
+import peopleReducer from "./slices/peopleSlice";
+
+export const store = configureStore({
+ reducer: {
+ meetingDetailsOpen: meetingDetailsOpenReducer,
+ favorites: favoritesReducer,
+ team: teamReducer,
+ meetings: meetingsReducer,
+ people: peopleReducer,
+ },
+});
+
+export type RootState = ReturnType;
+export type AppDispatch = typeof store.dispatch;