Compare commits

...

7 Commits
1.2 ... master

Author SHA1 Message Date
Theal0 58756dcc22 Release 1.7
Ajout d'un bouton "Retour au choix de semestre" dans la navbar
2021-06-28 22:33:53 +02:00
Theal0 5e00bd068c Release 1.6
Améliorations mineures de l'interface
Fix: "Absences de undefined" + Erreur
2021-06-11 12:53:42 +02:00
Theal0 ef3c3ce7b8 Release 1.5
Ajout de filtrage par groupe de TD/TP sur la page des étudiants inscrits au semestre
2021-06-11 02:02:21 +02:00
Theal0 3725d508ab Release 1.4
Erreur de la page blanche liée a une valeur de rang inexistant résolu
2021-06-10 12:47:28 +02:00
Theal0 8a5b2fc0e7 Actualisation du README 2021-06-04 12:03:45 +02:00
Theal0 05656acd0c Merge remote-tracking branch 'origin/master' 2021-06-04 12:03:04 +02:00
Theal0 6e41809da7 Release v1.3
Ajout des noms et logins sur la page d'acceuil de la gestion du semestre
2021-06-04 12:02:54 +02:00
7 changed files with 140 additions and 27 deletions

View File

@ -2,13 +2,13 @@
## Description ## Description
Version mobile de l'application web ScoDoc (v1.2) Version mobile de l'application web ScoDoc (v1.7)
### Fonctionnalités: ### Fonctionnalités:
- Login - Login
- Choix de département / formation - Choix de département / formation
- Affichage des profils étudiants - Affichage des profils étudiants
- Recherche d'élèves - Recherche d'élèves | Filtrage par groupe de TD/TP
- Affichage des bulletins de notes - Affichage des bulletins de notes
- Gestion des absences - Gestion des absences

View File

@ -115,16 +115,18 @@ class Etudiant extends Component {
<Link to={{ <Link to={{
pathname: `/${window.location.href.split('/')[7]}/Scolarite/${sem.formsemestre_id}/GestionSem`, pathname: `/${window.location.href.split('/')[7]}/Scolarite/${sem.formsemestre_id}/GestionSem`,
tab: "Absences", tab: "Absences",
etudid: window.location.href.split('/')[10] etudid: window.location.href.split('/')[10],
name: this.state.etud.nomprenom
}}> }}>
<Button variant="primary" style={{"margin-right": "2px"}}>Vers Absences</Button> <Button variant="primary" style={{"margin-right": "2px", "margin-bottom": "2px"}}>Vers Absences</Button>
</Link> </Link>
<Link to={{ <Link to={{
pathname: `/${window.location.href.split('/')[7]}/Scolarite/${sem.formsemestre_id}/GestionSem`, pathname: `/${window.location.href.split('/')[7]}/Scolarite/${sem.formsemestre_id}/GestionSem`,
tab: "Bulletin", tab: "Bulletin",
etudid: window.location.href.split('/')[10] etudid: window.location.href.split('/')[10],
name: this.state.etud.nomprenom
}}> }}>
<Button variant="primary" style={{"margin-left": "2px"}}>Vers bulletin</Button> <Button variant="primary" style={{"margin-left": "2px", "margin-bottom": "2px"}}>Vers bulletin</Button>
</Link> </Link>
</div> </div>
) )

View File

@ -1,5 +1,5 @@
import React, {Component} from "react"; import React, {Component} from "react";
import {Tabs, Tab} from "react-bootstrap" import {Tabs, Tab, Nav, NavItem, NavLink} from "react-bootstrap"
import Accueil from "./GestionSemestre/Accueil"; import Accueil from "./GestionSemestre/Accueil";
import Absences from "./GestionSemestre/Absences"; import Absences from "./GestionSemestre/Absences";
import Etudiants from "./GestionSemestre/Etudiants"; import Etudiants from "./GestionSemestre/Etudiants";
@ -17,7 +17,8 @@ class GestionSemestre extends Component {
id: "", id: "",
name: '', name: '',
defaulttab: "Accueil", defaulttab: "Accueil",
defaultsel: "" defaultsel: "",
loading: true
} }
} }
@ -26,7 +27,7 @@ class GestionSemestre extends Component {
if (this.props.location.tab) { if (this.props.location.tab) {
this.setState({defaulttab: this.props.location.tab, defaultsel: this.props.location.etudid, this.setState({defaulttab: this.props.location.tab, defaultsel: this.props.location.etudid,
id: this.props.location.etudid, name: this.state.selectOptions.find(option => option.value === this.state.id) id: this.props.location.etudid, name: this.props.location.name
}) })
} }
} }
@ -44,7 +45,7 @@ class GestionSemestre extends Component {
// Création d'une liste pour le select // Création d'une liste pour le select
res.data.map((student) => { res.data.map((student) => {
let joined = this.state.selectOptions.concat({label: student.nom_disp + " " + student.prenom, value: student.etudid}); let joined = this.state.selectOptions.concat({label: student.nom_disp + " " + student.prenom, value: student.etudid});
this.setState({selectOptions: joined}) this.setState({selectOptions: joined, loading: false})
}) })
}) })
} }
@ -62,20 +63,23 @@ class GestionSemestre extends Component {
{/* Selection de l'étudiant pour les sous-composants */} {/* Selection de l'étudiant pour les sous-composants */}
<div className="col-sm" id="wrapDept"> <div className="col-sm" id="wrapDept">
Choix de l'étudiant Choix de l'étudiant
<Select className="mySelect" options={this.state.selectOptions} onChange={this.handleSelectChange.bind(this)} <Select className="mySelect"
isLoading={this.state.loading}
options={this.state.selectOptions}
onChange={this.handleSelectChange.bind(this)}
value={this.state.selectOptions.find(option => option.value === this.state.defaultsel)} /> value={this.state.selectOptions.find(option => option.value === this.state.defaultsel)} />
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<Tabs defaultActiveKey={this.state.defaulttab} id="controlled-tab-example"> <Tabs fill defaultActiveKey={this.state.defaulttab} id="controlled-tab-example" variant="pills">
<Tab eventKey="Accueil" title="Accueil" > <Tab eventKey="Accueil" title="Accueil">
<Accueil /> <Accueil />
</Tab> </Tab>
<Tab eventKey="Absences" title="Absences"> <Tab eventKey="Absences" title="Absences">
<Absences id={this.state.id} name={this.state.name}/> <Absences id={this.state.id} name={this.state.name}/>
</Tab> </Tab>
<Tab eventKey="Bulletin" title="Bulletin"> <Tab eventKey="Bulletin" title="Bulletins">
<Bulletin id={this.state.id} name={this.state.name}/> <Bulletin id={this.state.id} name={this.state.name}/>
</Tab> </Tab>
<Tab eventKey="Etud" title="Etudiants"> <Tab eventKey="Etud" title="Etudiants">

View File

@ -26,10 +26,23 @@ class Accueil extends Component {
let dept = window.location.href.split('/')[7] let dept = window.location.href.split('/')[7]
let sem = window.location.href.split('/')[9] let sem = window.location.href.split('/')[9]
let BASE_URL = window.$api_url let BASE_URL = window.$api_url
// Recuperation des infos de semestre
getJson(BASE_URL + dept + '/Scolarite/Notes/formsemestre_list?format=json&formsemestre_id=' + sem) getJson(BASE_URL + dept + '/Scolarite/Notes/formsemestre_list?format=json&formsemestre_id=' + sem)
.then(res => { .then(res => {
this.setState({ semestre: res.data[0], resp: res.data[0].responsables, loading: false}); this.setState({ semestre: res.data[0], resp_l: res.data[0].responsables});
}); // Recuperation des noms complets des responsables
res.data[0].responsables.map((resp) =>
getJson(BASE_URL + dept + '/Scolarite/Users/user_info?format=json&user_name=' + resp)
.then(res => {
let joined = this.state.resp.concat(res.data.nomplogin)
this.setState({resp: joined, loading: false})
})
.catch(error => {
this.setState({resp: this.state.resp_l, loading: false})
})
)
})
} }
render() { render() {
@ -45,6 +58,7 @@ class Accueil extends Component {
})} })}
</h1> </h1>
: :
// En cas de chargement
<Spinner animation="border"/> <Spinner animation="border"/>
} }
</div> </div>

View File

@ -99,7 +99,9 @@ class Bulletin extends Component {
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item href="#">Min: {this.state.bltn.note.min}</Dropdown.Item> <Dropdown.Item href="#">Min: {this.state.bltn.note.min}</Dropdown.Item>
<Dropdown.Item href="#">Max: {this.state.bltn.note.max}</Dropdown.Item> <Dropdown.Item href="#">Max: {this.state.bltn.note.max}</Dropdown.Item>
<Dropdown.Item href="#">Classement: {this.state.bltn.rang.value}/{this.state.bltn.rang.ninscrits}</Dropdown.Item> {this.state.bltn.hasOwnProperty('rang') &&
<Dropdown.Item href="#">Classement: {this.state.bltn.rang.value}/{this.state.bltn.rang.ninscrits}</Dropdown.Item>
}
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
</th> </th>
@ -119,7 +121,9 @@ class Bulletin extends Component {
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item href="#">Min: {ue.note.min}</Dropdown.Item> <Dropdown.Item href="#">Min: {ue.note.min}</Dropdown.Item>
<Dropdown.Item href="#">Max: {ue.note.max}</Dropdown.Item> <Dropdown.Item href="#">Max: {ue.note.max}</Dropdown.Item>
<Dropdown.Item href="#">Classement: {ue.rang}/{this.state.bltn.rang.ninscrits}</Dropdown.Item> {ue.hasOwnProperty('rang') &&
<Dropdown.Item href="#">Classement: {ue.rang}/{this.state.bltn.rang.ninscrits}</Dropdown.Item>
}
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>
</td> </td>
@ -137,7 +141,9 @@ class Bulletin extends Component {
<Dropdown.Menu> <Dropdown.Menu>
<Dropdown.Item href="#">Min: {mod.note.min}</Dropdown.Item> <Dropdown.Item href="#">Min: {mod.note.min}</Dropdown.Item>
<Dropdown.Item href="#">Max: {mod.note.max}</Dropdown.Item> <Dropdown.Item href="#">Max: {mod.note.max}</Dropdown.Item>
<Dropdown.Item href="#">Classement: {mod.rang.value}/{this.state.bltn.rang.ninscrits}</Dropdown.Item> {mod.hasOwnProperty('rang') &&
<Dropdown.Item href="#">Classement: {mod.rang.value}/{this.state.bltn.rang.ninscrits}</Dropdown.Item>
}
<Dropdown.Item href="#">Coefficient: {mod.coefficient}</Dropdown.Item> <Dropdown.Item href="#">Coefficient: {mod.coefficient}</Dropdown.Item>
</Dropdown.Menu> </Dropdown.Menu>
</Dropdown> </Dropdown>

View File

@ -4,6 +4,33 @@ import '../Style.css'
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {getJson} from "../Request"; import {getJson} from "../Request";
import {Spinner} from "react-bootstrap"; import {Spinner} from "react-bootstrap";
import Select from "react-select";
// CONSTANTES DE STYLE SELECT GROUP
const groupStyles = {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
};
const groupBadgeStyles = {
backgroundColor: '#EBECF0',
borderRadius: '2em',
color: '#172B4D',
display: 'inline-block',
fontSize: 12,
fontWeight: 'normal',
lineHeight: '1',
minWidth: 1,
padding: '0.16666666666667em 0.5em',
textAlign: 'center',
};
const formatGroupLabel = data => (
<div style={groupStyles}>
<span>{data.label}</span>
<span style={groupBadgeStyles}>{data.options.length}</span>
</div>
);
/** Page de présentation des étudiants inscrits au semestre */ /** Page de présentation des étudiants inscrits au semestre */
class Etudiants extends Component { class Etudiants extends Component {
@ -12,16 +39,21 @@ class Etudiants extends Component {
this.state = { this.state = {
// Liste des étudiants inscrits au semestre // Liste des étudiants inscrits au semestre
students: [], students: [],
// Gestion du select
selectOptions: [{label: "Groupe: Aucun", value: "Default"}],
id: "",
name: '',
}; };
} }
componentWillMount() { componentWillMount() {
// this.getData() this.getData()
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (prevProps !== this.props) { if (prevProps !== this.props) {
if (this.props.students.length) { if (this.props.students.length && this.state.students.length === 0) {
const dat = this.props.students.map((x,i) => { const dat = this.props.students.map((x,i) => {
return i % 2 === 0 ? this.props.students.slice(i, i+2) : null; return i % 2 === 0 ? this.props.students.slice(i, i+2) : null;
}).filter(x => x != null); }).filter(x => x != null);
@ -31,27 +63,74 @@ class Etudiants extends Component {
} }
/** /**
* Recupère la liste des étudiants inscrits au semestre depuis l'API * Recupère la liste des groupes du semestre depuis l'API
*/ */
getData() { getData() {
let dept = window.location.href.split('/')[7] let dept = window.location.href.split('/')[7]
let sem = window.location.href.split('/')[9] let sem = window.location.href.split('/')[9]
let BASE_URL = window.$api_url let BASE_URL = window.$api_url
getJson(BASE_URL + dept + '/Scolarite/Notes/groups_view?with_codes=1&format=json&formsemestre_id=' + sem) getJson(BASE_URL + dept + '/Scolarite/formsemestre_partition_list?format=json&formsemestre_id=' + sem)
.then(res => {
// eslint-disable-next-line array-callback-return
res.data.map((part) => {
// Ajout de la catégorie
let new_part = {label: part.partition_name, options: []}
// Ajout des groupes
// eslint-disable-next-line array-callback-return
part.group.map((group) => {
new_part.options.push({label: group.group_name, value: group.group_id})
})
// Ajout au state
let joined = this.state.selectOptions.concat(new_part);
this.setState({ selectOptions: joined})
})
})
}
/**
* Recupère la liste des étudiants dans un groupe depuis l'API
*/
getStudents() {
let dept = window.location.href.split('/')[7]
let group = this.state.id
let BASE_URL = window.$api_url
getJson(BASE_URL + dept + '/Scolarite/groups_view?with_codes=1&format=json&group_ids=' + group)
.then(res => { .then(res => {
// Gestion des données sous forme de tableau a deux colonnes
const dat = res.data.map((x,i) => { const dat = res.data.map((x,i) => {
return i % 2 === 0 ? res.data.slice(i, i+2) : null; return i % 2 === 0 ? res.data.slice(i, i+2) : null;
}).filter(x => x != null); }).filter(x => x != null);
this.setState({ students: dat}); this.setState({students: dat});
}) })
} }
/**
* Gestion des données du Select
*/
handleSelectChange(e){
this.setState({id:e.value, name:e.label}, () => {
if (this.state.id !== "Default") {this.getStudents()}
else {
if (this.props.students.length) {
const dat = this.props.students.map((x,i) => {
return i % 2 === 0 ? this.props.students.slice(i, i+2) : null;
}).filter(x => x != null);
this.setState({ students: dat});
}
}
})
}
render() { render() {
return ( return (
<div className="wrapper"> <div className="wrapper">
<h1 id="pageTitle">Liste des étudiants</h1> <h1 id="pageTitle">Liste des étudiants</h1>
<div className="container"> <div className="container">
<Select
defaultValue={this.state.selectOptions[0]}
options={this.state.selectOptions}
formatGroupLabel={formatGroupLabel}
onChange={this.handleSelectChange.bind(this)}
/>
{this.state.students.length !== 0 ? {this.state.students.length !== 0 ?
this.state.students.map((students) => { this.state.students.map((students) => {
// Creation du tableau de deux colonnes // Creation du tableau de deux colonnes

View File

@ -37,8 +37,16 @@ class ScoNavBar extends Component {
<Navbar.Toggle aria-controls="basic-navbar-nav" /> <Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav"> <Navbar.Collapse id="basic-navbar-nav">
<Nav className="ml-auto"> <Nav className="ml-auto">
<Nav.Link href="/ScoDoc">Version Desktop</Nav.Link> <Button variant="outline-primary" href="/ScoDoc" style={{"margin": "1px"}}>Version Desktop</Button>
<Button variant="primary" onClick={() => {this.logout()}}>Déconnexion</Button> {window.location.href.split('/').length > 9 &&
<Button
variant="outline-primary"
href={"/ScoDoc/static/mobile/#/" + window.location.href.split('/')[7] + "/Scolarite"}
style={{"margin": "1px"}}>
Retour au choix de semestre
</Button>
}
<Button variant="primary" style={{"margin": "1px"}} onClick={() => {this.logout()}}>Déconnexion</Button>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
</Container> </Container>