Release v0

Optimisations finales
This commit is contained in:
Theal0 2021-05-11 17:46:17 +02:00
parent c6c2f25c80
commit deab35b121
9 changed files with 176 additions and 118 deletions

13
package-lock.json generated
View File

@ -13305,6 +13305,14 @@
} }
} }
}, },
"react-device-detect": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-1.17.0.tgz",
"integrity": "sha512-bBblIStwpHmoS281JFIVqeimcN3LhpoP5YKDWzxQdBIUP8S2xPvHDgizLDhUq2ScguLfVPmwfF5y268EEQR60w==",
"requires": {
"ua-parser-js": "^0.7.24"
}
},
"react-dom": { "react-dom": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@ -15844,6 +15852,11 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"ua-parser-js": {
"version": "0.7.28",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz",
"integrity": "sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g=="
},
"unbox-primitive": { "unbox-primitive": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",

View File

@ -13,6 +13,7 @@
"js-cookies": "^1.0.4", "js-cookies": "^1.0.4",
"react": "^17.0.2", "react": "^17.0.2",
"react-bootstrap": "^1.5.2", "react-bootstrap": "^1.5.2",
"react-device-detect": "^1.17.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",

View File

@ -1,7 +1,6 @@
import {Link} from "react-router-dom";
import React, {Component} from "react"; import React, {Component} from "react";
import {Link} from "react-router-dom";
import './Style.css' import './Style.css'
import SearchStudent from "./SearchStudent";
class ChoixDept extends Component { class ChoixDept extends Component {
constructor(props) { constructor(props) {
@ -31,7 +30,7 @@ class ChoixDept extends Component {
render() { render() {
return ( return (
<div className="wrapper"> <div className="wrapper">
<h1>Choix du département</h1> <h1 id="pageTitle">Choix du département</h1>
{this.state.depts.map((dept, index) => { {this.state.depts.map((dept, index) => {
return ( return (
<div id="wrapDept"> <div id="wrapDept">

View File

@ -77,10 +77,10 @@ class Etudiant extends Component {
this.state.etud.email !== "" || this.state.etud.emailperso !== "" ? this.state.etud.email !== "" || this.state.etud.emailperso !== "" ?
<div className="col-sm"> <div className="col-sm">
<h4>Contact</h4> <h4>Contact</h4>
{this.state.etud.telephone !== "" && "Téléphone: " + this.state.etud.telephone}<br/> {this.state.etud.telephone !== "" && <a href={'tel:' + this.state.etud.telephone}>Téléphone: {this.state.etud.telephone}</a>}<br/>
{this.state.etud.telephonemobile !== "" && "Mobile: " + this.state.etud.telephonemobile}<br/> {this.state.etud.telephonemobile !== "" && <a href={'tel:' + this.state.etud.telephonemobile}>Mobile: {this.state.etud.telephonemobile}</a>}<br/>
{this.state.etud.email !== "" && "Mail étudiant: " + this.state.etud.email}<br/> {this.state.etud.email !== "" && <a href={'mailto:' + this.state.etud.email}>Mail étudiant: {this.state.etud.email}</a>}<br/>
{this.state.etud.emailperso !== "" && "Mail perso: " + this.state.etud.emailperso}<br/> {this.state.etud.emailperso !== "" && <a href={'mailto:' + this.state.etud.emailperso}>Mail personnel: {this.state.etud.emailperso}</a>}<br/>
</div> </div>
: :
<div className="col-sm">Aucun contact disponible</div> <div className="col-sm">Aucun contact disponible</div>

View File

@ -5,22 +5,63 @@ import Absences from "./GestionSemestre/Absences";
import Eleves from "./GestionSemestre/Eleves"; import Eleves from "./GestionSemestre/Eleves";
import ScoNavBar from "./ScoNavBar"; import ScoNavBar from "./ScoNavBar";
import Bulletin from "./GestionSemestre/Bulletin"; import Bulletin from "./GestionSemestre/Bulletin";
import Select from "react-select";
class GestionSemestre extends Component { class GestionSemestre extends Component {
constructor(props){
super(props)
this.state = {
selectOptions: [],
id: "",
name: '',
}
}
componentWillMount() {
let dept = window.location.href.split('/')[6]
let sem = window.location.href.split('/')[8]
let BASE_URL = window.$api_url
fetch(BASE_URL + dept +
'/Scolarite/Notes/groups_view?with_codes=1&format=json&formsemestre_id=' + sem, {
method: 'GET',
verify: false,
credentials: 'include',
})
.then(response =>
response.json().then(data => ({
data: data,
})
).then(res => {
res.data.map((student, index) => {
let joined = this.state.selectOptions.concat({label: student.nom_disp + " " + student.prenom, value: student.etudid});
this.setState({selectOptions: joined})
})
})
);
}
handleSelectChange(e){
this.setState({id:e.value, name:e.label})
}
render() { render() {
return ( return (
<div> <div>
<ScoNavBar/> <ScoNavBar/>
<div id="wrapDept">
Choix de l'étudiant
<Select className="mySelect" options={this.state.selectOptions} onChange={this.handleSelectChange.bind(this)}/>
</div>
<div> <div>
<Tabs defaultActiveKey="Accueil" id="controlled-tab-example"> <Tabs defaultActiveKey="Accueil" id="controlled-tab-example">
<Tab eventKey="Accueil" title="Acceuil" > <Tab eventKey="Accueil" title="Acceuil" >
<Accueil /> <Accueil />
</Tab> </Tab>
<Tab eventKey="Absences" title="Absences"> <Tab eventKey="Absences" title="Absences">
<Absences /> <Absences id={this.state.id} name={this.state.name}/>
</Tab> </Tab>
<Tab eventKey="Bulletin" title="Bulletins"> <Tab eventKey="Bulletin" title="Bulletins">
<Bulletin /> <Bulletin id={this.state.id} name={this.state.name}/>
</Tab> </Tab>
<Tab eventKey="Eleves" title="Eleves"> <Tab eventKey="Eleves" title="Eleves">
<Eleves /> <Eleves />

View File

@ -1,50 +1,29 @@
import React, {Component} from "react"; import React, {Component} from "react";
import '../Style.css' import '../Style.css'
import Select from 'react-select'
class Absences extends Component { class Absences extends Component {
constructor(props){ constructor(props){
super(props) super(props)
this.state = { this.state = {
selectOptions: [],
id: "",
name: '',
abs: [] abs: []
} }
} }
componentWillMount() { componentDidUpdate(prevProps) {
let dept = window.location.href.split('/')[6] if (prevProps.id !== this.props.id) {
let sem = window.location.href.split('/')[8] this.getData();
let BASE_URL = window.$api_url }
fetch(BASE_URL + dept +
'/Scolarite/Notes/groups_view?with_codes=1&format=json&formsemestre_id=' + sem, {
method: 'GET',
verify: false,
credentials: 'include',
})
.then(response =>
response.json().then(data => ({
data: data,
})
).then(res => {
res.data.map((student, index) => {
let joined = this.state.selectOptions.concat({label: student.nom_disp + " " + student.prenom, value: student.etudid});
this.setState({selectOptions: joined})
})
})
);
} }
handleSelectChange(e){ componentDidMount() {
this.setState({id:e.value, name:e.label}, () => {this.getData()}) if (this.props.id !== "") {this.getData()}
} }
getData() { getData() {
let dept = window.location.href.split('/')[6] let dept = window.location.href.split('/')[6]
let BASE_URL = window.$api_url let BASE_URL = window.$api_url
if (this.state.id !== "") { if (this.state.id !== "") {
fetch(BASE_URL + dept + "/Scolarite/Absences/ListeAbsEtud?format=json&etudid=" + this.state.id, { fetch(BASE_URL + dept + "/Scolarite/Absences/ListeAbsEtud?format=json&etudid=" + this.props.id, {
method: 'GET', method: 'GET',
verify: false, verify: false,
credentials: 'include', credentials: 'include',
@ -64,10 +43,10 @@ class Absences extends Component {
return ( return (
<div className="wrapper"> <div className="wrapper">
<h1 id="pageTitle">Gestion des absences</h1> <h1 id="pageTitle">Gestion des absences</h1>
<Select className="mySelect" options={this.state.selectOptions} onChange={this.handleSelectChange.bind(this)}/> {this.props.name !== "" &&
<div className="col-sm" id="wrapDept"> <div className="col-sm" id="wrapDept">
{this.state.name !== "" && <h4>Absences de {this.state.name}</h4>} <h4>Absences de {this.props.name}</h4>
{(this.state.abs.length === 0 && this.state.name !== "") && {(this.state.abs.length === 0 && this.props.name !== "") &&
<h6>Aucune absence de l'élève</h6> <h6>Aucune absence de l'élève</h6>
} }
{this.state.abs.map((abs, index) => { {this.state.abs.map((abs, index) => {
@ -83,6 +62,7 @@ class Absences extends Component {
) )
})} })}
</div> </div>
}
</div> </div>
) )
} }

View File

@ -1,15 +1,12 @@
import React, {Component} from "react"; import React, {Component} from "react";
import Select from "react-select"; import Select from "react-select";
import {Table} from "react-bootstrap" import {Table, Button, Dropdown} from "react-bootstrap"
import '../Style.css' import '../Style.css'
class Bulletin extends Component { class Bulletin extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
selectOptions: [],
id: "",
name: '',
bltn: {}, bltn: {},
datue: {}, datue: {},
loaded: false loaded: false
@ -18,29 +15,6 @@ class Bulletin extends Component {
this.getJsonData = this.getJsonData.bind(this); this.getJsonData = this.getJsonData.bind(this);
} }
componentWillMount() {
let dept = window.location.href.split('/')[6]
let sem = window.location.href.split('/')[8]
let BASE_URL = window.$api_url
fetch(BASE_URL + dept +
'/Scolarite/Notes/groups_view?with_codes=1&format=json&formsemestre_id=' + sem, {
method: 'GET',
verify: false,
credentials: 'include',
})
.then(response =>
response.json().then(data => ({
data: data,
})
).then(res => {
res.data.map((student, index) => {
let joined = this.state.selectOptions.concat({label: student.nom_disp + " " + student.prenom, value: student.etudid});
this.setState({selectOptions: joined})
})
})
);
}
getJsonData () { getJsonData () {
this.setState({bltn: require('..\\..\\json\\bltn.json')}, () => { this.setState({bltn: require('..\\..\\json\\bltn.json')}, () => {
let ls = {} let ls = {}
@ -60,7 +34,7 @@ class Bulletin extends Component {
let sem = window.location.href.split('/')[8] let sem = window.location.href.split('/')[8]
let BASE_URL = window.$api_url let BASE_URL = window.$api_url
fetch(BASE_URL + dept + '/Scolarite/Notes/formsemestre_bulletinetud?formsemestre_id=' + fetch(BASE_URL + dept + '/Scolarite/Notes/formsemestre_bulletinetud?formsemestre_id=' +
sem +'&etudid=' + this.state.id +'&format=json', { sem +'&etudid=' + this.props.id +'&format=json', {
method: 'GET', method: 'GET',
verify: false, verify: false,
credentials: 'include', credentials: 'include',
@ -85,40 +59,62 @@ class Bulletin extends Component {
); );
} }
handleSelectChange(e){ getPdf() {
this.setState({id:e.value, name:e.label}, () => {this.getData()}) let BASE_URL = window.$api_url
let dept = window.location.href.split('/')[6]
let sem = window.location.href.split('/')[8]
fetch( BASE_URL + dept + "/Scolarite/Notes/formsemestre_bulletinetud?" +
"formsemestre_id=" + sem + "&etudid=" + this.props.id + "&format=pdf&version=selectedevals", {
method: 'GET',
verify: false,
credentials: 'include',
})
.then( res => res.blob() )
.then( blob => {
let file = window.URL.createObjectURL(blob);
window.location.assign(file);
});
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id) {
this.getData();
}
}
componentDidMount() {
if (this.props.id !== "") {this.getData()}
} }
render() { render() {
return ( return (
<div className="wrapper"> <div className="wrapper">
<div style={{"margin-bottom": "20px"}}>
<h1 id="pageTitle">Bulletins de notes</h1> <h1 id="pageTitle">Bulletins de notes</h1>
<Select className="mySelect" options={this.state.selectOptions} onChange={this.handleSelectChange.bind(this)}/> </div>
{this.state.loaded === true && {this.state.loaded === true &&
<div> <div>
<h2>Bulletin de {this.state.name}</h2>
<Table responsive="sm"> <Table responsive="sm">
<thead> <thead>
<tr> <tr>
<th colSpan="3"/> <th colSpan="3"/>
<th>Rang</th>
<th colSpan="2">Promotion</th>
<th>Note/20</th> <th>Note/20</th>
<th>Coef.</th>
</tr>
<tr className="smallRow">
<th colSpan="4"/>
<th>Mini</th>
<th>Maxi</th>
<th colSpan="2"/>
</tr> </tr>
<tr className="bigRow"> <tr className="bigRow">
<th colSpan="3">Moyenne générale</th> <th colSpan="3">Moyenne générale</th>
<th>{this.state.bltn.rang.value}/{this.state.bltn.rang.ninscrits}</th> <th>
<th>{this.state.bltn.note.min}</th> <Dropdown>
<th>{this.state.bltn.note.max}</th> <Dropdown.Toggle variant="primary" size="sm" id="dropdown-basic">
<th>{this.state.bltn.note.value}</th> {this.state.bltn.note.value}
<th/> </Dropdown.Toggle>
<Dropdown.Menu>
<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="#">Classement: {this.state.bltn.rang.value}/{this.state.bltn.rang.ninscrits}</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</th>
</tr> </tr>
</thead> </thead>
{this.state.bltn.ue.map((ue, index) => { {this.state.bltn.ue.map((ue, index) => {
@ -126,21 +122,38 @@ class Bulletin extends Component {
<tbody> <tbody>
<tr className="ueRow"> <tr className="ueRow">
<td colSpan="3">{ue.acronyme} - {this.state.datue[ue.acronyme]}</td> <td colSpan="3">{ue.acronyme} - {this.state.datue[ue.acronyme]}</td>
<td>{ue.rang}/{this.state.bltn.rang.ninscrits}</td> <td>
<td>{ue.note.min}</td> <Dropdown>
<td>{ue.note.max}</td> <Dropdown.Toggle variant="primary" size="sm" id={ue.acronyme}>
<td>{ue.note.value}</td> {ue.note.value}
<td>{/*Coef*/}</td> </Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item href="#">Min: {ue.note.min}</Dropdown.Item>
<Dropdown.Item href="#">Max: {ue.note.max}</Dropdown.Item>
<Dropdown.Item href="#">Classement: {ue.rang}/{this.state.bltn.rang.ninscrits}</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</td>
</tr> </tr>
{ue.module.map((mod, index) => { {ue.module.map((mod, index) => {
return ( return (
<tr> <tr>
<td colSpan="3">{mod.titre.replace("&apos;", "'")}</td> <td colSpan="3">{mod.titre.replace("&apos;", "'")}</td>
<td>{mod.rang.value}/{this.state.bltn.rang.ninscrits}</td> <td>
<td>{mod.note.min}</td> <Dropdown>
<td>{mod.note.max}</td> <Dropdown.Toggle variant="primary" size="sm" id={mod.code}>
<td>{mod.note.value}</td> {mod.note.value}
<td>{mod.coefficient}</td> </Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item href="#">Min: {mod.note.min}</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>
<Dropdown.Item href="#">Coefficient: {mod.coefficient}</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</td>
</tr> </tr>
) )
})} })}
@ -148,6 +161,9 @@ class Bulletin extends Component {
) )
})} })}
</Table> </Table>
<div>
<Button className="btn-primary" onClick={() => {this.getPdf()}}>Version PDF</Button>
</div>
</div> </div>
} }
</div> </div>

View File

@ -1,4 +1,6 @@
import React, {Component} from "react"; import React, {Component, useState} from "react";
import { isMobile } from 'react-device-detect';
import {Modal, Button} from 'react-bootstrap'
import './Style.css' import './Style.css'
import ChoixDept from "./ChoixDept"; import ChoixDept from "./ChoixDept";
import ScoNavBar from "./ScoNavBar"; import ScoNavBar from "./ScoNavBar";
@ -9,7 +11,7 @@ class Login extends Component {
this.state = { this.state = {
login: "", login: "",
pass: "", pass: "",
status: 0 status: 0,
}; };
this.handleChangeLogin = this.handleChangeLogin.bind(this); this.handleChangeLogin = this.handleChangeLogin.bind(this);
this.handleChangePass = this.handleChangePass.bind(this); this.handleChangePass = this.handleChangePass.bind(this);
@ -25,6 +27,8 @@ class Login extends Component {
} }
checkCredentials(e) { checkCredentials(e) {
e.preventDefault();
let login = this.state.login let login = this.state.login
let pass = this.state.pass let pass = this.state.pass
@ -41,17 +45,18 @@ class Login extends Component {
}) })
.then(res => { .then(res => {
this.setState({ status: res["status"] }); this.setState({ status: res["status"] });
console.log("Cookie (get): " + res.headers.get('Set-Cookie'));
console.log("Cookie (doc): " + document.cookie);
}) })
.catch(console.log) .catch(console.log)
e.preventDefault()
} }
render() { render() {
return ( return (
<div> <div>
{!isMobile &&
// TODO: Redirection mobile/desktop
<span/>
}
{(this.state.status !== 0 && this.state.status !== 200) && {(this.state.status !== 0 && this.state.status !== 200) &&
<div className="wrapper"> <div className="wrapper">
<div id="errorMsg"> <div id="errorMsg">
@ -59,7 +64,7 @@ class Login extends Component {
</div> </div>
</div> </div>
} }
{this.state.status !== 200 && {document.cookie === "" &&
<div className="wrapper"> <div className="wrapper">
<div id="formContent"> <div id="formContent">
<h2 id="loginTitle">Connexion a ScoDoc</h2> <h2 id="loginTitle">Connexion a ScoDoc</h2>
@ -73,9 +78,9 @@ class Login extends Component {
</div> </div>
} }
<div> <div>
{this.state.status === 200 && {document.cookie !== "" &&
<ScoNavBar/> <ScoNavBar/>
}{this.state.status === 200 && }{document.cookie !== "" &&
<ChoixDept/> <ChoixDept/>
} }
</div> </div>

View File

@ -1,7 +1,7 @@
import React, {Component} from "react"; import React, {Component} from "react";
import {Link, Redirect} from "react-router-dom";
import './Style.css'
import {Nav, Navbar, Button, Container} from 'react-bootstrap' import {Nav, Navbar, Button, Container} from 'react-bootstrap'
import { Redirect } from 'react-router-dom';
import './Style.css'
class ScoNavBar extends Component { class ScoNavBar extends Component {
constructor(props) { constructor(props) {
@ -9,6 +9,7 @@ class ScoNavBar extends Component {
this.state = { this.state = {
login: {}, login: {},
semestre: {}, semestre: {},
logout: false
}; };
} }
@ -16,7 +17,7 @@ class ScoNavBar extends Component {
let BASE_URL = window.$api_url let BASE_URL = window.$api_url
fetch(BASE_URL + "acl_users/logout") fetch(BASE_URL + "acl_users/logout")
.then(res => {return <Redirect to="/" />}) .then(res => {this.setState({logout: true})})
.catch(console.log) .catch(console.log)
} }
@ -24,7 +25,7 @@ class ScoNavBar extends Component {
return ( return (
<Navbar bg="light" expand="sm"> <Navbar bg="light" expand="sm">
<Container> <Container>
<Navbar.Brand> <Navbar.Brand href={window.$api_url + "static/mobile/"}>
<img <img
alt="ScodocLogo" alt="ScodocLogo"
src="/ScoDoc/static/icons/scologo_img.png" src="/ScoDoc/static/icons/scologo_img.png"
@ -37,12 +38,14 @@ 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">
<Link to="/ScoDoc/static/mobile/"> <Nav.Link href="/ScoDoc">Version Desktop</Nav.Link>
<Button variant="primary" onClick={() => {this.logout()}}>Déconnexion</Button> <Button variant="primary" onClick={() => {this.logout()}}>Déconnexion</Button>
</Link>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
</Container> </Container>
{this.state.logout === true &&
<Redirect push to={window.$api_url + 'static/mobile/'}/>
}
</Navbar> </Navbar>
) )
} }