mirror of
https://github.com/lemeow125/Borrowing-TrackerFrontend.git
synced 2024-11-17 06:19:27 +08:00
Merge pull request 'feature/student_pages' (#1) from feature/student_pages into master
Reviewed-on: https://git.keannu1.duckdns.org/keannu125/Borrowing-TrackerFrontend/pulls/1
This commit is contained in:
commit
8e51dc0abd
20 changed files with 1817 additions and 20 deletions
478
package-lock.json
generated
478
package-lock.json
generated
|
@ -13,6 +13,7 @@
|
|||
"@mui/material": "^5.14.17",
|
||||
"@mui/styled-engine": "^5.14.17",
|
||||
"@mui/styled-engine-sc": "^6.0.0-alpha.5",
|
||||
"@react-pdf/renderer": "^3.1.14",
|
||||
"@reduxjs/toolkit": "^1.9.7",
|
||||
"@tanstack/react-query": "^5.8.3",
|
||||
"axios": "^1.6.2",
|
||||
|
@ -1431,6 +1432,167 @@
|
|||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/fns": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/fns/-/fns-2.0.1.tgz",
|
||||
"integrity": "sha512-/vgecczzFYBQFkgUupH+sxXhLWQtBwdwCgweyh25XOlR4NZuaMD/UVUDl4loFHhRQqDMQq37lkTcchh7zzW6ug==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/font": {
|
||||
"version": "2.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/font/-/font-2.3.7.tgz",
|
||||
"integrity": "sha512-NoCieWea6c1mCpDBoyjPbUEC1qXa+S/M7+8vYPZ71aTMgX7co3gQc2e6YKwrSQeQP+BsBq3LSVhjI2ETXfcytw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/types": "^2.3.4",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"fontkit": "^2.0.2",
|
||||
"is-url": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/image": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/image/-/image-2.2.2.tgz",
|
||||
"integrity": "sha512-990JvRZuhsnHyAGd7gvmhfr+4/5PAHLH9IgDstaEDLEq2eFAIQFuNM7k3D6kjKgV1mM7Jqif3CWqrcHBF3jrJw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/png-js": "^2.2.0",
|
||||
"cross-fetch": "^3.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/layout": {
|
||||
"version": "3.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/layout/-/layout-3.6.3.tgz",
|
||||
"integrity": "sha512-w6ACZ9o18Q5wbzsY9a4KW2Gqn6Drt3AN/kb/I6SBz/L7PAJ9rPQBIDq/s5qZJ+/WwWy33rcC8WC1givtDhjCHQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/fns": "2.0.1",
|
||||
"@react-pdf/image": "^2.2.2",
|
||||
"@react-pdf/pdfkit": "^3.0.2",
|
||||
"@react-pdf/primitives": "^3.0.0",
|
||||
"@react-pdf/stylesheet": "^4.1.8",
|
||||
"@react-pdf/textkit": "^4.2.0",
|
||||
"@react-pdf/types": "^2.3.4",
|
||||
"@react-pdf/yoga": "^4.1.2",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"emoji-regex": "^10.2.1",
|
||||
"queue": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/pdfkit": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-3.0.2.tgz",
|
||||
"integrity": "sha512-+m5rwNCwyEH6lmnZWpsQJvdqb6YaCCR0nMWrc/KKDwznuPMrGmGWyNxqCja+bQPORcHZyl6Cd/iFL0glyB3QGw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/png-js": "^2.2.0",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"crypto-js": "^4.0.0",
|
||||
"fontkit": "^2.0.2",
|
||||
"vite-compatible-readable-stream": "^3.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/png-js": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-2.2.0.tgz",
|
||||
"integrity": "sha512-csZU5lfNW73tq7s7zB/1rWXGro+Z9cQhxtsXwxS418TSszHUiM6PwddouiKJxdGhbVLjRIcuuFVa0aR5cDOC6w==",
|
||||
"dependencies": {
|
||||
"browserify-zlib": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/primitives": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/primitives/-/primitives-3.0.1.tgz",
|
||||
"integrity": "sha512-0HGcknrLNwyhxe+SZCBL29JY4M85mXKdvTZE9uhjNbADGgTc8wVnkc5+e4S/lDvugbVISXyuIhZnYwtK9eDnyQ=="
|
||||
},
|
||||
"node_modules/@react-pdf/render": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/render/-/render-3.2.7.tgz",
|
||||
"integrity": "sha512-fAgbbAAkVL0hpcf1vUJLHxuPjPBqZuq8nors7fCwvoatBBwOWP9fza7IDPeFKN7+ZOnfmIZzes8Kc/DNHzJohw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/fns": "2.0.1",
|
||||
"@react-pdf/primitives": "^3.0.0",
|
||||
"@react-pdf/textkit": "^4.2.0",
|
||||
"@react-pdf/types": "^2.3.4",
|
||||
"abs-svg-path": "^0.1.1",
|
||||
"color-string": "^1.5.3",
|
||||
"normalize-svg-path": "^1.1.0",
|
||||
"parse-svg-path": "^0.1.2",
|
||||
"svg-arc-to-cubic-bezier": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/renderer": {
|
||||
"version": "3.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/renderer/-/renderer-3.1.14.tgz",
|
||||
"integrity": "sha512-Qk29uTamH6q+drK/YmiFbuQQ+yutesfIe+wyrsXFoUJUutIiDIaibO6zByMkhWb3M6CMt6NvG3NLHio1OF8U6Q==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/font": "^2.3.7",
|
||||
"@react-pdf/layout": "^3.6.3",
|
||||
"@react-pdf/pdfkit": "^3.0.2",
|
||||
"@react-pdf/primitives": "^3.0.0",
|
||||
"@react-pdf/render": "^3.2.7",
|
||||
"@react-pdf/types": "^2.3.4",
|
||||
"events": "^3.3.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"queue": "^6.0.1",
|
||||
"scheduler": "^0.17.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.6 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/renderer/node_modules/scheduler": {
|
||||
"version": "0.17.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.17.0.tgz",
|
||||
"integrity": "sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/stylesheet": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/stylesheet/-/stylesheet-4.1.8.tgz",
|
||||
"integrity": "sha512-/EuB9RBsH3YYRj8mwzImaul619MvX3rsHNF4h8LnlwDOuBehPA3L/fHrikfPqtJvHqK2ty3GXnkw0HG5SQpMzw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/fns": "2.0.1",
|
||||
"@react-pdf/types": "^2.3.4",
|
||||
"color-string": "^1.5.3",
|
||||
"hsl-to-hex": "^1.0.0",
|
||||
"media-engine": "^1.0.3",
|
||||
"postcss-value-parser": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/textkit": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-4.2.0.tgz",
|
||||
"integrity": "sha512-R90pEOW6NdhUx4p99iROvKmwB06IRYdXMhh0QcmUeoPOLe64ZdMfs3LZliNUWgI5fCmq71J+nv868i/EakFPDg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
"@react-pdf/fns": "2.0.1",
|
||||
"hyphen": "^1.6.4",
|
||||
"unicode-properties": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-pdf/types": {
|
||||
"version": "2.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.3.4.tgz",
|
||||
"integrity": "sha512-vGGz21BTE05EktBbotbd7fjC0Yi8A/lOSIpzd7L7aF1XY+vyIHlQVb35DWCipM1p/6XN4cr9etGAmm1e4Mtmjw=="
|
||||
},
|
||||
"node_modules/@react-pdf/yoga": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-pdf/yoga/-/yoga-4.1.2.tgz",
|
||||
"integrity": "sha512-OlMZkFrJDj4GyKZ70thiObwwPVZ52B7mlPyfzwa+sgwsioqHXg9nMWOO+7SQFNUbbOGagMUu0bCuTv+iXYZuaQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13"
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "1.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.7.tgz",
|
||||
|
@ -1462,6 +1624,15 @@
|
|||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.4.36",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.36.tgz",
|
||||
"integrity": "sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==",
|
||||
"dependencies": {
|
||||
"legacy-swc-helpers": "npm:@swc/helpers@=0.4.14",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.8.3.tgz",
|
||||
|
@ -1824,6 +1995,11 @@
|
|||
"vite": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/abs-svg-path": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz",
|
||||
"integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA=="
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
|
||||
|
@ -1931,6 +2107,25 @@
|
|||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
@ -1953,6 +2148,22 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/brotli": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
|
||||
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-zlib": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
|
||||
"integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
|
||||
"dependencies": {
|
||||
"pako": "~1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.22.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
|
||||
|
@ -2034,6 +2245,14 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
|
||||
|
@ -2055,6 +2274,15 @@
|
|||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
||||
},
|
||||
"node_modules/color-string": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
|
@ -2093,6 +2321,14 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-fetch": {
|
||||
"version": "3.1.8",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
|
||||
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
|
@ -2107,6 +2343,11 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
||||
},
|
||||
"node_modules/css-color-keywords": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
|
||||
|
@ -2161,6 +2402,11 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dfa": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
|
||||
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
|
@ -2200,6 +2446,11 @@
|
|||
"integrity": "sha512-dg5gj5qOgfZNkPNeyKBZQAQitIQ/xwfIDmEQJHCbXaD9ebTZxwJXUsDYcBlAvZGZLi+/354l35J1wkmP6CqYaw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz",
|
||||
"integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw=="
|
||||
},
|
||||
"node_modules/error-ex": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
|
@ -2522,11 +2773,18 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/events": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"engines": {
|
||||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.1",
|
||||
|
@ -2661,6 +2919,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fontkit": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.2.tgz",
|
||||
"integrity": "sha512-jc4k5Yr8iov8QfS6u8w2CnHWVmbOGtdBtOXMze5Y+QD966Rx6PEVWXSEGwXlsDlKtu1G12cJjcsybnqhSk/+LA==",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.4.2",
|
||||
"brotli": "^1.3.2",
|
||||
"clone": "^2.1.2",
|
||||
"dfa": "^1.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"restructure": "^3.0.0",
|
||||
"tiny-inflate": "^1.0.3",
|
||||
"unicode-properties": "^1.4.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
|
@ -2810,6 +3084,24 @@
|
|||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/hsl-to-hex": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hsl-to-hex/-/hsl-to-hex-1.0.0.tgz",
|
||||
"integrity": "sha512-K6GVpucS5wFf44X0h2bLVRDsycgJmf9FF2elg+CrqD8GcFU8c6vYhgXn8NjUkFCwj+xDFb70qgLbTUm6sxwPmA==",
|
||||
"dependencies": {
|
||||
"hsl-to-rgb-for-reals": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hsl-to-rgb-for-reals": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/hsl-to-rgb-for-reals/-/hsl-to-rgb-for-reals-1.1.1.tgz",
|
||||
"integrity": "sha512-LgOWAkrN0rFaQpfdWBQlv/VhkOxb5AsBjk6NQVx4yEzWS923T07X0M1Y0VNko2H52HeSpZrZNNMJ0aFqsdVzQg=="
|
||||
},
|
||||
"node_modules/hyphen": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.10.0.tgz",
|
||||
"integrity": "sha512-fXWGrQ2EMwMjf7rfy2MtLkr1HjcOcJLZMvQybMDBECPaX7qgERc1tC8M4Dj2fHJldTcFy3KDIWThUWVM/NBzwg=="
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
|
@ -2865,8 +3157,7 @@
|
|||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
|
@ -2923,6 +3214,11 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-url": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
|
||||
"integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
|
@ -3002,6 +3298,15 @@
|
|||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/legacy-swc-helpers": {
|
||||
"name": "@swc/helpers",
|
||||
"version": "0.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz",
|
||||
"integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/levn": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||
|
@ -3061,6 +3366,11 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/media-engine": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/media-engine/-/media-engine-1.0.3.tgz",
|
||||
"integrity": "sha512-aa5tG6sDoK+k70B9iEX1NeyfT8ObCKhNDs6lJVpwF6r8vhUfuKMslIcirq6HIUYuuUYLefcEQOn9bSBOvawtwg=="
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
|
@ -3143,12 +3453,39 @@
|
|||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.13",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
|
||||
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/normalize-svg-path": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-svg-path/-/normalize-svg-path-1.1.0.tgz",
|
||||
"integrity": "sha512-r9KHKG2UUeB5LoTouwDzBy2VxXlHsiM6fyLQvnJa0S5hrhzqElH/CH7TUGhT1fVvIYBIKf3OpY4YJ4CK+iaqHg==",
|
||||
"dependencies": {
|
||||
"svg-arc-to-cubic-bezier": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
@ -3213,6 +3550,11 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
|
@ -3241,6 +3583,11 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-svg-path": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz",
|
||||
"integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ=="
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
|
@ -3368,6 +3715,14 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/queue": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
|
||||
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
|
||||
"dependencies": {
|
||||
"inherits": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
@ -3582,6 +3937,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.0.tgz",
|
||||
"integrity": "sha512-Xj8/MEIhhfj9X2rmD9iJ4Gga9EFqVlpMj3vfLnV2r/Mh5jRMryNV+6lWh9GdJtDBcBSPIqzRdfBQ3wDtNFv/uw=="
|
||||
},
|
||||
"node_modules/reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
|
@ -3646,6 +4006,25 @@
|
|||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
|
@ -3713,6 +4092,19 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle/node_modules/is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||
},
|
||||
"node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
|
@ -3738,6 +4130,14 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
|
@ -3821,12 +4221,22 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/svg-arc-to-cubic-bezier": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/svg-arc-to-cubic-bezier/-/svg-arc-to-cubic-bezier-3.2.0.tgz",
|
||||
"integrity": "sha512-djbJ/vZKZO+gPoSDThGNpKDO+o+bAeA4XQKovvkNCqnIS2t+S4qnLAGQhyyrulhCFRl1WWzAp0wUDV8PpTVU3g=="
|
||||
},
|
||||
"node_modules/text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tiny-inflate": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
@ -3847,6 +4257,11 @@
|
|||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
|
||||
|
@ -3901,6 +4316,29 @@
|
|||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-properties": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||
"dependencies": {
|
||||
"pako": "^0.2.5",
|
||||
"tiny-inflate": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie/node_modules/pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||
|
@ -3948,6 +4386,11 @@
|
|||
"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",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
|
||||
|
@ -4003,6 +4446,33 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vite-compatible-readable-stream": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/vite-compatible-readable-stream/-/vite-compatible-readable-stream-3.6.1.tgz",
|
||||
"integrity": "sha512-t20zYkrSf868+j/p31cRIGN28Phrjm3nRSLR2fyc2tiWi4cZGVdv68yNlwnIINTkMTmPoMiSlc0OadaO7DXZaQ==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"@mui/material": "^5.14.17",
|
||||
"@mui/styled-engine": "^5.14.17",
|
||||
"@mui/styled-engine-sc": "^6.0.0-alpha.5",
|
||||
"@react-pdf/renderer": "^3.1.14",
|
||||
"@reduxjs/toolkit": "^1.9.7",
|
||||
"@tanstack/react-query": "^5.8.3",
|
||||
"axios": "^1.6.2",
|
||||
|
|
23
src/App.tsx
23
src/App.tsx
|
@ -18,6 +18,8 @@ import EquipmentInstanceLogsPage from "./Pages/EquipmentInstanceLogsPage/Equipme
|
|||
import EquipmentInstancesFilteredListPage from "./Pages/EquipmentInstancesListPage/EquipmentInstancesFilteredListPage";
|
||||
import RestrictedPage from "./Components/RestrictedPage/RestrictedPage";
|
||||
import TransactionsListPage from "./Pages/TransactionsListPage/TransactionsListPage";
|
||||
import AddTransactionPage from "./Pages/AddTransactionPage/AddTransactionPage";
|
||||
import TransactionPage from "./Pages/TransactionPage/TransactionPage";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
const router = createHashRouter([
|
||||
|
@ -125,6 +127,27 @@ const router = createHashRouter([
|
|||
),
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
{
|
||||
path: "/new/transaction",
|
||||
element: (
|
||||
<>
|
||||
<Revalidator />
|
||||
<RestrictedPage allow_only="Student" />
|
||||
<AddTransactionPage />
|
||||
</>
|
||||
),
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
{
|
||||
path: "/view/transaction/:id",
|
||||
element: (
|
||||
<>
|
||||
<Revalidator />
|
||||
<TransactionPage />
|
||||
</>
|
||||
),
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
]);
|
||||
|
||||
export default function App() {
|
||||
|
|
|
@ -19,6 +19,8 @@ import {
|
|||
TransactionListType,
|
||||
TransactionUpdateType,
|
||||
TransactionType,
|
||||
ClearanceType,
|
||||
TransactionCreateType,
|
||||
} from "../Types/Types";
|
||||
|
||||
const debug = true;
|
||||
|
@ -184,6 +186,29 @@ export function ResetPasswordConfirmAPI(info: ResetPasswordConfirmType) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function ClearanceAPI() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get("api/v1/accounts/clearance/", config)
|
||||
.then((response) => {
|
||||
return response.data as ClearanceType;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Error retrieving clearance status for user");
|
||||
});
|
||||
}
|
||||
|
||||
export async function TeachersAPI() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get("api/v1/accounts/teachers/", config)
|
||||
.then((response) => {
|
||||
return response.data as Array<UserType>;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Error retrieving teachers");
|
||||
});
|
||||
}
|
||||
// Equipment APIs
|
||||
|
||||
export async function EquipmentAPI(id: number) {
|
||||
|
@ -330,6 +355,18 @@ export async function EquipmentInstancesAPI() {
|
|||
});
|
||||
}
|
||||
|
||||
export async function AvailableEquipmentInstancesAPI() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get("api/v1/equipments/equipment_instances/available", config)
|
||||
.then((response) => {
|
||||
return response.data as EquipmentInstanceListType;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Error retrieving available equipments");
|
||||
});
|
||||
}
|
||||
|
||||
export async function EquipmentInstanceCreateAPI(
|
||||
equipment_instance: AddEquipmentInstanceType
|
||||
) {
|
||||
|
@ -371,6 +408,19 @@ export async function TransactionAPI(id: number) {
|
|||
});
|
||||
}
|
||||
|
||||
export async function TransactionCreateAPI(transaction: TransactionCreateType) {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.post(`api/v1/transactions/`, transaction, config)
|
||||
.then((response) => {
|
||||
return [true, response.data as TransactionType];
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("Error creating transaction");
|
||||
return [false, ParseError(error)];
|
||||
});
|
||||
}
|
||||
|
||||
export async function TransactionUpdateAPI(
|
||||
transaction: TransactionUpdateType,
|
||||
id: number
|
||||
|
@ -386,3 +436,27 @@ export async function TransactionUpdateAPI(
|
|||
return [false, ParseError(error)];
|
||||
});
|
||||
}
|
||||
|
||||
export async function TransactionsByStudentAPI() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get("api/v1/transactions/student/", config)
|
||||
.then((response) => {
|
||||
return response.data as TransactionListType;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Error retrieving transactions for current student");
|
||||
});
|
||||
}
|
||||
|
||||
export async function TransactionsByTeacherAPI() {
|
||||
const config = await GetConfig();
|
||||
return instance
|
||||
.get("api/v1/transactions/teacher/", config)
|
||||
.then((response) => {
|
||||
return response.data as TransactionListType;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("Error retrieving transactions for current teacher");
|
||||
});
|
||||
}
|
||||
|
|
62
src/Components/DashboardPage/Student/StudentDashboard.tsx
Normal file
62
src/Components/DashboardPage/Student/StudentDashboard.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import styles from "../../../styles";
|
||||
import { Button } from "@mui/material";
|
||||
import AddBoxIcon from "@mui/icons-material/AddBox";
|
||||
import { colors } from "../../../styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
export default function StudentDashboard() {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div style={styles.flex_column}>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Student Actions
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate("/new/transaction");
|
||||
}}
|
||||
>
|
||||
<AddBoxIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
New Transaction
|
||||
</p>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,388 @@
|
|||
import styles from "../../../styles";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
} from "@mui/material";
|
||||
import HourglassBottomIcon from "@mui/icons-material/HourglassBottom";
|
||||
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
||||
import FlashOffIcon from "@mui/icons-material/FlashOff";
|
||||
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
|
||||
import ShoppingCartCheckoutIcon from "@mui/icons-material/ShoppingCartCheckout";
|
||||
import AssignmentReturnedIcon from "@mui/icons-material/AssignmentReturned";
|
||||
import CancelOutlinedIcon from "@mui/icons-material/CancelOutlined";
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
import ClearAllIcon from "@mui/icons-material/ClearAll";
|
||||
|
||||
type props = {
|
||||
filter: string;
|
||||
setFilter: React.Dispatch<React.SetStateAction<string>>;
|
||||
};
|
||||
|
||||
export default function StudentTransactionFilterMenu(props: props) {
|
||||
return (
|
||||
<>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Personal Transactions
|
||||
</p>
|
||||
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<FormControl sx={{ width: "384px" }}>
|
||||
<InputLabel style={{ backgroundColor: "white", padding: 0 }}>
|
||||
Filter Transactions
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={props.filter}
|
||||
onChange={(e: SelectChangeEvent<string>) =>
|
||||
props.setFilter(e.target.value)
|
||||
}
|
||||
>
|
||||
<MenuItem value={""}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ClearAllIcon style={styles.student_filter_item} />
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
}}
|
||||
>
|
||||
All
|
||||
</p>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Pending Approval"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HourglassBottomIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Pending
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Awaiting techncian approval
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Approved"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CheckCircleOutlineIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Approved
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
To be delivered by technician
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Rejected"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CancelOutlinedIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Rejected
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Denied by technician
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Borrowed"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ShoppingCartCheckoutIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
On-Borrow
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Items currently with student
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Cancelled"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CancelIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Cancelled
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Approved but was not delivered to student
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Returned: Pending Checking"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<AssignmentReturnedIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Returned: Pending
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Being checked for any breakages
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"Finalized"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CheckCircleIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Finalized
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
Completed transaction without breakages
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
<MenuItem value={"With Breakages: Pending Resolution"}>
|
||||
<Button
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<FlashOffIcon style={styles.student_filter_item} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
}}
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
With Breakages
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_XS,
|
||||
...{ margin: 0, textAlign: "left" },
|
||||
}}
|
||||
>
|
||||
With broken items awaiting reimbursement
|
||||
</p>
|
||||
</div>
|
||||
</Button>
|
||||
</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { TransactionsByStudentAPI } from "../../API/API";
|
||||
import styles from "../../../styles";
|
||||
import CircularProgress from "@mui/material/CircularProgress/CircularProgress";
|
||||
import React, { useState } from "react";
|
||||
import TransactionEntry from "../../TransactionEntry/TransactionEntry";
|
||||
import StudentTransactionFilterMenu from "./StudentTransactionFilterMenu";
|
||||
|
||||
export default function StudentTransactionListView() {
|
||||
const transactions = useQuery({
|
||||
queryKey: ["transactions_student"],
|
||||
queryFn: TransactionsByStudentAPI,
|
||||
});
|
||||
const [filter, setFilter] = useState("");
|
||||
if (transactions.isLoading) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
paddingTop: "64px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CircularProgress style={{ height: "128px", width: "128px" }} />
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Loading
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div style={styles.flex_column}>
|
||||
<StudentTransactionFilterMenu filter={filter} setFilter={setFilter} />
|
||||
<div style={{ marginTop: "16px" }} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{ height: "50vh", overflowY: "scroll" },
|
||||
}}
|
||||
>
|
||||
{transactions.data ? (
|
||||
transactions.data
|
||||
.filter((transaction) =>
|
||||
filter !== "" ? transaction.transaction_status == filter : true
|
||||
)
|
||||
.map((transaction) => (
|
||||
<React.Fragment key={transaction.id}>
|
||||
<TransactionEntry transaction={transaction} />
|
||||
</React.Fragment>
|
||||
))
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
import styles from "../../styles";
|
||||
import styles from "../../../styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Button } from "@mui/material";
|
||||
import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted";
|
||||
import AddToQueueIcon from "@mui/icons-material/AddToQueue";
|
||||
import NoteAddIcon from "@mui/icons-material/NoteAdd";
|
||||
import NoteIcon from "@mui/icons-material/Note";
|
||||
import { colors } from "../../styles";
|
||||
import { colors } from "../../../styles";
|
||||
import ScienceIcon from "@mui/icons-material/Science";
|
||||
import ColorizeIcon from "@mui/icons-material/Colorize";
|
||||
import ArticleIcon from '@mui/icons-material/Article';
|
||||
import Popup from "reactjs-popup";
|
||||
import AddItemModal from "../AddItemModal/AddItemModal";
|
||||
import AddSKUModal from "../AddSKUModal/AddSKUModal";
|
||||
import AddItemModal from "../../AddItemModal/AddItemModal";
|
||||
import AddSKUModal from "../../AddSKUModal/AddSKUModal";
|
||||
import { useState } from "react";
|
||||
export default function TechnicianEquipmentButtons() {
|
||||
const [addSKUmodalOpen, SetAddSKUModalOpen] = useState(false);
|
|
@ -1,8 +1,8 @@
|
|||
import { Button } from "@mui/material";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import ManageSearchIcon from "@mui/icons-material/ManageSearch";
|
||||
import styles from "../../styles";
|
||||
import { colors } from "../../styles";
|
||||
import styles from "../../../styles";
|
||||
import { colors } from "../../../styles";
|
||||
|
||||
export default function TechnicianLogButtons() {
|
||||
const navigate = useNavigate();
|
|
@ -1,6 +1,6 @@
|
|||
import { useQueries } from "@tanstack/react-query";
|
||||
import styles from "../../styles";
|
||||
import { EquipmentsAPI, EquipmentInstancesAPI, UserAPI } from "../API/API";
|
||||
import styles from "../../../styles";
|
||||
import { EquipmentsAPI, EquipmentInstancesAPI, UserAPI } from "../../API/API";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
|
||||
export default function TechnicianWidgets() {
|
|
@ -3,7 +3,12 @@ import AccountCircleIcon from "@mui/icons-material/AccountCircle";
|
|||
import HomeIcon from "@mui/icons-material/Home";
|
||||
import LogoutIcon from "@mui/icons-material/Logout";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { UserAPI, setAccessToken, setRefreshToken } from "../API/API";
|
||||
import {
|
||||
ClearanceAPI,
|
||||
UserAPI,
|
||||
setAccessToken,
|
||||
setRefreshToken,
|
||||
} from "../API/API";
|
||||
import DrawerButton from "../DrawerButton/DrawerButton";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { auth_toggle } from "../Plugins/Redux/Slices/AuthSlice/AuthSlice";
|
||||
|
@ -11,6 +16,12 @@ import { toast } from "react-toastify";
|
|||
import { useNavigate } from "react-router-dom";
|
||||
export default function Drawer() {
|
||||
const user = useQuery({ queryKey: ["user"], queryFn: UserAPI });
|
||||
const clearance = useQuery({
|
||||
enabled:
|
||||
user.isFetched && !user?.data?.is_teacher && !user?.data?.is_technician,
|
||||
queryKey: ["clearance"],
|
||||
queryFn: ClearanceAPI,
|
||||
});
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
|
@ -62,6 +73,72 @@ export default function Drawer() {
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{user.isFetched &&
|
||||
user.data &&
|
||||
!user.data.is_teacher &&
|
||||
!user?.data?.is_technician ? (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
marginTop: "16px",
|
||||
width: "100%",
|
||||
height: "2px",
|
||||
marginBottom: 8,
|
||||
}}
|
||||
/>
|
||||
<div style={styles.flex_row}>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_light,
|
||||
...styles.text_M,
|
||||
...{
|
||||
textAlign: "left",
|
||||
paddingLeft: "8px",
|
||||
},
|
||||
margin: 0,
|
||||
alignSelf: "center",
|
||||
}}
|
||||
>
|
||||
Status:
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_light,
|
||||
...styles.text_M,
|
||||
...{
|
||||
textAlign: "left",
|
||||
paddingLeft: "8px",
|
||||
color:
|
||||
clearance.data?.cleared === "Cleared"
|
||||
? colors.font_dark
|
||||
: colors.red,
|
||||
margin: 0,
|
||||
alignSelf: "center",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{clearance.data?.cleared}
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_light,
|
||||
...styles.text_S,
|
||||
...{
|
||||
textAlign: "left",
|
||||
paddingLeft: "8px",
|
||||
},
|
||||
margin: 0,
|
||||
alignSelf: "center",
|
||||
}}
|
||||
>
|
||||
{`(${clearance.data?.uncleared_transactions} pending)`}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
|
|
|
@ -14,11 +14,10 @@ export default function Header(props: props) {
|
|||
style={{
|
||||
position: "sticky",
|
||||
top: 0,
|
||||
zIndex: 1,
|
||||
zIndex: 1000,
|
||||
backgroundColor: colors.header_color,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
|
||||
}}
|
||||
>
|
||||
<div
|
||||
|
|
18
src/Components/StatusTextColor/StatusTextColor.tsx
Normal file
18
src/Components/StatusTextColor/StatusTextColor.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { colors } from "../../styles";
|
||||
|
||||
export default function StatusTextColor(status: string) {
|
||||
if (
|
||||
status === "Pending Approval" ||
|
||||
status === "Returned: Pending Checking"
|
||||
) {
|
||||
return colors.orange;
|
||||
} else if (
|
||||
status === "Approved" ||
|
||||
status === "Finalized" ||
|
||||
status === "Borrowed"
|
||||
) {
|
||||
return colors.green;
|
||||
} else {
|
||||
return colors.red;
|
||||
}
|
||||
}
|
137
src/Components/TransactionEntry/TransactionEntry.tsx
Normal file
137
src/Components/TransactionEntry/TransactionEntry.tsx
Normal file
|
@ -0,0 +1,137 @@
|
|||
import styles from "../../styles";
|
||||
import { colors } from "../../styles";
|
||||
import { TransactionType } from "../Types/Types";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import StatusTextColor from "../StatusTextColor/StatusTextColor";
|
||||
export interface props {
|
||||
transaction: TransactionType;
|
||||
}
|
||||
|
||||
export default function TransactionEntry(props: props) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
justifySelf: "center",
|
||||
width: "384px",
|
||||
backgroundColor: colors.header_color,
|
||||
borderRadius: 16,
|
||||
margin: "8px",
|
||||
padding: "8px",
|
||||
}}
|
||||
onClick={() =>
|
||||
navigate(`/view/transaction/${props.transaction.id}`, {
|
||||
replace: true,
|
||||
state: { id: props.transaction.id },
|
||||
})
|
||||
}
|
||||
>
|
||||
<div style={styles.flex_row}>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{ textAlign: "left", flex: 1 },
|
||||
}}
|
||||
>
|
||||
ID: {props.transaction.id}
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{ textAlign: "right", flex: 2 },
|
||||
}}
|
||||
>
|
||||
{props.transaction.timestamp}
|
||||
</p>
|
||||
</div>
|
||||
<div style={styles.flex_row}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{ textAlign: "left", margin: 0 },
|
||||
}}
|
||||
>
|
||||
Borrower: {props.transaction.borrower.name}{" "}
|
||||
{`(ID:${props.transaction.borrower.id})`}
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{ textAlign: "left", margin: 0 },
|
||||
}}
|
||||
>
|
||||
Teacher: {props.transaction.teacher.name}{" "}
|
||||
{`(ID:${props.transaction.teacher.id})`}
|
||||
</p>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{
|
||||
height: "64px",
|
||||
textAlign: "left",
|
||||
margin: 0,
|
||||
marginTop: "8px",
|
||||
flexWrap: "wrap",
|
||||
overflowY: "scroll",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{props.transaction.remarks}
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ flex: 1 }}>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{ textAlign: "right", margin: 0 },
|
||||
}}
|
||||
>
|
||||
Equipments:
|
||||
</p>
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{ height: "96px", overflowY: "scroll" },
|
||||
}}
|
||||
>
|
||||
{props.transaction.equipments.map((equipment) => (
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_S,
|
||||
...{
|
||||
textAlign: "right",
|
||||
margin: 0,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{` - ${equipment.name} (ID:${equipment.id})`}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_M,
|
||||
...{
|
||||
textAlign: "center",
|
||||
margin: 0,
|
||||
color: StatusTextColor(props.transaction.transaction_status),
|
||||
},
|
||||
}}
|
||||
>
|
||||
{`${props.transaction.transaction_status}`}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
129
src/Components/TransactionPDF/TransactionPDF.tsx
Normal file
129
src/Components/TransactionPDF/TransactionPDF.tsx
Normal file
|
@ -0,0 +1,129 @@
|
|||
import { Document, Page, Text, View } from "@react-pdf/renderer";
|
||||
import { TransactionType } from "../Types/Types";
|
||||
import { colors } from "../../styles";
|
||||
import StatusTextColor from "../StatusTextColor/StatusTextColor";
|
||||
|
||||
type props = {
|
||||
transaction: TransactionType;
|
||||
};
|
||||
export default function TransactionPDF(props: props) {
|
||||
return (
|
||||
<Document>
|
||||
<Page size={"A4"}>
|
||||
<View
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
justifyContent: "center",
|
||||
width: "512px",
|
||||
backgroundColor: colors.header_color,
|
||||
borderRadius: 16,
|
||||
margin: "8px",
|
||||
padding: "8px",
|
||||
}}
|
||||
>
|
||||
<View style={{ display: "flex", flexDirection: "row" }}>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
fontSize: 16,
|
||||
textAlign: "left",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
Transaction ID: {props.transaction.id}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
fontSize: 16,
|
||||
textAlign: "right",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{props.transaction.timestamp}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ paddingVertical: 8 }}></View>
|
||||
<View style={{ display: "flex", flexDirection: "row" }}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
fontSize: 16,
|
||||
textAlign: "left",
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
Borrower: {props.transaction.borrower.name}{" "}
|
||||
{`(ID:${props.transaction.borrower.id})`}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
fontSize: 16,
|
||||
textAlign: "left",
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
Teacher: {props.transaction.teacher.name}{" "}
|
||||
{`(ID:${props.transaction.teacher.id})`}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
fontSize: 16,
|
||||
textAlign: "left",
|
||||
margin: 0,
|
||||
marginTop: 8,
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{props.transaction.remarks}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
textAlign: "right",
|
||||
fontSize: 16,
|
||||
margin: 0,
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
Equipments:
|
||||
</Text>
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
{props.transaction.equipments.map((equipment) => (
|
||||
<Text
|
||||
style={{
|
||||
color: colors.font_dark,
|
||||
textAlign: "right",
|
||||
fontSize: 12,
|
||||
margin: 0,
|
||||
marginTop: 2,
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{` - ${equipment.name} (ID:${equipment.id})`}
|
||||
</Text>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ alignContent: "center", justifyContent: "center" }}>
|
||||
<Text
|
||||
style={{
|
||||
color: StatusTextColor(props.transaction.transaction_status),
|
||||
textAlign: "center",
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{`${props.transaction.transaction_status}`}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
</Document>
|
||||
);
|
||||
}
|
|
@ -98,6 +98,7 @@ export type EquipmentInstanceLogType = {
|
|||
export type EquipmentInstanceLogListType = Array<EquipmentInstanceLogType>;
|
||||
|
||||
export type UserType = {
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
avatar: string;
|
||||
|
@ -122,10 +123,25 @@ export type TransactionType = {
|
|||
name: string;
|
||||
}>;
|
||||
transaction_status: string;
|
||||
timestamp: string;
|
||||
remarks: string;
|
||||
};
|
||||
|
||||
export type TransactionListType = Array<TransactionType>;
|
||||
|
||||
export type TransactionCreateType = {
|
||||
equipments: number[];
|
||||
remarks: string;
|
||||
teacher: number;
|
||||
borrower: number;
|
||||
transaction_status: "Pending Approval";
|
||||
};
|
||||
|
||||
export type TransactionUpdateType = {
|
||||
transaction_status: string;
|
||||
};
|
||||
|
||||
export type ClearanceType = {
|
||||
cleared: string;
|
||||
uncleared_transactions: number;
|
||||
};
|
||||
|
|
205
src/Pages/AddTransactionPage/AddTransactionPage.tsx
Normal file
205
src/Pages/AddTransactionPage/AddTransactionPage.tsx
Normal file
|
@ -0,0 +1,205 @@
|
|||
import { useState } from "react";
|
||||
import styles from "../../styles";
|
||||
import { colors } from "../../styles";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import AddToQueueIcon from "@mui/icons-material/AddToQueue";
|
||||
import Button from "../../Components/Button/Button";
|
||||
import { toast } from "react-toastify";
|
||||
import {
|
||||
AvailableEquipmentInstancesAPI,
|
||||
TransactionCreateAPI,
|
||||
TeachersAPI,
|
||||
UserAPI,
|
||||
} from "../../Components/API/API";
|
||||
import FormControl from "@mui/material/FormControl";
|
||||
import FormLabel from "@mui/material/FormLabel";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
Select,
|
||||
CircularProgress,
|
||||
MenuItem,
|
||||
OutlinedInput,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import Header from "../../Components/Header/Header";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export default function AddTransactionPage() {
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const [selecteditems, SetSelectedItems] = useState<number[]>([]);
|
||||
const [selectedteacher, SetSelectedTeacher] = useState<number>(0);
|
||||
const [remarks, SetRemarks] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const equipments = useQuery({
|
||||
queryKey: ["equipment_instances_available"],
|
||||
queryFn: AvailableEquipmentInstancesAPI,
|
||||
});
|
||||
|
||||
const teachers = useQuery({
|
||||
queryKey: ["teachers"],
|
||||
queryFn: TeachersAPI,
|
||||
});
|
||||
|
||||
const user = useQuery({
|
||||
queryKey: ["user"],
|
||||
queryFn: UserAPI,
|
||||
});
|
||||
const isLoading =
|
||||
equipments.isLoading || teachers.isLoading || user.isLoading;
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div style={styles.background}>
|
||||
<Header label={"New Transaction"} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_column,
|
||||
...{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
paddingTop: "64px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CircularProgress style={{ height: "128px", width: "128px" }} />
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Loading
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div style={styles.background}>
|
||||
<Header label={"New Transaction"} />
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
overflowY: "scroll",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<AddToQueueIcon
|
||||
style={{
|
||||
height: 64,
|
||||
width: 64,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
}}
|
||||
/>
|
||||
<p style={{ ...styles.text_dark, ...styles.text_L }}>New Transaction</p>
|
||||
</div>
|
||||
|
||||
<div style={styles.flex_column}>
|
||||
<FormControl style={{ marginTop: "8px" }}>
|
||||
<FormLabel style={styles.text_dark}>Items Requested</FormLabel>
|
||||
<Select
|
||||
multiple
|
||||
value={selecteditems}
|
||||
onChange={(event) =>
|
||||
SetSelectedItems(event.target.value as number[])
|
||||
}
|
||||
input={<OutlinedInput label="Name" />}
|
||||
>
|
||||
{equipments.data
|
||||
?.filter((equipment) => equipment.status == "Available")
|
||||
.map((equipment) => (
|
||||
<MenuItem key={equipment.id} value={equipment.id}>
|
||||
{`${equipment.equipment_name} (ID:${equipment.id})`}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl style={{ marginTop: "8px" }}>
|
||||
<FormLabel style={styles.text_dark}>Assigned Teacher</FormLabel>
|
||||
<Select
|
||||
value={selectedteacher}
|
||||
onChange={(event) =>
|
||||
SetSelectedTeacher(event.target.value as number)
|
||||
}
|
||||
input={<OutlinedInput label="Name" />}
|
||||
>
|
||||
{teachers.data?.map((teacher) => (
|
||||
<MenuItem key={teacher.id} value={teacher.id}>
|
||||
{`${teacher.first_name} ${teacher.last_name}`}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<TextField
|
||||
multiline
|
||||
style={styles.input_form}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
SetRemarks(e.target.value);
|
||||
setError("");
|
||||
}}
|
||||
value={remarks}
|
||||
placeholder={"Optionally add a brief description of the request"}
|
||||
/>
|
||||
</div>
|
||||
<p style={{ ...styles.text_dark, ...styles.text_M }}>{error}</p>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: colors.button_border,
|
||||
marginTop: "16px",
|
||||
width: "100%",
|
||||
height: "2px",
|
||||
marginBottom: 8,
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type={"dark"}
|
||||
label={"Create Transaction"}
|
||||
onClick={async () => {
|
||||
console.log(selecteditems);
|
||||
const data = await TransactionCreateAPI({
|
||||
equipments: selecteditems,
|
||||
teacher: selectedteacher,
|
||||
remarks: remarks || " ",
|
||||
transaction_status: "Pending Approval",
|
||||
borrower: user.data?.id || 0,
|
||||
});
|
||||
if (data[0]) {
|
||||
setError("Created successfully");
|
||||
toast(
|
||||
`New transaction created successfuly, ${
|
||||
typeof data[1] == "object" ? "ID:" + data[1].id : ""
|
||||
}`,
|
||||
{
|
||||
position: "top-right",
|
||||
autoClose: 2000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
}
|
||||
);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["equipment_instances"],
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["transactions"],
|
||||
});
|
||||
navigate("/dashboard");
|
||||
} else {
|
||||
setError(JSON.stringify(data[1]));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
import Header from "../../Components/Header/Header";
|
||||
import styles from "../../styles";
|
||||
import RestrictedComponent from "../../Components/RestrictedComponent/RestrictedComponent";
|
||||
import TechnicianWidgets from "../../Components/DashboardPage/TechnicianWidgets";
|
||||
import TechnicianEquipmentButtons from "../../Components/DashboardPage/TechnicianEquipmentButtons";
|
||||
import TechnicianLogButtons from "../../Components/DashboardPage/TechnicianLogButtons";
|
||||
import TechnicianWidgets from "../../Components/DashboardPage/Technician/TechnicianWidgets";
|
||||
import TechnicianEquipmentButtons from "../../Components/DashboardPage/Technician/TechnicianEquipmentButtons";
|
||||
import TechnicianLogButtons from "../../Components/DashboardPage/Technician/TechnicianLogButtons";
|
||||
import StudentTransactionListView from "../../Components/DashboardPage/Student/StudentTransactionListView";
|
||||
import StudentDashboard from "../../Components/DashboardPage/Student/StudentDashboard";
|
||||
export default function Dashboard() {
|
||||
return (
|
||||
<div style={styles.background}>
|
||||
|
@ -14,7 +16,20 @@ export default function Dashboard() {
|
|||
<TechnicianLogButtons />
|
||||
</RestrictedComponent>
|
||||
<RestrictedComponent allow_only={"Student"}>
|
||||
<p style={styles.text_dark}>Welcome student!</p>
|
||||
<div
|
||||
style={{
|
||||
...styles.flex_row,
|
||||
...{
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "center",
|
||||
marginLeft: "16px",
|
||||
marginRight: "16px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StudentTransactionListView />
|
||||
<StudentDashboard />
|
||||
</div>
|
||||
</RestrictedComponent>
|
||||
<RestrictedComponent allow_only={"Teacher"}>
|
||||
<p style={styles.text_dark}>Welcome teacher!</p>
|
||||
|
|
110
src/Pages/TransactionPage/TransactionPage.tsx
Normal file
110
src/Pages/TransactionPage/TransactionPage.tsx
Normal file
|
@ -0,0 +1,110 @@
|
|||
import styles from "../../styles";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { TransactionAPI } from "../../Components/API/API";
|
||||
import Header from "../../Components/Header/Header";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { PDFDownloadLink, PDFViewer } from "@react-pdf/renderer";
|
||||
import { toast } from "react-toastify";
|
||||
import TransactionPDF from "../../Components/TransactionPDF/TransactionPDF";
|
||||
import { CircularProgress } from "@mui/material";
|
||||
|
||||
export default function TransactionPage() {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
const transaction = useQuery({
|
||||
queryKey: ["transaction", id],
|
||||
queryFn: () => TransactionAPI(Number(id) || 0),
|
||||
});
|
||||
if (transaction.isLoading) {
|
||||
return (
|
||||
<>
|
||||
<CircularProgress style={{ height: "128px", width: "128px" }} />
|
||||
<p
|
||||
style={{
|
||||
...styles.text_dark,
|
||||
...styles.text_L,
|
||||
}}
|
||||
>
|
||||
Loading
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (transaction.isError) {
|
||||
toast(`Could not find transaction with ID:${id}`, {
|
||||
position: "top-right",
|
||||
autoClose: 2000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
});
|
||||
navigate("/dashboard");
|
||||
}
|
||||
return (
|
||||
<div style={styles.background}>
|
||||
<Header label={"View transaction"} />
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignContent: "center",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<PDFDownloadLink
|
||||
document={
|
||||
<TransactionPDF
|
||||
transaction={
|
||||
transaction.data || {
|
||||
id: 0,
|
||||
borrower: {
|
||||
id: 0,
|
||||
name: "",
|
||||
},
|
||||
teacher: {
|
||||
id: 0,
|
||||
name: "",
|
||||
},
|
||||
equipments: [],
|
||||
transaction_status: "",
|
||||
timestamp: "",
|
||||
remarks: "",
|
||||
}
|
||||
}
|
||||
/>
|
||||
}
|
||||
fileName="transaction.pdf"
|
||||
>
|
||||
{({ loading }) =>
|
||||
loading ? "Loading document..." : "Download Transaction"
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
<PDFViewer style={{ width: "90%", height: "80vh" }}>
|
||||
<TransactionPDF
|
||||
transaction={
|
||||
transaction.data || {
|
||||
id: 0,
|
||||
borrower: {
|
||||
id: 0,
|
||||
name: "",
|
||||
},
|
||||
teacher: {
|
||||
id: 0,
|
||||
name: "",
|
||||
},
|
||||
equipments: [],
|
||||
transaction_status: "",
|
||||
timestamp: "",
|
||||
remarks: "",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</PDFViewer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -25,7 +25,6 @@ const styles: { [key: string]: React.CSSProperties } = {
|
|||
text_dark: {
|
||||
color: colors.font_dark,
|
||||
fontWeight: "bold",
|
||||
|
||||
},
|
||||
text_light: {
|
||||
color: colors.font_light,
|
||||
|
@ -88,6 +87,13 @@ const styles: { [key: string]: React.CSSProperties } = {
|
|||
textAlign: "center",
|
||||
overflowY: "scroll",
|
||||
},
|
||||
student_filter_item: {
|
||||
height: 32,
|
||||
width: 32,
|
||||
fill: colors.font_dark,
|
||||
marginLeft: "1rem",
|
||||
marginRight: "1rem",
|
||||
},
|
||||
};
|
||||
|
||||
export default styles;
|
||||
|
|
Loading…
Reference in a new issue