diff --git a/code/package-lock.json b/code/package-lock.json index bb51e893e..22c8f182d 100644 --- a/code/package-lock.json +++ b/code/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "@babel/eslint-parser": "^7.18.9", + "@reduxjs/toolkit": "^1.9.4", "eslint": "^8.21.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.26.0", @@ -16,7 +17,10 @@ "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-redux": "^8.0.5", + "react-router-dom": "^6.10.0", + "sweetalert": "^2.1.2" }, "devDependencies": { "react-scripts": "5.0.1" @@ -3124,6 +3128,37 @@ } } }, + "node_modules/@reduxjs/toolkit": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.4.tgz", + "integrity": "sha512-j2R4I+dzt7cWjf50CNS17A/TBX0rH5SmFhKcOQDZlFtFvmSGWfEQvNPjrCI729Am5o1USFWT1PaxV/JflmP/Dg==", + "dependencies": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.0.2" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@remix-run/router": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3621,6 +3656,15 @@ "@types/node": "*" } }, + "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", @@ -3695,6 +3739,11 @@ "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==", "dev": true }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, "node_modules/@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", @@ -3713,6 +3762,16 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/react": { + "version": "18.0.35", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.35.tgz", + "integrity": "sha512-6Laome31HpetaIUGFWl1VQ3mdSImwxtFZ39rh059a1MNnKGqBpC88J6NJ8n/Is3Qx7CefDGLgf/KhN/sYCf7ag==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -3728,6 +3787,11 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "node_modules/@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, "node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -3768,6 +3832,11 @@ "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", "dev": true }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -6095,6 +6164,11 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -6640,6 +6714,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==" + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -8515,6 +8594,14 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -8800,10 +8887,9 @@ } }, "node_modules/immer": { - "version": "9.0.15", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", - "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==", - "dev": true, + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -14020,6 +14106,11 @@ "asap": "~2.0.6" } }, + "node_modules/promise-polyfill": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz", + "integrity": "sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ==" + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -14375,6 +14466,49 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "peerDependencies": { + "@types/react": "^16.8 || ^17.0 || ^18.0", + "@types/react-dom": "^16.8 || ^17.0 || ^18.0", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0", + "react-native": ">=0.59", + "redux": "^4" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -14384,6 +14518,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", + "dependencies": { + "@remix-run/router": "1.5.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", + "dependencies": { + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -14531,6 +14695,22 @@ "node": "*" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -14686,6 +14866,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "node_modules/reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -15802,6 +15987,15 @@ "boolbase": "~1.0.0" } }, + "node_modules/sweetalert": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.2.tgz", + "integrity": "sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA==", + "dependencies": { + "es6-object-assign": "^1.1.0", + "promise-polyfill": "^6.0.2" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -16340,6 +16534,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -19509,6 +19711,22 @@ "source-map": "^0.7.3" } }, + "@reduxjs/toolkit": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.4.tgz", + "integrity": "sha512-j2R4I+dzt7cWjf50CNS17A/TBX0rH5SmFhKcOQDZlFtFvmSGWfEQvNPjrCI729Am5o1USFWT1PaxV/JflmP/Dg==", + "requires": { + "immer": "^9.0.21", + "redux": "^4.2.1", + "redux-thunk": "^2.4.2", + "reselect": "^4.1.8" + } + }, + "@remix-run/router": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==" + }, "@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -19876,6 +20094,15 @@ "@types/node": "*" } }, + "@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", @@ -19950,6 +20177,11 @@ "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==", "dev": true }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + }, "@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", @@ -19968,6 +20200,16 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/react": { + "version": "18.0.35", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.35.tgz", + "integrity": "sha512-6Laome31HpetaIUGFWl1VQ3mdSImwxtFZ39rh059a1MNnKGqBpC88J6NJ8n/Is3Qx7CefDGLgf/KhN/sYCf7ag==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -19983,6 +20225,11 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "@types/scheduler": { + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", + "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" + }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -20023,6 +20270,11 @@ "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", "dev": true }, + "@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -21748,6 +22000,11 @@ } } }, + "csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -22170,6 +22427,11 @@ "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==" + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -23521,6 +23783,14 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -23739,10 +24009,9 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "immer": { - "version": "9.0.15", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", - "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==", - "dev": true + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==" }, "import-fresh": { "version": "3.3.0", @@ -27413,6 +27682,11 @@ "asap": "~2.0.6" } }, + "promise-polyfill": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz", + "integrity": "sha512-g0LWaH0gFsxovsU7R5LrrhHhWAWiHRnh1GPrhXnPgYsDkIqjRYUYSZEsej/wtleDrz5xVSIDbeKfidztp2XHFQ==" + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -27678,12 +27952,49 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-redux": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz", + "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/use-sync-external-store": "^0.0.3", + "hoist-non-react-statics": "^3.3.2", + "react-is": "^18.0.0", + "use-sync-external-store": "^1.0.0" + }, + "dependencies": { + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + } + } + }, "react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "dev": true }, + "react-router": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", + "requires": { + "@remix-run/router": "1.5.0" + } + }, + "react-router-dom": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", + "requires": { + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" + } + }, "react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -27800,6 +28111,20 @@ } } }, + "redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-thunk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz", + "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==", + "requires": {} + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -27924,6 +28249,11 @@ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, + "reselect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz", + "integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==" + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -28773,6 +29103,15 @@ } } }, + "sweetalert": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.2.tgz", + "integrity": "sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA==", + "requires": { + "es6-object-assign": "^1.1.0", + "promise-polyfill": "^6.0.2" + } + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -29163,6 +29502,12 @@ "punycode": "^2.1.0" } }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/code/package.json b/code/package.json index 7aad26ebc..ccc29b833 100644 --- a/code/package.json +++ b/code/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@babel/eslint-parser": "^7.18.9", + "@reduxjs/toolkit": "^1.9.4", "eslint": "^8.21.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.26.0", @@ -11,7 +12,10 @@ "eslint-plugin-react": "^7.30.1", "eslint-plugin-react-hooks": "^4.6.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-redux": "^8.0.5", + "react-router-dom": "^6.10.0", + "sweetalert": "^2.1.2" }, "scripts": { "start": "react-scripts start", diff --git a/code/public/android-chrome-192x192.png b/code/public/android-chrome-192x192.png new file mode 100644 index 000000000..ca9769acd Binary files /dev/null and b/code/public/android-chrome-192x192.png differ diff --git a/code/public/android-chrome-512x512.png b/code/public/android-chrome-512x512.png new file mode 100644 index 000000000..2684de487 Binary files /dev/null and b/code/public/android-chrome-512x512.png differ diff --git a/code/public/apple-touch-icon.png b/code/public/apple-touch-icon.png new file mode 100644 index 000000000..b5a8453bf Binary files /dev/null and b/code/public/apple-touch-icon.png differ diff --git a/code/public/favicon.ico b/code/public/favicon.ico new file mode 100644 index 000000000..f3008decf Binary files /dev/null and b/code/public/favicon.ico differ diff --git a/code/public/favicon.svg b/code/public/favicon.svg new file mode 100644 index 000000000..3d5481638 --- /dev/null +++ b/code/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/public/index.html b/code/public/index.html index e6730aa66..ea334bf59 100644 --- a/code/public/index.html +++ b/code/public/index.html @@ -1,6 +1,5 @@ - @@ -14,6 +13,10 @@ Learn how to configure a non-root public URL by running `npm run build`. --> Technigo React App + + + + @@ -30,5 +33,4 @@ To create a production bundle, use `npm run build` or `yarn build`. --> - diff --git a/code/public/manifest.json b/code/public/manifest.json new file mode 100644 index 000000000..5709d9e17 --- /dev/null +++ b/code/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "ToDO", + "name": "ToDo", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/code/src/App.js b/code/src/App.js index f2007d229..f7b5917b9 100644 --- a/code/src/App.js +++ b/code/src/App.js @@ -1,9 +1,26 @@ +/* eslint-disable comma-dangle */ +import { ToDoList } from 'components/ToDoList'; import React from 'react'; +import { Provider } from 'react-redux'; +import { combineReducers, configureStore } from '@reduxjs/toolkit'; +import { tasks } from 'reducers/tasks'; +import { Header } from 'components/Header'; +import { AddNewTask } from 'components/AddNewTask'; + +const reducer = combineReducers({ + tasks: tasks.reducer, +}); + +const store = configureStore({ reducer }); export const App = () => { return ( -
- Find me in src/app.js! -
+ +
+
+ + +
+
); -} +}; diff --git a/code/src/components/AddNewTask.css b/code/src/components/AddNewTask.css new file mode 100644 index 000000000..c8afd1269 --- /dev/null +++ b/code/src/components/AddNewTask.css @@ -0,0 +1,32 @@ +.add-task-btn img { + width: 1.5rem; + height: 1.5rem; + margin-left: 1rem; +} +.add-task-btn { + display: flex; + align-items: center; + font-size: 1rem; + color: rgb(48, 45, 43); + font-family: 'Sora', sans-serif; + padding: 10px; +} + +.form-container { + display: flex; + flex-direction: column; + align-items: center; + font-family: 'Sora', sans-serif; + width: 400px; + margin: auto; + margin-top: 20px; + margin-bottom: 20px; + padding: 20px; + font-size: 16px; + box-shadow: 10px 5px rgb(245, 244, 242); + border: 1px solid; + background-color: rgb(187, 173, 255); + color: rgb(48, 45, 43); + font-family: 'Sora', sans-serif; + border-radius: 55px; +} diff --git a/code/src/components/AddNewTask.js b/code/src/components/AddNewTask.js new file mode 100644 index 000000000..372015904 --- /dev/null +++ b/code/src/components/AddNewTask.js @@ -0,0 +1,78 @@ +/* eslint-disable comma-dangle */ +/* eslint-disable react/jsx-closing-bracket-location */ +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { tasks } from 'reducers/tasks'; +import './AddNewTask.css'; +import swal from 'sweetalert'; +import plus from '../img/plus.png'; + +function getOrdinalSuffix(day) { + if (day >= 11 && day <= 13) { + return 'th'; + } + switch (day % 10) { + case 1: + return 'st'; + case 2: + return 'nd'; + case 3: + return 'rd'; + default: + return 'th'; + } +} +// Create a functional component named 'AddNewTask' +export const AddNewTask = () => { + const date = new Date(); + const month = date.toLocaleString('default', { month: 'long' }); + const day = date.getDate(); + const ordinal = getOrdinalSuffix(day); + const year = date.getFullYear(); + // Use the useDispatch hook to get access to the Redux dispatch function + const dispatch = useDispatch(); + // Use the useState hook to declare a new state variable 'newTaskValue' + const [newTaskValue, setNewTaskValue] = React.useState(''); + + // Define a function to handle the form submission + const onFormSubmit = (event) => { + // Prevent the default form submission behavior + event.preventDefault(); + // Check if the new task input field is empty + if (newTaskValue === '') { + // If it is, show an alert to the user + swal({ + title: 'Please enter a task', + text: 'You need to enter a task to add it to your list', + icon: 'warning', + }); + return; + } + + // Dispatch an action to add the new task to the store + dispatch(tasks.actions.addTask(newTaskValue)); + // Reset the value of the new task input field + setNewTaskValue(''); + }; + // Render a section with a class name of 'add-new-task' + return ( +
+

What do you need to do today?

+

{`${month} ${day}${ordinal}, ${year}`}

{' '} + + +
+ ); +}; diff --git a/code/src/components/Header.css b/code/src/components/Header.css new file mode 100644 index 000000000..cb59a3dff --- /dev/null +++ b/code/src/components/Header.css @@ -0,0 +1,75 @@ +/* .header { + background-color: rgb(54, 50, 64); + min-height: 25vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; + font-family: 'Sora', sans-serif; +} */ +.header { + background-color: rgb(54, 50, 64); + display: flex; + flex-direction: column; + align-items: center; + font-family: 'Sora', sans-serif; + width: 400px; + margin: auto; + margin-top: 20px; + margin-bottom: 20px; + padding: 20px; + font-size: 16px; + box-shadow: 10px 5px rgb(245, 244, 242); + border: 1px solid; + background-color: rgb(187, 173, 255); + color: rgb(48, 45, 43); + border-radius: 55px; +} +.clear-all-button { + display: flex; + background: none; + border: none; + cursor: pointer; + font-family: 'Sora', sans-serif; + color: rgb(48, 45, 43); + font-size: 1rem; + margin-left: 1rem; + margin-bottom: 1rem; + align-items: center; +} + +.clear-all-button img { + width: 1.5rem; + height: 1.5rem; + margin-left: 1rem; + text-align: center; +} +.clear-all { + display: flex; + flex-direction: column; + align-items: center; + font-family: 'Sora', sans-serif; +} +h4 { + margin: 5px; + padding: 10px; +} +h1 { + margin: 5px; +} +input { + background-color: #fff; + border-radius: 20px; + border: none; + color: black; + cursor: pointer; + padding: 10px 20px; + box-shadow: fff; +} +.header-container { + display: flex; + flex-direction: column; + align-items: center; +} diff --git a/code/src/components/Header.js b/code/src/components/Header.js new file mode 100644 index 000000000..e4163fe9e --- /dev/null +++ b/code/src/components/Header.js @@ -0,0 +1,42 @@ +/* eslint-disable react/jsx-closing-bracket-location */ +import React from 'react'; +import { tasks } from 'reducers/tasks'; +import { useDispatch, useSelector } from 'react-redux'; +import './Header.css'; +import remove from '../img/remove.png'; + +export const Header = () => { + const dispatch = useDispatch(); + const numberOfTasks = useSelector((store) => store.tasks.length); + // const completedTasks = tasks.filter((task) => task.isComplete); + + // const allDone = () => { + // if (tasks.length === completedTasks.length) { + // return 'You are all done!'; + // } + // return `${completedTasks.length} out of ${tasks.length} tasks completed`; + // }; + + return ( +
+
+
+
+

My To Do List ✅

+

# {numberOfTasks} remaining todos

+
+ +
+
+
{/*

{allDone()}

*/}
+
+
+
+ ); +}; diff --git a/code/src/components/ToDoList.css b/code/src/components/ToDoList.css new file mode 100644 index 000000000..8a2c33d4d --- /dev/null +++ b/code/src/components/ToDoList.css @@ -0,0 +1,98 @@ +/* .task-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + background-color: #282c34; + min-height: 25vh; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; + gap: 1rem; + width: 100%; +} +.grow { + flex-grow: 1; +} +.task { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + width: 100%; + max-width: 500px; +} + +.task-button { + background: none; + border: none; + margin: 0; + padding: 0; + cursor: pointer; + font-family: 'Lato', sans-serif; + color: white; + font-size: 1.5rem; + margin-left: 1rem; +} +.task-button img { + width: 1.5rem; + height: 1.5rem; + margin-right: 1rem; +} */ + +.task-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + background-color: rgb(54, 50, 64); + min-height: 25vh; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; + gap: 1rem; + width: 100%; +} + +.grow { + width: 400px; + margin: auto; + margin-bottom: 20px; + padding: 20px; + box-shadow: 10px 5px rgb(245, 244, 242); + font-size: 20px; + border: 1px solid; + background-color: rgb(215, 254, 152); + color: rgb(48, 45, 43); + font-family: 'Sora', sans-serif; + border-radius: 55px; +} +.task { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + width: 100%; + max-width: 500px; +} + +.task-button { + background: none; + border: none; + margin: 0; + padding: 0; + cursor: pointer; + font-family: 'Lato', sans-serif; + color: white; + font-size: 1.5rem; + margin-left: 1rem; +} +.task-button img { + width: 1.5rem; + height: 1.5rem; + margin-right: 1rem; +} diff --git a/code/src/components/ToDoList.js b/code/src/components/ToDoList.js new file mode 100644 index 000000000..631c54b5b --- /dev/null +++ b/code/src/components/ToDoList.js @@ -0,0 +1,45 @@ +/* eslint-disable react/jsx-closing-bracket-location */ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { tasks } from 'reducers/tasks'; +import './ToDoList.css'; +import delete1 from '../img/delete1.png'; + +export const ToDoList = () => { + const dispatch = useDispatch(); + // useSelector is a hook that allows us to access the store + const allTasks = useSelector((store) => store.tasks); + const checkboxToggle = (id) => { + dispatch(tasks.actions.toggleComplete(id)); + }; + + return ( +
+
+ {/* map over the tasks array and render a checkbox and a task for each task */} + {allTasks.map((task) => ( +
+
+ checkboxToggle(task.id)} + /> +

{task.text}

+

{task.emoji}

+ +
+
+ ))} +
+
+ ); +}; diff --git a/code/src/img/delete.png b/code/src/img/delete.png new file mode 100644 index 000000000..e77b80c3a Binary files /dev/null and b/code/src/img/delete.png differ diff --git a/code/src/img/delete1.png b/code/src/img/delete1.png new file mode 100644 index 000000000..efc47ecf7 Binary files /dev/null and b/code/src/img/delete1.png differ diff --git a/code/src/img/minus.png b/code/src/img/minus.png new file mode 100644 index 000000000..869df7526 Binary files /dev/null and b/code/src/img/minus.png differ diff --git a/code/src/img/plus.png b/code/src/img/plus.png new file mode 100644 index 000000000..aa1818203 Binary files /dev/null and b/code/src/img/plus.png differ diff --git a/code/src/img/remove.png b/code/src/img/remove.png new file mode 100644 index 000000000..2b4c3568f Binary files /dev/null and b/code/src/img/remove.png differ diff --git a/code/src/index.css b/code/src/index.css index 4a1df4db7..879611055 100644 --- a/code/src/index.css +++ b/code/src/index.css @@ -1,13 +1,32 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", - "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + font-family: 'Sora', sans-serif; + background-color: rgb(54, 50, 64); } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", - monospace; + font-family: 'Sora', sans-serif; } + +button { + background: none; + border: none; + margin: 0; + padding: 0; + cursor: pointer; + font-family: 'Sora', sans-serif; + border-radius: 50px; +} + +/* add-task-btn { + padding: 0.6em 1.2em; + font-size: 16px; + background-color: rgb(177, 162, 255); + border: none; + border-radius: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; + font-size: 1rem; + padding: 0.7rem 0.9rem; +} */ diff --git a/code/src/reducers/tasks.js b/code/src/reducers/tasks.js new file mode 100644 index 000000000..1eaf7111f --- /dev/null +++ b/code/src/reducers/tasks.js @@ -0,0 +1,42 @@ +/* eslint-disable comma-dangle */ +import { createSlice } from '@reduxjs/toolkit'; + +const taskData = [ + { id: 1, text: 'Review research results', isComplete: true, emoji: '👩‍🔬' }, + { id: 2, text: 'Submit report', isComplete: false, emoji: '📩' }, + { id: 3, text: 'Prepare for meeting', isComplete: false, emoji: '📅' }, +]; + +export const tasks = createSlice({ + name: 'tasks', + initialState: taskData, + reducers: { + addTask: (state, action) => { + const newTask = { + id: Date.now(), + text: action.payload, + isComplete: false, + emoji: '❓', + }; + state.push(newTask); + }, + removeTask: (state, action) => { + const taskToRemove = state.find((task) => task.id === action.payload); + state.splice(state.indexOf(taskToRemove), 1); + }, + clearAll: (state) => { + state.splice(0, state.length); + // add a note to the user that the list is empty + // const newTask = { + // id: Date.now(), + // text: 'Your list is empty', + // emoji: '👋', + // }; + // state.push(newTask); + }, + toggleComplete: (state, action) => { + const taskToToggle = state.find((task) => task.id === action.payload); + taskToToggle.isComplete = !taskToToggle.isComplete; + }, + }, +});