From 71475830819d4d86f7cb535c05081ec7e7d9a50f Mon Sep 17 00:00:00 2001 From: Johan Girod Date: Wed, 5 May 2021 13:55:59 +0200 Subject: [PATCH] =?UTF-8?q?:gear::art:=20Ajoute=20la=20possibilit=C3=A9=20?= =?UTF-8?q?d'explorer=20les=20calculs=20dans=20un=20recalcul?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 1 + .vscode/settings.json | 5 +- modele-social/règles/dirigeant.yaml | 1 + mon-entreprise/source/components/ui/Card.css | 3 +- mon-entreprise/source/components/ui/index.css | 1 + publicodes/core/source/mecanisms/recalcul.ts | 6 +- publicodes/ui-react/source/RuleLink.tsx | 28 ++++-- publicodes/ui-react/source/contexts.tsx | 8 +- publicodes/ui-react/source/index.tsx | 86 ++++++++++++++----- .../ui-react/source/mecanisms/Recalcul.tsx | 28 +++++- publicodes/ui-react/source/rule/Header.tsx | 6 +- publicodes/ui-react/source/rule/RulePage.tsx | 35 +++++++- 12 files changed, 170 insertions(+), 38 deletions(-) diff --git a/.editorconfig b/.editorconfig index c6c8a0f85..3a04b5e17 100644 --- a/.editorconfig +++ b/.editorconfig @@ -28,3 +28,4 @@ trim_trailing_whitespace = false trim_trailing_whitespace = false indent_style = space indent_size = 4 + diff --git a/.vscode/settings.json b/.vscode/settings.json index 57144ed6b..b8b3839ef 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,8 @@ "cSpell.words": [ "mycompanyinfrance", "smarttag" - ] + ], + "search.exclude": { + "**/dist": true + } } diff --git a/modele-social/règles/dirigeant.yaml b/modele-social/règles/dirigeant.yaml index fd9acc9c2..70af4461e 100644 --- a/modele-social/règles/dirigeant.yaml +++ b/modele-social/règles/dirigeant.yaml @@ -942,6 +942,7 @@ dirigeant . indépendant . cotisations et contributions . début activité: règle: cotisations et contributions avec: assiette des cotisations: assiette forfaitaire + assiette des cotisations . sans plancher: assiette forfaitaire situation personnelle . RSA: non références: Fiche Urssaf: https://www.urssaf.fr/portail/home/independant/mes-cotisations/les-etapes-de-calcul/le-mode-de-calcul/lajustement-et-la-regularisation.html diff --git a/mon-entreprise/source/components/ui/Card.css b/mon-entreprise/source/components/ui/Card.css index ce8744da5..118fdfb24 100644 --- a/mon-entreprise/source/components/ui/Card.css +++ b/mon-entreprise/source/components/ui/Card.css @@ -68,7 +68,8 @@ } .ui__.card.plain small, .ui__.card.plain .notice { - color: rgba(255, 255, 255, 0.8); + opacity: 0.9; + color: white; } .ui__.card.plain .targetInput { diff --git a/mon-entreprise/source/components/ui/index.css b/mon-entreprise/source/components/ui/index.css index b44805e3a..80522ee74 100644 --- a/mon-entreprise/source/components/ui/index.css +++ b/mon-entreprise/source/components/ui/index.css @@ -96,6 +96,7 @@ span.ui__.enumeration:not(:last-of-type)::after { font-size: 85%; line-height: initial; padding: 0.4rem 0.6rem; + white-space: nowrap; font-weight: bold; color: white !important; background: var(--darkColor); diff --git a/publicodes/core/source/mecanisms/recalcul.ts b/publicodes/core/source/mecanisms/recalcul.ts index f24f2aec8..084f35f82 100644 --- a/publicodes/core/source/mecanisms/recalcul.ts +++ b/publicodes/core/source/mecanisms/recalcul.ts @@ -1,4 +1,4 @@ -import { EvaluationFunction } from '..' +import Engine, { EvaluationFunction } from '..' import { ASTNode, EvaluatedNode } from '../AST/types' import { defaultNode } from '../evaluation' import { registerEvaluationFunction } from '../evaluationFunctions' @@ -11,6 +11,7 @@ export type RecalculNode = { explanation: { recalcul: ASTNode amendedSituation: Array<[ReferenceNode, ASTNode]> + parsedSituation?: Engine['parsedSituation'] } nodeKind: 'recalcul' } @@ -46,6 +47,7 @@ const evaluateRecalcul: EvaluationFunction<'recalcul'> = function (node) { ), }) : this + engine.cache._meta.inRecalcul = true const evaluatedNode = engine.evaluate(node.explanation.recalcul) engine.cache._meta.inRecalcul = false @@ -55,7 +57,9 @@ const evaluateRecalcul: EvaluationFunction<'recalcul'> = function (node) { nodeValue: evaluatedNode.nodeValue, explanation: { recalcul: evaluatedNode, + engine, amendedSituation, + parsedSituation: engine.parsedSituation, }, missingVariables: evaluatedNode.missingVariables, ...('unit' in evaluatedNode && { unit: evaluatedNode.unit }), diff --git a/publicodes/ui-react/source/RuleLink.tsx b/publicodes/ui-react/source/RuleLink.tsx index 18638c9e9..3e68a3f6b 100644 --- a/publicodes/ui-react/source/RuleLink.tsx +++ b/publicodes/ui-react/source/RuleLink.tsx @@ -1,8 +1,12 @@ +import Engine, { utils } from 'publicodes' import React, { useContext } from 'react' import emoji from 'react-easy-emoji' -import { Link } from 'react-router-dom' -import Engine, { utils } from 'publicodes' -import { BasepathContext, EngineContext } from './contexts' +import { Link, useLocation } from 'react-router-dom' +import { + BasepathContext, + EngineContext, + SituationMetaContext, +} from './contexts' const { encodeRuleName } = utils @@ -14,6 +18,7 @@ type RuleLinkProps = Omit< engine: Engine documentationPath: string displayIcon?: boolean + situationName?: string children?: React.ReactNode } @@ -21,6 +26,7 @@ export function RuleLink({ dottedName, engine, documentationPath, + situationName, displayIcon = false, children, ...props @@ -46,7 +52,16 @@ export function RuleLink({ throw new Error(`Unknown rule: ${dottedName}`) } return ( - + {children || rule.title}{' '} {displayIcon && rule.rawNode.icônes && ( {emoji(rule.rawNode.icônes)} @@ -63,11 +78,14 @@ export function RuleLinkWithContext( throw new Error('an engine should be provided in context') } const documentationPath = useContext(BasepathContext) - + const { state } = useLocation<{ situationName?: string } | undefined>() + const situationName = + useContext(SituationMetaContext)?.name ?? state?.situationName return ( ) diff --git a/publicodes/ui-react/source/contexts.tsx b/publicodes/ui-react/source/contexts.tsx index e81906340..8adc7bf03 100644 --- a/publicodes/ui-react/source/contexts.tsx +++ b/publicodes/ui-react/source/contexts.tsx @@ -1,6 +1,12 @@ -import { createContext } from 'react' import Engine from 'publicodes' +import { createContext } from 'react' export const BasepathContext = createContext('/documentation') +export const SituationMetaContext = createContext<{ name: string } | undefined>( + undefined +) export const EngineContext = createContext | null>(null) +export const RegisterEngineContext = createContext<(engine: Engine) => void>( + () => {} +) export const ReferencesImagesContext = createContext>({}) diff --git a/publicodes/ui-react/source/index.tsx b/publicodes/ui-react/source/index.tsx index 112f71884..4a79e5a5a 100644 --- a/publicodes/ui-react/source/index.tsx +++ b/publicodes/ui-react/source/index.tsx @@ -1,14 +1,15 @@ import Engine, { utils } from 'publicodes' -import { Route } from 'react-router-dom' +import { useCallback, useRef } from 'react' +import { Route, useLocation } from 'react-router-dom' import { BasepathContext, EngineContext, ReferencesImagesContext, + RegisterEngineContext, } from './contexts' import References from './rule/References' import RulePage from './rule/RulePage' const { decodeRuleName, encodeRuleName } = utils - export { default as Explanation } from './Explanation' export { RuleLink } from './RuleLink' export { References } @@ -20,30 +21,73 @@ type DocumentationProps = { referenceImages?: Record } +function useCacheEngineBySituation( + defaultEngine: Engine, + currentSituation?: Engine['parsedSituation'] +) { + const registeredEngines = useRef( + new WeakMap().set( + defaultEngine.parsedSituation, + defaultEngine.shallowCopy() + ) + ) + const registerEngine = useCallback( + (engine: Engine) => + registeredEngines.current.set( + engine.parsedSituation, + engine.shallowCopy() + ), + [registeredEngines] + ) + if (currentSituation && !registeredEngines.current.has(currentSituation)) { + registeredEngines.current.set( + currentSituation, + defaultEngine.shallowCopy().setSituation(currentSituation) + ) + } + const engine = currentSituation + ? registeredEngines.current.get(currentSituation) + : defaultEngine + return [engine, registerEngine] +} + export function Documentation({ documentationPath, - engine, + engine: defaultEngine, referenceImages = {}, }: DocumentationProps) { + const { state } = useLocation< + | { + situation?: Engine['parsedSituation'] + situationName?: string + } + | undefined + >() + const [engine, cacheEngine] = useCacheEngineBySituation( + defaultEngine, + state?.situation + ) return ( - - - - { - return ( - - ) - }} - /> - - - + + + + + { + return ( + + ) + }} + /> + + + + ) } diff --git a/publicodes/ui-react/source/mecanisms/Recalcul.tsx b/publicodes/ui-react/source/mecanisms/Recalcul.tsx index c96381df6..0da51ba1f 100644 --- a/publicodes/ui-react/source/mecanisms/Recalcul.tsx +++ b/publicodes/ui-react/source/mecanisms/Recalcul.tsx @@ -1,16 +1,36 @@ +import { useContext } from 'react' +import { + EngineContext, + RegisterEngineContext, + SituationMetaContext, +} from '../contexts' import Explanation from '../Explanation' import { RuleLinkWithContext } from '../RuleLink' import { Mecanism } from './common' export default function Recalcul({ nodeValue, explanation, unit }) { + const engine = useContext(EngineContext) + if (!engine) { + throw new Error() + } + useContext(RegisterEngineContext)( + engine.shallowCopy().setSituation(explanation.parsedSituation) + ) return ( <> {explanation.recalcul && ( - <> - Recalcul de la valeur de {' '} - avec la situation suivante : - + + + Recalcul de la valeur de{' '} + avec la situation + suivante : + + )}
    {explanation.amendedSituation.map(([origin, replacement]) => ( diff --git a/publicodes/ui-react/source/rule/Header.tsx b/publicodes/ui-react/source/rule/Header.tsx index 55c352a95..5fceeeb1d 100644 --- a/publicodes/ui-react/source/rule/Header.tsx +++ b/publicodes/ui-react/source/rule/Header.tsx @@ -1,9 +1,9 @@ -import React, { useContext } from 'react' import { utils } from 'publicodes' -import { RuleLinkWithContext } from '../RuleLink' +import React, { useContext } from 'react' import styled from 'styled-components' -import Meta from './Meta' import { EngineContext } from '../contexts' +import { RuleLinkWithContext } from '../RuleLink' +import Meta from './Meta' export default function RuleHeader({ dottedName }) { const engine = useContext(EngineContext) diff --git a/publicodes/ui-react/source/rule/RulePage.tsx b/publicodes/ui-react/source/rule/RulePage.tsx index f11e561a8..4a887cc06 100644 --- a/publicodes/ui-react/source/rule/RulePage.tsx +++ b/publicodes/ui-react/source/rule/RulePage.tsx @@ -5,6 +5,9 @@ import Engine, { utils, } from 'publicodes' import { isEmpty } from 'ramda' +import { useContext } from 'react' +import { Link, useLocation } from 'react-router-dom' +import { EngineContext } from '../contexts' import Explanation from '../Explanation' import { Markdown } from '../Markdown' import { RuleLinkWithContext } from '../RuleLink' @@ -12,7 +15,13 @@ import RuleHeader from './Header' import References from './References' import RuleSource from './RuleSource' -export default function Rule({ dottedName, engine, language }) { +export default function Rule({ dottedName, language, situationName }) { + const engine = useContext(EngineContext) + const { pathname } = useLocation() + + if (!engine) { + throw new Error('Engine expected') + } if (!(dottedName in engine.getParsedRules())) { return

    Cette règle est introuvable dans la base

    } @@ -21,7 +30,30 @@ export default function Rule({ dottedName, engine, language }) { const { parent, valeur } = rule.explanation return (
    + {situationName && ( +
    +
    + Vous explorez la documentation avec le contexte{' '} + {situationName}{' '} +
    +
    +
    + Retourner à la version de base +
    +
    + )} +
    @@ -56,6 +88,7 @@ export default function Rule({ dottedName, engine, language }) { )}

    Comment cette donnée est-elle calculée ?

    +