Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit 7cb5f6f

Browse files
author
nicoSix
committed
Adding open/close all category feature; adding a modal window to explain the computation of scores
1 parent 04b0b8c commit 7cb5f6f

File tree

4 files changed

+113
-32
lines changed

4 files changed

+113
-32
lines changed

blade/front/src/components/pages/Recommendation/Recommendation.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { stringify } from 'json2yaml';
55
import RecommendationCategoryForm from '../../parts/RecommendationCategoryForm/RecommendationCategoryForm';
66
import RecommendationLogs from '../../parts/RecommendationLogs/RecommendationLogs';
77
import ResultsTable from '../../parts/ResultsTable/ResultsTable';
8+
import InfoModal from '../../parts/InfoModal/InfoModal';
89
import { apiUrl } from '../../../static/js/variables';
910
import { struct } from './struct';
1011
import './Recommendation.css';
@@ -20,14 +21,15 @@ class Recommendation extends Component {
2021
super(props);
2122
var attributeKeys = [];
2223
var attributeForm = {};
24+
var categoryRefs = {};
25+
this.infoModal = React.createRef();
2326

24-
this.resultsField = React.createRef();
25-
this.yamlField = React.createRef();
26-
2727
struct.forEach(category => {
2828
category.fields.forEach(attribute => {
2929
attributeKeys.push(attribute.key);
3030
})
31+
32+
categoryRefs[category.name] = React.createRef();
3133
})
3234

3335
attributeKeys.forEach(key => {
@@ -43,10 +45,23 @@ class Recommendation extends Component {
4345
this.state = {
4446
form: attributeForm,
4547
yamlFile: "",
46-
results: {}
48+
results: {},
49+
categoryRefs: categoryRefs
4750
};
4851
}
4952

53+
openInfoModal() {
54+
this.infoModal.current.openModal()
55+
}
56+
57+
toggleCategories(isOpen) {
58+
Object.keys(this.state.categoryRefs).forEach(key => {
59+
console.log(this.state.categoryRefs)
60+
console.log(this.state.categoryRefs[key].current)
61+
this.state.categoryRefs[key].current.toggleAccordion(isOpen);
62+
})
63+
}
64+
5065
updateFormValues(attrKey, newAttrValues) {
5166
var newForm = this.state.form;
5267
newForm[attrKey] = newAttrValues;
@@ -77,6 +92,7 @@ class Recommendation extends Component {
7792
render() {
7893
return (
7994
<div className="recommendation">
95+
<InfoModal ref={ this.infoModal }/>
8096
<Container fluid>
8197
<Row>
8298
<Col>
@@ -93,13 +109,13 @@ class Recommendation extends Component {
93109
<p className="lead">Please select your requirements below.</p>
94110
</Col>
95111
<Col className="buttonGroup">
96-
<Button variant="secondary">Open all</Button>{' '}
97-
<Button variant="secondary">Close all</Button>
112+
<Button variant="secondary" onClick={ this.toggleCategories.bind(this, true) }>Open all</Button>{' '}
113+
<Button variant="secondary" onClick={ this.toggleCategories.bind(this, false) }>Close all</Button>
98114
</Col>
99115
</Row>
100116
{
101-
struct.map(categoryInfo => {
102-
return <RecommendationCategoryForm key={ categoryInfo.name } categoryInfo={ categoryInfo } updateFormValues={ this.updateFormValues.bind(this) }/>
117+
struct.map((categoryInfo) => {
118+
return <RecommendationCategoryForm ref={ this.state.categoryRefs[categoryInfo.name] } key={ categoryInfo.name } categoryInfo={ categoryInfo } updateFormValues={ this.updateFormValues.bind(this) }/>
103119
})
104120
}
105121
</div>
@@ -111,7 +127,7 @@ class Recommendation extends Component {
111127
<h2 className="inputHeader">Results panel</h2>
112128
</Col>
113129
<Col className="buttonGroup">
114-
<Button variant="secondary">?</Button>
130+
<Button variant="secondary" onClick={ this.openInfoModal.bind(this) }>?</Button>
115131
</Col>
116132
</Row>
117133
<ResultsTable results={ (this.state.results ? this.state.results.res : {}) }/>

blade/front/src/components/parts/InfoModal/InfoModal.css

Whitespace-only changes.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
import React, { Component } from 'react';
3+
import { Modal, Button } from 'react-bootstrap';
4+
import './InfoModal.css';
5+
6+
/**
7+
* InfoModal: displayed when the user click on info in the results field
8+
* @version 1.0.0
9+
* @author [Nicolas Six](https://github.com/nicoSix)
10+
*/
11+
class InfoModal extends Component {
12+
constructor(props) {
13+
super(props);
14+
this.state = {
15+
modalShow: false,
16+
};
17+
this.openModal = this.openModal.bind(this);
18+
this.closeModal = this.closeModal.bind(this);
19+
}
20+
21+
openModal() {
22+
this.setState({
23+
modalShow: true,
24+
});
25+
}
26+
27+
closeModal() {
28+
this.setState({
29+
modalShow: false,
30+
});
31+
}
32+
33+
componentDidMount() {
34+
this.props.isOpen ? this.openModal() : this.closeModal();
35+
}
36+
37+
componentDidUpdate(prevProps) {
38+
if (prevProps.isOpen !== this.props.isOpen) {
39+
this.props.isOpen ? this.openModal() : this.closeModal();
40+
}
41+
}
42+
43+
render() {
44+
return (
45+
<Modal show={this.state.modalShow} onHide={ this.closeModal } animation={false} className="infoModal">
46+
<Modal.Header closeButton>
47+
<Modal.Title>How to interpret the results</Modal.Title>
48+
</Modal.Header>
49+
<Modal.Body>
50+
<p>
51+
At each submission of requirements, the platform automatically computes a score using TOPSIS algorithm.
52+
The score is a floating number between 0 and 1. Having a score close to 1 means that the alternative is close to the perfect
53+
alternative for the submitted requirements (and the inverse for 0). Thus, an alternative can be ranked #1 in the results but far
54+
from your requirements.
55+
</p>
56+
<p>
57+
An alternative can also have a score of -1. It means that one of your strict requirement is incompatible with the alternative.
58+
Thus, the score is not computed.
59+
</p>
60+
<p>
61+
To ease your comprehension of the scores, you can see the content of the knowledge base in the corresponding section, on the platform.
62+
You can also consult the documentation of TOPSIS to understand how are the scores computed in detail.
63+
</p>
64+
</Modal.Body>
65+
<Modal.Footer>
66+
<Button variant="secondary" onClick={this.closeModal}>
67+
Close
68+
</Button>
69+
</Modal.Footer>
70+
</Modal>
71+
)
72+
};
73+
}
74+
75+
export default InfoModal;

blade/front/src/components/parts/RecommendationCategoryForm/RecommendationCategoryForm.js

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11

22
import React, { Component } from 'react';
3-
import { Accordion, Card, Row } from 'react-bootstrap';
4-
import { useAccordionToggle } from 'react-bootstrap/AccordionToggle';
53
import RecommendationAttributeForm from '../../parts/RecommendationAttributeForm/RecommendationAttributeForm';
64
import './RecommendationCategoryForm.css';
75

@@ -22,8 +20,6 @@ class RecommendationCategoryForm extends Component {
2220
if(isOpen !== this.state.open) {
2321
this.setState({
2422
open: isOpen
25-
}, () => {
26-
useAccordionToggle(0, null);
2723
})
2824
}
2925
}
@@ -36,25 +32,19 @@ class RecommendationCategoryForm extends Component {
3632

3733
render() {
3834
return (
39-
<Accordion className="category">
40-
<Card>
41-
<Accordion.Toggle as={Card.Header} eventKey="0" className="accordionHeader" onClick={ this.accordionHandler.bind(this) }>
42-
<h2 className="accordionTitle">{ this.props.categoryInfo.name }</h2>
43-
<small className="text-muted">(Click to { this.state.open ? "hide" : "display"})</small>
44-
</Accordion.Toggle>
45-
<Accordion.Collapse eventKey="0">
46-
<Card.Body>
47-
<Row>
48-
{
49-
this.props.categoryInfo.fields.map(attribute => {
50-
return <RecommendationAttributeForm key={attribute.key} attribute={ attribute } updateFormValues={ this.props.updateFormValues }/>
51-
})
52-
}
53-
</Row>
54-
</Card.Body>
55-
</Accordion.Collapse>
56-
</Card>
57-
</Accordion>
35+
<div className="card category">
36+
<div className="card-header accordionHeader" onClick={this.accordionHandler.bind(this)}>
37+
<h2 className="accordionTitle">{ this.props.categoryInfo.name }</h2>
38+
<small className="text-muted">(Click to { this.state.open ? "hide" : "display"})</small>
39+
</div>
40+
<ul className={"card-body " + (this.state.open ? "" : "collapse")}>
41+
{
42+
this.props.categoryInfo.fields.map(attribute => {
43+
return <RecommendationAttributeForm key={attribute.key} attribute={ attribute } updateFormValues={ this.props.updateFormValues }/>
44+
})
45+
}
46+
</ul>
47+
</div>
5848
)
5949
};
6050
}

0 commit comments

Comments
 (0)