mon-entreprise/source/reducers.js

168 lines
4.9 KiB
JavaScript
Raw Normal View History

import React from 'react'
import { combineReducers } from 'redux'
import reduceReducers from 'reduce-reducers'
import {reducer as formReducer, formValueSelector} from 'redux-form'
2017-01-20 10:52:39 +00:00
import {analyseSituation, variableType} from './engine/traverse'
import { euro } from './components/conversation/formValueTypes.js'
import Question from './components/conversation/Question'
import Input from './components/conversation/Input'
import RhetoricalQuestion from './components/conversation/RhetoricalQuestion'
import { STEP_ACTION, UNSUBMIT_ALL, START_CONVERSATION} from './actions'
import R from 'ramda'
2017-01-23 18:06:46 +00:00
import {borrify} from './engine/remove-diacritics'
import {findGroup} from './engine/rules'
import computeThemeColours from './components/themeColours'
function steps(steps = [], {type}) {
switch (type) {
case UNSUBMIT_ALL:
return []
default:
return steps
}
}
function themeColours(state = computeThemeColours(), {type, colour}) {
if (type == 'CHANGE_THEME_COLOUR')
return computeThemeColours(colour)
else return state
}
export default reduceReducers(
combineReducers({
// this is handled by redux-form, pas touche !
form: formReducer,
/* Have forms been filled or ignored ?
false means the user is reconsidering its previous input */
steps,
analysedSituation: (state = []) => state,
themeColours
}),
// cross-cutting concerns because here `state` is the whole state tree
(state, action) => {
if (action.type == STEP_ACTION || action.type == START_CONVERSATION) {
let {newState, name} = action
// une étape vient d'être validée : on va changer son état
let newSteps = R.pipe(
R.map(step => step.name == name ? {...step, state: newState} : step),
R.reject(R.whereEq({theEnd: true}))
)(state.steps)
// on calcule la prochaine étape, à ajouter sur la pile
let analysedSituation = analyseSituation(name => formValueSelector('conversation')(state, name)),
missingVariables = R.pipe(
R.map( ({name, derived: [missingVariables]}) =>
(missingVariables || []).map(mv => [mv, name])
),
R.unnest,
//groupBy but remove mv from value, it's now in the key
R.reduce( (memo, [mv, dependencyOf]) => ({...memo, [mv]: [...(memo[mv] || []), dependencyOf] }), {})
2017-01-23 18:06:46 +00:00
)(analysedSituation),
missingVariablesList = R.keys(missingVariables),
// identification des groupes de variables manquantes
groups = [...missingVariablesList.reduce(
(set, variable) => {
let subs = R.pipe(
borrify,
R.split(' . '),
R.dropLast(1),
R.join(' . ')
)(variable)
if (subs.length)
set.add(subs)
return set
}
, new Set())],
// -> groups Set [ "salariat . cdd . evenements", "salariat . cdd . type", "salariat", "salariat . cdd" ]
richGroups = R.pipe(
R.map(findGroup),
R.reject(R.isNil)
)(groups),
possibilities = richGroups[0]['choix exclusif']
// récupération du groupe. Inclure toutes les possibilités du groupe dans la question pour permettre à
// l'utilisateur de faire un choix réfléchi -> Question (réponses possibles)
// la question doit pouvoir stocker tout ça dans la situation (redux-form) correctement
console.log("groupPossibilities", possibilities)
return {...state, steps: [{
name: 'év',
question: 'év',
title: 'év',
dependencyOfVariables: ['je sais pas'],
visible: true,
component: Question,
choices: possibilities,
defaultValue: 'Non'
}], analysedSituation}
let [firstMissingVariable, dependencyOfVariables] = R.isEmpty(missingVariables) ? [] : R.toPairs(missingVariables)[0],
type = variableType(firstMissingVariable),
stepData = Object.assign({
name: firstMissingVariable,
state: null,
dependencyOfVariables: dependencyOfVariables,
title: firstMissingVariable,
question: firstMissingVariable,
visible: true,
helpText: <p>
Le contrat à durée indéterminée est une exception au CDI.
<br/>
<a href="https://www.service-public.fr/professionnels-entreprises/vosdroits/F33777" target="_blank">
En savoir plus (service-public.fr)
</a>
</p>
}, type == 'boolean' ? {
component: Question,
choices: ['non', 'oui'],
defaultValue: 'Non'
}: type == 'numeric' ? {
component: Input,
defaultValue: 0,
valueType: euro,
attributes: {
/* We use 'text' inputs : browser behaviour with input=number
doesn't quite work with our "update simulation on input change"... */
inputMode: 'numeric',
placeholder: 'votre réponse'
}
} : firstMissingVariable == undefined ? {
theEnd: true,
component: RhetoricalQuestion,
question: <span>
{'Merci. N\'hésitez pas à partager le simulateur !'}
</span>,
helpText: null
}: {})
return {...state, steps: [...newSteps, stepData], analysedSituation}
// ... do stuff
} else {
return state
}
}
)