⚙️🎨 Ajoute la possibilité d'explorer les calculs dans un recalcul
parent
f9fb6fc4b6
commit
7147583081
|
@ -28,3 +28,4 @@ trim_trailing_whitespace = false
|
|||
trim_trailing_whitespace = false
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
|
|
|
@ -8,5 +8,8 @@
|
|||
"cSpell.words": [
|
||||
"mycompanyinfrance",
|
||||
"smarttag"
|
||||
]
|
||||
],
|
||||
"search.exclude": {
|
||||
"**/dist": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 }),
|
||||
|
|
|
@ -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<Name extends string> = Omit<
|
|||
engine: Engine<Name>
|
||||
documentationPath: string
|
||||
displayIcon?: boolean
|
||||
situationName?: string
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
|
@ -21,6 +26,7 @@ export function RuleLink<Name extends string>({
|
|||
dottedName,
|
||||
engine,
|
||||
documentationPath,
|
||||
situationName,
|
||||
displayIcon = false,
|
||||
children,
|
||||
...props
|
||||
|
@ -46,7 +52,16 @@ export function RuleLink<Name extends string>({
|
|||
throw new Error(`Unknown rule: ${dottedName}`)
|
||||
}
|
||||
return (
|
||||
<Link to={newPath} {...props}>
|
||||
<Link
|
||||
to={{
|
||||
pathname: newPath,
|
||||
state: {
|
||||
situation: engine.parsedSituation,
|
||||
situationName,
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
{children || rule.title}{' '}
|
||||
{displayIcon && rule.rawNode.icônes && (
|
||||
<span>{emoji(rule.rawNode.icônes)} </span>
|
||||
|
@ -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 (
|
||||
<RuleLink
|
||||
engine={engine}
|
||||
documentationPath={documentationPath}
|
||||
situationName={situationName}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { createContext } from 'react'
|
||||
import Engine from 'publicodes'
|
||||
import { createContext } from 'react'
|
||||
|
||||
export const BasepathContext = createContext<string>('/documentation')
|
||||
export const SituationMetaContext = createContext<{ name: string } | undefined>(
|
||||
undefined
|
||||
)
|
||||
export const EngineContext = createContext<Engine<string> | null>(null)
|
||||
export const RegisterEngineContext = createContext<(engine: Engine) => void>(
|
||||
() => {}
|
||||
)
|
||||
export const ReferencesImagesContext = createContext<Record<string, string>>({})
|
||||
|
|
|
@ -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<string, string>
|
||||
}
|
||||
|
||||
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 (
|
||||
<EngineContext.Provider value={engine}>
|
||||
<BasepathContext.Provider value={documentationPath}>
|
||||
<ReferencesImagesContext.Provider value={referenceImages}>
|
||||
<Route
|
||||
path={documentationPath + '/:name+'}
|
||||
render={({ match }) => {
|
||||
return (
|
||||
<RulePage
|
||||
dottedName={decodeRuleName(match.params.name)}
|
||||
engine={engine}
|
||||
language={'fr'}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ReferencesImagesContext.Provider>
|
||||
</BasepathContext.Provider>
|
||||
</EngineContext.Provider>
|
||||
<RegisterEngineContext.Provider value={cacheEngine}>
|
||||
<EngineContext.Provider value={engine}>
|
||||
<BasepathContext.Provider value={documentationPath}>
|
||||
<ReferencesImagesContext.Provider value={referenceImages}>
|
||||
<Route
|
||||
path={documentationPath + '/:name+'}
|
||||
render={({ match }) => {
|
||||
return (
|
||||
<RulePage
|
||||
situationName={state?.situationName}
|
||||
dottedName={decodeRuleName(match.params.name)}
|
||||
language={'fr'}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ReferencesImagesContext.Provider>
|
||||
</BasepathContext.Provider>
|
||||
</EngineContext.Provider>
|
||||
</RegisterEngineContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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 (
|
||||
<Mecanism name="recalcul" value={nodeValue} unit={unit}>
|
||||
<>
|
||||
{explanation.recalcul && (
|
||||
<>
|
||||
Recalcul de la valeur de <Explanation node={explanation.recalcul} />{' '}
|
||||
avec la situation suivante :
|
||||
</>
|
||||
<EngineContext.Provider value={explanation.engine}>
|
||||
<SituationMetaContext.Provider
|
||||
value={{
|
||||
name: 'Mécanisme recalcul',
|
||||
}}
|
||||
>
|
||||
Recalcul de la valeur de{' '}
|
||||
<Explanation node={explanation.recalcul} /> avec la situation
|
||||
suivante :
|
||||
</SituationMetaContext.Provider>
|
||||
</EngineContext.Provider>
|
||||
)}
|
||||
<ul>
|
||||
{explanation.amendedSituation.map(([origin, replacement]) => (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 <p>Cette règle est introuvable dans la base</p>
|
||||
}
|
||||
|
@ -21,7 +30,30 @@ export default function Rule({ dottedName, engine, language }) {
|
|||
const { parent, valeur } = rule.explanation
|
||||
return (
|
||||
<div id="documentationRuleRoot">
|
||||
{situationName && (
|
||||
<div
|
||||
className="ui__ card notice light-bg"
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
flexWrap: 'wrap',
|
||||
margin: '1rem 0',
|
||||
paddingTop: '0.4rem',
|
||||
paddingBottom: '0.4rem',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
Vous explorez la documentation avec le contexte{' '}
|
||||
<strong className="ui__ label">{situationName}</strong>{' '}
|
||||
</div>
|
||||
<div style={{ flex: 1 }} />
|
||||
<div>
|
||||
<Link to={pathname}>Retourner à la version de base</Link>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<RuleHeader dottedName={dottedName} />
|
||||
|
||||
<section>
|
||||
<Markdown source={description || question} />
|
||||
</section>
|
||||
|
@ -56,6 +88,7 @@ export default function Rule({ dottedName, engine, language }) {
|
|||
)}
|
||||
|
||||
<h2>Comment cette donnée est-elle calculée ?</h2>
|
||||
|
||||
<Explanation node={valeur} />
|
||||
<RuleSource key={dottedName} dottedName={dottedName} engine={engine} />
|
||||
|
||||
|
|
Loading…
Reference in New Issue