Release v1

Optimisations finales
Ajout de la gestion d'absences (Ajout, suppression, justification)
This commit is contained in:
Theal0 2021-05-18 17:21:19 +02:00
parent deab35b121
commit 7569934ce8
19 changed files with 539 additions and 1292 deletions

View File

@ -2,14 +2,15 @@
## Description
Version mobile de l'application web ScoDoc (v0)
Version mobile de l'application web ScoDoc (v1)
### Fonctionnalités:
- Login
- Choix de département / formation
- Affichage des profils étudiants
- Recherche d'élèves
- Affichage des absences
- Affichage des bulletins de notes
- Gestion des absences
## Usage
@ -21,18 +22,6 @@ Modifier le fichier index.js (ligne 8) afin de mettre l'endpoint de l'API ScoDoc
Le contenu du dossier `build` doit etre la racine du site web.
Pour éviter des erreurs 404 liées à l'arborescence dynamique de React:
```
<Directory ...>
...
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^ index.html [L]
</Directory>
```
## Arborescence
### `/`

551
package-lock.json generated
View File

@ -4,43 +4,6 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@ant-design/colors": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-6.0.0.tgz",
"integrity": "sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==",
"requires": {
"@ctrl/tinycolor": "^3.4.0"
}
},
"@ant-design/icons": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-4.6.2.tgz",
"integrity": "sha512-QsBG2BxBYU/rxr2eb8b2cZ4rPKAPBpzAR+0v6rrZLp/lnyvflLH3tw1vregK+M7aJauGWjIGNdFmUfpAOtw25A==",
"requires": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons-svg": "^4.0.0",
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"rc-util": "^5.9.4"
}
},
"@ant-design/icons-svg": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.1.0.tgz",
"integrity": "sha512-Fi03PfuUqRs76aI3UWYpP864lkrfPo0hluwGqh7NJdLhvH4iRDc3jbJqZIvRDLHKbXrvAfPPV3+zjUccfFvWOQ=="
},
"@ant-design/react-slick": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-0.28.3.tgz",
"integrity": "sha512-u3onF2VevGRbkGbgpldVX/nzd7LFtLeZJE0x2xIFT2qYHKkJZ6QT/jQ7KqYK4UpeTndoyrbMqLN4DiJza4BVBg==",
"requires": {
"@babel/runtime": "^7.10.4",
"classnames": "^2.2.5",
"json2mq": "^0.2.0",
"lodash": "^4.17.21",
"resize-observer-polyfill": "^1.5.0"
}
},
"@babel/code-frame": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
@ -1198,11 +1161,6 @@
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
"integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
},
"@ctrl/tinycolor": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz",
"integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ=="
},
"@emotion/cache": {
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
@ -2948,55 +2906,6 @@
"color-convert": "^1.9.0"
}
},
"antd": {
"version": "4.15.2",
"resolved": "https://registry.npmjs.org/antd/-/antd-4.15.2.tgz",
"integrity": "sha512-9IwlR022xSQrG+iJG8d7adSo9gy4n7AuS5x0/OxDi/V3CYSTTfaE24jp1wnmgmXOVAT/77Llg9OEbKcSyFim2g==",
"requires": {
"@ant-design/colors": "^6.0.0",
"@ant-design/icons": "^4.6.2",
"@ant-design/react-slick": "~0.28.1",
"@babel/runtime": "^7.12.5",
"array-tree-filter": "^2.1.0",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.2.0",
"lodash": "^4.17.21",
"moment": "^2.25.3",
"rc-cascader": "~1.4.0",
"rc-checkbox": "~2.3.0",
"rc-collapse": "~3.1.0",
"rc-dialog": "~8.5.1",
"rc-drawer": "~4.3.0",
"rc-dropdown": "~3.2.0",
"rc-field-form": "~1.20.0",
"rc-image": "~5.2.4",
"rc-input-number": "~7.0.1",
"rc-mentions": "~1.5.0",
"rc-menu": "~8.10.0",
"rc-motion": "^2.4.0",
"rc-notification": "~4.5.2",
"rc-pagination": "~3.1.6",
"rc-picker": "~2.5.10",
"rc-progress": "~3.1.0",
"rc-rate": "~2.9.0",
"rc-resize-observer": "^1.0.0",
"rc-select": "~12.1.6",
"rc-slider": "~9.7.1",
"rc-steps": "~4.1.0",
"rc-switch": "~3.2.0",
"rc-table": "~7.13.0",
"rc-tabs": "~11.7.0",
"rc-textarea": "~0.3.0",
"rc-tooltip": "~5.1.0",
"rc-tree": "~4.1.0",
"rc-tree-select": "~4.3.0",
"rc-trigger": "^5.2.1",
"rc-upload": "~4.2.0-alpha.0",
"rc-util": "^5.9.4",
"scroll-into-view-if-needed": "^2.2.25",
"warning": "^4.0.3"
}
},
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
@ -3065,11 +2974,6 @@
"is-string": "^1.0.5"
}
},
"array-tree-filter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz",
"integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw=="
},
"array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@ -3204,11 +3108,6 @@
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
"integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
"async-validator": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-3.5.1.tgz",
"integrity": "sha512-DDmKA7sdSAJtTVeNZHrnr2yojfFaoeW8MfQN8CeuXg8DDQHTqKk9Fdv38dSvnesHoO8MUwMI2HphOeSyIF+wmQ=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -4453,11 +4352,6 @@
}
}
},
"compute-scroll-into-view": {
"version": "1.0.17",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz",
"integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg=="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -4591,14 +4485,6 @@
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
},
"copy-to-clipboard": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz",
"integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==",
"requires": {
"toggle-selection": "^1.0.6"
}
},
"core-js": {
"version": "3.10.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.10.2.tgz",
@ -5107,11 +4993,6 @@
"whatwg-url": "^8.0.0"
}
},
"date-fns": {
"version": "2.21.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.21.1.tgz",
"integrity": "sha512-m1WR0xGiC6j6jNFAyW4Nvh4WxAi4JF4w9jRJwSI8nBmNcyZXPcP9VUQG+6gHQXAmqaGEKDKhOqAtENDC941UkA=="
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@ -5396,11 +5277,6 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz",
"integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ=="
},
"dom-align": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.0.tgz",
"integrity": "sha512-YkoezQuhp3SLFGdOlr5xkqZ640iXrnHAwVYcDg8ZKRUtO7mSzSC2BA5V0VuyAwPSJA4CLIc6EDDJh4bEsD2+zA=="
},
"dom-converter": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
@ -9930,14 +9806,6 @@
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json2mq": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz",
"integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=",
"requires": {
"string-convert": "^0.2.0"
}
},
"json3": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
@ -10477,15 +10345,6 @@
}
}
},
"mini-store": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/mini-store/-/mini-store-3.0.6.tgz",
"integrity": "sha512-YzffKHbYsMQGUWQRKdsearR79QsMzzJcDDmZKlJBqt5JNkqpyJHYlK6gP61O36X+sLf76sO9G6mhKBe83gIZIQ==",
"requires": {
"hoist-non-react-statics": "^3.3.2",
"shallowequal": "^1.0.2"
}
},
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
@ -10594,11 +10453,6 @@
"minimist": "^1.2.5"
}
},
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@ -12775,383 +12629,6 @@
}
}
},
"rc-align": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.9.tgz",
"integrity": "sha512-myAM2R4qoB6LqBul0leaqY8gFaiECDJ3MtQDmzDo9xM9NRT/04TvWOYd2YHU9zvGzqk9QXF6S9/MifzSKDZeMw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"dom-align": "^1.7.0",
"rc-util": "^5.3.0",
"resize-observer-polyfill": "^1.5.1"
}
},
"rc-cascader": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-1.4.2.tgz",
"integrity": "sha512-JVuLGrSi+3G8DZyPvlKlGVWJjhoi9NTz6REHIgRspa5WnznRkKGm2ejb0jJtz0m2IL8Q9BG4ZA2sXuqAu71ltQ==",
"requires": {
"@babel/runtime": "^7.12.5",
"array-tree-filter": "^2.1.0",
"rc-trigger": "^5.0.4",
"rc-util": "^5.0.1",
"warning": "^4.0.1"
}
},
"rc-checkbox": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.3.2.tgz",
"integrity": "sha512-afVi1FYiGv1U0JlpNH/UaEXdh6WUJjcWokj/nUN2TgG80bfG+MDdbfHKlLcNNba94mbjy2/SXJ1HDgrOkXGAjg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1"
}
},
"rc-collapse": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.1.0.tgz",
"integrity": "sha512-EwpNPJcLe7b+5JfyaxM9ZNnkCgqArt3QQO0Cr5p5plwz/C9h8liAmjYY5I4+hl9lAjBqb7ZwLu94+z+rt5g1WQ==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-motion": "^2.3.4",
"rc-util": "^5.2.1",
"shallowequal": "^1.1.0"
}
},
"rc-dialog": {
"version": "8.5.2",
"resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-8.5.2.tgz",
"integrity": "sha512-3n4taFcjqhTE9uNuzjB+nPDeqgRBTEGBfe46mb1e7r88DgDo0lL4NnxY/PZ6PJKd2tsCt+RrgF/+YeTvJ/Thsw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-motion": "^2.3.0",
"rc-util": "^5.6.1"
}
},
"rc-drawer": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-4.3.1.tgz",
"integrity": "sha512-GMfFy4maqxS9faYXEhQ+0cA1xtkddEQzraf6SAdzWbn444DrrLogwYPk1NXSpdXjLCLxgxOj9MYtyYG42JsfXg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-util": "^5.7.0"
}
},
"rc-dropdown": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.2.0.tgz",
"integrity": "sha512-j1HSw+/QqlhxyTEF6BArVZnTmezw2LnSmRk6I9W7BCqNCKaRwleRmMMs1PHbuaG8dKHVqP6e21RQ7vPBLVnnNw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-trigger": "^5.0.4"
}
},
"rc-field-form": {
"version": "1.20.0",
"resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.20.0.tgz",
"integrity": "sha512-jkzsIfXR7ywEYdeAtktt1aLff88wxIPDLpq7KShHNl4wlsWrCE+TzkXBfjvVzYOVZt5GGrD8YDqNO/q6eaR/eA==",
"requires": {
"@babel/runtime": "^7.8.4",
"async-validator": "^3.0.3",
"rc-util": "^5.8.0"
}
},
"rc-image": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/rc-image/-/rc-image-5.2.4.tgz",
"integrity": "sha512-kWOjhZC1OoGKfvWqtDoO9r8WUNswBwnjcstI6rf7HMudz0usmbGvewcWqsOhyaBRJL9+I4eeG+xiAoxV1xi75Q==",
"requires": {
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"rc-dialog": "~8.5.0",
"rc-util": "^5.0.6"
}
},
"rc-input-number": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-7.0.6.tgz",
"integrity": "sha512-J5DIoCKIunoPb16FEghaEOyNDuZXD5F9LxLNcqd31z/0e37XtuHgo4QF/TonKLsESwdg7UAzWhiD0K6PPrN3YQ==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-util": "^5.9.8"
}
},
"rc-mentions": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.5.3.tgz",
"integrity": "sha512-NG/KB8YiKBCJPHHvr/QapAb4f9YzLJn7kDHtmI1K6t7ZMM5YgrjIxNNhoRKKP9zJvb9PdPts69Hbg4ZMvLVIFQ==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-menu": "^8.0.1",
"rc-textarea": "^0.3.0",
"rc-trigger": "^5.0.4",
"rc-util": "^5.0.1"
}
},
"rc-menu": {
"version": "8.10.7",
"resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-8.10.7.tgz",
"integrity": "sha512-m/ypV7OjkkUsMdutzMUxEI8tWyi0Y1TQ5YkSDk7k2uv2aCKkHYEoDKsDAfcPeejo3HMo2z5unWE+jD+dCphraw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"mini-store": "^3.0.1",
"rc-motion": "^2.0.1",
"rc-trigger": "^5.1.2",
"rc-util": "^5.7.0",
"resize-observer-polyfill": "^1.5.0",
"shallowequal": "^1.1.0"
}
},
"rc-motion": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.4.3.tgz",
"integrity": "sha512-GZLLFXHl/VqTfI7bSZNNZozcblNmDka1AAoQig7EZ6s0rWg5y0RlgrcHWO+W+nrOVbYfJDxoaQUoP2fEmvCWmA==",
"requires": {
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
"rc-util": "^5.2.1"
}
},
"rc-notification": {
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-4.5.5.tgz",
"integrity": "sha512-YIfhTSw+h5GsSdgMnuMx24wqiPlg3FeamuOlkh9RkyHx+SeZVAKzQ0juy2NGvPEF2hDWi5xTqxUqLdo0L2AmGg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-motion": "^2.2.0",
"rc-util": "^5.0.1"
}
},
"rc-overflow": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.1.1.tgz",
"integrity": "sha512-bkGrxvWtz6xQfxBPBQcN8xOEHFCeG0R4pfLAku6kFLQF9NPMTt5HvT+Bq0+stqom9eI3WRlun6RPzfjTamPwew==",
"requires": {
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.5.1"
}
},
"rc-pagination": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.1.6.tgz",
"integrity": "sha512-Pb2zJEt8uxXzYCWx/2qwsYZ3vSS9Eqdw0cJBli6C58/iYhmvutSBqrBJh51Z5UzYc5ZcW5CMeP5LbbKE1J3rpw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1"
}
},
"rc-picker": {
"version": "2.5.10",
"resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.5.10.tgz",
"integrity": "sha512-d2or2jql9SSY8CaRPybpbKkXBq3bZ6g88UKyWQZBLTCrc92Xm87RfRC/P3UEQo/CLmia3jVF7IXVi1HmNe2DZA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"date-fns": "^2.15.0",
"moment": "^2.24.0",
"rc-trigger": "^5.0.4",
"rc-util": "^5.4.0",
"shallowequal": "^1.1.0"
}
},
"rc-progress": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-3.1.3.tgz",
"integrity": "sha512-Jl4fzbBExHYMoC6HBPzel0a9VmhcSXx24LVt/mdhDM90MuzoMCJjXZAlhA0V0CJi+SKjMhfBoIQ6Lla1nD4QNw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6"
}
},
"rc-rate": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.1.tgz",
"integrity": "sha512-MmIU7FT8W4LYRRHJD1sgG366qKtSaKb67D0/vVvJYR0lrCuRrCiVQ5qhfT5ghVO4wuVIORGpZs7ZKaYu+KMUzA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-util": "^5.0.1"
}
},
"rc-resize-observer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.0.0.tgz",
"integrity": "sha512-RgKGukg1mlzyGdvzF7o/LGFC8AeoMH9aGzXTUdp6m+OApvmRdUuOscq/Y2O45cJA+rXt1ApWlpFoOIioXL3AGg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"rc-util": "^5.0.0",
"resize-observer-polyfill": "^1.5.1"
}
},
"rc-select": {
"version": "12.1.10",
"resolved": "https://registry.npmjs.org/rc-select/-/rc-select-12.1.10.tgz",
"integrity": "sha512-LQdUhYncvcULlrNcAShYicc1obPtnNK7/rvCD+YCm0b2BLLYxl3M3b/HOX6o+ppPej+yZulkUPeU6gcgcp9nag==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-motion": "^2.0.1",
"rc-overflow": "^1.0.0",
"rc-trigger": "^5.0.4",
"rc-util": "^5.9.8",
"rc-virtual-list": "^3.2.0"
}
},
"rc-slider": {
"version": "9.7.2",
"resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.7.2.tgz",
"integrity": "sha512-mVaLRpDo6otasBs6yVnG02ykI3K6hIrLTNfT5eyaqduFv95UODI9PDS6fWuVVehVpdS4ENgOSwsTjrPVun+k9g==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-tooltip": "^5.0.1",
"rc-util": "^5.0.0",
"shallowequal": "^1.1.0"
}
},
"rc-steps": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-4.1.3.tgz",
"integrity": "sha512-GXrMfWQOhN3sVze3JnzNboHpQdNHcdFubOETUHyDpa/U3HEKBZC3xJ8XK4paBgF4OJ3bdUVLC+uBPc6dCxvDYA==",
"requires": {
"@babel/runtime": "^7.10.2",
"classnames": "^2.2.3",
"rc-util": "^5.0.1"
}
},
"rc-switch": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-3.2.2.tgz",
"integrity": "sha512-+gUJClsZZzvAHGy1vZfnwySxj+MjLlGRyXKXScrtCTcmiYNPzxDFOxdQ/3pK1Kt/0POvwJ/6ALOR8gwdXGhs+A==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"rc-util": "^5.0.1"
}
},
"rc-table": {
"version": "7.13.3",
"resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.13.3.tgz",
"integrity": "sha512-oP4fknjvKCZAaiDnvj+yzBaWcg+JYjkASbeWonU1BbrLcomkpKvMUgPODNEzg0QdXA9OGW0PO86h4goDSW06Kg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.4.0",
"shallowequal": "^1.1.0"
}
},
"rc-tabs": {
"version": "11.7.3",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.7.3.tgz",
"integrity": "sha512-5nd2NVss9TprPRV9r8N05SjQyAE7zDrLejxFLcbJ+BdLxSwnGnk3ws/Iq0smqKZUnPQC0XEvnpF3+zlllUUT2w==",
"requires": {
"@babel/runtime": "^7.11.2",
"classnames": "2.x",
"rc-dropdown": "^3.1.3",
"rc-menu": "^8.6.1",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.5.0"
}
},
"rc-textarea": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-0.3.4.tgz",
"integrity": "sha512-ILUYx831ZukQPv3m7R4RGRtVVWmL1LV4ME03L22mvT56US0DGCJJaRTHs4vmpcSjFHItph5OTmhodY4BOwy81A==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.7.0"
}
},
"rc-tooltip": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.1.0.tgz",
"integrity": "sha512-pFqD1JZwNIpbdcefB7k5xREoHAWM/k3yQwYF0iminbmDXERgq4rvBfUwIvlCqqZSM7HDr9hYeYr6ZsVNaKtvCQ==",
"requires": {
"@babel/runtime": "^7.11.2",
"rc-trigger": "^5.0.0"
}
},
"rc-tree": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-4.1.5.tgz",
"integrity": "sha512-q2vjcmnBDylGZ9/ZW4F9oZMKMJdbFWC7um+DAQhZG1nqyg1iwoowbBggUDUaUOEryJP+08bpliEAYnzJXbI5xQ==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-motion": "^2.0.1",
"rc-util": "^5.0.0",
"rc-virtual-list": "^3.0.1"
}
},
"rc-tree-select": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-4.3.2.tgz",
"integrity": "sha512-tkouzhl8OpbTg4C9tVuP8nJ5jiZS7/wiusOIcFVgswhs1V3Jc+XHMKpLhR01egJ1bgsW1A6VrVCz3udxtdJSDA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-select": "^12.0.0",
"rc-tree": "^4.0.0",
"rc-util": "^5.0.5"
}
},
"rc-trigger": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.5.tgz",
"integrity": "sha512-RlF5RpWqK+JeiFeQVOzwjLFzpNe2FowoXc/42azz+20wr/bYF1Q/MwprUK+3+vs/oFhLC0ht3/NlrslAo/OoWA==",
"requires": {
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"rc-align": "^4.0.0",
"rc-motion": "^2.0.0",
"rc-util": "^5.5.0"
}
},
"rc-upload": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.2.0.tgz",
"integrity": "sha512-BXtvBs1PnwLjaUzBBU5z4yb9NMSaxc6mUIoPmS9LUAzaTz12L3TLrwu+8dnopYUiyLmYFS3LEO7aUfEWBqJfSA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-util": "^5.2.0"
}
},
"rc-util": {
"version": "5.10.1",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.10.1.tgz",
"integrity": "sha512-Mr3lpl6PYL/wr16t5p8BJVN/sb8+x9U2pf81ijoozzNOb5oTg/meeBnoPuiEaxHt1zTDRokZ5+V8xoErTjP2AA==",
"requires": {
"@babel/runtime": "^7.12.5",
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
}
},
"rc-virtual-list": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.2.6.tgz",
"integrity": "sha512-8FiQLDzm3c/tMX0d62SQtKDhLH7zFlSI6pWBAPt+TUntEqd3Lz9zFAmpvTu8gkvUom/HCsDSZs4wfV4wDPWC0Q==",
"requires": {
"classnames": "^2.2.6",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.0.7"
}
},
"react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
@ -13919,11 +13396,6 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
},
"resolve": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
@ -14399,14 +13871,6 @@
"ajv-keywords": "^3.5.2"
}
},
"scroll-into-view-if-needed": {
"version": "2.2.28",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz",
"integrity": "sha512-8LuxJSuFVc92+0AdNv4QOxRL4Abeo1DgLnGNkn1XlaujPH/3cCFz3QI60r2VNu4obJJROzgnIUw5TKQkZvZI1w==",
"requires": {
"compute-scroll-into-view": "^1.0.17"
}
},
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@ -14581,11 +14045,6 @@
"safe-buffer": "^5.0.1"
}
},
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@ -15121,11 +14580,6 @@
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
},
"string-convert": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz",
"integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c="
},
"string-length": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@ -15710,11 +15164,6 @@
"is-number": "^7.0.0"
}
},
"toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
"integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",

View File

@ -7,7 +7,6 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3",
"antd": "^4.15.2",
"bootstrap": "^4.6.0",
"js-cookie": "^2.2.1",
"js-cookies": "^1.0.4",

View File

@ -6,6 +6,7 @@ class ChoixDept extends Component {
constructor(props) {
super(props);
this.state = {
// Liste des départements disponibles pour l'utilisateur
depts: [],
};
}
@ -18,6 +19,7 @@ class ChoixDept extends Component {
credentials: 'include',
})
.then(response =>
// Traitement des données JSON
response.json().then(data => ({
data: data,
status: response.status
@ -31,15 +33,19 @@ class ChoixDept extends Component {
return (
<div className="wrapper">
<h1 id="pageTitle">Choix du département</h1>
{this.state.depts.map((dept, index) => {
return (
<div id="wrapDept">
<Link to={`/ScoDoc/static/mobile/${dept}/Scolarite`}>
Département {dept}
</Link>
</div>
)
},)}
<div className="container">
<div className="row">
{this.state.depts.map((dept, index) => {
return (
<div className="col-sm" key={index} id="wrapDept">
<Link to={`/ScoDoc/static/mobile/${dept}/Scolarite`}>
Département {dept}
</Link>
</div>
)
},)}
</div>
</div>
</div>
);
}

View File

@ -6,9 +6,12 @@ class Etudiant extends Component {
constructor(props) {
super(props);
this.state = {
// Données de l'étudiant
etud: {},
semestres: [],
// Formation actuelle de l'étudiant
formation: [],
// Semestres correspondant a la formation de l'étudiant
semestres: [],
loaded: false
};
}
@ -23,20 +26,15 @@ class Etudiant extends Component {
credentials: 'include',
})
.then(response =>
// Traitement des données JSON
response.json().then(data => ({
data: data,
status: response.status
})
).then(res => {
// Utilisation de '???' en cas de données vides pour le moment}
/*for (let propName in res.data) {
if (res.data[propName] === null || res.data[propName] === undefined || res.data[propName] === "") {
res.data[propName] = "???";
}
}*/
this.setState({ etud: res.data })
this.setState({ formation: res.data.insemestre })
// Recuperation des données de semestres pour la formation d'un étudiant
res.data.insemestre.map((sem, index) => {
fetch(BASE_URL + dept + '/Scolarite/Notes/formsemestre_list?format=json&formsemestre_id=' + sem.formsemestre_id, {
method: 'GET',
@ -45,11 +43,12 @@ class Etudiant extends Component {
})
.then(response =>
response.json().then(data => ({
// Traitement des données JSON
data: data,
status: response.status
}))
).then(res => {
var joined = this.state.semestres.concat(res.data[0]);
let joined = this.state.semestres.concat(res.data[0]);
this.setState({ semestres: joined, loaded: true })
})
})

View File

@ -18,6 +18,7 @@ class GestionSemestre extends Component {
}
componentWillMount() {
// Recuperation de la liste des semestres
let dept = window.location.href.split('/')[6]
let sem = window.location.href.split('/')[8]
let BASE_URL = window.$api_url
@ -28,10 +29,12 @@ class GestionSemestre extends Component {
credentials: 'include',
})
.then(response =>
// Traitement des données JSON
response.json().then(data => ({
data: data,
})
).then(res => {
// Création d'une liste pour le select
res.data.map((student, index) => {
let joined = this.state.selectOptions.concat({label: student.nom_disp + " " + student.prenom, value: student.etudid});
this.setState({selectOptions: joined})
@ -48,13 +51,18 @@ class GestionSemestre extends Component {
return (
<div>
<ScoNavBar/>
<div id="wrapDept">
Choix de l'étudiant
<Select className="mySelect" options={this.state.selectOptions} onChange={this.handleSelectChange.bind(this)}/>
<div className="container">
<div className="row justify-content-center">
{/* Selection de l'étudiant pour les sous-composants */}
<div className="col-sm" id="wrapDept">
Choix de l'étudiant
<Select className="mySelect" options={this.state.selectOptions} onChange={this.handleSelectChange.bind(this)}/>
</div>
</div>
</div>
<div>
<Tabs defaultActiveKey="Accueil" id="controlled-tab-example">
<Tab eventKey="Accueil" title="Acceuil" >
<Tab eventKey="Accueil" title="Accueil" >
<Accueil />
</Tab>
<Tab eventKey="Absences" title="Absences">

View File

@ -1,63 +1,178 @@
import React, {Component} from "react";
import {Button, Col} from 'react-bootstrap'
import '../Style.css'
import SaisieAbs from "./Absences/SaisieAbs";
import SupprAbs from "./Absences/SupprAbs";
import JustAbs from "./Absences/JustAbs";
class Absences extends Component {
constructor(props){
super(props)
this.state = {
abs: []
// Gestion des fenetres modales
// Ajout d'absences
isOpen: false,
// Suppression
isDelOpen: false,
// Justification
isJustOpen: false,
// Données de la liste des absences
abs: [],
absjust: [],
// Données d'une absence selectionnée
data: {}
}
}
// Recuperation des données en cas de changement de props (dans notre cas, changement d'élève)
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.getData();
}
}
// Recuperation des données lors du chargement de la page si un étudiant est selectionné
componentDidMount() {
if (this.props.id !== "") {this.getData()}
}
openModal(key, data) {
this.setState({[key]: true}, () => setTimeout(() => {
this.setState({[key]: false})
}, 500))
if (data) {this.setState({data: data})}
}
getData() {
this.getAbs()
this.getAbsJust()
}
getAbs() {
let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url
if (this.state.id !== "") {
fetch(BASE_URL + dept + "/Scolarite/Absences/ListeAbsEtud?format=json&etudid=" + this.props.id, {
fetch(BASE_URL + dept + "/Scolarite/Absences/ListeAbsEtud?format=json&absjust_only=0&etudid=" + this.props.id, {
method: 'GET',
verify: false,
credentials: 'include',
})
.then(response =>
// Traitement des données JSON
response.json().then(data => ({
data: data,
})
).then(res => {
// Recuperation de la liste des absences
this.setState({abs: res.data})
})
);
}
}
getAbsJust() {
let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url
if (this.state.id !== "") {
fetch(BASE_URL + dept + "/Scolarite/Absences/ListeAbsEtud?format=json&absjust_only=1&etudid=" + this.props.id, {
method: 'GET',
verify: false,
credentials: 'include',
})
.then(response =>
// Traitement des données JSON
response.json().then(data => ({
data: data,
})
).then(res => {
// Recuperation de la liste des absences
this.setState({absjust: res.data})
})
);
}
}
render() {
return (
<div className="wrapper">
{this.props.id !== "" &&
// Gestion du modal de saisie
<SaisieAbs open={this.state.isOpen} etudid={this.props.id}/>
} {this.props.id !== "" &&
// Gestion du modal de suppression
<SupprAbs open={this.state.isDelOpen} etudid={this.props.id} data={this.state.data}/>
} {this.props.id !== "" &&
// Gestion du modal de justification
<JustAbs open={this.state.isJustOpen} etudid={this.props.id} data={this.state.data}/>
}
<h1 id="pageTitle">Gestion des absences</h1>
{this.props.name !== "" &&
<div className="col-sm" id="wrapDept">
<h4>Absences de {this.props.name}</h4>
{(this.state.abs.length === 0 && this.props.name !== "") &&
<h6>Aucune absence de l'élève</h6>
<h4>Absences de {this.props.name + " "}
<Button variant="primary" size="sm" style={{"margin-right": "2px"}}
onClick={() => this.openModal('isOpen', null)}>
<span>+</span>
</Button>
<Button variant="secondary" size="sm" style={{"margin-left": "2px"}}
onClick={() => this.getData()}>
<span>🗘</span>
</Button>
</h4>
{(this.state.abs.length === 0 && this.state.absjust.length === 0 && this.props.name !== "") &&
<h6>Aucune absence de l'élève</h6>
}
{this.state.abs.map((abs, index) => {
return (
<div className="col-sm" id="wrapDept">
<h6>{abs.datedmy} | {abs.matin}</h6>
{abs.motif !== "" &&
<span>Motif: {abs.motif}</span>
} {abs.exams !== "" &&
<span>Exam a rattraper: {abs.exams}</span>
}
<Col>
<h5>{abs.datedmy} | {abs.matin}</h5>
{abs.motif !== "" &&
<span>Motif: {abs.motif}</span>
} {abs.exams !== "" &&
<span>Exam a rattraper: {abs.exams}</span>
}
</Col>
<Col>
{abs.motif === "" &&
<Button variant="primary" size="sm" style={{"margin-right": "2px"}}
onClick={() => this.openModal('isJustOpen', {
date: abs.datedmy,
demijournee: abs.ampm
})}>
Justifier
</Button>
}
<Button variant="danger" size="sm" style={{"margin-left": "2px"}}
onClick={() => this.openModal('isDelOpen', {
date: abs.datedmy,
demijournee: abs.ampm
})}>
Supprimer
</Button>
</Col>
</div>
)
})}
{this.state.absjust.map((abs, index) => {
return (
<div className="col-sm" id="wrapDept">
<Col>
<h5>{abs.datedmy} | {abs.matin}</h5>
{abs.motif !== "" &&
<span>Motif: {abs.motif}</span>
} {abs.exams !== "" &&
<span>Exam a rattraper: {abs.exams}</span>
}
</Col>
<Col>
<Button variant="danger" size="sm" style={{"margin-left": "2px"}}
onClick={() => this.openModal('isDelOpen', {
date: abs.datedmy,
demijournee: abs.ampm
})}>
Supprimer
</Button>
</Col>
</div>
)
})}

View File

@ -0,0 +1,115 @@
import React, {Component} from "react";
import {Button, Col, Form, Modal} from "react-bootstrap";
class JustAbs extends Component {
constructor(props){
super(props)
this.state = {
isOpen: false,
etudid: "",
date: ""
}
}
openModal = () => this.setState({ isOpen: true });
closeModal = () => this.setState({ isOpen: false });
componentDidUpdate(prevProps) {
if (prevProps.open !== this.props.open) {
this.setState({etudid: this.props.etudid})
if (this.props.open === true) {
this.setState({isOpen: true})
}
// Recuperation et conversion de la date par defaut de l'absence (Format ISO demandé par les form Bootstrap)
let date = this.props.data.date.split("/")
date = new Date(date[2] + "-" + date[1] + "-" + date[0])
date = date.toISOString().substr(0,10);
this.setState({date: date})
}
}
postData(data) {
let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url
fetch(BASE_URL + dept + "/Scolarite/Absences/doJustifAbsence", {
method: 'POST',
verify: false,
credentials: 'include',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: data
})
// Fermeture du modal
this.setState({isOpen: false})
}
onFormSubmit = e => {
// Traitement du formulaire
// Empeche le bouton de rediriger ou actualiser la page
e.preventDefault()
// Recuperation des valeurs
const formData = new FormData(e.target), formDataObj = Object.fromEntries(formData.entries())
let reqstr = "etudid=" + this.state.etudid + "&datedebut=" + this.props.data.date
if (formDataObj.hasOwnProperty('dateFin') && formDataObj['dateFin'] !== "") {
let dateFin = formDataObj['dateFin'].split("-")
dateFin = dateFin[2] + "/" + dateFin[1] + "/" + dateFin[0]
reqstr += "&datefin=" + dateFin
} else {
reqstr += "&datefin=" + this.props.data.date
} if (formDataObj.hasOwnProperty('duree')) {
reqstr += "&demijournee=" + formDataObj['duree']
} else {
reqstr += "&demijournee=" + this.props.data.demijournee
} if (formDataObj.hasOwnProperty('motif') && formDataObj['motif'] !== "") {
reqstr += "&description=" + formDataObj['motif']
}
this.postData(reqstr)
}
render() {
return (
<>
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Suppression d'absence</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form onSubmit={this.onFormSubmit}>
<Form.Row>
<Form.Group as={Col} ControlId="dateDebut">
<Form.Label>Date début</Form.Label>
<Form.Control type="date" name="dateDebut" defaultValue={this.state.date} readOnly/>
</Form.Group>
<Form.Group as={Col} ControlId="dateFin">
<Form.Label>Date fin (Optionnel)</Form.Label>
<Form.Control type="date" name="dateFin" defaultValue={this.state.date}/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} ControlId="duree">
<Form.Check inline label="Journée" name="duree" type="radio" value="2"/>
<Form.Check inline label="Demie-journée" name="duree" type="radio" defaultValue={this.props.data.demijournee} checked/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} ControlId="motif">
<Form.Label>Motif</Form.Label>
<Form.Control as="textarea" rows={3} name="motif"/>
</Form.Group>
</Form.Row>
<Form.Row>
<Button type="submit" variant="primary">Sauvegarder</Button>
</Form.Row>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => {this.closeModal()}}>Fermer</Button>
</Modal.Footer>
</Modal>
</>
)
}
}
export default JustAbs

View File

@ -0,0 +1,134 @@
import React, {Component} from "react";
import {Button, Col, Form, Modal} from "react-bootstrap";
import Absences from '../Absences'
class SaisieAbs extends Component {
constructor(props){
super(props)
this.state = {
isOpen: false,
form: {},
error: false,
etudid: ""
}
}
openModal = () => this.setState({ isOpen: true });
closeModal = () => this.setState({ isOpen: false });
componentDidUpdate(prevProps) {
if (prevProps.open !== this.props.open) {
this.setState({etudid: this.props.etudid})
if (this.props.open === true) {
this.setState({isOpen: true})
}
}
}
onFormSubmit = e => {
// Traitement du formulaire
// Empeche le bouton de rediriger ou actualiser la page
e.preventDefault()
// Recuperation des valeurs
const formData = new FormData(e.target), formDataObj = Object.fromEntries(formData.entries())
let reqstr = "etudid=" + this.state.etudid + "&datedebut="
if (formDataObj.hasOwnProperty('dateDebut') && formDataObj['dateDebut'] !== "") {
let dateDebut = formDataObj['dateDebut'].split("-")
dateDebut = dateDebut[2] + "/" + dateDebut[1] + "/" + dateDebut[0]
reqstr += dateDebut
if (formDataObj.hasOwnProperty('dateFin') && formDataObj['dateFin'] !== "") {
let dateFin = formDataObj['dateFin'].split("-")
dateFin = dateFin[2] + "/" + dateFin[1] + "/" + dateFin[0]
reqstr += "&datefin=" + dateFin
} else {
reqstr += "&datefin=" + dateDebut
}
if (formDataObj.hasOwnProperty('duree')) {
reqstr += "&demijournee=" + formDataObj['duree']
}
if (formDataObj.hasOwnProperty('estjust') && formDataObj.hasOwnProperty('motif') && formDataObj['motif'] !== "") {
reqstr += "&estjust=True&description=" + formDataObj['motif']
}
this.postData(reqstr)
} else {
this.setState({error: true})
}
}
postData(data) {
let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url
fetch(BASE_URL + dept + "/Scolarite/Absences/doSignaleAbsence", {
method: 'POST',
verify: false,
credentials: 'include',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: data
})
.then(response => {
if (response.status === 200) {
// Fermeture du modal
this.closeModal()
}
});
}
render() {
return (
<>
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Saisie d'absence</Modal.Title>
</Modal.Header>
<Modal.Body>
{this.state.error &&
<span>Erreur: La date de début ne doit pas être vide</span>
}
<Form onSubmit={this.onFormSubmit}>
<Form.Row>
<Form.Group as={Col} ControlId="dateDebut">
<Form.Label>Date début</Form.Label>
<Form.Control type="date" name="dateDebut"/>
</Form.Group>
<Form.Group as={Col} ControlId="dateFin">
<Form.Label>Date fin (Optionnel)</Form.Label>
<Form.Control type="date" name="dateFin"/>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} ControlId="duree">
<Form.Check inline label="Journée(s)" name="duree" type="radio" value="2" />
<Form.Check inline label="Matin(s)" name="duree" type="radio" value="1" />
<Form.Check inline label="Après-midi" name="duree" type="radio" value="0" />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} ControlId="estjust">
<Form.Check label="Justifiée" name="estjust" type="checkbox" id="estjust" />
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} ControlId="motif">
<Form.Label>Motif</Form.Label>
<Form.Control as="textarea" rows={3} name="motif"/>
</Form.Group>
</Form.Row>
<Form.Row>
<Button type="submit" variant="primary">Sauvegarder</Button>
</Form.Row>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={() => {this.closeModal()}}>Fermer</Button>
</Modal.Footer>
</Modal>
</>
)
}
}
export default SaisieAbs

View File

@ -0,0 +1,61 @@
import React, {Component} from "react";
import {Button, Modal} from "react-bootstrap";
class SupprAbs extends Component {
constructor(props){
super(props)
this.state = {
isOpen: false,
etudid: "",
}
}
openModal = () => this.setState({ isOpen: true });
closeModal = () => this.setState({ isOpen: false });
componentDidUpdate(prevProps) {
if (prevProps.open !== this.props.open) {
this.setState({etudid: this.props.etudid})
if (this.props.open === true) {
this.setState({isOpen: true})
}
}
}
postData() {
let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url
let data = "datedebut=" + this.props.data.date + "&datefin=" + this.props.data.date +
"&demijournee=" + this.props.data.demijournee + "&etudid=" + this.state.etudid
fetch(BASE_URL + dept + "/Scolarite/Absences/doAnnuleAbsence", {
method: 'POST',
verify: false,
credentials: 'include',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: data
})
// Fermeture du modal
this.setState({isOpen: false})
}
render() {
return (
<>
<Modal show={this.state.isOpen} onHide={this.closeModal}>
<Modal.Header closeButton>
<Modal.Title>Suppression d'absence</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Etes-vous sûr.e de vouloir supprimer cette absence ?</p>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={() => {this.postData()}}>Supprimer</Button>
<Button variant="secondary" onClick={() => {this.closeModal()}}>Fermer</Button>
</Modal.Footer>
</Modal>
</>
)
}
}
export default SupprAbs

View File

@ -6,7 +6,6 @@ class Accueil extends Component {
super(props);
this.state = {
semestre: {},
students: [],
};
}

View File

@ -1,5 +1,4 @@
import React, {Component} from "react";
import Select from "react-select";
import {Table, Button, Dropdown} from "react-bootstrap"
import '../Style.css'
@ -12,21 +11,6 @@ class Bulletin extends Component {
loaded: false
};
this.getData = this.getData.bind(this);
this.getJsonData = this.getJsonData.bind(this);
}
getJsonData () {
this.setState({bltn: require('..\\..\\json\\bltn.json')}, () => {
let ls = {}
for (let elm in this.state.bltn.decision_ue) {
elm = this.state.bltn.decision_ue[elm]
ls[elm.acronyme] = elm.titre
}
this.setState({datue: ls}, () => {
this.setState({loaded: true})
})
})
}
getData() {
@ -45,13 +29,16 @@ class Bulletin extends Component {
status: response.status
})
).then(res => {
// Recuperation des données du bulletin
this.setState({ bltn: res.data }, () => {
// Recuperation d'un tableau CodeUE | NomUE
let ls = {}
for (let elm in this.state.bltn.decision_ue) {
elm = this.state.bltn.decision_ue[elm]
ls[elm.acronyme] = elm.titre
}
this.setState({datue: ls}, () => {
// Marquage du bulletin comme "chargé"
this.setState({loaded: true})
})
})
@ -59,6 +46,7 @@ class Bulletin extends Component {
);
}
// Recuperation du bulletin au format PDF
getPdf() {
let BASE_URL = window.$api_url
let dept = window.location.href.split('/')[6]
@ -76,12 +64,14 @@ class Bulletin extends Component {
});
}
// Recuperation des données en cas de changement de props (dans notre cas, changement d'élève)
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.getData();
}
}
// Recuperation des données lors du chargement de la page si un étudiant est selectionné
componentDidMount() {
if (this.props.id !== "") {this.getData()}
}

View File

@ -1,5 +1,4 @@
import React, {Component} from "react";
import {Row, Col} from "react-bootstrap"
import '../Style.css'
import {Link} from "react-router-dom";
@ -7,6 +6,7 @@ class Eleves extends Component {
constructor(props) {
super(props);
this.state = {
// Liste des élèves inscrits au semestre
students: [],
};
}
@ -22,11 +22,16 @@ class Eleves extends Component {
credentials: 'include',
})
.then(response =>
// Traitement des données JSON
response.json().then(data => ({
data: data,
})
).then(res => {
this.setState({ students: res.data});
// Gestion des données sous forme de tableau a deux colonnes
const dat = res.data.map((x,i) => {
return i % 2 === 0 ? res.data.slice(i, i+2) : null;
}).filter(x => x != null);
this.setState({ students: dat});
}));
}
@ -35,17 +40,30 @@ class Eleves extends Component {
<div className="wrapper">
<h1 id="pageTitle">Liste des élèves</h1>
<div className="container">
<div className="row">
{this.state.students.map((student, index) => {
return (
<div className="col-sm" key={index} id="wrapDept">
<Link to={`/ScoDoc/static/mobile/${window.location.href.split('/')[6]}/Scolarite/Etudiant/${student.etudid}`}>
{student.nom_disp} {student.prenom}
</Link>
</div>
)
},)}
</div>
{this.state.students.map((students, index) => {
// Creation du tableau de deux colonnes
return (
<div className="row justify-content-center">
{students.map((etud, index) => {
return (
<div className="col" key={index} id="wrapDept">
<Link to={`/ScoDoc/static/mobile/${window.location.href.split('/')[6]}/Scolarite/Etudiant/${etud.etudid}`}>
{/* Recuperation de la photo de l'etudiant */}
<img
alt={`${etud.nom_disp} ${etud.prenom}`}
src={`/ScoDoc/RT/Scolarite/Notes/get_photo_image?etudid=${etud.etudid}`}
width="102"
height="128"
className="d-inline-block align-top"
/>{' '}<br/>
{etud.nom_disp} {etud.prenom}
</Link>
</div>
)
})}
</div>
)
})}
</div>
</div>
)

View File

@ -1,6 +1,5 @@
import React, {Component, useState} from "react";
import React, {Component} from "react";
import { isMobile } from 'react-device-detect';
import {Modal, Button} from 'react-bootstrap'
import './Style.css'
import ChoixDept from "./ChoixDept";
import ScoNavBar from "./ScoNavBar";

View File

@ -7,8 +7,6 @@ class ScoNavBar extends Component {
constructor(props) {
super(props);
this.state = {
login: {},
semestre: {},
logout: false
};
}

View File

@ -17,10 +17,6 @@ class Scolarite extends Component {
this.getData = this.getData.bind(this);
}
/* getJsonData () {
return require('..\\json\\sems.json');
} */
componentWillMount() {
let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url
@ -64,17 +60,21 @@ class Scolarite extends Component {
</Card.Header>
<Accordion.Collapse eventKey="0">
<Card.Body>
{this.state.semestres.map((sem, index) => {
if(sem.etat === "1")
return (
<div className="col-12" key={index} id="wrapDept">
<Link to={`/ScoDoc/static/mobile/${window.location.href.split('/')[6]}/Scolarite/${sem.formsemestre_id}/GestionSem`}>
<h3>{sem.titre} [{sem.modalite}]</h3>
<p>Semestre {sem.semestre_id} - Année {sem.anneescolaire} [{sem.date_debut} - {sem.date_fin}]</p>
</Link>
</div>
)
})}
<div className="container">
<div className="row">
{this.state.semestres.map((sem, index) => {
if(sem.etat === "1")
return (
<div className="col-sm" key={index} id="wrapDept">
<Link to={`/ScoDoc/static/mobile/${window.location.href.split('/')[6]}/Scolarite/${sem.formsemestre_id}/GestionSem`}>
<h4>{sem.titre} [{sem.modalite}]</h4>
<p>Semestre {sem.semestre_id} - Année {sem.anneescolaire} [{sem.date_debut} - {sem.date_fin}]</p>
</Link>
</div>
)
})}
</div>
</div>
</Card.Body>
</Accordion.Collapse>
</Card>

View File

@ -1,5 +1,5 @@
import React, {Component} from "react";
import {Link, Redirect} from "react-router-dom";
import {Link} from "react-router-dom";
import {Row, Col} from "react-bootstrap"
class SearchStudent extends Component {
@ -8,7 +8,7 @@ class SearchStudent extends Component {
this.state = {
students: [],
// Status possibles:
// 0: Vide - 1: Pas de resultat - 2: Plusieurs resultats
// 0: Vide - 1: Pas de resultat - 2: Un ou plusieurs resultats
search_status: 0,
};
this.handleChangeSearch = this.handleChangeSearch.bind(this)
@ -29,20 +29,16 @@ class SearchStudent extends Component {
credentials: "include",
})
.then(response =>
response.json().then(data => ({data: data,})
).then(res => {
this.setState({ students: res.data });
console.log(this.state.students)
}))
.then(res => {
if (this.state.students.length === 0) {
this.setState({search_status: 1, toast: true});
} else if (this.state.students.length === 1) {
return <Redirect to="/" />
} else {
this.setState({search_status: 2, toast: false});
}
})
response.json().then(data => ({data: data}))
.then(res => {
this.setState({ students: res.data });
if (this.state.students.length === 0) {
this.setState({search_status: 1, toast: true});
} else {
this.setState({search_status: 2, toast: false});
}
}))
this.setState({searched: true})
}

View File

@ -1,5 +1,3 @@
/* BASIC */
body {
font-family: "Poppins", sans-serif;
height: 100vh;

View File

@ -1,626 +0,0 @@
{
"rang": {
"ninscrits": 52,
"value": "1"
},
"etape_apo2": "",
"etape_apo3": "",
"etape_apo4": "",
"etudiant": {
"nom": "BOLANO",
"prenom": "Roberto",
"sexe": "M.",
"code_ine": "",
"etudid": "EID9860",
"code_nip": "123456789",
"email": "roberto@santateresa.mx",
"photo_url": "\/ScoDoc\/static\/photos\/F68\/RT_EID29960.h90.jpg"
},
"bonus_sport_culture": {
"value": 0
},
"absences": {
"nbabsjust": 0,
"nbabs": 1
},
"decision": {
"etat": "I",
"code": "ADM",
"compense_formsemestre_id" : "SEM12345"
},
"note": {
"max": "15.51",
"moy": "10.80",
"value": "15.51",
"min": "07.29"
},
"etudid": "EID9860",
"decision_ue": [
{
"acronyme": "UE11",
"code": "ADM",
"ects": "16.0",
"titre": "D\u00e9couverte m\u00e9tiers",
"numero": "11",
"ue_id": "UE21456"
},
{
"acronyme": "UE12",
"code": "ADM",
"ects": "14.0",
"titre": "Mise \u00e0 niveau des comp\u00e9tences transversales et scientifiques",
"numero": "12",
"ue_id": "UE21478"
}
],
"ue_capitalisee": [
],
"publie": 1,
"autorisation_inscription": [
{
"semestre_id": 2
}
],
"appreciation": [
],
"note_max": {
"value": 20
},
"date": "2014-07-12T17:38:47.693262",
"rang_group": [
{
"ninscrits": 26,
"value": "1",
"group_type": "TD",
"group_name": "B"
},
{
"ninscrits": 13,
"value": "1",
"group_type": "TP",
"group_name": "B1"
},
{
"ninscrits": 4,
"value": "1",
"group_type": "G",
"group_name": "G4"
},
{
"ninscrits": "",
"value": "",
"group_type": "tutorat",
"group_name": ""
},
{
"ninscrits": "",
"value": "",
"group_type": "App",
"group_name": ""
},
{
"ninscrits": "",
"value": "",
"group_type": "sport",
"group_name": ""
}
],
"formsemestre_id": "SEM12345",
"etape_apo": "V1RT",
"ue": [
{
"acronyme": "UE11",
"rang": "1",
"code_apogee": "VRTU11",
"ects": "16",
"numero": "11",
"note": {
"max": "16.17",
"value": "16.17",
"min": "06.56"
},
"module": [
{
"coefficient": 3,
"rang": {
"value": "1"
},
"code": "M1101",
"code_apogee": "VRT1101",
"numero": 1101,
"note": {
"moy": "08.94",
"nb_notes": 51,
"nb_missing": 0,
"max": "19.18",
"min": "03.70",
"nb_valid_evals": 3,
"value": "19.18"
},
"abbrev": "R\u00e9seaux d&apos;entreprises",
"effectif": {
"value": 51
},
"titre": "Initiation aux r\u00e9seaux d&apos;entreprises",
"evaluation": [
],
"id": "MIP27427"
},
{
"coefficient": 2,
"rang": {
"value": "2"
},
"code": "M1102",
"code_apogee": "VRT1102",
"numero": 1102,
"note": {
"moy": "12.58",
"nb_notes": 50,
"nb_missing": 1,
"max": "16.79",
"min": "02.50",
"nb_valid_evals": 2,
"value": "16.50"
},
"abbrev": "Initiation \u00e0 la t\u00e9l\u00e9phonie",
"effectif": {
"value": 51
},
"titre": "Initiation \u00e0 la t\u00e9l\u00e9phonie d&apos;entreprise",
"evaluation": [
],
"id": "MIP27437"
},
{
"coefficient": 1.5,
"rang": {
"value": "1"
},
"code": "M1103",
"code_apogee": "VRT1103",
"numero": 1103,
"note": {
"moy": "08.26",
"nb_notes": 51,
"nb_missing": 0,
"max": "13.41",
"min": "00.94",
"nb_valid_evals": 2,
"value": "13.41"
},
"abbrev": "Architecture des \u00e9quipements informatiques",
"effectif": {
"value": 51
},
"titre": "Architecture des \u00e9quipements informatiques",
"evaluation": [
],
"id": "MIP27451"
},
{
"coefficient": 2,
"rang": {
"value": "1"
},
"code": "M1104",
"code_apogee": "VRT1104",
"numero": 1104,
"note": {
"moy": "10.77",
"nb_notes": 51,
"nb_missing": 0,
"max": "17.90",
"min": "04.63",
"nb_valid_evals": 3,
"value": "17.90"
},
"abbrev": "Principe et architecture des r\u00e9seaux",
"effectif": {
"value": 51
},
"titre": "Principe et architecture des r\u00e9seaux",
"evaluation": [
],
"id": "MIP27431"
},
{
"coefficient": 2,
"rang": {
"value": "1"
},
"code": "M1105",
"code_apogee": "VRT1105",
"numero": 1105,
"note": {
"moy": "11.00",
"nb_notes": 51,
"nb_missing": 0,
"max": "17.83",
"min": "04.98",
"nb_valid_evals": 2,
"value": "17.83"
},
"abbrev": "Bases des syst\u00e8mes d&apos;exploitation",
"effectif": {
"value": 51
},
"titre": "Bases des syst\u00e8mes d&apos;exploitation",
"evaluation": [
],
"id": "MIP27433"
},
{
"coefficient": 1.5,
"rang": {
"value": "6"
},
"code": "M1106",
"code_apogee": "VRT1106",
"numero": 1106,
"note": {
"moy": "13.05",
"nb_notes": 51,
"nb_missing": 0,
"max": "17.79",
"min": "07.08",
"nb_valid_evals": 1,
"value": "16.25"
},
"abbrev": "Initiation au d\u00e9veloppement Web",
"effectif": {
"value": 51
},
"titre": "Initiation au d\u00e9veloppement Web",
"evaluation": [
],
"id": "MIP27449"
},
{
"coefficient": 1.5,
"rang": {
"value": "9"
},
"code": "M1107",
"code_apogee": "VRT1107",
"numero": 1107,
"note": {
"moy": "09.36",
"nb_notes": 51,
"nb_missing": 0,
"max": "14.21",
"min": "04.17",
"nb_valid_evals": 3,
"value": "11.66"
},
"abbrev": "Initiation \u00e0 la mesure du signal",
"effectif": {
"value": 51
},
"titre": "Initiation \u00e0 la mesure du signal",
"evaluation": [
],
"id": "MIP27440"
},
{
"coefficient": 1.5,
"rang": {
"value": "7"
},
"code": "M1108",
"code_apogee": "VRT1108",
"numero": 1108,
"note": {
"moy": "10.49",
"nb_notes": 51,
"nb_missing": 0,
"max": "16.31",
"min": "05.39",
"nb_valid_evals": 4,
"value": "13.22"
},
"abbrev": "Acquisition et codage de l&apos;information",
"effectif": {
"value": 51
},
"titre": "Acquisition et codage de l&apos;information",
"evaluation": [
],
"id": "MIP27453"
},
{
"coefficient": 1,
"rang": {
"value": "4 ex"
},
"code": "M1109",
"code_apogee": "VRT1109",
"numero": 1109,
"note": {
"moy": "12.46",
"nb_notes": 51,
"nb_missing": 0,
"max": "16.00",
"min": "09.00",
"nb_valid_evals": 1,
"value": "15.00"
},
"abbrev": "PT : Recherche documentaire",
"effectif": {
"value": 51
},
"titre": "PT : Recherche documentaire",
"evaluation": [
],
"id": "MIP27444"
}
],
"effectif": "51",
"titre": "D\u00e9couverte m\u00e9tiers",
"id": "UE21456"
},
{
"acronyme": "UE12",
"rang": "5",
"code_apogee": "VRTU12",
"ects": "14",
"numero": "12",
"note": {
"max": "15.20",
"value": "14.63",
"min": "07.94"
},
"module": [
{
"coefficient": 2,
"rang": {
"value": "3 ex"
},
"code": "M1201",
"code_apogee": "VRT1201",
"numero": 10,
"note": {
"moy": "13.02",
"nb_notes": 51,
"nb_missing": 0,
"max": "16.00",
"min": "10.00",
"nb_valid_evals": 1,
"value": "14.00"
},
"abbrev": "Anglais",
"effectif": {
"value": 51
},
"titre": "Anglais g\u00e9n\u00e9ral de communication et initiation au vocabulaire technique",
"evaluation": [
],
"id": "MIP27430"
},
{
"coefficient": 2,
"rang": {
"value": "16 ex"
},
"code": "M1202",
"code_apogee": "VRT1202",
"numero": 20,
"note": {
"moy": "12.74",
"nb_notes": 51,
"nb_missing": 0,
"max": "17.75",
"min": "04.00",
"nb_valid_evals": 2,
"value": "14.00"
},
"abbrev": "Expression",
"effectif": {
"value": 51
},
"titre": "EC: \u00c9l\u00e9ments fondamentaux de la communication",
"evaluation": [
],
"id": "MIP27439"
},
{
"coefficient": 1,
"rang": {
"value": "1 ex"
},
"code": "M1203",
"code_apogee": "VRT1203",
"numero": 30,
"note": {
"moy": "NA",
"nb_notes": 0,
"nb_missing": 51,
"max": "-",
"min": "-",
"nb_valid_evals": 0,
"value": "-"
},
"abbrev": "PPP: Connaitre son champ d&apos;activit\u00e9",
"effectif": {
"value": 51
},
"titre": "PPP: Connaitre son champ d&apos;activit\u00e9",
"evaluation": [
],
"id": "MIP27436"
},
{
"coefficient": 2,
"rang": {
"value": "6"
},
"code": "M1204",
"code_apogee": "VRT1204",
"numero": 40,
"note": {
"moy": "10.66",
"nb_notes": 51,
"nb_missing": 0,
"max": "16.35",
"min": "05.73",
"nb_valid_evals": 8,
"value": "14.09"
},
"abbrev": "Mise \u00e0 niveau en num\u00e9ration et calculs",
"effectif": {
"value": 51
},
"titre": "Mise \u00e0 niveau en num\u00e9ration et calculs",
"evaluation": [
],
"id": "MIP27454"
},
{
"coefficient": 2,
"rang": {
"value": "23"
},
"code": "M1205",
"code_apogee": "VRT1205",
"numero": 50,
"note": {
"moy": "10.37",
"nb_notes": 51,
"nb_missing": 0,
"max": "18.69",
"min": "05.01",
"nb_valid_evals": 5,
"value": "10.58"
},
"abbrev": "Connaissances et Outils pour le signal",
"effectif": {
"value": 51
},
"titre": "Harmonisation des connaissances et des outils pour le signal",
"evaluation": [
],
"id": "MIP27432"
},
{
"coefficient": 2,
"rang": {
"value": "3 ex"
},
"code": "M1206",
"code_apogee": "VRT1206",
"numero": 60,
"note": {
"moy": "11.22",
"nb_notes": 51,
"nb_missing": 0,
"max": "16.76",
"min": "03.91",
"nb_valid_evals": 6,
"value": "15.12"
},
"abbrev": "Circuits \u00e9lectroniques : mise \u00e0 niveau",
"effectif": {
"value": 51
},
"titre": "Circuits \u00e9lectroniques : mise \u00e0 niveau",
"evaluation": [
],
"id": "MIP27435"
},
{
"coefficient": 2,
"rang": {
"value": "1 ex"
},
"code": "M1207",
"code_apogee": "VRT1207",
"numero": 70,
"note": {
"moy": "08.39",
"nb_notes": 51,
"nb_missing": 0,
"max": "20.00",
"min": "00.00",
"nb_valid_evals": 1,
"value": "20.00"
},
"abbrev": "Programmation 1",
"effectif": {
"value": 51
},
"titre": "Bases de la programmation",
"evaluation": [
],
"id": "MIP27445"
},
{
"coefficient": 1,
"rang": {
"value": "1 ex"
},
"code": "M1208",
"code_apogee": "VRT1208",
"numero": 80,
"note": {
"moy": "NA",
"nb_notes": 0,
"nb_missing": 51,
"max": "-",
"min": "-",
"nb_valid_evals": 0,
"value": "-"
},
"abbrev": "M\u00e9thodologie Universitaire 1",
"effectif": {
"value": 51
},
"titre": "Adaptation et m\u00e9thodologie pour la r\u00e9ussite Universitaire",
"evaluation": [
],
"id": "MIP27434"
}
],
"effectif": "51",
"titre": "Mise \u00e0 niveau des comp\u00e9tences transversales et scientifiques",
"id": "UE21478"
},
{
"acronyme": "UE 1S",
"rang": "1 ex",
"code_apogee": "",
"ects": "0",
"numero": "13",
"note": {
"max": "00.00",
"value": "00.00",
"min": "00.00"
},
"module": [
],
"effectif": "51",
"titre": "Sport &amp;amp; Culture",
"id": "UE23716"
}
],
"situation": "Inscrit le 02\/09\/2015. D\u00e9cision jury: Valid\u00e9. UE acquises: UE11, UE12. Autoris\u00e9 \u00e0 s&apos;inscrire en S2."
}