diff --git a/règles/rémunération-travail/entités/ok/CDD.yaml b/règles/rémunération-travail/entités/ok/CDD.yaml index e315eec4a..671a6bc7d 100644 --- a/règles/rémunération-travail/entités/ok/CDD.yaml +++ b/règles/rémunération-travail/entités/ok/CDD.yaml @@ -78,3 +78,7 @@ titre: Votre obligation motivation: Découvrez en quelques clics le montant des 4 obligations du CDD # CIF, majoration chômage, indemnité de fin de contrat, indemnité compensatrice des congés payés + par défaut: + contrat salarié . CDD . événement: non + contrat salarié . CDD . congés non pris: 0 + contrat salarié . CDD . contrat jeune vacances: non diff --git a/source/components/Results.js b/source/components/Results.js index bfcfecf84..edaa9e34a 100644 --- a/source/components/Results.js +++ b/source/components/Results.js @@ -22,7 +22,7 @@ let humanFigure = decimalDigits => value => fmt(value.toFixed(decimalDigits)) analysedSituation: state.analysedSituation, conversationStarted: !R.isEmpty(state.form), conversationFirstAnswer: R.path(['form', 'conversation', 'values'])(state), - situationGate: (name => formValueSelector('conversation')(state, name)) + situationGate: state.situationGate }) ) export default class Results extends Component { diff --git a/source/components/Simulateur.js b/source/components/Simulateur.js index 5d432475e..1c2dc724f 100644 --- a/source/components/Simulateur.js +++ b/source/components/Simulateur.js @@ -24,6 +24,7 @@ let situationSelector = formValueSelector('conversation') situation: variableName => situationSelector(state, variableName), foldedSteps: state.foldedSteps, unfoldedSteps: state.unfoldedSteps, + extraSteps: state.extraSteps, themeColours: state.themeColours, analysedSituation: state.analysedSituation, }), @@ -57,7 +58,7 @@ export default class extends React.Component { let started = !this.props.match.params.intro, - {foldedSteps, unfoldedSteps, situation} = this.props, + {foldedSteps, extraSteps, unfoldedSteps, situation} = this.props, sim = path => R.path(R.unless(R.is(Array), R.of)(path))(this.rule.simulateur || {}), reinitalise = () => { @@ -132,6 +133,22 @@ export default class extends React.Component { ))} } + { !R.isEmpty(extraSteps) && +
+
+

Affiner votre situation

+
+ {extraSteps + .map(step => ( + + ))} +
+ }
{ !R.isEmpty(unfoldedSteps) && do { let step = R.head(unfoldedSteps) diff --git a/source/reducers.js b/source/reducers.js index 4189518ba..8ba4b1b88 100644 --- a/source/reducers.js +++ b/source/reducers.js @@ -4,58 +4,89 @@ import { combineReducers } from 'redux' import reduceReducers from 'reduce-reducers' import {reducer as formReducer, formValueSelector} from 'redux-form' -import {rules} from 'Engine/rules' -import {buildNextSteps, generateGridQuestions, generateSimpleQuestions} from 'Engine/generateQuestions' +import {rules, findRuleByName } from 'Engine/rules' +import {buildNextSteps} from 'Engine/generateQuestions' import computeThemeColours from 'Components/themeColours' import { STEP_ACTION, START_CONVERSATION, EXPLAIN_VARIABLE, POINT_OUT_OBJECTIVES, CHANGE_THEME_COLOUR} from './actions' import {analyseTopDown} from 'Engine/traverse' -let situationGate = state => - name => formValueSelector('conversation')(state, name) +// Our situationGate retrieves data from the "conversation" form +let fromConversation = state => name => formValueSelector('conversation')(state, name) -let analyse = rootVariable => R.pipe( - situationGate, - // une liste des objectifs de la simulation (des 'rules' aussi nommées 'variables') - analyseTopDown(rules, rootVariable) -) +// assume "wraps" a given situation function with one that overrides its values with +// the given assumptions +let assume = (evaluator, assumptions) => state => name => + assumptions[name] != null ? assumptions[name] : evaluator(state)(name) export let reduceSteps = (state, action) => { + let flatRules = rules + if (![START_CONVERSATION, STEP_ACTION].includes(action.type)) return state let rootVariable = action.type == START_CONVERSATION ? action.rootVariable : state.analysedSituation.root.name + let sim = findRuleByName(flatRules, rootVariable), + // Hard assumptions cannot be changed, they are used to specialise a simulator + hardAssumptions = R.pathOr({},['simulateur','hypothèses'],sim), + // Soft assumptions are revealed after the simulation starts, and can be changed + softAssumptions = R.pathOr({},['simulateur','par défaut'],sim), + intermediateSituation = assume(fromConversation, hardAssumptions), + completeSituation = assume(intermediateSituation,softAssumptions) + + let situationGate = completeSituation(state), + analysedSituation = analyseTopDown(flatRules,rootVariable)(situationGate) + let returnObject = { ...state, - analysedSituation: analyse(rootVariable)(state) + analysedSituation, + situationGate: situationGate } if (action.type == START_CONVERSATION) { return { ...returnObject, foldedSteps: [], - unfoldedSteps: buildNextSteps(situationGate(state), rules, returnObject.analysedSituation) + unfoldedSteps: buildNextSteps(situationGate, flatRules, returnObject.analysedSituation) } } if (action.type == STEP_ACTION && action.name == 'fold') { - return { - ...returnObject, - foldedSteps: [...state.foldedSteps, R.head(state.unfoldedSteps)], - unfoldedSteps: buildNextSteps(situationGate(state), rules, returnObject.analysedSituation) + let foldedSteps = [...state.foldedSteps, R.head(state.unfoldedSteps)], + unfoldedSteps = buildNextSteps(situationGate, flatRules, returnObject.analysedSituation) + + // The simulation is "over" - except we can now fill in extra questions + // where the answers were previously given reasonable assumptions + if (unfoldedSteps.length == 0 && !R.isEmpty(softAssumptions)) { + let newSituation = intermediateSituation(state), + reanalyse = analyseTopDown(flatRules,rootVariable)(newSituation), + extraSteps = buildNextSteps(newSituation, flatRules, reanalyse) + + return { + ...returnObject, + foldedSteps, + extraSteps, + unfoldedSteps + } } - } - if (action.type == STEP_ACTION && action.name == 'unfold') { - let stepFinder = R.propEq('name', action.step), - foldedSteps = R.reject(stepFinder)(state.foldedSteps) - if (foldedSteps.length != state.foldedSteps.length - 1) - throw 'Problème lors du dépliement d\'une réponse' return { ...returnObject, foldedSteps, - unfoldedSteps: [R.find(stepFinder)(state.foldedSteps)] + unfoldedSteps + } + } + if (action.type == STEP_ACTION && action.name == 'unfold') { + let stepFinder = R.propEq('name', action.step), + foldedSteps = R.reject(stepFinder)(state.foldedSteps), + extraSteps = R.reject(stepFinder)(state.extraSteps) + + return { + ...returnObject, + foldedSteps, + extraSteps, + unfoldedSteps: [R.find(stepFinder)(R.concat(state.foldedSteps,state.extraSteps))] } } } @@ -93,10 +124,14 @@ export default reduceReducers( /* Have forms been filled or ignored ? false means the user is reconsidering its previous input */ foldedSteps: (steps = []) => steps, + extraSteps: (steps = []) => steps, unfoldedSteps: (steps = []) => steps, analysedSituation: (state = []) => state, + situationGate: (state = state => name => null) => state, + refine: (state = false) => state, + themeColours, explainedVariable,