merge changes on development branch
This commit is contained in:
commit
0ddc602959
@ -34,7 +34,7 @@ class ExaminationSchedulesQuerySchema(Schema):
|
|||||||
|
|
||||||
|
|
||||||
class ProjectSupervisorStatisticsSchema(Schema):
|
class ProjectSupervisorStatisticsSchema(Schema):
|
||||||
fullname = fields.Str()
|
full_name = fields.Str()
|
||||||
assigned_to_committee = fields.Integer()
|
assigned_to_committee = fields.Integer()
|
||||||
groups_assigned_to_his_committee = fields.Integer()
|
groups_assigned_to_his_committee = fields.Integer()
|
||||||
|
|
||||||
|
165
frontend/package-lock.json
generated
165
frontend/package-lock.json
generated
@ -18,10 +18,11 @@
|
|||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"daisyui": "^2.15.2",
|
"daisyui": "^2.15.2",
|
||||||
"luxon": "^3.0.4",
|
"dayjs": "^1.11.7",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-big-calendar": "^1.5.0",
|
"react-big-calendar": "^1.5.0",
|
||||||
"react-date-picker": "^9.1.0",
|
"react-date-picker": "^9.1.0",
|
||||||
|
"react-datetime-picker": "^4.1.1",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
"react-hook-form": "^7.31.3",
|
"react-hook-form": "^7.31.3",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
@ -34,8 +35,8 @@
|
|||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/luxon": "^3.0.2",
|
|
||||||
"@types/react-big-calendar": "^0.38.2",
|
"@types/react-big-calendar": "^0.38.2",
|
||||||
|
"@types/react-datetime-picker": "^3.4.1",
|
||||||
"@types/react-modal": "^3.13.1",
|
"@types/react-modal": "^3.13.1",
|
||||||
"autoprefixer": "^10.4.7",
|
"autoprefixer": "^10.4.7",
|
||||||
"postcss": "^8.4.14",
|
"postcss": "^8.4.14",
|
||||||
@ -3823,12 +3824,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/luxon": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-HM2OVWckUMmXbWYZufmWT2XMURGDZ6XbyNyQ+Lx+gCFGFqbZaIjsz7b+AGeGP/AuVYHBiuGY+wXfweP1RremnA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/mime": {
|
"node_modules/@types/mime": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||||
@ -3897,6 +3892,15 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-datetime-picker": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-datetime-picker/-/react-datetime-picker-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-JHqB74+8Zq6cY0PTJ6Wi5Pm6qkNUmooyFfW5SiknSY2xJG1UG8+ljyWTZAvgHvj0XpqcWCHqqYUPiAVagnf9Sg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "18.0.4",
|
"version": "18.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.4.tgz",
|
||||||
@ -6310,6 +6314,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
|
||||||
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
|
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/dayjs": {
|
||||||
|
"version": "1.11.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
|
||||||
|
"integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@ -11565,14 +11574,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/luxon": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz",
|
|
||||||
"integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lz-string": {
|
"node_modules/lz-string": {
|
||||||
"version": "1.4.4",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
|
||||||
@ -13914,6 +13915,24 @@
|
|||||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-clock": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-clock/-/react-clock-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-CBevN5B40TDUegSWzXk6bSwXhYzyerL9JGTme8GMAY0zO4FiEhVTGN1uzgC0rn/oSAMJw3M5wSf/OJpp9vcN2Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@wojtekmaj/date-utils": "^1.0.0",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"get-user-locale": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/wojtekmaj/react-clock?sponsor=1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-date-picker": {
|
"node_modules/react-date-picker": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-date-picker/-/react-date-picker-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-date-picker/-/react-date-picker-9.1.0.tgz",
|
||||||
@ -13937,6 +13956,30 @@
|
|||||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-datetime-picker": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-datetime-picker/-/react-datetime-picker-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-e8ANKLcWFL4/TutvggqVfRiDigyelcVdLvWQzOP5cMJ6IxR08Qv2dOncjBWVkwU9vTsDemuHSAGIGqZXtr3aXA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@wojtekmaj/date-utils": "^1.0.3",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"get-user-locale": "^1.2.0",
|
||||||
|
"make-event-props": "^1.1.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-calendar": "^4.0.0",
|
||||||
|
"react-clock": "^4.0.0",
|
||||||
|
"react-date-picker": "^9.1.0",
|
||||||
|
"react-fit": "^1.4.0",
|
||||||
|
"react-time-picker": "^5.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/wojtekmaj/react-datetime-picker?sponsor=1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dev-utils": {
|
"node_modules/react-dev-utils": {
|
||||||
"version": "12.0.1",
|
"version": "12.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
||||||
@ -14297,6 +14340,28 @@
|
|||||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-time-picker": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-time-picker/-/react-time-picker-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-NGpy5FM8WYdgCKXE/a85mhf0TunOk+N8ZG6rXBahD0mXeQZ/aBM+iVuKN4ell+QFH8/7F8dhT200ZKatBIphnA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@wojtekmaj/date-utils": "^1.0.0",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"get-user-locale": "^1.2.0",
|
||||||
|
"make-event-props": "^1.1.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-clock": "^4.0.0",
|
||||||
|
"react-fit": "^1.4.0",
|
||||||
|
"update-input-width": "^1.2.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/wojtekmaj/react-time-picker?sponsor=1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-transition-group": {
|
"node_modules/react-transition-group": {
|
||||||
"version": "4.4.2",
|
"version": "4.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
|
||||||
@ -19744,12 +19809,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||||
},
|
},
|
||||||
"@types/luxon": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.0.2.tgz",
|
|
||||||
"integrity": "sha512-HM2OVWckUMmXbWYZufmWT2XMURGDZ6XbyNyQ+Lx+gCFGFqbZaIjsz7b+AGeGP/AuVYHBiuGY+wXfweP1RremnA==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/mime": {
|
"@types/mime": {
|
||||||
"version": "1.3.2",
|
"version": "1.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||||
@ -19818,6 +19877,15 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-datetime-picker": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-datetime-picker/-/react-datetime-picker-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-JHqB74+8Zq6cY0PTJ6Wi5Pm6qkNUmooyFfW5SiknSY2xJG1UG8+ljyWTZAvgHvj0XpqcWCHqqYUPiAVagnf9Sg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
"version": "18.0.4",
|
"version": "18.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.4.tgz",
|
||||||
@ -21612,6 +21680,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-arithmetic/-/date-arithmetic-4.1.0.tgz",
|
||||||
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
|
"integrity": "sha512-QWxYLR5P/6GStZcdem+V1xoto6DMadYWpMXU82ES3/RfR3Wdwr3D0+be7mgOJ+Ov0G9D5Dmb9T17sNLQYj9XOg=="
|
||||||
},
|
},
|
||||||
|
"dayjs": {
|
||||||
|
"version": "1.11.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz",
|
||||||
|
"integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ=="
|
||||||
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
@ -25438,11 +25511,6 @@
|
|||||||
"yallist": "^4.0.0"
|
"yallist": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"luxon": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz",
|
|
||||||
"integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw=="
|
|
||||||
},
|
|
||||||
"lz-string": {
|
"lz-string": {
|
||||||
"version": "1.4.4",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
|
||||||
@ -26995,6 +27063,17 @@
|
|||||||
"prop-types": "^15.6.0"
|
"prop-types": "^15.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-clock": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-clock/-/react-clock-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-CBevN5B40TDUegSWzXk6bSwXhYzyerL9JGTme8GMAY0zO4FiEhVTGN1uzgC0rn/oSAMJw3M5wSf/OJpp9vcN2Q==",
|
||||||
|
"requires": {
|
||||||
|
"@wojtekmaj/date-utils": "^1.0.0",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"get-user-locale": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-date-picker": {
|
"react-date-picker": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-date-picker/-/react-date-picker-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-date-picker/-/react-date-picker-9.1.0.tgz",
|
||||||
@ -27011,6 +27090,23 @@
|
|||||||
"update-input-width": "^1.2.2"
|
"update-input-width": "^1.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-datetime-picker": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-datetime-picker/-/react-datetime-picker-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-e8ANKLcWFL4/TutvggqVfRiDigyelcVdLvWQzOP5cMJ6IxR08Qv2dOncjBWVkwU9vTsDemuHSAGIGqZXtr3aXA==",
|
||||||
|
"requires": {
|
||||||
|
"@wojtekmaj/date-utils": "^1.0.3",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"get-user-locale": "^1.2.0",
|
||||||
|
"make-event-props": "^1.1.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-calendar": "^4.0.0",
|
||||||
|
"react-clock": "^4.0.0",
|
||||||
|
"react-date-picker": "^9.1.0",
|
||||||
|
"react-fit": "^1.4.0",
|
||||||
|
"react-time-picker": "^5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-dev-utils": {
|
"react-dev-utils": {
|
||||||
"version": "12.0.1",
|
"version": "12.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
|
||||||
@ -27264,6 +27360,21 @@
|
|||||||
"react-transition-group": "^4.3.0"
|
"react-transition-group": "^4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-time-picker": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-time-picker/-/react-time-picker-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-NGpy5FM8WYdgCKXE/a85mhf0TunOk+N8ZG6rXBahD0mXeQZ/aBM+iVuKN4ell+QFH8/7F8dhT200ZKatBIphnA==",
|
||||||
|
"requires": {
|
||||||
|
"@wojtekmaj/date-utils": "^1.0.0",
|
||||||
|
"clsx": "^1.2.1",
|
||||||
|
"get-user-locale": "^1.2.0",
|
||||||
|
"make-event-props": "^1.1.0",
|
||||||
|
"prop-types": "^15.6.0",
|
||||||
|
"react-clock": "^4.0.0",
|
||||||
|
"react-fit": "^1.4.0",
|
||||||
|
"update-input-width": "^1.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-transition-group": {
|
"react-transition-group": {
|
||||||
"version": "4.4.2",
|
"version": "4.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
|
||||||
|
@ -13,10 +13,11 @@
|
|||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"daisyui": "^2.15.2",
|
"daisyui": "^2.15.2",
|
||||||
"luxon": "^3.0.4",
|
"dayjs": "^1.11.7",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-big-calendar": "^1.5.0",
|
"react-big-calendar": "^1.5.0",
|
||||||
"react-date-picker": "^9.1.0",
|
"react-date-picker": "^9.1.0",
|
||||||
|
"react-datetime-picker": "^4.1.1",
|
||||||
"react-dom": "^18.1.0",
|
"react-dom": "^18.1.0",
|
||||||
"react-hook-form": "^7.31.3",
|
"react-hook-form": "^7.31.3",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
@ -53,8 +54,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/luxon": "^3.0.2",
|
|
||||||
"@types/react-big-calendar": "^0.38.2",
|
"@types/react-big-calendar": "^0.38.2",
|
||||||
|
"@types/react-datetime-picker": "^3.4.1",
|
||||||
"@types/react-modal": "^3.13.1",
|
"@types/react-modal": "^3.13.1",
|
||||||
"autoprefixer": "^10.4.7",
|
"autoprefixer": "^10.4.7",
|
||||||
"postcss": "^8.4.14",
|
"postcss": "^8.4.14",
|
||||||
|
@ -26,6 +26,11 @@ import SupervisorAvailabilities from './views/coordinator/SupervisorAvailabiliti
|
|||||||
import AvailabilitySchedule from './views/coordinator/AvailabilitySchedule'
|
import AvailabilitySchedule from './views/coordinator/AvailabilitySchedule'
|
||||||
import GradeCard from './views/GradeCard'
|
import GradeCard from './views/GradeCard'
|
||||||
import Group from './views/coordinator/Group'
|
import Group from './views/coordinator/Group'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import WorkloadStatistics from './views/coordinator/WorkloadStatistics'
|
||||||
|
|
||||||
|
require('dayjs/locale/pl')
|
||||||
|
dayjs.locale('pl')
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
@ -61,6 +66,10 @@ function App() {
|
|||||||
path="supervisors_availability/:id"
|
path="supervisors_availability/:id"
|
||||||
element={<AvailabilitySchedule />}
|
element={<AvailabilitySchedule />}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="schedule/:id/workload"
|
||||||
|
element={<WorkloadStatistics />}
|
||||||
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path="student" element={<Student />}>
|
<Route path="student" element={<Student />}>
|
||||||
<Route index element={<Navigate to="enrollment" />} />
|
<Route index element={<Navigate to="enrollment" />} />
|
||||||
|
@ -8,8 +8,9 @@ interface TermOfDefences {
|
|||||||
end_date: string
|
end_date: string
|
||||||
title: string
|
title: string
|
||||||
members_of_committee: {
|
members_of_committee: {
|
||||||
members: { first_name: string; last_name: string }[]
|
first_name: string
|
||||||
}
|
last_name: string
|
||||||
|
}[]
|
||||||
group: { name: string; students: Student[] }
|
group: { name: string; students: Student[] }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,3 +192,13 @@ export const setDateOfExaminationSchedule = (
|
|||||||
export const generateTermsOfDefence = (scheduleId: number) => {
|
export const generateTermsOfDefence = (scheduleId: number) => {
|
||||||
return axiosInstance.post(`coordinator/enrollments/${scheduleId}/generate`)
|
return axiosInstance.post(`coordinator/enrollments/${scheduleId}/generate`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const geWorkloadStatistics = (scheduleId: number) => {
|
||||||
|
return axiosInstance.get<{
|
||||||
|
workloads: {
|
||||||
|
assigned_to_committee: number
|
||||||
|
full_name: string
|
||||||
|
groups_assigned_to_his_committee: number
|
||||||
|
}[]
|
||||||
|
}>(`coordinator/examination_schedule/${scheduleId}/workloads/`)
|
||||||
|
}
|
||||||
|
409
frontend/src/utils/dayjsLocalizer.js
Normal file
409
frontend/src/utils/dayjsLocalizer.js
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
import { DateLocalizer } from 'react-big-calendar'
|
||||||
|
|
||||||
|
// import dayjs plugins
|
||||||
|
// Note that the timezone plugin is not imported here
|
||||||
|
// this plugin can be optionally loaded by the user
|
||||||
|
import isBetween from 'dayjs/plugin/isBetween'
|
||||||
|
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
|
||||||
|
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
||||||
|
import localeData from 'dayjs/plugin/localeData'
|
||||||
|
import localizedFormat from 'dayjs/plugin/localizedFormat'
|
||||||
|
import minMax from 'dayjs/plugin/minMax'
|
||||||
|
import utc from 'dayjs/plugin/utc'
|
||||||
|
|
||||||
|
const weekRangeFormat = ({ start, end }, culture, local) =>
|
||||||
|
local.format(start, 'MMMM DD', culture) +
|
||||||
|
' – ' +
|
||||||
|
// updated to use this localizer 'eq()' method
|
||||||
|
local.format(end, local.eq(start, end, 'month') ? 'DD' : 'MMMM DD', culture)
|
||||||
|
|
||||||
|
const dateRangeFormat = ({ start, end }, culture, local) =>
|
||||||
|
local.format(start, 'L', culture) + ' – ' + local.format(end, 'L', culture)
|
||||||
|
|
||||||
|
const timeRangeFormat = ({ start, end }, culture, local) =>
|
||||||
|
local.format(start, 'LT', culture) + ' – ' + local.format(end, 'LT', culture)
|
||||||
|
|
||||||
|
const timeRangeStartFormat = ({ start }, culture, local) =>
|
||||||
|
local.format(start, 'LT', culture) + ' – '
|
||||||
|
|
||||||
|
const timeRangeEndFormat = ({ end }, culture, local) =>
|
||||||
|
' – ' + local.format(end, 'LT', culture)
|
||||||
|
|
||||||
|
export const formats = {
|
||||||
|
dateFormat: 'DD',
|
||||||
|
dayFormat: 'DD ddd',
|
||||||
|
weekdayFormat: 'ddd',
|
||||||
|
|
||||||
|
selectRangeFormat: timeRangeFormat,
|
||||||
|
eventTimeRangeFormat: timeRangeFormat,
|
||||||
|
eventTimeRangeStartFormat: timeRangeStartFormat,
|
||||||
|
eventTimeRangeEndFormat: timeRangeEndFormat,
|
||||||
|
|
||||||
|
timeGutterFormat: 'LT',
|
||||||
|
|
||||||
|
monthHeaderFormat: 'MMMM YYYY',
|
||||||
|
dayHeaderFormat: 'dddd MMM DD',
|
||||||
|
dayRangeHeaderFormat: weekRangeFormat,
|
||||||
|
agendaHeaderFormat: dateRangeFormat,
|
||||||
|
|
||||||
|
agendaDateFormat: 'ddd MMM DD',
|
||||||
|
agendaTimeFormat: 'LT',
|
||||||
|
agendaTimeRangeFormat: timeRangeFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixUnit(unit) {
|
||||||
|
let datePart = unit ? unit.toLowerCase() : unit
|
||||||
|
if (datePart === 'FullYear') {
|
||||||
|
datePart = 'year'
|
||||||
|
} else if (!datePart) {
|
||||||
|
datePart = undefined
|
||||||
|
}
|
||||||
|
return datePart
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (dayjsLib) {
|
||||||
|
// load dayjs plugins
|
||||||
|
dayjsLib.extend(isBetween)
|
||||||
|
dayjsLib.extend(isSameOrAfter)
|
||||||
|
dayjsLib.extend(isSameOrBefore)
|
||||||
|
dayjsLib.extend(localeData)
|
||||||
|
dayjsLib.extend(localizedFormat)
|
||||||
|
dayjsLib.extend(minMax)
|
||||||
|
dayjsLib.extend(utc)
|
||||||
|
|
||||||
|
const locale = (dj, c) => (c ? dj.locale(c) : dj)
|
||||||
|
|
||||||
|
// if the timezone plugin is loaded,
|
||||||
|
// then use the timezone aware version
|
||||||
|
const dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib
|
||||||
|
|
||||||
|
function getTimezoneOffset(date) {
|
||||||
|
// ensures this gets cast to timezone
|
||||||
|
return dayjs(date).toDate().getTimezoneOffset()
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDstOffset(start, end) {
|
||||||
|
// convert to dayjs, in case
|
||||||
|
const st = dayjs(start)
|
||||||
|
const ed = dayjs(end)
|
||||||
|
// if not using the dayjs timezone plugin
|
||||||
|
if (!dayjs.tz) {
|
||||||
|
return st.toDate().getTimezoneOffset() - ed.toDate().getTimezoneOffset()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* If a default timezone has been applied, then
|
||||||
|
* use this to get the proper timezone offset, otherwise default
|
||||||
|
* the timezone to the browser local
|
||||||
|
*/
|
||||||
|
const tzName = st.tz().$x.$timezone ?? dayjsLib.tz.guess()
|
||||||
|
// invert offsets to be inline with moment.js
|
||||||
|
const startOffset = -dayjs.tz(+st, tzName).utcOffset()
|
||||||
|
const endOffset = -dayjs.tz(+ed, tzName).utcOffset()
|
||||||
|
return startOffset - endOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDayStartDstOffset(start) {
|
||||||
|
const dayStart = dayjs(start).startOf('day')
|
||||||
|
return getDstOffset(dayStart, start)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** BEGIN localized date arithmetic methods with dayjs ***/
|
||||||
|
function defineComparators(a, b, unit) {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
const dtA = datePart ? dayjs(a).startOf(datePart) : dayjs(a)
|
||||||
|
const dtB = datePart ? dayjs(b).startOf(datePart) : dayjs(b)
|
||||||
|
return [dtA, dtB, datePart]
|
||||||
|
}
|
||||||
|
|
||||||
|
function startOf(date = null, unit) {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
if (datePart) {
|
||||||
|
return dayjs(date).startOf(datePart).toDate()
|
||||||
|
}
|
||||||
|
return dayjs(date).toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function endOf(date = null, unit) {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
if (datePart) {
|
||||||
|
return dayjs(date).endOf(datePart).toDate()
|
||||||
|
}
|
||||||
|
return dayjs(date).toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// dayjs comparison operations *always* convert both sides to dayjs objects
|
||||||
|
// prior to running the comparisons
|
||||||
|
function eq(a, b, unit) {
|
||||||
|
const [dtA, dtB, datePart] = defineComparators(a, b, unit)
|
||||||
|
return dtA.isSame(dtB, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function neq(a, b, unit) {
|
||||||
|
return !eq(a, b, unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
function gt(a, b, unit) {
|
||||||
|
const [dtA, dtB, datePart] = defineComparators(a, b, unit)
|
||||||
|
return dtA.isAfter(dtB, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function lt(a, b, unit) {
|
||||||
|
const [dtA, dtB, datePart] = defineComparators(a, b, unit)
|
||||||
|
return dtA.isBefore(dtB, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function gte(a, b, unit) {
|
||||||
|
const [dtA, dtB, datePart] = defineComparators(a, b, unit)
|
||||||
|
return dtA.isSameOrBefore(dtB, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function lte(a, b, unit) {
|
||||||
|
const [dtA, dtB, datePart] = defineComparators(a, b, unit)
|
||||||
|
return dtA.isSameOrBefore(dtB, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function inRange(day, min, max, unit = 'day') {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
const djDay = dayjs(day)
|
||||||
|
const djMin = dayjs(min)
|
||||||
|
const djMax = dayjs(max)
|
||||||
|
return djDay.isBetween(djMin, djMax, datePart, '[]')
|
||||||
|
}
|
||||||
|
|
||||||
|
function min(dateA, dateB) {
|
||||||
|
const dtA = dayjs(dateA)
|
||||||
|
const dtB = dayjs(dateB)
|
||||||
|
const minDt = dayjsLib.min(dtA, dtB)
|
||||||
|
return minDt.toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function max(dateA, dateB) {
|
||||||
|
const dtA = dayjs(dateA)
|
||||||
|
const dtB = dayjs(dateB)
|
||||||
|
const maxDt = dayjsLib.max(dtA, dtB)
|
||||||
|
return maxDt.toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge(date, time) {
|
||||||
|
if (!date && !time) return null
|
||||||
|
|
||||||
|
const tm = dayjs(time).format('HH:mm:ss')
|
||||||
|
const dt = dayjs(date).startOf('day').format('MM/DD/YYYY')
|
||||||
|
// We do it this way to avoid issues when timezone switching
|
||||||
|
return dayjsLib(`${dt} ${tm}`, 'MM/DD/YYYY HH:mm:ss').toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(date, adder, unit) {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
return dayjs(date).add(adder, datePart).toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function range(start, end, unit = 'day') {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
// because the add method will put these in tz, we have to start that way
|
||||||
|
let current = dayjs(start).toDate()
|
||||||
|
const days = []
|
||||||
|
|
||||||
|
while (lte(current, end)) {
|
||||||
|
days.push(current)
|
||||||
|
current = add(current, 1, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
return days
|
||||||
|
}
|
||||||
|
|
||||||
|
function ceil(date, unit) {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
const floor = startOf(date, datePart)
|
||||||
|
|
||||||
|
return eq(floor, date) ? floor : add(floor, 1, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function diff(a, b, unit = 'day') {
|
||||||
|
const datePart = fixUnit(unit)
|
||||||
|
// don't use 'defineComparators' here, as we don't want to mutate the values
|
||||||
|
const dtA = dayjs(a)
|
||||||
|
const dtB = dayjs(b)
|
||||||
|
return dtB.diff(dtA, datePart)
|
||||||
|
}
|
||||||
|
|
||||||
|
function minutes(date) {
|
||||||
|
const dt = dayjs(date)
|
||||||
|
return dt.minutes()
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstOfWeek(culture) {
|
||||||
|
const data = culture ? dayjsLib.localeData(culture) : dayjsLib.localeData()
|
||||||
|
return data ? data.firstDayOfWeek() : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstVisibleDay(date) {
|
||||||
|
return dayjs(date).startOf('month').startOf('week').toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function lastVisibleDay(date) {
|
||||||
|
return dayjs(date).endOf('month').endOf('week').toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
function visibleDays(date) {
|
||||||
|
let current = firstVisibleDay(date)
|
||||||
|
const last = lastVisibleDay(date)
|
||||||
|
const days = []
|
||||||
|
|
||||||
|
while (lte(current, last)) {
|
||||||
|
days.push(current)
|
||||||
|
current = add(current, 1, 'd')
|
||||||
|
}
|
||||||
|
|
||||||
|
return days
|
||||||
|
}
|
||||||
|
/*** END localized date arithmetic methods with dayjs ***/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moved from TimeSlots.js, this method overrides the method of the same name
|
||||||
|
* in the localizer.js, using dayjs to construct the js Date
|
||||||
|
* @param {Date} dt - date to start with
|
||||||
|
* @param {Number} minutesFromMidnight
|
||||||
|
* @param {Number} offset
|
||||||
|
* @returns {Date}
|
||||||
|
*/
|
||||||
|
function getSlotDate(dt, minutesFromMidnight, offset) {
|
||||||
|
return dayjs(dt)
|
||||||
|
.startOf('day')
|
||||||
|
.minute(minutesFromMidnight + offset)
|
||||||
|
.toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// dayjs will automatically handle DST differences in it's calculations
|
||||||
|
function getTotalMin(start, end) {
|
||||||
|
return diff(start, end, 'minutes')
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMinutesFromMidnight(start) {
|
||||||
|
const dayStart = dayjs(start).startOf('day')
|
||||||
|
const day = dayjs(start)
|
||||||
|
return day.diff(dayStart, 'minutes') + getDayStartDstOffset(start)
|
||||||
|
}
|
||||||
|
|
||||||
|
// These two are used by DateSlotMetrics
|
||||||
|
function continuesPrior(start, first) {
|
||||||
|
const djStart = dayjs(start)
|
||||||
|
const djFirst = dayjs(first)
|
||||||
|
return djStart.isBefore(djFirst, 'day')
|
||||||
|
}
|
||||||
|
|
||||||
|
function continuesAfter(start, end, last) {
|
||||||
|
const djEnd = dayjs(end)
|
||||||
|
const djLast = dayjs(last)
|
||||||
|
return djEnd.isSameOrAfter(djLast, 'minutes')
|
||||||
|
}
|
||||||
|
|
||||||
|
// These two are used by eventLevels
|
||||||
|
function sortEvents({
|
||||||
|
evtA: { start: aStart, end: aEnd, allDay: aAllDay },
|
||||||
|
evtB: { start: bStart, end: bEnd, allDay: bAllDay },
|
||||||
|
}) {
|
||||||
|
const startSort = +startOf(aStart, 'day') - +startOf(bStart, 'day')
|
||||||
|
|
||||||
|
const durA = diff(aStart, ceil(aEnd, 'day'), 'day')
|
||||||
|
|
||||||
|
const durB = diff(bStart, ceil(bEnd, 'day'), 'day')
|
||||||
|
|
||||||
|
return (
|
||||||
|
startSort || // sort by start Day first
|
||||||
|
Math.max(durB, 1) - Math.max(durA, 1) || // events spanning multiple days go first
|
||||||
|
!!bAllDay - !!aAllDay || // then allDay single day events
|
||||||
|
+aStart - +bStart || // then sort by start time *don't need dayjs conversion here
|
||||||
|
+aEnd - +bEnd // then sort by end time *don't need dayjs conversion here either
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function inEventRange({
|
||||||
|
event: { start, end },
|
||||||
|
range: { start: rangeStart, end: rangeEnd },
|
||||||
|
}) {
|
||||||
|
const startOfDay = dayjs(start).startOf('day')
|
||||||
|
const eEnd = dayjs(end)
|
||||||
|
const rStart = dayjs(rangeStart)
|
||||||
|
const rEnd = dayjs(rangeEnd)
|
||||||
|
|
||||||
|
const startsBeforeEnd = startOfDay.isSameOrBefore(rEnd, 'day')
|
||||||
|
// when the event is zero duration we need to handle a bit differently
|
||||||
|
const sameMin = !startOfDay.isSame(eEnd, 'minutes')
|
||||||
|
const endsAfterStart = sameMin
|
||||||
|
? eEnd.isAfter(rStart, 'minutes')
|
||||||
|
: eEnd.isSameOrAfter(rStart, 'minutes')
|
||||||
|
|
||||||
|
return startsBeforeEnd && endsAfterStart
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameDate(date1, date2) {
|
||||||
|
const dt = dayjs(date1)
|
||||||
|
const dt2 = dayjs(date2)
|
||||||
|
return dt.isSame(dt2, 'day')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method, called once in the localizer constructor, is used by eventLevels
|
||||||
|
* 'eventSegments()' to assist in determining the 'span' of the event in the display,
|
||||||
|
* specifically when using a timezone that is greater than the browser native timezone.
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
function browserTZOffset() {
|
||||||
|
/**
|
||||||
|
* Date.prototype.getTimezoneOffset horrifically flips the positive/negative from
|
||||||
|
* what you see in it's string, so we have to jump through some hoops to get a value
|
||||||
|
* we can actually compare.
|
||||||
|
*/
|
||||||
|
const dt = new Date()
|
||||||
|
const neg = /-/.test(dt.toString()) ? '-' : ''
|
||||||
|
const dtOffset = dt.getTimezoneOffset()
|
||||||
|
const comparator = Number(`${neg}${Math.abs(dtOffset)}`)
|
||||||
|
// dayjs correctly provides positive/negative offset, as expected
|
||||||
|
const mtOffset = dayjs().utcOffset()
|
||||||
|
return mtOffset > comparator ? 1 : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DateLocalizer({
|
||||||
|
formats,
|
||||||
|
|
||||||
|
firstOfWeek,
|
||||||
|
firstVisibleDay,
|
||||||
|
lastVisibleDay,
|
||||||
|
visibleDays,
|
||||||
|
|
||||||
|
format(value, format, culture) {
|
||||||
|
return locale(dayjs(value), culture).format(format)
|
||||||
|
},
|
||||||
|
|
||||||
|
lt,
|
||||||
|
lte,
|
||||||
|
gt,
|
||||||
|
gte,
|
||||||
|
eq,
|
||||||
|
neq,
|
||||||
|
merge,
|
||||||
|
inRange,
|
||||||
|
startOf,
|
||||||
|
endOf,
|
||||||
|
range,
|
||||||
|
add,
|
||||||
|
diff,
|
||||||
|
ceil,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
minutes,
|
||||||
|
|
||||||
|
getSlotDate,
|
||||||
|
getTimezoneOffset,
|
||||||
|
getDstOffset,
|
||||||
|
getTotalMin,
|
||||||
|
getMinutesFromMidnight,
|
||||||
|
continuesPrior,
|
||||||
|
continuesAfter,
|
||||||
|
sortEvents,
|
||||||
|
inEventRange,
|
||||||
|
isSameDate,
|
||||||
|
browserTZOffset,
|
||||||
|
})
|
||||||
|
}
|
@ -12,7 +12,7 @@ import styles from './GradeCard.module.css' // Import css modules stylesheet as
|
|||||||
const GradeCard = () => {
|
const GradeCard = () => {
|
||||||
const { register, handleSubmit, setValue } = useForm()
|
const { register, handleSubmit, setValue } = useForm()
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
const [supervisorId] = useLocalStorageState('supervisorId')
|
const [supervisorId] = useLocalStorageState('userId')
|
||||||
|
|
||||||
useQuery(
|
useQuery(
|
||||||
['getGradesFirst'],
|
['getGradesFirst'],
|
||||||
|
@ -22,6 +22,8 @@ const Login = () => {
|
|||||||
const [userId, setUserId] = useLocalStorageState('userId', {
|
const [userId, setUserId] = useLocalStorageState('userId', {
|
||||||
defaultValue: -1,
|
defaultValue: -1,
|
||||||
})
|
})
|
||||||
|
const [studentId, setStudentId] = useLocalStorageState('studentId')
|
||||||
|
|
||||||
const [userType, setUserType] = useLocalStorageState('userType', {
|
const [userType, setUserType] = useLocalStorageState('userType', {
|
||||||
defaultValue: 'coordinator',
|
defaultValue: 'coordinator',
|
||||||
})
|
})
|
||||||
@ -66,19 +68,22 @@ const Login = () => {
|
|||||||
{
|
{
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
setLeaderOptions(
|
setLeaderOptions(
|
||||||
data?.data.project_supervisors.map(({ first_name, last_name, id }) => {
|
data?.data.project_supervisors.map(
|
||||||
return {
|
({ first_name, last_name, id }) => {
|
||||||
value: id,
|
return {
|
||||||
label: `${first_name} ${last_name}`,
|
value: id,
|
||||||
}
|
label: `${first_name} ${last_name}`,
|
||||||
}),
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const onStudentChange = (v: any) => {
|
const onStudentChange = (v: any) => {
|
||||||
setUserId(v.value)
|
setStudentId(v.value)
|
||||||
|
// setUserId(v.value)
|
||||||
setUserType('student')
|
setUserType('student')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +136,7 @@ const Login = () => {
|
|||||||
<Select
|
<Select
|
||||||
closeMenuOnSelect={true}
|
closeMenuOnSelect={true}
|
||||||
options={leaderOptions}
|
options={leaderOptions}
|
||||||
placeholder="Wybierz studenta"
|
placeholder="Wybierz opiekuna"
|
||||||
onChange={onLeaderChange}
|
onChange={onLeaderChange}
|
||||||
styles={{
|
styles={{
|
||||||
control: (styles: any) => ({
|
control: (styles: any) => ({
|
||||||
@ -162,10 +167,15 @@ const Login = () => {
|
|||||||
Zaloguj
|
Zaloguj
|
||||||
</button>
|
</button>
|
||||||
<div className="flex flex-col mt-3">
|
<div className="flex flex-col mt-3">
|
||||||
<span onClick={() => {
|
<span
|
||||||
setUserType('coordinator')
|
onClick={() => {
|
||||||
navigate("/coordinator")
|
setUserType('coordinator')
|
||||||
}} className="cursor-pointer">Koordynator</span>
|
navigate('/coordinator')
|
||||||
|
}}
|
||||||
|
className="cursor-pointer"
|
||||||
|
>
|
||||||
|
Koordynator
|
||||||
|
</span>
|
||||||
{/* <NavLink to="/student">Student</NavLink> */}
|
{/* <NavLink to="/student">Student</NavLink> */}
|
||||||
{/* <NavLink to="/supervisor">Opiekun</NavLink> */}
|
{/* <NavLink to="/supervisor">Opiekun</NavLink> */}
|
||||||
</div>
|
</div>
|
||||||
|
@ -101,13 +101,12 @@ const AddLeader = () => {
|
|||||||
<InputError>Email jest wymagany</InputError>
|
<InputError>Email jest wymagany</InputError>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="form-control">
|
<div className="form-control">
|
||||||
<label className="label" htmlFor="limit_group">
|
<label className="label" htmlFor="limit_group">
|
||||||
Limit grup
|
Limit grup
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
className="input input-bordered"
|
className="input input-bordered"
|
||||||
value="3"
|
|
||||||
id="limit_group"
|
id="limit_group"
|
||||||
type="text"
|
type="text"
|
||||||
{...register('limit_group', {
|
{...register('limit_group', {
|
||||||
@ -118,7 +117,7 @@ const AddLeader = () => {
|
|||||||
{errors.limit_group?.type === 'pattern' && (
|
{errors.limit_group?.type === 'pattern' && (
|
||||||
<InputError>Limit grup musi być liczbą dodatnią</InputError>
|
<InputError>Limit grup musi być liczbą dodatnią</InputError>
|
||||||
)}
|
)}
|
||||||
</div> */}
|
</div>
|
||||||
<button className="btn btn-success mt-4">Dodaj opiekuna</button>
|
<button className="btn btn-success mt-4">Dodaj opiekuna</button>
|
||||||
</form>
|
</form>
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar'
|
import { Calendar, Views } from 'react-big-calendar'
|
||||||
import { DateTime, Settings } from 'luxon'
|
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { useMutation, useQuery } from 'react-query'
|
import { useMutation, useQuery } from 'react-query'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
@ -9,14 +8,15 @@ import {
|
|||||||
generateTermsOfDefence,
|
generateTermsOfDefence,
|
||||||
getAvailabilityForCoordinator,
|
getAvailabilityForCoordinator,
|
||||||
} from '../../api/schedule'
|
} from '../../api/schedule'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import dayjsLocalizer from '../../utils/dayjsLocalizer'
|
||||||
|
|
||||||
|
const localizer = dayjsLocalizer(dayjs)
|
||||||
|
|
||||||
const SupervisorSchedule = () => {
|
const SupervisorSchedule = () => {
|
||||||
Settings.defaultZone = DateTime.local().zoneName
|
|
||||||
Settings.defaultLocale = 'pl'
|
|
||||||
|
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
const [yearGroupId] = useLocalStorageState('yearGroupId')
|
const [yearGroupId] = useLocalStorageState('yearGroupId')
|
||||||
const [supervisorId] = useLocalStorageState('supervisorId')
|
const [supervisorId] = useLocalStorageState('userId')
|
||||||
const [events, setEvents] = useState<
|
const [events, setEvents] = useState<
|
||||||
{
|
{
|
||||||
id: number
|
id: number
|
||||||
@ -61,15 +61,15 @@ const SupervisorSchedule = () => {
|
|||||||
Generuj harmonogram
|
Generuj harmonogram
|
||||||
</button>
|
</button>
|
||||||
<Calendar
|
<Calendar
|
||||||
localizer={luxonLocalizer(DateTime)}
|
localizer={localizer}
|
||||||
startAccessor="start"
|
startAccessor="start"
|
||||||
endAccessor="end"
|
endAccessor="end"
|
||||||
style={{ height: '80vh' }}
|
style={{ height: '80vh' }}
|
||||||
events={events}
|
events={events}
|
||||||
onView={onView}
|
onView={onView}
|
||||||
view={view}
|
view={view}
|
||||||
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()}
|
min={dayjs().set('hour', 8).set('minute', 0).toDate()}
|
||||||
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()}
|
max={dayjs().set('hour', 16).set('minute', 0).toDate()}
|
||||||
messages={bigCalendarTranslations}
|
messages={bigCalendarTranslations}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DateTime } from 'luxon'
|
import dayjs from 'dayjs'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Controller, NestedValue, useForm } from 'react-hook-form'
|
import { Controller, NestedValue, useForm } from 'react-hook-form'
|
||||||
import { useMutation, useQuery } from 'react-query'
|
import { useMutation, useQuery } from 'react-query'
|
||||||
@ -72,8 +72,8 @@ const EditSchedule = ({
|
|||||||
<form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}>
|
<form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}>
|
||||||
<h3> Termin </h3>
|
<h3> Termin </h3>
|
||||||
<p className="mb-2">
|
<p className="mb-2">
|
||||||
{DateTime.fromJSDate(eventData.start).toFormat('yyyy-LL-dd HH:mm:ss')}{' '}
|
{dayjs(eventData.start).format('YYYY-MM-DD HH:mm:ss')} -{' '}
|
||||||
- {DateTime.fromJSDate(eventData.end).toFormat('yyyy-LL-dd HH:mm:ss')}
|
{dayjs(eventData.end).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
</p>
|
</p>
|
||||||
{eventData.resource?.members_of_committee?.length ? (
|
{eventData.resource?.members_of_committee?.length ? (
|
||||||
<>
|
<>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar'
|
import { Calendar, Views } from 'react-big-calendar'
|
||||||
import { DateTime, Settings } from 'luxon'
|
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { useMutation, useQuery } from 'react-query'
|
import { useMutation, useQuery } from 'react-query'
|
||||||
import {
|
import {
|
||||||
@ -9,7 +8,7 @@ import {
|
|||||||
getTermsOfDefencesWithGroups,
|
getTermsOfDefencesWithGroups,
|
||||||
setDateOfExaminationSchedule,
|
setDateOfExaminationSchedule,
|
||||||
} from '../../api/schedule'
|
} from '../../api/schedule'
|
||||||
import { useParams } from 'react-router-dom'
|
import { Link, useParams } from 'react-router-dom'
|
||||||
import Modal from 'react-modal'
|
import Modal from 'react-modal'
|
||||||
import { Controller, NestedValue, useForm } from 'react-hook-form'
|
import { Controller, NestedValue, useForm } from 'react-hook-form'
|
||||||
import EditSchedule from './EditSchedule'
|
import EditSchedule from './EditSchedule'
|
||||||
@ -17,7 +16,9 @@ import Select from 'react-select'
|
|||||||
import { getLeaders } from '../../api/leaders'
|
import { getLeaders } from '../../api/leaders'
|
||||||
import useLocalStorageState from 'use-local-storage-state'
|
import useLocalStorageState from 'use-local-storage-state'
|
||||||
import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
|
import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
|
||||||
import DatePicker from 'react-date-picker'
|
import DateTimePicker from 'react-datetime-picker'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import dayjsLocalizer from '../../utils/dayjsLocalizer'
|
||||||
|
|
||||||
const customStyles = {
|
const customStyles = {
|
||||||
content: {
|
content: {
|
||||||
@ -34,10 +35,9 @@ type SelectValue = {
|
|||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const Schedule = () => {
|
const localizer = dayjsLocalizer(dayjs)
|
||||||
Settings.defaultZone = DateTime.local().zoneName
|
|
||||||
Settings.defaultLocale = 'pl'
|
|
||||||
|
|
||||||
|
const Schedule = () => {
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
const [yearGroupId] = useLocalStorageState('yearGroupId')
|
const [yearGroupId] = useLocalStorageState('yearGroupId')
|
||||||
const [events, setEvents] = useState<
|
const [events, setEvents] = useState<
|
||||||
@ -184,10 +184,10 @@ const Schedule = () => {
|
|||||||
} else {
|
} else {
|
||||||
// await mutateCreateEvent({
|
// await mutateCreateEvent({
|
||||||
// start_date: DateTime.fromJSDate(event.start).toFormat(
|
// start_date: DateTime.fromJSDate(event.start).toFormat(
|
||||||
// 'yyyy-LL-dd HH:mm:ss',
|
// 'YYYY-MM-DD HH:mm:ss',
|
||||||
// ),
|
// ),
|
||||||
// end_date: DateTime.fromJSDate(event.end).toFormat(
|
// end_date: DateTime.fromJSDate(event.end).toFormat(
|
||||||
// 'yyyy-LL-dd HH:mm:ss',
|
// 'YYYY-MM-DD HH:mm:ss',
|
||||||
// ),
|
// ),
|
||||||
// scheduleId: Number(id),
|
// scheduleId: Number(id),
|
||||||
// })
|
// })
|
||||||
@ -217,12 +217,14 @@ const Schedule = () => {
|
|||||||
const from = data.from.split(':')
|
const from = data.from.split(':')
|
||||||
const to = data.to.split(':')
|
const to = data.to.split(':')
|
||||||
await mutateCreateEvent({
|
await mutateCreateEvent({
|
||||||
start_date: DateTime.fromJSDate(selectedDate.start)
|
start_date: dayjs(selectedDate.start)
|
||||||
.set({ hour: from[0], minute: from[1] })
|
.set('hour', from[0])
|
||||||
.toFormat('yyyy-LL-dd HH:mm:ss'),
|
.set('minute', from[1])
|
||||||
end_date: DateTime.fromJSDate(selectedDate.start)
|
.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
.set({ hour: to[0], minute: to[1] })
|
end_date: dayjs(selectedDate.start)
|
||||||
.toFormat('yyyy-LL-dd HH:mm:ss'),
|
.set('hour', to[0])
|
||||||
|
.set('minute', to[1])
|
||||||
|
.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
scheduleId: Number(id),
|
scheduleId: Number(id),
|
||||||
project_supervisors: data?.project_supervisors,
|
project_supervisors: data?.project_supervisors,
|
||||||
})
|
})
|
||||||
@ -278,16 +280,20 @@ const Schedule = () => {
|
|||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div>
|
<div>
|
||||||
Start zapisów dla studentów: <label htmlFor="end_date">Od </label>
|
Start zapisów dla studentów: <label htmlFor="end_date">Od </label>
|
||||||
<DatePicker
|
<DateTimePicker
|
||||||
onChange={setStartDate}
|
onChange={setStartDate}
|
||||||
value={startDate}
|
value={startDate}
|
||||||
format={'yyyy-MM-dd'}
|
format={'yyyy-MM-dd HH:mm:ss'}
|
||||||
|
locale={'pl'}
|
||||||
|
disableClock
|
||||||
/>
|
/>
|
||||||
<label htmlFor="end_date">Do </label>
|
<label htmlFor="end_date">Do </label>
|
||||||
<DatePicker
|
<DateTimePicker
|
||||||
onChange={setEndDate}
|
onChange={setEndDate}
|
||||||
value={endDate}
|
value={endDate}
|
||||||
format={'yyyy-MM-dd'}
|
format={'yyyy-MM-dd HH:mm:ss'}
|
||||||
|
locale={'pl'}
|
||||||
|
disableClock
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
className="btn btn-success ml-2"
|
className="btn btn-success ml-2"
|
||||||
@ -301,15 +307,22 @@ const Schedule = () => {
|
|||||||
ZAPISZ
|
ZAPISZ
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex self-end gap-4 mb-4">
|
||||||
<button
|
<Link
|
||||||
className="btn btn-success btn-xs md:btn-md self-end mb-4"
|
className="underline font-bold self-center"
|
||||||
onClick={() => mutateDownload(Number(id))}
|
to={`/coordinator/schedule/${id}/workload`}
|
||||||
>
|
>
|
||||||
Eksportuj harmonogram
|
Statystyki
|
||||||
</button>
|
</Link>
|
||||||
|
<button
|
||||||
|
className="btn btn-success btn-xs md:btn-md "
|
||||||
|
onClick={() => mutateDownload(Number(id))}
|
||||||
|
>
|
||||||
|
Eksportuj harmonogram
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<Calendar
|
<Calendar
|
||||||
localizer={luxonLocalizer(DateTime)}
|
localizer={localizer}
|
||||||
startAccessor="start"
|
startAccessor="start"
|
||||||
endAccessor="end"
|
endAccessor="end"
|
||||||
style={{ height: '85vh' }}
|
style={{ height: '85vh' }}
|
||||||
@ -320,8 +333,8 @@ const Schedule = () => {
|
|||||||
onView={onView}
|
onView={onView}
|
||||||
view={view}
|
view={view}
|
||||||
eventPropGetter={eventGetter}
|
eventPropGetter={eventGetter}
|
||||||
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()}
|
min={dayjs().set('hour', 8).set('minute', 0).toDate()}
|
||||||
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()}
|
max={dayjs().set('hour', 16).set('minute', 0).toDate()}
|
||||||
messages={bigCalendarTranslations}
|
messages={bigCalendarTranslations}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { createSchedule, getSchedules } from '../../api/schedule'
|
|||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import useLocalStorageState from 'use-local-storage-state'
|
import useLocalStorageState from 'use-local-storage-state'
|
||||||
import DatePicker from 'react-date-picker'
|
import DateTimePicker from 'react-datetime-picker'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
const Schedules = () => {
|
const Schedules = () => {
|
||||||
@ -60,20 +60,24 @@ const Schedules = () => {
|
|||||||
Od
|
Od
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<DatePicker
|
<DateTimePicker
|
||||||
onChange={setStartDate}
|
onChange={setStartDate}
|
||||||
value={startDate}
|
value={startDate}
|
||||||
format={'yyyy-MM-dd'}
|
format={'yyyy-MM-dd HH:mm:ss'}
|
||||||
|
locale={'pl'}
|
||||||
|
disableClock
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label className="label" htmlFor="end_date">
|
<label className="label" htmlFor="end_date">
|
||||||
Do
|
Do
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<DatePicker
|
<DateTimePicker
|
||||||
onChange={setEndDate}
|
onChange={setEndDate}
|
||||||
value={endDate}
|
value={endDate}
|
||||||
format={'yyyy-MM-dd'}
|
format={'yyyy-MM-dd HH:mm:ss'}
|
||||||
|
locale={'pl'}
|
||||||
|
disableClock
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button className="btn btn-success mt-4">Stwórz zapisy</button>
|
<button className="btn btn-success mt-4">Stwórz zapisy</button>
|
||||||
|
35
frontend/src/views/coordinator/WorkloadStatistics.tsx
Normal file
35
frontend/src/views/coordinator/WorkloadStatistics.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { useQuery } from 'react-query'
|
||||||
|
import { useParams } from 'react-router-dom'
|
||||||
|
import { geWorkloadStatistics } from '../../api/schedule'
|
||||||
|
|
||||||
|
const WorkloadStatistics = () => {
|
||||||
|
const { id } = useParams<{ id: string }>()
|
||||||
|
|
||||||
|
const { data: workloads } = useQuery(['workload'], () =>
|
||||||
|
geWorkloadStatistics(Number(id)),
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<div className="flex">
|
||||||
|
<table className="table table-compact border border-gray-100">
|
||||||
|
<thead>
|
||||||
|
<tr className="bg-gray-50">
|
||||||
|
<th>Imię i nazwisko</th>
|
||||||
|
<th>Ilość przypisanych komisji</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody className="divide-y divide-gray-100">
|
||||||
|
{workloads?.data?.workloads.map(
|
||||||
|
({ full_name, assigned_to_committee }) => (
|
||||||
|
<tr key={full_name}>
|
||||||
|
<td>{full_name}</td>
|
||||||
|
<td>{assigned_to_committee}</td>
|
||||||
|
</tr>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WorkloadStatistics
|
@ -1,4 +1,4 @@
|
|||||||
import { DateTime } from 'luxon'
|
import dayjs from 'dayjs'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useForm } from 'react-hook-form'
|
import { useForm } from 'react-hook-form'
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query'
|
||||||
@ -51,9 +51,8 @@ const ScheduleAddGroup = ({
|
|||||||
<div>
|
<div>
|
||||||
<form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}>
|
<form className="w-full flex flex-col " onSubmit={handleSubmit(onSubmit)}>
|
||||||
<h3>
|
<h3>
|
||||||
Termin{' '}
|
Termin {dayjs(eventData.start).format('YYYY-MM-DD HH:mm:ss')} -{' '}
|
||||||
{DateTime.fromJSDate(eventData.start).toFormat('yyyy-LL-dd HH:mm:ss')}{' '}
|
{dayjs(eventData.end).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
- {DateTime.fromJSDate(eventData.end).toFormat('yyyy-LL-dd HH:mm:ss')}
|
|
||||||
</h3>
|
</h3>
|
||||||
{eventData.resource?.members_of_committee?.length > 0 && (
|
{eventData.resource?.members_of_committee?.length > 0 && (
|
||||||
<>
|
<>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar'
|
import { Calendar, Views } from 'react-big-calendar'
|
||||||
import { DateTime, Settings } from 'luxon'
|
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { useQuery } from 'react-query'
|
import { useQuery } from 'react-query'
|
||||||
import { getStudentsTermsOfDefences } from '../../api/schedule'
|
import { getStudentsTermsOfDefences } from '../../api/schedule'
|
||||||
@ -9,6 +8,8 @@ import { useForm } from 'react-hook-form'
|
|||||||
import ScheduleAddGroup from './ScheduleAddGroup'
|
import ScheduleAddGroup from './ScheduleAddGroup'
|
||||||
import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
|
import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
|
||||||
import useLocalStorageState from 'use-local-storage-state'
|
import useLocalStorageState from 'use-local-storage-state'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import dayjsLocalizer from '../../utils/dayjsLocalizer'
|
||||||
|
|
||||||
const customStyles = {
|
const customStyles = {
|
||||||
content: {
|
content: {
|
||||||
@ -20,11 +21,9 @@ const customStyles = {
|
|||||||
transform: 'translate(-50%, -50%)',
|
transform: 'translate(-50%, -50%)',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
const localizer = dayjsLocalizer(dayjs)
|
||||||
|
|
||||||
const StudentSchedule = () => {
|
const StudentSchedule = () => {
|
||||||
Settings.defaultZone = DateTime.local().zoneName
|
|
||||||
Settings.defaultLocale = 'pl'
|
|
||||||
|
|
||||||
const [studentId] = useLocalStorageState('studentId')
|
const [studentId] = useLocalStorageState('studentId')
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
const [events, setEvents] = useState<
|
const [events, setEvents] = useState<
|
||||||
@ -131,7 +130,7 @@ const StudentSchedule = () => {
|
|||||||
Wybierz i zatwierdź termin obrony dla swojej grupy
|
Wybierz i zatwierdź termin obrony dla swojej grupy
|
||||||
</h1>
|
</h1>
|
||||||
<Calendar
|
<Calendar
|
||||||
localizer={luxonLocalizer(DateTime)}
|
localizer={localizer}
|
||||||
startAccessor="start"
|
startAccessor="start"
|
||||||
endAccessor="end"
|
endAccessor="end"
|
||||||
style={{ height: '85vh' }}
|
style={{ height: '85vh' }}
|
||||||
@ -141,8 +140,8 @@ const StudentSchedule = () => {
|
|||||||
onView={onView}
|
onView={onView}
|
||||||
view={view}
|
view={view}
|
||||||
eventPropGetter={eventGetter}
|
eventPropGetter={eventGetter}
|
||||||
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()}
|
min={dayjs().set('hour', 8).set('minute', 0).toDate()}
|
||||||
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()}
|
max={dayjs().set('hour', 16).set('minute', 0).toDate()}
|
||||||
messages={bigCalendarTranslations}
|
messages={bigCalendarTranslations}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Calendar, luxonLocalizer, Views } from 'react-big-calendar'
|
import { Calendar, Views } from 'react-big-calendar'
|
||||||
import { DateTime, Settings } from 'luxon'
|
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
import { useMutation, useQuery } from 'react-query'
|
import { useMutation, useQuery } from 'react-query'
|
||||||
import {
|
import {
|
||||||
@ -13,6 +12,8 @@ import { useForm } from 'react-hook-form'
|
|||||||
import EditSchedule from '../coordinator/EditSchedule'
|
import EditSchedule from '../coordinator/EditSchedule'
|
||||||
import useLocalStorageState from 'use-local-storage-state'
|
import useLocalStorageState from 'use-local-storage-state'
|
||||||
import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
|
import bigCalendarTranslations from '../../utils/bigCalendarTranslations'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import dayjsLocalizer from '../../utils/dayjsLocalizer'
|
||||||
|
|
||||||
const customStyles = {
|
const customStyles = {
|
||||||
content: {
|
content: {
|
||||||
@ -28,11 +29,9 @@ type SelectValue = {
|
|||||||
value: string | number
|
value: string | number
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
const localizer = dayjsLocalizer(dayjs)
|
||||||
|
|
||||||
const SupervisorSchedule = () => {
|
const SupervisorSchedule = () => {
|
||||||
Settings.defaultZone = DateTime.local().zoneName
|
|
||||||
Settings.defaultLocale = 'pl'
|
|
||||||
|
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id } = useParams<{ id: string }>()
|
||||||
const [yearGroupId] = useLocalStorageState('yearGroupId')
|
const [yearGroupId] = useLocalStorageState('yearGroupId')
|
||||||
const [supervisorId] = useLocalStorageState('userId')
|
const [supervisorId] = useLocalStorageState('userId')
|
||||||
@ -155,12 +154,14 @@ const SupervisorSchedule = () => {
|
|||||||
const from = data.from.split(':')
|
const from = data.from.split(':')
|
||||||
const to = data.to.split(':')
|
const to = data.to.split(':')
|
||||||
await mutateAddAvailability({
|
await mutateAddAvailability({
|
||||||
start_date: DateTime.fromJSDate(selectedDate.start)
|
start_date: dayjs(selectedDate.start)
|
||||||
.set({ hour: from[0], minute: from[1] })
|
.set('hour', from[0])
|
||||||
.toFormat('yyyy-LL-dd HH:mm:ss'),
|
.set('minute', from[1])
|
||||||
end_date: DateTime.fromJSDate(selectedDate.start)
|
.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
.set({ hour: to[0], minute: to[1] })
|
end_date: dayjs(selectedDate.start)
|
||||||
.toFormat('yyyy-LL-dd HH:mm:ss'),
|
.set('hour', to[0])
|
||||||
|
.set('minute', to[1])
|
||||||
|
.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
scheduleId: Number(id),
|
scheduleId: Number(id),
|
||||||
project_supervisor_id: Number(supervisorId),
|
project_supervisor_id: Number(supervisorId),
|
||||||
})
|
})
|
||||||
@ -189,7 +190,7 @@ const SupervisorSchedule = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Calendar
|
<Calendar
|
||||||
localizer={luxonLocalizer(DateTime)}
|
localizer={localizer}
|
||||||
startAccessor="start"
|
startAccessor="start"
|
||||||
endAccessor="end"
|
endAccessor="end"
|
||||||
selectable
|
selectable
|
||||||
@ -200,8 +201,8 @@ const SupervisorSchedule = () => {
|
|||||||
onView={onView}
|
onView={onView}
|
||||||
view={view}
|
view={view}
|
||||||
eventPropGetter={eventGetter}
|
eventPropGetter={eventGetter}
|
||||||
min={DateTime.fromObject({ hour: 8, minute: 0 }).toJSDate()}
|
min={dayjs().set('hour', 8).set('minute', 0).toDate()}
|
||||||
max={DateTime.fromObject({ hour: 16, minute: 0 }).toJSDate()}
|
max={dayjs().set('hour', 16).set('minute', 0).toDate()}
|
||||||
messages={bigCalendarTranslations}
|
messages={bigCalendarTranslations}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user