diff --git a/source/components/StackedBarChart.tsx b/source/components/StackedBarChart.tsx index a9578f480..2ec149853 100644 --- a/source/components/StackedBarChart.tsx +++ b/source/components/StackedBarChart.tsx @@ -3,7 +3,7 @@ import useDisplayOnIntersecting from 'Components/utils/useDisplayOnIntersecting' import React from 'react' import { animated, useSpring } from 'react-spring' import styled from 'styled-components' -import { Rule } from 'Types/rule' +import { EvaluatedRule } from 'Types/rule' import { capitalise0 } from '../utils' const BarStack = styled.div` @@ -80,7 +80,7 @@ export function roundedPercentages(values: Array) { } type StackedBarChartProps = { - data: Array<{ color?: string } & Rule> + data: Array<{ color?: string } & EvaluatedRule> } export default function StackedBarChart({ data }: StackedBarChartProps) { diff --git a/source/components/TargetSelection.tsx b/source/components/TargetSelection.tsx index ed7931aee..f23f5a09a 100644 --- a/source/components/TargetSelection.tsx +++ b/source/components/TargetSelection.tsx @@ -289,10 +289,10 @@ function AidesGlimpse() { // Dans le cas où il n'y a qu'une seule aide à l'embauche qui s'applique, nous // faisons un lien direct vers cette aide, plutôt qu'un lien vers la liste qui // est une somme des aides qui sont toutes nulle sauf l'aide active. - const aidesNode = aides.explanation - const aidesDetail = aides.explanation.formule.explanation.explanation - const aidesNotNul = aidesDetail.filter(node => node.nodeValue !== 0) - const aideLink = aidesNotNul.length === 1 ? aidesNotNul[0] : aidesNode + const aidesNode = aides?.explanation + const aidesDetail = aides?.explanation.formule.explanation.explanation + const aidesNotNul = aidesDetail?.filter(node => node.nodeValue !== 0) + const aideLink = aidesNotNul?.length === 1 ? aidesNotNul[0] : aidesNode if (!aides?.nodeValue) return null return ( diff --git a/source/components/Value.tsx b/source/components/Value.tsx index 6dd858c61..73ea25b36 100644 --- a/source/components/Value.tsx +++ b/source/components/Value.tsx @@ -2,7 +2,7 @@ import { T } from 'Components' import { formatValue, formatValueOptions } from 'Engine/format' import React from 'react' import { useTranslation } from 'react-i18next' -import { Rule } from 'Types/rule' +import { EvaluatedRule } from 'Types/rule' // let booleanTranslations = { true: '✅', false: '❌' } @@ -18,7 +18,7 @@ let style = customStyle => ` ` export type ValueProps = Partial< - Pick & + Pick & Pick< formatValueOptions, 'maximumFractionDigits' | 'minimumFractionDigits' diff --git a/source/engine/traverse.ts b/source/engine/traverse.ts index d0d7c3eac..8b9b3e290 100644 --- a/source/engine/traverse.ts +++ b/source/engine/traverse.ts @@ -1,7 +1,7 @@ import { evaluateControls } from 'Engine/controls' import parseRule from 'Engine/parseRule' import { chain, path } from 'ramda' -import { DottedName } from 'Types/rule' +import { DottedName, EvaluatedRule } from 'Types/rule' import { evaluateNode } from './evaluation' import { parseReference } from './parseReference' import { @@ -152,7 +152,7 @@ export let analyseMany = ( return parsedTarget }), targets = chain(pt => getTargets(pt, parsedRules), parsedTargets).map( - t => + (t): EvaluatedRule => cache[t.dottedName] || // This check exists because it is not done in parseRuleRoot's eval, while it is in parseVariable. This should be merged : we should probably call parseVariable here : targetNames could be expressions (hence with filters) TODO evaluateNode(cache, situationGate, parsedRules, t) ) diff --git a/source/reducers/rootReducer.ts b/source/reducers/rootReducer.ts index e0de4f39a..ad276a037 100644 --- a/source/reducers/rootReducer.ts +++ b/source/reducers/rootReducer.ts @@ -112,12 +112,25 @@ function conversationSteps( return state } -function updateSituation(situation, { fieldName, value, analysis }) { - const goals = analysis.targets - .map(target => target.explanation || target) - .filter(target => !!target.formule == !!target.question) - .map(({ dottedName }) => dottedName) - const removePreviousTarget = goals.includes(fieldName) +function updateSituation( + situation, + { + fieldName, + value, + analysis + }: { + fieldName: DottedName + value: any + analysis: Analysis | Array | null + } +) { + const goals = + analysis && + (Array.isArray(analysis) ? analysis[0] : analysis).targets + .map(target => target.explanation || target) + .filter(target => !!target.formule == !!target.question) + .map(({ dottedName }) => dottedName) + const removePreviousTarget = goals?.includes(fieldName) ? omit(goals) : identity return { ...removePreviousTarget(situation), [fieldName]: value } diff --git a/source/selectors/repartitionSelectors.ts b/source/selectors/repartitionSelectors.ts index bcb1744ec..21c3dac00 100644 --- a/source/selectors/repartitionSelectors.ts +++ b/source/selectors/repartitionSelectors.ts @@ -25,7 +25,7 @@ import { mergeCotisations } from './ficheDePaieSelectors' -export type Cotisation = Rule & { +export type Cotisation = Partial & { branche: Branch montant: MontantPartagé } diff --git a/source/types/rule.ts b/source/types/rule.ts index 4c7f4ebef..7d8aa2fbd 100644 --- a/source/types/rule.ts +++ b/source/types/rule.ts @@ -3,9 +3,22 @@ export type DottedName = keyof typeof jsonRules export type Rule = { dottedName: DottedName - nodeValue?: number question?: string + unité: string unit: string name?: string title?: string + defaultValue: any + icons: string + formule: any +} + +// This type should be defined inline by the function evaluating the rule (and +// probably infered as its return type). This is only a partial definition but +// it type-checks. +export type EvaluatedRule = Rule & { + nodeValue?: number + isApplicable: boolean + missingVariables: Array + explanation: EvaluatedRule }