diff --git a/client/package-lock.json b/client/package-lock.json index 0dc09e06..edc3d7ba 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -18,17 +18,21 @@ "date-fns": "^2.29.3", "date-fns-tz": "^2.0.0", "dompurify": "^2.3.3", + "file-saver": "^2.0.5", "focus-trap-react": "^10.1.1", "frappe-gantt": "^0.5.0", "html-react-parser": "^1.2.7", "js-cookie": "^2.2.1", "marked": "^4.0.10", + "papaparse": "^5.4.1", "prop-types": "^15.7.2", + "qs": "^6.11.2", "query-string": "^6.14.1", "react": "^17.0.2", "react-big-calendar": "^0.38.1", "react-circular-progressbar": "^2.1.0", "react-color": "^2.19.3", + "react-cool-inview": "^3.0.1", "react-datepicker": "^4.12.0", "react-day-picker": "^8.6.0", "react-dom": "^17.0.2", @@ -47,14 +51,18 @@ "style-it": "^2.1.4", "typescript": "^4.9.5", "validator": "^13.7.0", - "web-vitals": "^0.2.4" + "web-vitals": "^0.2.4", + "zod": "^3.22.4" }, "devDependencies": { "@types/date-and-time": "^0.13.0", "@types/dompurify": "^3.0.0", + "@types/file-saver": "^2.0.6", "@types/js-cookie": "^3.0.3", "@types/marked": "^4.0.8", "@types/node": "^18.14.0", + "@types/papaparse": "^5.3.14", + "@types/qs": "^6.9.10", "@types/react": "^18.0.28", "@types/react-datepicker": "^4.11.2", "@types/react-dom": "^18.0.11", @@ -315,11 +323,11 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" @@ -345,9 +353,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1202,9 +1210,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "optional": true, "peer": true, @@ -1214,9 +1222,9 @@ } }, "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "optional": true, "peer": true, @@ -1515,6 +1523,12 @@ "@types/trusted-types": "*" } }, + "node_modules/@types/file-saver": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.6.tgz", + "integrity": "sha512-Mw671DVqoMHbjw0w4v2iiOro01dlT/WhWp5uwecBa0Wg8c+bcZOjgF1ndBnlaxhtvFCgTRBtsGivSVhrK/vnag==", + "dev": true + }, "node_modules/@types/history": { "version": "4.7.11", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", @@ -1606,6 +1620,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==" }, + "node_modules/@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -1617,6 +1640,12 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "node_modules/@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, "node_modules/@types/react": { "version": "18.0.28", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", @@ -1783,9 +1812,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "optional": true, "peer": true, @@ -2220,9 +2249,9 @@ } }, "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/date-and-time": { "version": "0.14.2", @@ -2590,6 +2619,11 @@ "reusify": "^1.0.4" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3772,6 +3806,11 @@ "wrappy": "1" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4047,6 +4086,20 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/query-string": { "version": "6.14.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", @@ -4142,6 +4195,14 @@ "react": "*" } }, + "node_modules/react-cool-inview": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-cool-inview/-/react-cool-inview-3.0.1.tgz", + "integrity": "sha512-ly6i3Pv5p0fvm12NmJGfKS34eOhA+iU43Th+gZ6t3G6UwsxQsWoITHTHzA9pdkOc/3VmnReqvC/hJkQUDGhQFA==", + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/react-datepicker": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.12.0.tgz", @@ -4925,15 +4986,15 @@ } }, "node_modules/terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", + "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", "dev": true, "optional": true, "peer": true, "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -5280,6 +5341,14 @@ "engines": { "node": ">= 6" } + }, + "node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } }, "dependencies": { @@ -5472,11 +5541,11 @@ } }, "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.15" } }, "@babel/helper-module-transforms": { @@ -5496,9 +5565,9 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true }, "@babel/helper-simple-access": { @@ -6045,9 +6114,9 @@ "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" }, "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "optional": true, "peer": true, @@ -6057,9 +6126,9 @@ }, "dependencies": { "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "optional": true, "peer": true, @@ -6300,6 +6369,12 @@ "@types/trusted-types": "*" } }, + "@types/file-saver": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.6.tgz", + "integrity": "sha512-Mw671DVqoMHbjw0w4v2iiOro01dlT/WhWp5uwecBa0Wg8c+bcZOjgF1ndBnlaxhtvFCgTRBtsGivSVhrK/vnag==", + "dev": true + }, "@types/history": { "version": "4.7.11", "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", @@ -6384,6 +6459,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.0.tgz", "integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==" }, + "@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -6395,6 +6479,12 @@ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "@types/qs": { + "version": "6.9.10", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", + "integrity": "sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==", + "dev": true + }, "@types/react": { "version": "18.0.28", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", @@ -6551,9 +6641,9 @@ } }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "optional": true, "peer": true @@ -6835,9 +6925,9 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" }, "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "date-and-time": { "version": "0.14.2", @@ -7116,6 +7206,11 @@ "reusify": "^1.0.4" } }, + "file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -7972,6 +8067,11 @@ "wrappy": "1" } }, + "papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -8151,6 +8251,14 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "requires": { + "side-channel": "^1.0.4" + } + }, "query-string": { "version": "6.14.1", "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.14.1.tgz", @@ -8214,6 +8322,12 @@ "tinycolor2": "^1.4.1" } }, + "react-cool-inview": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-cool-inview/-/react-cool-inview-3.0.1.tgz", + "integrity": "sha512-ly6i3Pv5p0fvm12NmJGfKS34eOhA+iU43Th+gZ6t3G6UwsxQsWoITHTHzA9pdkOc/3VmnReqvC/hJkQUDGhQFA==", + "requires": {} + }, "react-datepicker": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.12.0.tgz", @@ -8808,15 +8922,15 @@ } }, "terser": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", - "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.22.0.tgz", + "integrity": "sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==", "dev": true, "optional": true, "peer": true, "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -9040,6 +9154,11 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "peer": true + }, + "zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==" } } } diff --git a/client/package.json b/client/package.json index d6f2e021..8d607d11 100644 --- a/client/package.json +++ b/client/package.json @@ -19,17 +19,21 @@ "date-fns": "^2.29.3", "date-fns-tz": "^2.0.0", "dompurify": "^2.3.3", + "file-saver": "^2.0.5", "focus-trap-react": "^10.1.1", "frappe-gantt": "^0.5.0", "html-react-parser": "^1.2.7", "js-cookie": "^2.2.1", "marked": "^4.0.10", + "papaparse": "^5.4.1", "prop-types": "^15.7.2", + "qs": "^6.11.2", "query-string": "^6.14.1", "react": "^17.0.2", "react-big-calendar": "^0.38.1", "react-circular-progressbar": "^2.1.0", "react-color": "^2.19.3", + "react-cool-inview": "^3.0.1", "react-datepicker": "^4.12.0", "react-day-picker": "^8.6.0", "react-dom": "^17.0.2", @@ -48,7 +52,8 @@ "style-it": "^2.1.4", "typescript": "^4.9.5", "validator": "^13.7.0", - "web-vitals": "^0.2.4" + "web-vitals": "^0.2.4", + "zod": "^3.22.4" }, "eslintConfig": { "extends": [ @@ -72,9 +77,12 @@ "devDependencies": { "@types/date-and-time": "^0.13.0", "@types/dompurify": "^3.0.0", + "@types/file-saver": "^2.0.6", "@types/js-cookie": "^3.0.3", "@types/marked": "^4.0.8", "@types/node": "^18.14.0", + "@types/papaparse": "^5.3.14", + "@types/qs": "^6.9.10", "@types/react": "^18.0.28", "@types/react-datepicker": "^4.11.2", "@types/react-dom": "^18.0.11", diff --git a/client/src/Conductor.jsx b/client/src/Conductor.jsx index 019fdba4..240d988a 100644 --- a/client/src/Conductor.jsx +++ b/client/src/Conductor.jsx @@ -40,7 +40,7 @@ import ProjectsFlagged from './components/projects/ProjectsFlagged'; import ProjectsPortal from './components/projects/ProjectsPortal'; import ProjectTimeline from './components/projects/ProjectTimeline'; import ProjectView from './components/projects/ProjectView'; -import Search from './components/search/Search'; +const Search = lazy(() => import('./screens/conductor/Search')); import UserDetails from './components/controlpanel/UserDetails'; import UsersManager from './components/controlpanel/UsersManager'; import LoadingSpinner from './components/LoadingSpinner'; @@ -87,7 +87,7 @@ const Conductor = () => { - {/**/} + diff --git a/client/src/Platform.jsx b/client/src/Platform.jsx index 470c96e0..b8bd0311 100644 --- a/client/src/Platform.jsx +++ b/client/src/Platform.jsx @@ -49,6 +49,7 @@ const Platform = () => { "/homework", "/underdevelopment", "/libraries", + "/search-results", ]; const standalonePaths = [ "/adopt", diff --git a/client/src/api.ts b/client/src/api.ts new file mode 100644 index 00000000..7f3ffbdb --- /dev/null +++ b/client/src/api.ts @@ -0,0 +1,304 @@ +import axios from "axios"; +import { + AssetTagFramework, + AssetTagFrameworkWithCampusDefault, + Book, + CentralIdentityLicense, + CentralIdentityOrg, + ConductorBaseResponse, + Homework, + Project, + ProjectFile, + User, +} from "./types"; +import { + CIDDescriptor, + ProjectFileWProjectID, + ProjectTag, +} from "./types/Project"; + +/** + * @fileoverview + * We don't create an Axios instance here because not all api calls + * have been converted to use this class yet, but we still want global config to apply + */ + +class API { + // ASSET TAGS FRAMEWORKS + async getFrameworks({ + page, + limit, + sort, + query, + }: { + page?: number; + limit?: number; + sort?: string; + query?: string; + }) { + const res = await axios.get< + { + frameworks: AssetTagFrameworkWithCampusDefault[]; + totalCount: number; + } & ConductorBaseResponse + >("/assettagframeworks", { + params: { + page, + limit, + sort, + query, + }, + }); + return res; + } + + async getFramework(id: string) { + const res = await axios.get< + { + framework: AssetTagFramework; + } & ConductorBaseResponse + >(`/assettagframeworks/${id}`); + return res; + } + + async getCampusDefaultFramework(orgID: string) { + const res = await axios.get< + { + framework: AssetTagFramework | null; + } & ConductorBaseResponse + >(`/assettagframeworks/campusdefault/${orgID}`); + return res; + } + + async createFramework(framework: AssetTagFramework) { + const res = await axios.post< + { + framework: AssetTagFramework; + } & ConductorBaseResponse + >("/assettagframeworks", framework); + return res; + } + + async updateFramework(framework: AssetTagFramework) { + const res = await axios.patch< + { + framework: AssetTagFramework; + } & ConductorBaseResponse + >(`/assettagframeworks/${framework.uuid}`, framework); + return res; + } + + async setAsCampusDefaultFramework(orgID: string, frameworkID: string) { + const res = await axios.put(`/org/${orgID}`, { + defaultAssetTagFrameworkUUID: frameworkID, + }); + return res; + } + + // Central Identity + async getCentralIdentityOrgs({ + activePage, + limit, + query, + }: { + activePage?: number; + limit?: number; + query?: string; + }) { + const res = await axios.get< + { + orgs: CentralIdentityOrg[]; + totalCount: number; + } & ConductorBaseResponse + >("/central-identity/orgs", { + params: { + activePage, + limit, + query, + }, + }); + return res; + } + + async getCentralIdentityLicenses() { + const res = await axios.get< + { + licenses: CentralIdentityLicense[]; + } & ConductorBaseResponse + >("/central-identity/licenses"); + return res; + } + + // Commons + async getCommonsCatalog(paramsObj?: { activePage?: number; limit?: number }) { + const res = await axios.get< + { + books: Book[]; + numFound: number; + numTotal: number; + } & ConductorBaseResponse + >("/commons/catalog", { + params: paramsObj, + }); + return res; + } + + // Search + async conductorSearch({ + searchQuery, + projLocation, + projStatus, + projVisibility, + projSort, + bookSort, + hwSort, + userSort, + activePage, + limit, + }: { + searchQuery?: string; + projLocation?: string; + projStatus?: string; + projVisibility?: string; + projSort?: string; + bookSort?: string; + hwSort?: string; + userSort?: string; + activePage?: number; + limit?: number; + }) { + const res = await axios.get< + { + numResults: number; + results: { + projects: Project[]; + books: Book[]; + files: ProjectFileWProjectID[]; + homework: Homework[]; + users: User[]; + }; + } & ConductorBaseResponse + >("/search", { + params: { + searchQuery, + projLocation, + projStatus, + projVisibility, + projSort, + bookSort, + hwSort, + userSort, + activePage, + limit, + }, + }); + return res; + } + + //Projects + async getPublicProjects(params?: { page?: number; limit?: number }) { + const res = await axios.get< + { + projects: Project[]; + totalCount: number; + } & ConductorBaseResponse + >("/projects/public", { + params, + }); + return res; + } + async getProject(projectID: string) { + const res = await axios.get("/project", { + params: { + projectID, + }, + }); + return res; + } + + async deleteProject(projectID: string) { + const res = await axios.delete(`/project/${projectID}`); + return res; + } + + async getTags() { + const res = await axios.get<{ tags: ProjectTag[] } & ConductorBaseResponse>( + "projects/tags/org" + ); + return res; + } + + async getCIDDescriptors(detailed?: boolean) { + const res = await axios.get< + { + descriptors: CIDDescriptor[]; + } & ConductorBaseResponse + >("/c-ids", { + params: { + detailed, + }, + }); + return res; + } + + async getProjectFiles(projectID: string, folderID?: string) { + const res = await axios.get< + { + files: ProjectFile[]; + path: { fileID: string; name: string }[]; + } & ConductorBaseResponse + >(`/project/${projectID}/files/content/${folderID ? folderID : ""}`); + return res; + } + + async getProjectFile(projectID: string, fileID: string) { + const res = await axios.get< + { + file: ProjectFile; + } & ConductorBaseResponse + >(`/project/${projectID}/files/${fileID}`); + return res; + } + + async getFileDownloadURL( + projectID: string, + fileID: string, + shouldIncrement?: boolean + ) { + const res = await axios.get< + { + url: string; + } & ConductorBaseResponse + >(`/project/${projectID}/files/${fileID}/download`, { + params: { + shouldIncrement, + }, + }); + return res; + } + + async bulkDownloadFiles(projectID: string, fileIDs: string[]) { + const arrQuery = fileIDs.map((id) => `fileID=${id}`).join(`&`); + const res = await axios.get(`/project/${projectID}/files/bulk`, { + params: { + fileIDs: arrQuery, + }, + responseType: "blob", + }); + return res; + } + + async getPublicProjectFiles(params?: { page?: number; limit?: number }) { + const res = await axios.get< + { + files: ProjectFileWProjectID[]; + totalCount: number; + } & ConductorBaseResponse + >("/projects/files/public", { + params, + }); + return res; + } +} + +export default new API(); diff --git a/client/src/components/ControlledInputs/CtlCheckbox.tsx b/client/src/components/ControlledInputs/CtlCheckbox.tsx index bd379c9c..c27ba673 100644 --- a/client/src/components/ControlledInputs/CtlCheckbox.tsx +++ b/client/src/components/ControlledInputs/CtlCheckbox.tsx @@ -9,7 +9,7 @@ import { ControlledInputProps } from "../../types"; interface CtlCheckboxProps extends CheckboxProps { label?: string; - labelDirection?: "col" | "row"; + labelDirection?: "col" | "row" | "col-reverse" | "row-reverse"; required?: boolean; negated?: boolean; } @@ -51,7 +51,7 @@ export default function CtlCheckbox< fieldState: { error }, }) => (
{label && (