2017-01-10 18:22:44 +00:00
import React from 'react'
2016-11-15 18:46:17 +00:00
import { combineReducers } from 'redux'
2017-01-10 18:22:44 +00:00
import reduceReducers from 'reduce-reducers'
import { reducer as formReducer , formValueSelector } from 'redux-form'
2017-03-16 18:30:30 +00:00
import { analyseSituation } from './engine/traverse'
2017-02-16 10:45:40 +00:00
import { euro , months } from './components/conversation/formValueTypes.js'
2017-01-10 18:22:44 +00:00
import Question from './components/conversation/Question'
import Input from './components/conversation/Input'
2017-03-16 18:30:30 +00:00
import { STEP _ACTION , START _CONVERSATION , EXPLAIN _VARIABLE , POINT _OUT _OBJECTIVES } from './actions'
2017-01-10 18:22:44 +00:00
import R from 'ramda'
2017-01-23 18:06:46 +00:00
2017-03-16 18:30:30 +00:00
import { findGroup , findRuleByDottedName , parentName , collectMissingVariables } from './engine/rules'
2017-01-24 15:22:40 +00:00
import { constructStepMeta } from './engine/conversation'
2017-01-10 18:22:44 +00:00
import computeThemeColours from './components/themeColours'
function themeColours ( state = computeThemeColours ( ) , { type , colour } ) {
if ( type == 'CHANGE_THEME_COLOUR' )
return computeThemeColours ( colour )
else return state
}
2017-01-26 12:19:04 +00:00
let situationGate = state =>
name => formValueSelector ( 'conversation' ) ( state , name )
2017-02-09 17:38:51 +00:00
function explainedVariable ( state = null , { type , variableName = null } ) {
switch ( type ) {
case EXPLAIN _VARIABLE :
2017-02-09 17:15:25 +00:00
return variableName
2017-02-09 17:38:51 +00:00
default :
return state
}
2017-02-08 16:50:22 +00:00
}
2017-03-15 15:26:00 +00:00
function pointedOutObjectives ( state = [ ] , { type , objectives } ) {
switch ( type ) {
case POINT _OUT _OBJECTIVES :
return objectives
default :
return state
}
}
2017-01-10 18:22:44 +00:00
export default reduceReducers (
combineReducers ( {
// this is handled by redux-form, pas touche !
form : formReducer ,
/ * H a v e f o r m s b e e n f i l l e d o r i g n o r e d ?
false means the user is reconsidering its previous input * /
2017-03-13 15:15:19 +00:00
steps : ( steps = [ ] ) => steps ,
submittedSteps : ( steps = [ ] ) => steps ,
2017-01-10 18:22:44 +00:00
analysedSituation : ( state = [ ] ) => state ,
2017-02-08 16:50:22 +00:00
themeColours ,
2017-03-15 15:26:00 +00:00
explainedVariable ,
pointedOutObjectives
2017-01-10 18:22:44 +00:00
} ) ,
// cross-cutting concerns because here `state` is the whole state tree
( state , action ) => {
if ( action . type == STEP _ACTION || action . type == START _CONVERSATION ) {
2017-03-01 19:27:35 +00:00
// pour débugguer :
2017-01-26 12:19:04 +00:00
window . situationGate = situationGate ( state )
2017-03-13 15:15:19 +00:00
let newlySubmittedSteps =
action . newState == 'filled'
? [ {
... state . steps . find ( s => s . name === action . name ) ,
state : 'filled'
} ]
: [ ]
2017-01-10 18:22:44 +00:00
// on calcule la prochaine étape, à ajouter sur la pile
2017-01-26 12:19:04 +00:00
let
2017-03-01 19:27:35 +00:00
// une liste des objectifs de la simulation (des 'rules' aussi nommées 'variables')
2017-01-26 12:19:04 +00:00
analysedSituation = analyseSituation (
situationGate ( state )
) ,
2017-03-16 18:30:30 +00:00
// y = console.log('analysedSituation',analysedSituation),
2017-03-01 19:27:35 +00:00
2017-03-15 15:26:00 +00:00
/ *
on collecte les variables manquantes : celles qui sont nécessaires pour
remplir les objectifs de la simulation ( calculer des cotisations ) mais qui n ' ont pas
encore été renseignées
2017-02-10 14:12:00 +00:00
2017-03-16 18:30:30 +00:00
TODO perf : peut - on le faire en même temps que l 'on traverse l' AST ?
Oui sûrement , cette liste se complète en remontant l ' arbre . En fait , on le fait déjà pour nodeValue ,
et quand nodeValue vaut null , c 'est qu' il y a des missingVariables ! Il suffit donc de remplacer les
null par un tableau , et d 'ailleurs utiliser des fonction d' aide pour mutualiser ces tests .
2017-03-15 15:26:00 +00:00
missingVariables : { variable : [ objectives ] }
* /
2017-03-20 09:53:43 +00:00
missingVariables = collectMissingVariables ( 'groupByMissingVariable' , R . path ( [ 'formule' , 'explanation' , 'explanation' ] ) ( analysedSituation ) ) ,
2017-03-20 11:17:49 +00:00
// yy = console.log('missingVariables',missingVariables),
2017-03-20 09:53:43 +00:00
2017-01-23 18:06:46 +00:00
missingVariablesList = R . keys ( missingVariables ) ,
2017-03-13 15:15:19 +00:00
/ *
Certaines variables manquantes peuvent être factorisées dans des groupes .
Par exemple , au lieu de :
q1 : "Pensez vous porlonger le CDD en CDI" ,
r1 : Oui | Non
q2 : "Pensez-vous qu'une rupture pour faute grave est susceptible d'arriver"
r2 : Oui | Non
on préfère :
q : "Pensez-vous être confronté à l'un de ces événements ?"
r : Prolongation du CDD en CDI | Rupture pour faute grave
* /
2017-01-24 15:22:40 +00:00
groups = R . groupBy (
2017-01-26 12:19:04 +00:00
parentName
2017-01-24 15:22:40 +00:00
) ( missingVariablesList ) ,
2017-03-13 15:15:19 +00:00
// on va maintenant construire la liste des composants React qui afficheront les questions à l'utilisateur pour que l'on obtienne les variables manquantes
2017-03-01 19:27:35 +00:00
steps = R . pipe (
2017-01-24 15:22:40 +00:00
R . mapObjIndexed ( ( variables , group ) =>
R . pipe (
findGroup ,
R . cond ( [
// Pas de groupe trouvé : ce sont des variables individuelles
2017-01-26 10:27:24 +00:00
[ R . isNil , ( ) => variables . map ( dottedName => {
let rule = findRuleByDottedName ( dottedName )
2017-01-24 15:22:40 +00:00
return Object . assign ( constructStepMeta ( rule ) ,
2017-02-13 14:50:51 +00:00
rule . format == 'nombre positif' ||
rule . format == 'période' ?
2017-01-24 15:22:40 +00:00
{
component : Input ,
2017-02-16 10:45:40 +00:00
valueType : rule . format == 'nombre positif' ? euro : months ,
2017-01-24 15:22:40 +00:00
attributes : {
inputMode : 'numeric' ,
placeholder : 'votre réponse'
2017-02-16 13:15:45 +00:00
} ,
suggestions : rule . suggestions
2017-01-24 15:22:40 +00:00
} : {
component : Question ,
2017-01-26 12:19:04 +00:00
choices : [
{ value : 'non' , label : 'Non' } ,
{ value : 'oui' , label : 'Oui' }
2017-02-13 15:20:26 +00:00
]
2017-03-15 15:26:00 +00:00
} ,
{
objectives : missingVariables [ dottedName ]
2017-01-24 15:22:40 +00:00
}
) } ) ] ,
2017-03-15 15:26:00 +00:00
[ R . T , group => do {
let possibilities = group [ 'une possibilité' ]
2017-01-24 15:22:40 +00:00
Object . assign (
constructStepMeta ( group ) ,
{
component : Question ,
2017-02-09 17:15:25 +00:00
choices :
2017-03-15 15:26:00 +00:00
possibilities . concat (
2017-03-13 12:35:38 +00:00
group [ 'langue au chat possible' ] === 'oui' ?
2017-02-13 15:20:26 +00:00
[ { value : '_' , label : 'Aucun' } ] : [ ]
)
2017-03-15 15:26:00 +00:00
} ,
{
objectives : R . pipe (
R . chain ( v => missingVariables [ group . dottedName + ' . ' + v ] ) ,
R . uniq ( )
) ( possibilities )
2017-01-24 15:22:40 +00:00
}
2017-03-15 15:26:00 +00:00
) } ]
2017-01-24 15:22:40 +00:00
] )
) ( group )
) ,
R . values ,
R . unnest
2017-01-26 12:19:04 +00:00
) ( groups )
2017-01-23 18:06:46 +00:00
2017-03-13 15:15:19 +00:00
return {
... state ,
steps ,
submittedSteps : state . submittedSteps . concat ( newlySubmittedSteps ) ,
analysedSituation
}
2017-01-26 12:19:04 +00:00
2017-01-10 18:22:44 +00:00
} else {
return state
}
2016-11-15 18:46:17 +00:00
2017-01-10 18:22:44 +00:00
}
)