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-03-22 17:18:37 +00:00
let handleSteps = ( state , action ) => {
2017-03-27 13:02:50 +00:00
if ( ! [ START _CONVERSATION , STEP _ACTION ] . includes ( action . type ) )
return state
2017-03-22 17:18:37 +00:00
let returnObject = {
... state ,
analysedSituation : analyse ( state )
}
2017-03-27 13:02:50 +00:00
2017-03-22 17:18:37 +00:00
if ( action . type == START _CONVERSATION ) {
return {
... returnObject ,
unfoldedSteps : buildNextSteps ( returnObject . analysedSituation )
}
}
if ( action . type == STEP _ACTION && action . name == 'fold' ) {
return {
... returnObject ,
foldedSteps : [ ... state . foldedSteps , R . head ( state . unfoldedSteps ) ] ,
unfoldedSteps : buildNextSteps ( returnObject . analysedSituation )
}
}
if ( action . type == STEP _ACTION && action . name == 'unfold' ) {
let stepFinder = R . propEq ( 'name' , action . step ) ,
foldedSteps = R . pipe (
R . splitWhen ( stepFinder ) ,
R . head
) ( state . foldedSteps )
return {
... returnObject ,
foldedSteps ,
unfoldedSteps : [ R . find ( stepFinder ) ( state . foldedSteps ) ]
}
}
}
let analyse = R . pipe (
situationGate ,
// une liste des objectifs de la simulation (des 'rules' aussi nommées 'variables')
analyseSituation
)
let missingVariables
let buildNextSteps = R . pipe (
/ *
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
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 .
missingVariables : { variable : [ objectives ] }
* /
R . path ( [ 'formule' , 'explanation' , 'explanation' ] ) ,
analysedSituation => {
//TODO temporary fix
missingVariables = collectMissingVariables ( 'groupByMissingVariable' ) ( analysedSituation )
return missingVariables
} ,
R . keys ,
/ *
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
* /
R . groupBy ( parentName ) ,
// on va maintenant construire la liste des composants React qui afficheront les questions à l'utilisateur pour que l'on obtienne les variables manquantes
R . pipe (
R . mapObjIndexed ( ( variables , group ) =>
R . pipe (
findGroup ,
R . cond ( [
// Pas de groupe trouvé : ce sont des variables individuelles
[ R . isNil , ( ) => variables . map ( dottedName => {
let rule = findRuleByDottedName ( dottedName )
return Object . assign ( constructStepMeta ( rule ) ,
rule . format == 'nombre positif' ||
rule . format == 'période' ?
{
component : Input ,
valueType : rule . format == 'nombre positif' ? euro : months ,
attributes : {
inputMode : 'numeric' ,
placeholder : 'votre réponse'
} ,
suggestions : rule . suggestions
} : {
component : Question ,
choices : [
{ value : 'non' , label : 'Non' } ,
{ value : 'oui' , label : 'Oui' }
]
} ,
{
objectives : missingVariables [ dottedName ]
}
) } ) ] ,
[ R . T , group => do {
let possibilities = group [ 'une possibilité' ]
Object . assign (
constructStepMeta ( group ) ,
{
component : Question ,
choices :
possibilities . concat (
group [ 'langue au chat possible' ] === 'oui' ?
[ { value : '_' , label : 'Aucun' } ] : [ ]
)
} ,
{
objectives : R . pipe (
R . chain ( v => missingVariables [ group . dottedName + ' . ' + v ] ) ,
R . uniq ( )
) ( possibilities )
}
) } ]
] )
) ( group )
) ,
R . values ,
R . unnest
)
)
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-22 17:18:37 +00:00
foldedSteps : ( steps = [ ] ) => steps ,
unfoldedSteps : ( steps = [ ] ) => steps ,
2017-03-13 15:15:19 +00:00
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
2017-03-22 17:18:37 +00:00
handleSteps
2017-01-10 18:22:44 +00:00
)