107 lines
3.0 KiB
JavaScript
107 lines
3.0 KiB
JavaScript
import React from 'react';
|
||
import PropTypes from 'prop-types';
|
||
import Graph from './Graph.js';
|
||
import {useAsync} from '../util.js';
|
||
import {Term, termTypes} from '../data/model.js';
|
||
import {symptomsSubgraph} from '../data/mock';
|
||
|
||
/**
|
||
* Graphe de maladies et symptômes.
|
||
*
|
||
* @prop terms Termes à afficher.
|
||
* @prop query Ensemble de termes recherchés par l’utilisateur.
|
||
* @prop addQueryTerm Fonction de rappel pour ajouter un terme à la requête.
|
||
* @prop removeQueryTerm Fonction de rappel pour ôter un terme de la requête.
|
||
*/
|
||
const DiseaseGraph = ({
|
||
terms,
|
||
query,
|
||
addQueryTerm,
|
||
removeQueryTerm,
|
||
}) =>
|
||
{
|
||
const {nodes, edges} = useAsync({
|
||
nodes: {},
|
||
edges: [],
|
||
}, symptomsSubgraph, terms);
|
||
|
||
/**
|
||
* Rendu d’un nœud du graphe.
|
||
*
|
||
* @param id Identifiant du nœud à afficher.
|
||
*/
|
||
const render = id =>
|
||
{
|
||
const term = nodes[id];
|
||
const isInQuery = query.some(({id: termId}) => termId === id);
|
||
const isDisease = nodes[id].types.includes(termTypes.disease);
|
||
|
||
return (
|
||
<span
|
||
className={[
|
||
'SearchResults_result',
|
||
isInQuery ? 'SearchResults_result-inQuery' : '',
|
||
isDisease ? 'SearchResults_result-disease' : '',
|
||
].join(' ')}
|
||
title={
|
||
`Cliquez pour plus d’informations sur « ${term.name} »\n`
|
||
+ `(Ctrl-clic pour ${
|
||
isInQuery
|
||
? 'l’enlever de'
|
||
: 'l’ajouter à'
|
||
} la requête)`
|
||
}
|
||
>
|
||
{nodes[id].name}
|
||
</span>
|
||
);
|
||
};
|
||
|
||
/**
|
||
* Gère le clic sur un nœud du graphe.
|
||
*
|
||
* @param id Identifiant du nœud cliqué.
|
||
* @param ev Événement DOM décrivant le clic.
|
||
*/
|
||
const handleNodeClick = (id, ev) =>
|
||
{
|
||
const term = nodes[id];
|
||
const queryIndex = query.findIndex(({id: termId}) => termId === id);
|
||
|
||
if (!ev.ctrlKey)
|
||
{
|
||
// Clic normal : Ouverture de la ressource
|
||
window.open(term.url, '_blank');
|
||
}
|
||
else if (queryIndex >= 0)
|
||
{
|
||
// Ctrl-clic : Retrait d’un terme déjà dans la requête
|
||
removeQueryTerm(queryIndex);
|
||
}
|
||
else
|
||
{
|
||
// Ctrl-clic : Ajout d’un nouveau terme dans la requête
|
||
addQueryTerm(term);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Graph
|
||
nodes={Object.keys(nodes)}
|
||
edges={edges}
|
||
emptyMessage="Aucune maladie ne corresond à ces symptômes"
|
||
render={render}
|
||
onNodeClick={handleNodeClick}
|
||
/>
|
||
);
|
||
};
|
||
|
||
DiseaseGraph.propTypes = {
|
||
terms: PropTypes.arrayOf(Term).isRequired,
|
||
query: PropTypes.arrayOf(Term).isRequired,
|
||
addQueryTerm: PropTypes.func.isRequired,
|
||
removeQueryTerm: PropTypes.func.isRequired,
|
||
};
|
||
|
||
export default DiseaseGraph;
|