Add form for adding students

This commit is contained in:
adam-skowronek 2022-06-04 21:03:40 +02:00
parent b03e369b73
commit 3d36569844
8 changed files with 352 additions and 61 deletions

View File

@ -16,8 +16,10 @@
"@types/react": "^18.0.9", "@types/react": "^18.0.9",
"@types/react-dom": "^18.0.4", "@types/react-dom": "^18.0.4",
"axios": "^0.27.2", "axios": "^0.27.2",
"daisyui": "^2.15.2",
"react": "^18.1.0", "react": "^18.1.0",
"react-dom": "^18.1.0", "react-dom": "^18.1.0",
"react-hook-form": "^7.31.3",
"react-query": "^3.39.0", "react-query": "^3.39.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
@ -5314,6 +5316,18 @@
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
"integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg=="
}, },
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"dependencies": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -5327,6 +5341,31 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}, },
"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/color/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/colord": { "node_modules/colord": {
"version": "2.9.2", "version": "2.9.2",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz",
@ -5782,6 +5821,15 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
}, },
"node_modules/css-selector-tokenizer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
"integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
"dependencies": {
"cssesc": "^3.0.0",
"fastparse": "^1.1.2"
}
},
"node_modules/css-tree": { "node_modules/css-tree": {
"version": "1.0.0-alpha.37", "version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
@ -5981,6 +6029,21 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
}, },
"node_modules/daisyui": {
"version": "2.15.2",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.15.2.tgz",
"integrity": "sha512-12hjzlOUkGVzMPKhaBc8soqNY2mJWGTYJF8sTuCibDcdGbHDmYgBUY0OX1HHIVq/qh2vELh5yHb4QCgCDWUAwg==",
"dependencies": {
"color": "^4.2",
"css-selector-tokenizer": "^0.8.0",
"postcss-js": "^4.0.0",
"tailwindcss": "^3.0"
},
"peerDependencies": {
"autoprefixer": "^10.0.2",
"postcss": "^8.1.6"
}
},
"node_modules/damerau-levenshtein": { "node_modules/damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@ -7400,6 +7463,11 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
}, },
"node_modules/fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ=="
},
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.13.0", "version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@ -13561,6 +13629,21 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
}, },
"node_modules/react-hook-form": {
"version": "7.31.3",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.31.3.tgz",
"integrity": "sha512-NVZdCWViIWXXXlQ3jxVQH0NuNfwPf8A/0KvuCxrM9qxtP1qYosfR2ZudarziFrVOC7eTUbWbm1T4OyYCwv9oSQ==",
"engines": {
"node": ">=12.22.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-hook-form"
},
"peerDependencies": {
"react": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@ -14423,6 +14506,19 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
}, },
"node_modules/simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"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/sisteransi": { "node_modules/sisteransi": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@ -20186,6 +20282,30 @@
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
"integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg=="
}, },
"color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"requires": {
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"dependencies": {
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}
}
},
"color-convert": { "color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -20199,6 +20319,15 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
}, },
"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==",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colord": { "colord": {
"version": "2.9.2", "version": "2.9.2",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz",
@ -20517,6 +20646,15 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
}, },
"css-selector-tokenizer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
"integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
"requires": {
"cssesc": "^3.0.0",
"fastparse": "^1.1.2"
}
},
"css-tree": { "css-tree": {
"version": "1.0.0-alpha.37", "version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
@ -20659,6 +20797,17 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz",
"integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA=="
}, },
"daisyui": {
"version": "2.15.2",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.15.2.tgz",
"integrity": "sha512-12hjzlOUkGVzMPKhaBc8soqNY2mJWGTYJF8sTuCibDcdGbHDmYgBUY0OX1HHIVq/qh2vELh5yHb4QCgCDWUAwg==",
"requires": {
"color": "^4.2",
"css-selector-tokenizer": "^0.8.0",
"postcss-js": "^4.0.0",
"tailwindcss": "^3.0"
}
},
"damerau-levenshtein": { "damerau-levenshtein": {
"version": "1.0.8", "version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@ -21705,6 +21854,11 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
}, },
"fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ=="
},
"fastq": { "fastq": {
"version": "1.13.0", "version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@ -26009,6 +26163,12 @@
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
}, },
"react-hook-form": {
"version": "7.31.3",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.31.3.tgz",
"integrity": "sha512-NVZdCWViIWXXXlQ3jxVQH0NuNfwPf8A/0KvuCxrM9qxtP1qYosfR2ZudarziFrVOC7eTUbWbm1T4OyYCwv9oSQ==",
"requires": {}
},
"react-is": { "react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@ -26636,6 +26796,21 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
}, },
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
},
"dependencies": {
"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=="
}
}
},
"sisteransi": { "sisteransi": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",

View File

@ -11,8 +11,10 @@
"@types/react": "^18.0.9", "@types/react": "^18.0.9",
"@types/react-dom": "^18.0.4", "@types/react-dom": "^18.0.4",
"axios": "^0.27.2", "axios": "^0.27.2",
"daisyui": "^2.15.2",
"react": "^18.1.0", "react": "^18.1.0",
"react-dom": "^18.1.0", "react-dom": "^18.1.0",
"react-hook-form": "^7.31.3",
"react-query": "^3.39.0", "react-query": "^3.39.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",

View File

@ -2,6 +2,7 @@ import React from 'react'
import { QueryClient, QueryClientProvider } from 'react-query' import { QueryClient, QueryClientProvider } from 'react-query'
import { Route, Routes } from 'react-router-dom' import { Route, Routes } from 'react-router-dom'
import './App.css' import './App.css'
import AddStudent from './views/coordinator/AddStudent'
import Coordinator from './views/coordinator/Coordinator' import Coordinator from './views/coordinator/Coordinator'
import Groups from './views/coordinator/Groups' import Groups from './views/coordinator/Groups'
import Leaders from './views/coordinator/Leaders' import Leaders from './views/coordinator/Leaders'
@ -25,6 +26,7 @@ function App() {
<Route path="groups" element={<Groups />} /> <Route path="groups" element={<Groups />} />
<Route path="students" element={<Students />} /> <Route path="students" element={<Students />} />
<Route path="leaders" element={<Leaders />} /> <Route path="leaders" element={<Leaders />} />
<Route path="add-student" element={<AddStudent />} />
</Route> </Route>
</Routes> </Routes>
</QueryClientProvider> </QueryClientProvider>

View File

@ -2,13 +2,15 @@ import axiosInstance from './axiosInstance'
interface StudentResponse { interface StudentResponse {
max_pages: number max_pages: number
students: { students: Student[]
}
export interface Student {
first_name: string first_name: string
last_name: string last_name: string
index: number index: number
mode: boolean mode: boolean
group: any group?: any
}[]
} }
export const getStudents = () => export const getStudents = () =>
@ -16,6 +18,9 @@ export const getStudents = () =>
'http://127.0.0.1:5000/api/coordinator/students', 'http://127.0.0.1:5000/api/coordinator/students',
) )
export const createStudent = (payload: Student) =>
axiosInstance.post('http://127.0.0.1:5000/api/coordinator/students/', payload)
export const uploadStudents = (payload: FormData) => export const uploadStudents = (payload: FormData) =>
axiosInstance.post( axiosInstance.post(
'http://127.0.0.1:5000/api/coordinator/students/upload/', 'http://127.0.0.1:5000/api/coordinator/students/upload/',

View File

@ -0,0 +1,4 @@
const InputError = (props: { children: React.ReactNode }) => (
<p className="text-rose-600 ">{props.children}</p>
)
export default InputError

View File

@ -0,0 +1,125 @@
import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { useMutation } from 'react-query'
import { createStudent, Student } from '../../api/students'
import InputError from '../../components/InputError'
const AddStudent = () => {
const [isAlertVisible, setIsAlertVisible] = useState(false)
const {
register,
handleSubmit,
formState: { errors },
reset,
} = useForm<Student>({ mode: 'onBlur' })
const { mutate: mutateCreateStudent } = useMutation(
'createStudent',
(payload: Student) => createStudent(payload),
{
onSuccess: () => {
reset()
setIsAlertVisible(true)
},
},
)
const onSubmit = (data: Student) => {
mutateCreateStudent(data)
}
return (
<form
className="w-full lg:w-1/4 flex flex-col mx-auto"
onSubmit={handleSubmit(onSubmit)}
>
{isAlertVisible && (
<div className="alert alert-success shadow-lg">
<span>Udało się dodać studenta!</span>
</div>
)}
<div className="form-control">
<label className="label" htmlFor="first_name">
Imię
</label>
<input
className="input input-bordered"
id="first_name"
type="text"
{...register('first_name', { required: true })}
/>
{errors.first_name?.type === 'required' && (
<InputError>Imię jest wymagane</InputError>
)}
</div>
<div className="form-control">
<label className="label" htmlFor="last_name">
Nazwisko
</label>
<input
className="input input-bordered"
id="last_name"
type="text"
{...register('last_name', { required: true })}
/>
{errors.last_name?.type === 'required' && (
<InputError>Nazwisko jest wymagane</InputError>
)}
</div>
<div className="form-control">
<label className="label" htmlFor="index">
Indeks
</label>
<input
className="input input-bordered"
id="index"
type="text"
{...register('index', {
required: true,
pattern: /^[0-9]{6}$/,
})}
/>
{errors.index?.type === 'required' && (
<InputError>Indeks jest wymagany</InputError>
)}
{errors.index?.type === 'pattern' && (
<InputError>Indeks musi mieć 6 cyfr</InputError>
)}
</div>
<div className="form-control gap-2">
<label className="label">Tryb studiów</label>
<div className="flex gap-2">
<input
className="radio"
id="mode-0"
type="radio"
{...register('mode', {
required: true,
})}
value="0"
/>
<label htmlFor="mode-0">Stacjonarny</label>
</div>
<div className="flex gap-2">
<input
className="radio"
id="mode-1"
type="radio"
{...register('mode', {
required: true,
})}
value="1"
/>
<label htmlFor="mode-1">Niestacjonarny</label>
</div>
{errors.mode?.type === 'required' && (
<InputError>Wybierz tryb studiów</InputError>
)}
</div>
<button className="btn btn-success mt-4">Dodaj studenta</button>
</form>
)
}
export default AddStudent

View File

@ -1,14 +1,12 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { useMutation, useQuery } from 'react-query' import { useMutation, useQuery } from 'react-query'
import { useNavigate } from 'react-router-dom'
import { getStudents, uploadStudents } from '../../api/students' import { getStudents, uploadStudents } from '../../api/students'
const TableHeader = (props: { children: React.ReactNode }) => (
<th className="px-4 py-2 font-medium text-left text-gray-900 whitespace-nowrap">
{props.children}
</th>
)
const Students = () => { const Students = () => {
let navigate = useNavigate()
const [showGroupless, setShowGroupless] = useState(false)
const { const {
isLoading: isStudentsLoading, isLoading: isStudentsLoading,
data: students, data: students,
@ -30,23 +28,19 @@ const Students = () => {
mutateUpload(payload) mutateUpload(payload)
} }
const [state, setState] = useState({
showGroupless: false
});
if (isStudentsLoading) { if (isStudentsLoading) {
return <div>Ładowanie</div> return <div>Ładowanie</div>
} }
return ( return (
<div> <div>
<div className="flex items-center"> <div className="flex items-center">
<button className="bg-green-400 p-3 rounded-lg text-white font-extrabold hover:bg-green-300"> <button
className="btn btn-success"
onClick={() => navigate('/coordinator/add-student')}
>
Dodaj nowego studenta Dodaj nowego studenta
</button> </button>
<label <label className="ml-4 btn btn-success btn-outline" htmlFor="file">
className="ml-4 text-green-400 font-extrabold rounded-lg border-2 p-3 border-green-400 hover:border-green-300 cursor-pointer"
htmlFor="file"
>
Importuj Importuj
</label> </label>
<input <input
@ -57,53 +51,39 @@ const Students = () => {
className="hidden" className="hidden"
onChange={handleOnChange} onChange={handleOnChange}
/> />
<label className="ml-auto"> <label className="label ml-auto">
<span className="slider round">Tylko niezapisani</span> <span className="mr-2">Tylko niezapisani</span>
<input type="checkbox" <input
className="m-2 checked: bg-black-400" type="checkbox"
onChange={() => setState({ className="checkbox"
...state, onChange={() => setShowGroupless(!showGroupless)}
showGroupless: !state.showGroupless
})}
/> />
</label> </label>
</div> </div>
<div className="flex mx-auto mt-5 overflow-hidden overflow-x-auto border border-gray-100 rounded"> <div className="flex mx-auto mt-5 overflow-hidden overflow-x-auto border border-gray-100 rounded">
<table className="min-w-full text-sm divide-y divide-gray-200"> <table className="min-w-full table table-compact">
<thead> <thead>
<tr className="bg-gray-50"> <tr className="bg-gray-50">
<TableHeader>Imie</TableHeader> <th>Imię</th>
<TableHeader>Nazwisko</TableHeader> <th>Nazwisko</th>
<TableHeader>Indeks</TableHeader> <th>Indeks</th>
<TableHeader>Zapisany</TableHeader> <th>Zapisany</th>
<TableHeader>Tryb</TableHeader> <th>Tryb</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-gray-100"> <tbody className="divide-y divide-gray-100">
{students?.data?.students?.filter( {students?.data?.students
(st) => (st.group === null || !state.showGroupless) ?.filter((st) => st.group === null || !showGroupless)
).map( .map(({ first_name, last_name, index, group, mode }) => (
({ first_name, last_name, index, group, mode }) => (
<tr key={index}> <tr key={index}>
<td className="px-4 py-2 font-medium text-gray-900 whitespace-nowrap"> <td>{first_name}</td>
{first_name} <td>{last_name}</td>
</td> <td>{index}</td>
<td className="px-4 py-2 text-gray-700 whitespace-nowrap"> <td>{group === null ? 'Nie' : 'Tak'}</td>
{last_name} <td>{mode ? 'stacjonarny' : 'niestacjonarny'}</td>
</td>
<td className="px-4 py-2 text-gray-700 whitespace-nowrap">
{index}
</td>
<td className="px-4 py-2 text-gray-700 whitespace-nowrap">
{group === null ? 'Nie' : 'Tak'}
</td>
<td className="px-4 py-2 text-gray-700 whitespace-nowrap">
{mode ? 'stacjonarny' : 'niestacjonarny'}
</td>
</tr> </tr>
), ))}
)}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -1,9 +1,7 @@
module.exports = { module.exports = {
content: [ content: ['./src/**/*.{js,jsx,ts,tsx}'],
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: { theme: {
extend: {}, extend: {},
}, },
plugins: [], plugins: [require('daisyui')],
} }