diff --git a/infra/staff/package-lock.json b/infra/staff/package-lock.json index 7b7e447aa9..366258637a 100644 --- a/infra/staff/package-lock.json +++ b/infra/staff/package-lock.json @@ -8,12 +8,16 @@ "name": "staff", "version": "0.0.0", "dependencies": { + "@mui/icons-material": "^5.16.0", + "date-fns": "^3.6.0", "react": "^18", + "react-datepicker": "^7.1.0", "react-dom": "^18", "react-toastify": "^10.0.5", "zod": "^3" }, "devDependencies": { + "@rollup/plugin-node-resolve": "^15.2.3", "@types/react": "^18", "@types/react-dom": "^18", "@typescript-eslint/eslint-plugin": "^7", @@ -26,7 +30,7 @@ "prettier": "^3", "prettier-plugin-organize-imports": "^3.2", "prettier-plugin-packagejson": "^2.5", - "typescript": "^5.4.5", + "typescript": "^5", "vite": "^5.2" } }, @@ -339,6 +343,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.24.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", @@ -388,6 +403,43 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "peer": true, + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "peer": true + }, + "node_modules/@emotion/sheet": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", + "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==", + "peer": true + }, + "node_modules/@emotion/utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", + "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==", + "peer": true + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==", + "peer": true + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", @@ -849,6 +901,54 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", + "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", + "dependencies": { + "@floating-ui/utils": "^0.2.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", + "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.4" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.19", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.19.tgz", + "integrity": "sha512-Jk6zITdjjIvjO/VdQFvpRaD3qPwOHH6AoDHxjhpy+oK4KFgaSP871HYWUAPdnLmx1gQ+w/pB312co3tVml+BXA==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.1", + "@floating-ui/utils": "^0.2.4", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", + "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -952,6 +1052,271 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", + "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.15.14", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.0.tgz", + "integrity": "sha512-8SLffXYPRVpcZx5QzxNE8fytTqzp+IuU3deZbQWg/vSaTlDpR5YVrQ4qQtXTi5cRdhOufV5INylmwlKK+//nPw==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.0.tgz", + "integrity": "sha512-6ISoOhkp9w5gD0PEW9JklrcbyARDkFWNTBdwXZ1Oy5IGlyu9B0zG0hnUIe4H17IaF1Vgj6C8VI+v4tkSdK0veg==", + "dependencies": { + "@babel/runtime": "^7.23.9" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^5.0.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.0.tgz", + "integrity": "sha512-DbR1NckTLpjt9Zut9EGQ70th86HfN0BYQgyYro6aXQrNfjzSwe3BJS1AyBQ5mJ7TdL6YVRqohfukxj9JlqZZUg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40", + "@mui/core-downloads-tracker": "^5.16.0", + "@mui/system": "^5.16.0", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.16.0", + "@types/react-transition-group": "^4.4.10", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.2.0", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "peer": true + }, + "node_modules/@mui/private-theming": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.0.tgz", + "integrity": "sha512-sYpubkO1MZOnxNyVOClrPNOTs0MfuRVVnAvCeMaOaXt6GimgQbnUcshYv2pSr6PFj+Mqzdff/FYOBceK8u5QgA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.16.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.15.14", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.15.14.tgz", + "integrity": "sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.11.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.0.tgz", + "integrity": "sha512-9YbkC2m3+pNumAvubYv+ijLtog6puJ0fJ6rYfzfLCM47pWrw3m+30nXNM8zMgDaKL6vpfWJcCXm+LPaWBpy7sw==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.16.0", + "@mui/styled-engine": "^5.15.14", + "@mui/types": "^7.2.14", + "@mui/utils": "^5.16.0", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.14", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.14.tgz", + "integrity": "sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==", + "peer": true, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.0.tgz", + "integrity": "sha512-kLLi5J1xY+mwtUlMb8Ubdxf4qFAA1+U7WPBvjM/qQ4CIwLCohNb0sHo1oYPufjSIH/Z9+dhVxD7dJlfGjd1AVA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.23.9", + "@types/prop-types": "^15.7.11", + "prop-types": "^15.8.1", + "react-is": "^18.2.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "peer": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -999,6 +1364,80 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.18.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", @@ -1257,14 +1696,12 @@ "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1279,6 +1716,21 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", + "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "peer": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", @@ -1778,6 +2230,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -1892,8 +2356,7 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/data-view-buffer": { "version": "1.0.1", @@ -1946,6 +2409,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", @@ -1969,6 +2441,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -2048,6 +2529,16 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.788", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz", @@ -2616,6 +3107,12 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -3194,6 +3691,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -3308,6 +3820,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -3732,7 +4250,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4070,7 +4587,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4117,6 +4633,22 @@ "node": ">=0.10.0" } }, + "node_modules/react-datepicker": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.3.0.tgz", + "integrity": "sha512-EqRKLAtLZUTztiq6a+tjSjQX9ES0Xd229JPckAtyZZ4GoY3rtvNWAzkYZnQUf6zTWT50Ki0+t+W9VRQIkSJLfg==", + "dependencies": { + "@floating-ui/react": "^0.26.2", + "clsx": "^2.1.0", + "date-fns": "^3.3.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.13.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18", + "react-dom": "^16.9.0 || ^17 || ^18" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -4132,8 +4664,20 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-onclickoutside": { + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz", + "integrity": "sha512-LdrrxK/Yh9zbBQdFbMTXPp3dTSN9B+9YJQucdDu3JNKRrbdU+H+/TVONJoWtOwy4II8Sqf1y/DTI6w/vGPYW0w==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x || ^18.x", + "react-dom": "^15.5.x || ^16.x || ^17.x || ^18.x" + } }, "node_modules/react-refresh": { "version": "0.14.2", @@ -4156,6 +4700,22 @@ "react-dom": ">=18" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -4177,6 +4737,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", @@ -4604,6 +5169,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "peer": true + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4644,6 +5215,11 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/infra/staff/package.json b/infra/staff/package.json index 094e3cfb05..c171f60a72 100644 --- a/infra/staff/package.json +++ b/infra/staff/package.json @@ -11,9 +11,17 @@ "preview": "vite preview" }, "dependencies": { + "@date-io/date-fns": "^3.0.0", + "@emotion/react": "^11.11.4", + "@emotion/styled": "^11.11.5", + "@mui/icons-material": "^5.16.0", + "@mui/lab": "^5.0.0-alpha.171", + "@mui/material": "^5.16.0", + "@mui/x-date-pickers": "^7.9.0", + "@types/react-datepicker": "^6.2.0", "date-fns": "^3.6.0", "react": "^18", - "react-datepicker": "^7.1.0", + "react-datepicker": "^7.3.0", "react-dom": "^18", "react-toastify": "^10.0.5", "zod": "^3" diff --git a/infra/staff/src/App.css b/infra/staff/src/App.css index e080f6b3b2..e1c9e003de 100644 --- a/infra/staff/src/App.css +++ b/infra/staff/src/App.css @@ -1,456 +1,347 @@ -.fetch-button-container { - margin-right: 180px; - margin-left: 10px; +.container { + position: relative; /* Ensure the parent is relatively positioned */ + height: 100vh; /* Full viewport height */ + width: 100vw; /* Full viewport width */ + display: flex; + justify-content: center; + align-items: center; } -.content-wrapper { +.center-table { + display: table; +} + +.input-form { display: flex; - align-items: flex-start; - margin-left: 175px; + flex-direction: column; + align-items: center; +} + +.horizontal-group { + position: absolute; /* Use absolute positioning */ + top: 32px; /* 32px below the top of the page */ + left: 32px; /* 32px from the leftmost edge of the page */ + right: 32px; + display: flex; + align-items: center; /* Align items vertically centered */ + gap: 20px; /* Adjust the gap between elements as needed */ + background-color: #fafafa; + height: 104px; + width: 1375px; + border-radius: 10px; } .fetch-button-container button { - padding: 10px 20px; - font-size: 16px; - cursor: pointer; - background-color: #009879; + background-color: #00b33c; color: white; border: none; - border-radius: 5px; - margin-top: 20px; -} -#submitbtn { - padding: 10px 20px; - font-size: 16px; - cursor: pointer; - background-color: #009879; - color: white; - border: none; - border-radius: 5px; - margin-top: 20px; -} - -#submitbtn:hover { - background-color: #007c6c; + width: 199px; + height: 56px; + margin-left: 20px; } .fetch-button-container button:hover { background-color: #007c6c; } -.sidebar { - padding: 20px; - flex: 0 0 auto; -} - -.button-container { +.link-text { display: flex; - gap: 10px; + align-items: center; + padding: 0 16px; /* Add padding for better appearance */ + text-decoration: none; /* Remove underline */ + color: inherit; /* Inherit color from parent */ + font-weight: bold; /* Make the text bold */ + font-size: 40px; } -button { - padding: 10px 20px; - font-size: 16px; +.text-field-token { + margin-left: 70px !important; /* Adjust margin for Token field */ +} + +.text-field-email { + margin-left: 20px !important; /* Adjust margin for Email field */ +} +.duckie-container { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} +.center-content { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; /* Adjust as necessary */ + position: relative; } .error-message { - margin-top: 20px; color: red; + font-size: 1.5em; } -.message { - position: fixed; - bottom: 10px; - left: 50%; - transform: translateX(-50%); - padding: 10px; - border-radius: 5px; - background-color: #f0f0f0; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); +.duckie-container { + display: flex; + justify-content: center; + align-items: center; +} +.container { + position: relative; /* Ensure the parent is relatively positioned */ + height: 100vh; /* Full viewport height */ + width: 100vw; /* Full viewport width */ + display: flex; + flex-direction: column; /* Add this */ + justify-content: center; /* Center vertically */ + align-items: center; /* Center horizontally */ } -.message.error { - background-color: #f44336; - color: white; +.input-form { + display: flex; + flex-direction: column; + align-items: center; + z-index: 1; /* Ensure form is on top */ } -.message.success { - background-color: #4caf50; - color: white; +.horizontal-group { + display: flex; + align-items: center; + gap: 20px; /* Adjust the gap between elements as needed */ + background-color: #fafafa; + padding: 20px; /* Add padding around content */ + border-radius: 10px; } -.dropdown-container { - margin-bottom: 20px; - position: relative; /* Ensure relative positioning for dropdown menu */ -} - -.more-button { - padding: 10px 20px; - font-size: 16px; - cursor: pointer; - background-color: #009879; +.fetch-button-container button { + background-color: #00b33c; color: white; border: none; - border-radius: 5px; - margin-top: 1px; + width: 199px; + height: 56px; } -.more-button:hover { +.fetch-button-container button:hover { background-color: #007c6c; } -.dropdown-menu { - position: absolute; - top: calc(100% + 5px); /* Position right below the More button */ - left: 0; - z-index: 100; - display: block; - background-color: #fff; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - border: 1px solid #ccc; - border-radius: 5px; - padding: 10px; - max-height: 150px; /* Example: Set max height for scrollability */ - overflow-y: auto; /* Enable vertical scroll */ -} - -/* Remove bullets from unordered list */ -.dropdown-menu ul { - list-style-type: none; - padding: 0; - margin: 0; -} - -.dropdown-menu button { - display: block; - width: 100%; - padding: 8px 16px; - font-size: 14px; - color: #333; - background-color: transparent; - border: none; - cursor: pointer; - transition: background-color 0.3s ease; -} - -.dropdown-menu button:hover { - background-color: #f0f0f0; -} -.modal { - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: #ffffff; - padding: 20px; - border: 1px solid #ccc; - border-radius: 5px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - z-index: 1000; - max-width: 80%; - max-height: 80%; - overflow: auto; -} - -.modal-header { +.link-text { display: flex; - justify-content: space-between; align-items: center; - padding-bottom: 10px; - border-bottom: 1px solid #ccc; + padding: 0 16px; /* Add padding for better appearance */ + text-decoration: none; /* Remove underline */ + color: inherit; /* Inherit color from parent */ + font-weight: bold; /* Make the text bold */ + font-size: 40px; } -.modal-header .close-btn { - cursor: pointer; - color: #777; - font-size: 20px; +.text-field-token { + margin-left: 70px !important; /* Adjust margin for Token field */ } -.modal-content { - margin-top: 10px; +.text-field-email { + margin-left: 50px !important; /* Adjust margin for Email field */ } -/* Styles for draggable modal */ -.modal.draggable { - cursor: move; -} - -.modal.draggable .modal-header { - cursor: move; -} -.popup { - position: fixed; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: lightgreen; - padding: 20px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - z-index: 1000; -} - -.popup-content { +.center-content { display: flex; - flex-direction: column; -} - -.popup-content div { - margin-bottom: 10px; -} -:root { - --popup-bg-color-light: #fff; - --popup-bg-color-dark: #2c2c2c; - --popup-border-color-light: #ccc; - --popup-border-color-dark: #444; - --popup-text-color-light: #000; - --popup-text-color-dark: #fff; - --popup-shadow-light: rgba(0, 0, 0, 0.1); - --popup-shadow-dark: rgba(255, 255, 255, 0.1); -} - -.update-subscription-popup { - position: fixed; - top: 50%; - left: 50%; - width: 400px; - transform: translate(-50%, -50%); - background-color: var(--popup-bg-color-light); - border: 1px solid var(--popup-border-color-light); - padding: 20px; - z-index: 1000; - box-shadow: 0px 0px 10px var(--popup-shadow-light); -} - -.popup-content { - display: flex; - flex-direction: column; -} - -.close-button { - align-self: flex-end; - background: none; - border: none; - font-size: 1.5rem; - cursor: pointer; - color: var(--popup-text-color-light); -} - -.popup-content h2 { - margin-top: 0; -} - -.popup-content form label { - display: block; - margin-bottom: 10px; -} - -.popup-content form input, -.popup-content form select { - width: 100%; - padding: 8px; - margin-top: 5px; - background-color: var(--popup-bg-color-light); - color: var(--popup-text-color-light); - border: 1px solid var(--popup-border-color-light); -} - -.popup-content form button { - padding: 10px 15px; - margin-top: 10px; - cursor: pointer; - background-color: var(--popup-bg-color-light); - color: var(--popup-text-color-light); - border: 1px solid var(--popup-border-color-light); -} - -.custom-select { - position: relative; - width: 100%; -} - -.custom-select select { - width: 100%; - padding: 8px; - cursor: pointer; - background-color: var(--popup-bg-color-light); - color: var(--popup-text-color-light); - border: 1px solid var(--popup-border-color-light); - appearance: none; -} - -.custom-select::after { - content: "\25BC"; + justify-content: center; + align-items: center; position: absolute; top: 50%; - right: 10px; - transform: translateY(-50%); - pointer-events: none; + left: 50%; + transform: translate(-50%, -50%); } -.message { - margin-top: 10px; - padding: 10px; - border-radius: 5px; +.duckie-container { + display: flex; + justify-content: center; + align-items: center; } -.message.error { - background-color: #f8d7da; - color: #721c24; +/* Example CSS to maintain tabs fixed position */ +.tabs-container { + position: sticky; + top: 20px; /* Adjust as needed */ + z-index: 1000; /* Ensure tabs are above other content */ +} +.container { + position: relative; /* Ensure the parent is relatively positioned */ + height: 100vh; /* Full viewport height */ + width: 100vw; /* Full viewport width */ + display: flex; + flex-direction: column; /* Ensure children stack vertically */ + justify-content: center; /* Center vertically */ + align-items: center; /* Center horizontally */ } -.message.success { - background-color: #d4edda; - color: #155724; +.input-form { + display: flex; + flex-direction: column; + align-items: center; + z-index: 1; /* Ensure form is on top */ + margin-bottom: 20px; /* Add space between form and tabs */ } -@media (prefers-color-scheme: dark) { - .update-subscription-popup { - background-color: var(--popup-bg-color-dark); - border-color: var(--popup-border-color-dark); - color: var(--popup-text-color-dark); - box-shadow: 0px 0px 10px var(--popup-shadow-dark); - } - - .close-button { - color: var(--popup-text-color-dark); - } - - .popup-content form input, - .popup-content form select { - background-color: var(--popup-bg-color-dark); - color: var(--popup-text-color-dark); - border: 1px solid var(--popup-border-color-dark); - } - - .popup-content form button { - background-color: var(--popup-bg-color-dark); - color: var(--popup-text-color-dark); - border: 1px solid var(--popup-border-color-dark); - } -} -:root { - --popup-bg-color-light: #fff; - --popup-bg-color-dark: #2c2c2c; - --popup-border-color-light: #ccc; - --popup-border-color-dark: #444; - --popup-text-color-light: #000; - --popup-text-color-dark: #fff; - --popup-shadow-light: rgba(0, 0, 0, 0.1); - --popup-shadow-dark: rgba(255, 255, 255, 0.1); +.horizontal-group { + display: flex; + align-items: center; + gap: 20px; /* Adjust the gap between elements as needed */ + background-color: #fafafa; + padding: 20px; /* Add padding around content */ + border-radius: 10px; } -.update-subscription-popup { - position: fixed; +.fetch-button-container button { + background-color: #00b33c; + color: white; + border: none; + width: 199px; + height: 56px; +} + +.fetch-button-container button:hover { + background-color: #007c6c; +} + +.link-text { + display: flex; + align-items: center; + padding: 0 16px; /* Add padding for better appearance */ + text-decoration: none; /* Remove underline */ + color: inherit; /* Inherit color from parent */ + font-weight: bold; /* Make the text bold */ + font-size: 40px; +} + +.text-field-token { + margin-left: 70px !important; /* Adjust margin for Token field */ +} + +.text-field-email { + margin-left: 50px !important; /* Adjust margin for Email field */ +} + +.center-content { + display: flex; + justify-content: center; + align-items: center; + position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - background-color: var(--popup-bg-color-light); - border: 1px solid var(--popup-border-color-light); - padding: 20px; - z-index: 1000; - box-shadow: 0px 0px 10px var(--popup-shadow-light); } -.popup-content { +.duckie-container { display: flex; - flex-direction: column; + justify-content: center; + align-items: center; } -.close-button { - align-self: flex-end; - background: none; - border: none; - font-size: 1.5rem; - cursor: pointer; - color: var(--popup-text-color-light); +.tabs-container { + position: sticky; /* Make the tabs sticky */ + top: 0; /* Stick to the top of the viewport */ + z-index: 1000; /* Ensure tabs are above other content */ + background-color: #fafafa; /* Optional: Add background color to tabs */ + padding: 10px 20px; /* Optional: Add padding for better appearance */ + border-bottom: 1px solid #ccc; /* Optional: Add bottom border */ +} +.dialog-popup-container { + /* Styles for the overlay/background */ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black */ + display: flex; + align-items: center; + justify-content: center; } -.popup-content h2 { - margin-top: 0; +.dialog-popup { + background-color: white; + padding: 20px; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); } -.form-group { - margin-bottom: 20px; +.dialog-popup-header h2 { + margin-bottom: 20px; /* Add space between heading and fields */ } -.form-group label { +.dialog-popup-field { + margin-bottom: 15px; +} + +.dialog-popup-field label { display: block; margin-bottom: 5px; + font-weight: bold; } -.form-group input, -.form-group select { +.dialog-popup-field input { width: 100%; padding: 8px; - background-color: var(--popup-bg-color-light); - color: var(--popup-text-color-light); - border: 1px solid var(--popup-border-color-light); - border-radius: 5px; - margin-top: 5px; + border: 1px solid #ccc; + border-radius: 3px; } -.custom-select { - position: relative; - width: 100%; -} - -.custom-select select { - width: 100%; - padding: 8px; +.submit-button { + background-color: #4caf50; /* Green */ + color: white; + padding: 10px 15px; + border: none; + border-radius: 3px; cursor: pointer; - background-color: var(--popup-bg-color-light); - color: var(--popup-text-color-light); - border: 1px solid var(--popup-border-color-light); - appearance: none; } -.custom-select::after { - content: "\25BC"; - position: absolute; - top: 50%; - right: 10px; - transform: translateY(-50%); - pointer-events: none; +/* Specific styles for each field to match the image */ +.name-field input, +.shortname-field input, +.code-field input { + width: calc(100% - 100px); /* Adjust as needed */ } -.message { - margin-top: 10px; - padding: 10px; - border-radius: 5px; +.active-field input { + width: 50px; +} +/* Add to App.css or your CSS file */ +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + min-height: 100vh; } -.message.error { - background-color: #f8d7da; - color: #721c24; +.input-form { + margin-bottom: 16px; } -.message.success { - background-color: #d4edda; - color: #155724; +.content-container { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + margin-top: 300px; } -@media (prefers-color-scheme: dark) { - .update-subscription-popup { - background-color: var(--popup-bg-color-dark); - border-color: var(--popup-border-color-dark); - color: var(--popup-text-color-dark); - box-shadow: 0px 0px 10px var(--popup-shadow-dark); - } - - .close-button { - color: var(--popup-text-color-dark); - } - - .form-group input, - .form-group select { - background-color: var(--popup-bg-color-dark); - color: var(--popup-text-color-dark); - border: 1px solid var(--popup-border-color-dark); - } - - .form-group button { - background-color: var(--popup-bg-color-dark); - color: var(--popup-text-color-dark); - border: 1px solid var(--popup-border-color-dark); - } +.horizontal-group { + display: flex; + align-items: center; +} + +.fetch-button-container { + margin-right: 10px; + margin-left: 10px; +} + +.text-field-token, +.text-field-email { + margin: 0 8px; +} + +.error-message { + color: red; + font-weight: bold; + margin-top: 16px; } diff --git a/infra/staff/src/App.tsx b/infra/staff/src/App.tsx index aaac53273d..1db3e87212 100644 --- a/infra/staff/src/App.tsx +++ b/infra/staff/src/App.tsx @@ -1,38 +1,122 @@ -import React, { useEffect, useState } from "react"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import CircularProgress from "@mui/material/CircularProgress"; +import Tab from "@mui/material/Tab"; +import Tabs from "@mui/material/Tabs"; +import TextField from "@mui/material/TextField"; +import * as React from "react"; +import { useEffect, useState } from "react"; import "./App.css"; -import { Sidebar } from "./components/Sidebar"; +import FamilyTableComponent from "./components/FamilyComponentTable"; +import StorageBonusTableComponent from "./components/StorageBonusTableComponent"; +import type { UserData } from "./components/UserComponent"; +import UserComponent from "./components/UserComponent"; +import duckieimage from "./components/duckie.png"; import { apiOrigin } from "./services/support"; -import S from "./utils/strings"; -type User = Record< - string, - string | number | boolean | null | undefined | Record ->; -type UserData = Record; +export let email = ""; +export let token = ""; -export const App: React.FC = () => { - const [token, setToken] = useState(""); - const [email, setEmail] = useState(""); +export const setEmail = (newEmail: string) => { + email = newEmail; +}; + +export const setToken = (newToken: string) => { + token = newToken; +}; + +export const getEmail = () => email; +export const getToken = () => token; + +interface User { + ID: string; + email: string; + creationTime: number; +} + +interface Subscription { + productID: string; + paymentProvider: string; + expiryTime: number; + storage: number; +} + +interface Security { + isEmailMFAEnabled: boolean; + isTwoFactorEnabled: boolean; + passkeys: string; +} + +interface UserResponse { + user: User; + subscription: Subscription; + details?: { + usage?: number; + storageBonus?: number; + profileData: Security; + }; +} + +const App: React.FC = () => { + const [localEmail, setLocalEmail] = useState(""); + const [localToken, setLocalToken] = useState(""); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + const [fetchSuccess, setFetchSuccess] = useState(false); + const [tabValue, setTabValue] = useState(0); const [userData, setUserData] = useState(null); - const [error, setError] = useState(null); - const [isDataFetched, setIsDataFetched] = useState(false); useEffect(() => { const storedToken = localStorage.getItem("token"); if (storedToken) { setToken(storedToken); + setLocalToken(storedToken); } }, []); useEffect(() => { - if (token) { - localStorage.setItem("token", token); + if (localToken) { + setToken(localToken); + localStorage.setItem("token", localToken); } else { localStorage.removeItem("token"); } - }, [token]); + }, [localToken]); + + useEffect(() => { + if (localEmail) { + setEmail(localEmail); + localStorage.setItem("email", localEmail); + } else { + localStorage.removeItem("email"); + } + }, [localEmail]); + + useEffect(() => { + const urlParams = new URLSearchParams(window.location.search); + const urlEmail = urlParams.get("email"); + const urlToken = urlParams.get("token"); + + if (urlEmail && urlToken) { + setLocalEmail(urlEmail); + setLocalToken(urlToken); + console.log(localEmail); + console.log(localToken); + setEmail(urlEmail); + setToken(urlToken); + fetchData().catch((error: unknown) => + console.error("Fetch data error:", error), + ); + } + console.log(email); + console.log(token); + }, []); const fetchData = async () => { + setLoading(true); + setError(""); + setFetchSuccess(false); + const startTime = Date.now(); try { const encodedEmail = encodeURIComponent(email); const encodedToken = encodeURIComponent(token); @@ -42,119 +126,79 @@ export const App: React.FC = () => { if (!response.ok) { throw new Error("Network response was not ok"); } - const userDataResponse = (await response.json()) as UserData; + const userDataResponse: UserResponse = + (await response.json()) as UserResponse; console.log("API Response:", userDataResponse); - setUserData(userDataResponse); - setError(null); - setIsDataFetched(true); + + const extractedUserData: UserData = { + User: { + "User ID": userDataResponse.user.ID || "None", + Email: userDataResponse.user.email || "None", + "Creation time": + new Date( + userDataResponse.user.creationTime / 1000, + ).toLocaleString() || "None", + }, + Storage: { + Total: userDataResponse.subscription.storage + ? userDataResponse.subscription.storage >= 1024 ** 3 + ? `${(userDataResponse.subscription.storage / 1024 ** 3).toFixed(2)} GB` + : `${(userDataResponse.subscription.storage / 1024 ** 2).toFixed(2)} MB` + : "None", + Consumed: + userDataResponse.details?.usage !== undefined + ? userDataResponse.details.usage >= 1024 ** 3 + ? `${(userDataResponse.details.usage / 1024 ** 3).toFixed(2)} GB` + : `${(userDataResponse.details.usage / 1024 ** 2).toFixed(2)} MB` + : "None", + Bonus: + userDataResponse.details?.storageBonus !== undefined + ? userDataResponse.details.storageBonus >= 1024 ** 3 + ? `${(userDataResponse.details.storageBonus / 1024 ** 3).toFixed(2)} GB` + : `${(userDataResponse.details.storageBonus / 1024 ** 2).toFixed(2)} MB` + : "None", + }, + Subscription: { + "Product ID": + userDataResponse.subscription.productID || "None", + Provider: + userDataResponse.subscription.paymentProvider || "None", + "Expiry time": + new Date( + userDataResponse.subscription.expiryTime / 1000, + ).toLocaleString() || "None", + }, + Security: { + "Email MFA": userDataResponse.details?.profileData + .isEmailMFAEnabled + ? "Enabled" + : "Disabled", + "Two factor 2FA": userDataResponse.details?.profileData + .isTwoFactorEnabled + ? "Enabled" + : "Disabled", + Passkeys: "None", + }, + }; + + const elapsedTime = Date.now() - startTime; + const delay = Math.max(3000 - elapsedTime, 0); + setTimeout(() => { + setLoading(false); + setFetchSuccess(true); + setUserData(extractedUserData); + }, delay); } catch (error) { console.error("Error fetching data:", error); - setError((error as Error).message); - setIsDataFetched(false); + const elapsedTime = Date.now() - startTime; + const delay = Math.max(3000 - elapsedTime, 0); + setTimeout(() => { + setLoading(false); + setError("Invalid token or email id"); + }, delay); } }; - const renderAttributes = ( - data: Record | User | null, - ): React.ReactNode => { - if (!data) return null; - - const nullAttributes: string[] = []; - - const rows = Object.entries(data).map(([key, value]) => { - console.log("Processing key:", key, "value:", value); - - if ( - typeof value === "object" && - value !== null && - !Array.isArray(value) - ) { - return ( - - - - {key.toUpperCase()} - - - {renderAttributes( - value as Record | User, - )} - - ); - } else { - if (value === null) { - nullAttributes.push(key); - } - - let displayValue: React.ReactNode; - if (key === "expiryTime" && typeof value === "number") { - displayValue = new Date(value / 1000).toLocaleString(); - } else if ( - key === "creationTime" && - typeof value === "number" - ) { - displayValue = new Date(value / 1000).toLocaleString(); - } else if (key === "storage" && typeof value === "number") { - displayValue = `${(value / 1024 ** 3).toFixed(2)} GB`; - } else if (typeof value === "string") { - try { - const parsedValue = JSON.parse( - value, - ) as React.ReactNode; - displayValue = parsedValue; - } catch (error) { - displayValue = value; - } - } else if (typeof value === "object" && value !== null) { - displayValue = JSON.stringify(value, null, 2); - } else if (value === null) { - displayValue = "null"; - } else if ( - typeof value === "boolean" || - typeof value === "number" - ) { - displayValue = value.toString(); - } else if (typeof value === "undefined") { - displayValue = "undefined"; - } else { - displayValue = value as string; - } - - return ( - - - {key} - - - {displayValue} - - - ); - } - }); - - console.log("Attributes with null values:", nullAttributes); - - return rows; - }; - const handleKeyPress = (event: React.KeyboardEvent) => { if (event.key === "Enter") { event.preventDefault(); @@ -164,94 +208,134 @@ export const App: React.FC = () => { } }; + const handleTabChange = ( + _event: React.SyntheticEvent, + newValue: number, + ) => { + setTabValue(newValue); + }; + return ( -
-

{S.hello}

+
-
-
+ + ); }; diff --git a/infra/staff/src/components/UserComponent.tsx b/infra/staff/src/components/UserComponent.tsx new file mode 100644 index 0000000000..ec794f10ef --- /dev/null +++ b/infra/staff/src/components/UserComponent.tsx @@ -0,0 +1,369 @@ +import DeleteIcon from "@mui/icons-material/Delete"; +import EditIcon from "@mui/icons-material/Edit"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; + +import Grid from "@mui/material/Grid"; +import IconButton from "@mui/material/IconButton"; +import Paper from "@mui/material/Paper"; +import Switch from "@mui/material/Switch"; +import Table from "@mui/material/Table"; +import TableBody from "@mui/material/TableBody"; +import TableCell from "@mui/material/TableCell"; +import TableContainer from "@mui/material/TableContainer"; +import TableRow from "@mui/material/TableRow"; +import Typography from "@mui/material/Typography"; +import * as React from "react"; +import ChangeEmail from "./ChangeEmail"; +import DeleteAccount from "./DeleteAccont"; +import Disable2FA from "./Disable2FA"; +import DisablePasskeys from "./DisablePasskeys"; +import UpdateSubscription from "./UpdateSubscription"; +export interface UserData { + User: Record; + Storage: Record; + Subscription: Record; + Security: Record; +} + +interface UserComponentProps { + userData: UserData | null; +} + +const UserComponent: React.FC = ({ userData }) => { + const [deleteAccountOpen, setDeleteAccountOpen] = React.useState(false); + const [disable2FAOpen, setDisable2FAOpen] = React.useState(false); + const [twoFactorEnabled, setTwoFactorEnabled] = React.useState(false); + const [is2FADisabled, setIs2FADisabled] = React.useState(false); + const [updateSubscriptionOpen, setUpdateSubscriptionOpen] = + React.useState(false); + const [changeEmailOpen, setChangeEmailOpen] = React.useState(false); // State for ChangeEmail dialog + const [DisablePasskeysOpen, setDisablePasskeysOpen] = React.useState(false); + + React.useEffect(() => { + if (userData?.Security["Two factor 2FA"] === "Enabled") { + setTwoFactorEnabled(true); + } else { + setTwoFactorEnabled(false); + } + }, [userData]); + + const handleEditEmail = () => { + console.log("Edit Email clicked"); + setChangeEmailOpen(true); + }; + + const handleCloseChangeEmail = () => { + setChangeEmailOpen(false); // Close ChangeEmail dialog + }; + + const handleDeleteAccountClick = () => { + setDeleteAccountOpen(true); + }; + + const handleCloseDeleteAccount = () => { + setDeleteAccountOpen(false); + }; + + const handleOpenDisable2FA = () => { + setDisable2FAOpen(true); + }; + + const handleCloseDisable2FA = () => { + setDisable2FAOpen(false); + }; + + const handleDisable2FA = () => { + setIs2FADisabled(true); + }; + + const handleCancelDisable2FA = () => { + setTwoFactorEnabled(true); + handleCloseDisable2FA(); + }; + + const handleEditSubscription = () => { + setUpdateSubscriptionOpen(true); + }; + + const handleCloseUpdateSubscription = () => { + setUpdateSubscriptionOpen(false); + }; + + const handleOpenDisablePasskeys = () => { + setDisablePasskeysOpen(true); // Open the CloseFamily dialog + }; + + const handleCloseDisablePasskeys = () => { + setDisablePasskeysOpen(false); // Close the CloseFamily dialog + }; + + const handleDisablePasskeys = () => { + // Implement your logic to close family here + console.log("Close family action"); + handleOpenDisablePasskeys(); // Open CloseFamily dialog after closing family + }; + + if (!userData) { + return null; + } + + return ( + + {Object.entries(userData).map(([title, data]) => ( + + + + + {title} + + {title === "User" && ( + + + + )} + {title === "Subscription" && ( + + + + )} + + + + + {Object.entries( + data as Record, + ).map(([label, value], index) => ( + + + {label} + + + {label === "Email" ? ( + + + {value} + + + + + + ) : label === "Passkeys" ? ( + + ) : typeof value === "string" ? ( + label === "Two factor 2FA" ? ( + is2FADisabled || + value === "Disabled" ? ( + + {value} + + ) : ( + + + {value} + + {value === + "Enabled" && ( + { + const isChecked = + e + .target + .checked; + setTwoFactorEnabled( + isChecked, + ); + if ( + !isChecked + ) { + handleOpenDisable2FA(); + } + }} + sx={{ + "& .MuiSwitch-switchBase.Mui-checked": + { + color: "#00B33C", + "&:hover": + { + backgroundColor: + "rgba(0, 179, 60, 0.08)", + }, + }, + "& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track": + { + backgroundColor: + "#00B33C", + }, + }} + /> + )} + + ) + ) : ( + + {value} + + ) + ) : ( + + {String(value)} + + )} + + + ))} + +
+
+
+ ))} + + {/* Render DeleteAccount dialog */} + + + {/* Render Disable2FA dialog */} + + + {/* Render UpdateSubscription dialog */} + + + {/* Render ChangeEmail dialog */} + + + {/* Render Passkeys Dialog */} + +
+ ); +}; + +export default UserComponent; diff --git a/infra/staff/src/components/duckie.png b/infra/staff/src/components/duckie.png new file mode 100644 index 0000000000..7453b60207 Binary files /dev/null and b/infra/staff/src/components/duckie.png differ diff --git a/infra/staff/src/main.tsx b/infra/staff/src/main.tsx index 528729a238..162cfad3cf 100644 --- a/infra/staff/src/main.tsx +++ b/infra/staff/src/main.tsx @@ -1,6 +1,6 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import { App } from "./App"; +import App from "./App"; import "./styles/globals.css"; const root = document.getElementById("root");