import { Action } from 'Actions/actions' import { Unit } from 'Engine/units' import { defaultTo, omit, without } from 'ramda' import reduceReducers from 'reduce-reducers' import { combineReducers, Reducer } from 'redux' import originRules, { Rules } from 'Rules' import { SavedSimulation } from 'Selectors/storageSelectors' import i18n, { AvailableLangs } from '../i18n' import { DottedName } from './../rules/index' import { objectifsSelector } from '../selectors/simulationSelectors' import inFranceAppReducer, { Company } from './inFranceAppReducer' import storageRootReducer from './storageReducer' function rules(state: Rules = originRules) { return state } function explainedVariable( state: DottedName | null = null, action: Action ): DottedName | null { switch (action.type) { case 'EXPLAIN_VARIABLE': return action.variableName case 'STEP_ACTION': return null default: return state } } type Example = null | { name: string situation: object dottedName: DottedName defaultUnit?: Unit } function situationBranch(state: number | null = null, action: Action) { switch (action.type) { case 'SET_SITUATION_BRANCH': return action.id default: return state } } function activeTargetInput(state: DottedName | null = null, action: Action) { switch (action.type) { case 'SET_ACTIVE_TARGET_INPUT': return action.name case 'RESET_SIMULATION': return null default: return state } } function lang( state = i18n.language as AvailableLangs, { type, lang } ): AvailableLangs { switch (type) { case 'SWITCH_LANG': return lang default: return state } } type QuestionsKind = | "à l'affiche" | 'non prioritaires' | 'uniquement' | 'liste noire' export type SimulationConfig = { objectifs: | Array | Array<{ icône: string; nom: string; objectifs: Array }> situation: Simulation['situation'] bloquant?: Array questions?: Partial>> branches?: Array<{ nom: string; situation: SimulationConfig['situation'] }> 'unité par défaut': string } type Situation = Partial> export type Simulation = { config: SimulationConfig url: string hiddenControls: Array situation: Situation initialSituation: Situation targetUnit: string foldedSteps: Array unfoldedStep?: DottedName | null } function getCompanySituation(company: Company): Situation { return { ...(company?.localisation && { 'établissement . localisation': company.localisation }), ...(company?.dateDeCréation && { 'entreprise . date de création': company.dateDeCréation.replace( /(.*)-(.*)-(.*)/, '$3/$2/$1' ) }) } } function simulation( state: Simulation | null = null, action: Action, existingCompany: Company ): Simulation | null { if (action.type === 'SET_SIMULATION') { const companySituation = action.useCompanyDetails ? getCompanySituation(existingCompany) : {} const { config, url } = action if (state && state.config === config) { return state } return { config, url, hiddenControls: [], situation: companySituation, initialSituation: companySituation, targetUnit: config['unité par défaut'] || '€/mois', foldedSteps: Object.keys(companySituation) as Array, unfoldedStep: null } } 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: state.initialSituation, foldedSteps: [], unfoldedStep: null } case 'UPDATE_SITUATION': const targets = without( ['entreprise . charges'], objectifsSelector({ simulation: state }) ) const situation = state.situation const { fieldName: dottedName, value } = action return { ...state, situation: { ...(targets.includes(dottedName) ? omit(targets, situation) : situation), [dottedName]: value } } case 'STEP_ACTION': const { name, step } = action if (name === 'fold') return { ...state, foldedSteps: [...state.foldedSteps, step], unfoldedStep: null } if (name === 'unfold') { return { ...state, foldedSteps: without([step], state.foldedSteps), unfoldedStep: step } } return state case 'UPDATE_TARGET_UNIT': return { ...state, targetUnit: action.targetUnit } } return state } const existingCompanyReducer = (state, action: Action) => { if (action.type.startsWith('EXISTING_COMPANY::') && state.simulation) { return { ...state, simulation: { ...state.simulation, situation: { ...state.simulation.situation, ...getCompanySituation(state.inFranceApp.existingCompany) } } } } return state } const mainReducer = (state, action: Action) => combineReducers({ lang, explainedVariable, // We need to access the `rules` in the simulation reducer simulation: (a: Simulation | null = null, b: Action): Simulation | null => simulation(a, b, state?.inFranceApp?.existingCompany), previousSimulation: defaultTo(null) as Reducer, situationBranch, activeTargetInput, inFranceApp: inFranceAppReducer })(state, action) export default reduceReducers( mainReducer as any, existingCompanyReducer as any, storageRootReducer as any ) as Reducer export type RootState = ReturnType