1
0
Fork 0
mirror of https://github.com/betagouv/mon-entreprise synced 2025-02-10 13:55:03 +00:00
mon-entreprise/source/reducers/rootReducer.js
Maxime Quandalle fdb8ddc203
MAJ lors de la simulation ssi nouvelle saisie
Auparavant nous mettions à jour la "situation" de la simulation, dès le
changement de focus des champs "objectifs", bien que le changement de
focus dans l'interface ne change rien aux calculs. Nous attendons
maintenant que l'utilisateur fasse une nouvelle saisie.
2019-09-25 17:10:01 +02:00

232 lines
5.4 KiB
JavaScript

/* @flow */
import {
compose,
defaultTo,
identity,
isNil,
lensPath,
omit,
over,
set,
uniq,
without
} from 'ramda'
import reduceReducers from 'reduce-reducers'
import { combineReducers } from 'redux'
import i18n from '../i18n'
import inFranceAppReducer from './inFranceAppReducer'
import storageReducer from './storageReducer'
import { findRuleByDottedName } from 'Engine/rules'
import { targetNamesSelector } from 'Selectors/analyseSelectors'
import type { Action } from 'Types/ActionsTypes'
function explainedVariable(state = null, { type, variableName = null }) {
switch (type) {
case 'EXPLAIN_VARIABLE':
return variableName
case 'STEP_ACTION':
return null
default:
return state
}
}
function currentExample(state = null, { type, situation, name, dottedName }) {
switch (type) {
case 'SET_EXAMPLE':
return name != null ? { name, situation, dottedName } : null
default:
return state
}
}
function situationBranch(state = null, { type, id }) {
switch (type) {
case 'SET_SITUATION_BRANCH':
return id
default:
return state
}
}
function activeTargetInput(state = null, { type, name }) {
switch (type) {
case 'SET_ACTIVE_TARGET_INPUT':
return name
case 'RESET_SIMULATION':
return null
default:
return state
}
}
function lang(state = i18n.language, { type, lang }) {
switch (type) {
case 'SWITCH_LANG':
return lang
default:
return state
}
}
type ConversationSteps = {|
+foldedSteps: Array<string>,
+unfoldedStep: ?string
|}
function conversationSteps(
state: ConversationSteps = {
foldedSteps: [],
unfoldedStep: null
},
action: Action
): ConversationSteps {
if (action.type === 'RESET_SIMULATION')
return { foldedSteps: [], unfoldedStep: null }
if (action.type !== 'STEP_ACTION') return state
const { name, step } = action
if (name === 'fold')
return {
foldedSteps: [...state.foldedSteps, step],
unfoldedStep: null
}
if (name === 'unfold') {
return {
foldedSteps: without([step], state.foldedSteps),
unfoldedStep: step
}
}
return state
}
function updateSituation(situation, { fieldName, value, config, rules }) {
const goals = targetNamesSelector({ simulation: { config } }).filter(
dottedName => {
const target = rules.find(r => r.dottedName === dottedName)
const isSmallTarget = !target.question || !target.formule
return !isSmallTarget
}
)
const removePreviousTarget = goals.includes(fieldName)
? omit(goals)
: identity
return { ...removePreviousTarget(situation), [fieldName]: value }
}
function updatePeriod(situation, { toPeriod, rules }) {
const currentPeriod = situation['période']
if (currentPeriod === toPeriod) {
return situation
}
if (!['mois', 'année'].includes(toPeriod)) {
throw new Error('Oups, changement de période invalide')
}
const needConversion = Object.keys(situation).filter(dottedName => {
const rule = findRuleByDottedName(rules, dottedName)
return rule?.période === 'flexible'
})
const updatedSituation = Object.entries(situation)
.filter(([fieldName]) => needConversion.includes(fieldName))
.map(([fieldName, value]) => [
fieldName,
currentPeriod === 'mois' && toPeriod === 'année' ? value * 12 : value / 12
])
return {
...situation,
...Object.fromEntries(updatedSituation),
période: toPeriod
}
}
function simulation(state = null, action, rules) {
if (action.type === 'SET_SIMULATION') {
const { config, url } = action
return { config, url, hiddenControls: [], situation: {} }
}
if (state === null) {
return state
}
switch (action.type) {
case 'HIDE_CONTROL':
return { ...state, hiddenControls: [...state.hiddenControls, action.id] }
case 'RESET_SIMULATION':
return { ...state, hiddenControls: [], situation: {} }
case 'UPDATE_SITUATION':
return {
...state,
situation: updateSituation(state.situation, {
fieldName: action.fieldName,
value: action.value,
config: state.config,
rules
})
}
case 'UPDATE_PERIOD':
return {
...state,
situation: updatePeriod(state.situation, {
toPeriod: action.toPeriod,
rules
})
}
}
return state
}
const addAnswerToSituation = (dottedName, value, state) => {
const dottedPath = dottedName.split(' . ')
return compose(
set(lensPath(['form', 'conversation', 'values', ...dottedPath]), value),
over(lensPath(['conversationSteps', 'foldedSteps']), (steps = []) =>
uniq([...steps, dottedName])
)
)(state)
}
const existingCompanyReducer = (state, action) => {
if (action.type !== 'SAVE_EXISTING_COMPANY_DETAILS') {
return state
}
const details = action.details
let newState = state
if (details.localisation) {
newState = addAnswerToSituation(
'établissement . localisation',
JSON.stringify(details.localisation),
newState
)
}
if (!isNil(details.effectif)) {
newState = addAnswerToSituation(
'entreprise . effectif',
details.effectif,
newState
)
}
return newState
}
export default reduceReducers(
existingCompanyReducer,
storageReducer,
(state, action) =>
combineReducers({
sessionId: defaultTo(Math.floor(Math.random() * 1000000000000) + ''),
conversationSteps,
lang,
rules: defaultTo(null),
explainedVariable,
// We need to access the `rules` in the simulation reducer
simulation: (a, b) => simulation(a, b, state.rules),
previousSimulation: defaultTo(null),
currentExample,
situationBranch,
activeTargetInput,
inFranceApp: inFranceAppReducer
})(state, action)
)