+
+
+ {small &&
}
-
dispatch(updateSituation(dottedName, x))}
- useSwitch
- />
+ {editable ? (
+ <>
+ setFocused(true)}
+ onBlur={() => setFocused(false)}
+ onChange={(x) => dispatch(updateSituation(dottedName, x))}
+ useSwitch
+ />
+ >
+ ) : (
+ <>
+
+
+ {formatValue(evaluation, { displayedUnit: '€' })}
+
+ >
+ )}
diff --git a/mon-entreprise/source/components/TargetSelection.css b/mon-entreprise/source/components/TargetSelection.css
index a5227df4a..d892c9bba 100644
--- a/mon-entreprise/source/components/TargetSelection.css
+++ b/mon-entreprise/source/components/TargetSelection.css
@@ -24,29 +24,42 @@
#targetSelection .targets > li.small-target {
border-top: none;
+ padding: 0.4rem 1rem;
}
-#targetSelection .targets > li.small-target .targetInput {
+
+#targetSelection .targets > li.small-target .targetInput,
+#targetSelection .targets > li.small-target .editableTarget {
border-width: 1px;
+ border-radius: 0.2rem;
padding-top: 0;
padding-bottom: 0;
}
#targetSelection .targets > li {
- border-top: 1px solid rgba(255, 255, 255, 0.5);
+ border-top: 1px dashed rgba(255, 255, 255, 0.6);
padding: 0.8rem 1rem;
margin-left: -1rem;
margin-right: -1rem;
}
-
-.light #targetSelection .targets > li:not(:first-child) {
+.light #targetSelection .targets > li {
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
+.light #targetSelection .targets > li.small-target,
+.light #targetSelection .targets > li:not(.small-target):first-of-type {
+ border-top: none;
+}
#targetSelection .targets > li .main {
display: flex;
+ flex-wrap: wrap;
align-items: center;
justify-content: space-between;
}
+#targetSelection .targets > li .guide-lecture {
+ flex: 1;
+ border-bottom: 1px dashed rgba(255, 255, 255, 0.25);
+ margin-left: 1rem;
+}
#targetSelection li .header {
display: flex;
@@ -94,7 +107,7 @@
#targetSelection .targetInputOrValue {
font-size: 115%;
- margin-left: 0.6rem;
+ min-width: 5.5rem;
text-align: right;
display: flex;
flex-direction: column;
@@ -110,26 +123,26 @@
text-decoration: none;
}
-#targetSelection .targetInputOrValue > :not(.targetInput) {
- margin: 0 0.6rem;
-}
-
#targetSelection input {
margin: 2.7px 0;
}
#targetSelection .targetInput {
width: 5.5em;
+ margin-left: 1rem;
max-width: 7.5em;
text-align: right;
background: rgba(255, 255, 255, 0.2);
- padding: 0;
padding: 0.2rem 0.6rem;
border-radius: 0.3rem;
- border: 2px solid;
+ border: 1px solid;
font-size: inherit;
}
+#targetSelection .targetInput.focused {
+ box-shadow: 0 0 0px 1px white;
+}
+
.light #targetSelection .targetInput {
color: var(--darkColor);
border-color: var(--darkColor);
@@ -142,23 +155,19 @@
#targetSelection .editableTarget {
max-width: 7.5em;
+ width: 5.5em;
+
display: inline-block;
text-align: right;
- padding: 0 2px;
+ padding: 0.2rem 0.6rem;
+
+ background: transparent;
+ border: 1px dashed rgba(255, 255, 255, 0.5);
+ border-radius: 0.3rem;
+
font-size: inherit;
}
-#targetSelection .targetInputBottomBorder {
- margin: 0;
- padding: 0 2px;
- height: 0;
- overflow: hidden;
-}
-
-#targetSelection .editableTarget + .targetInputBottomBorder {
- border-bottom: 1px dashed #ffffff91;
-}
-
#targetSelection .unit {
margin-left: 0.4em;
font-size: 110%;
diff --git a/mon-entreprise/source/components/TargetSelection.tsx b/mon-entreprise/source/components/TargetSelection.tsx
index 6e0382672..c2854ebda 100644
--- a/mon-entreprise/source/components/TargetSelection.tsx
+++ b/mon-entreprise/source/components/TargetSelection.tsx
@@ -1,5 +1,5 @@
-import { setActiveTarget, updateSituation } from 'Actions/actions'
-import InputSuggestions from 'Components/conversation/InputSuggestions'
+import { updateSituation } from 'Actions/actions'
+import classnames from 'classnames'
import Value, { Condition } from 'Components/EngineValue'
import PeriodSwitch from 'Components/PeriodSwitch'
import RuleLink from 'Components/RuleLink'
@@ -21,18 +21,17 @@ import {
reduceAST,
RuleNode,
} from 'publicodes'
-import { isNil } from 'ramda'
-import { Fragment, useCallback, useContext, useEffect, useState } from 'react'
+import { Fragment, useCallback, useContext, useState } from 'react'
import emoji from 'react-easy-emoji'
import { Trans, useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import { useLocation } from 'react-router-dom'
import { RootState } from 'Reducers/rootReducer'
import {
- firstStepCompletedSelector,
situationSelector,
targetUnitSelector,
} from 'Selectors/simulationSelectors'
+import InputSuggestions from './conversation/InputSuggestions'
import CurrencyInput from './CurrencyInput/CurrencyInput'
import './TargetSelection.css'
@@ -102,19 +101,7 @@ const Target = ({ dottedName }: TargetProps) => {
unité: useSelector(targetUnitSelector),
arrondi: 'oui',
})
- const situation = useSelector(situationSelector)
-
const target: TargetType = { ...evaluation, ...rule.rawNode, ...rule }
- const dispatch = useDispatch()
- const onSuggestionClick = useCallback(
- (value) => {
- dispatch(updateSituation(dottedName, value))
- },
- [target.dottedName, dispatch]
- )
- const isActive =
- dottedName in situation || Object.keys(situation).length === 0
-
const isSmallTarget =
!rule.rawNode.question ||
(dottedName in evaluation.missingVariables &&
@@ -134,34 +121,14 @@ const Target = ({ dottedName }: TargetProps) => {
- {isSmallTarget && (
-
- )}
-
+ {isSmallTarget && }
- {isActive && (
-
-
-
-
-
- )}
@@ -193,30 +160,35 @@ const Header = ({ target }: { target: TargetType }) => {
type TargetInputOrValueProps = {
target: TargetType
- isActive: boolean
isSmallTarget: boolean
}
function TargetInputOrValue({
target,
- isActive,
isSmallTarget,
}: TargetInputOrValueProps) {
const { language } = useTranslation().i18n
const colors = useContext(ThemeColorsContext)
const dispatch = useDispatch()
- const [isActiveOrFocused, setActive] = useState(isActive)
- useEffect(() => setActive(isActive), [isActive])
+ const [isFocused, setFocused] = useState(false)
const targetUnit = useSelector(targetUnitSelector)
const engine = useContext(EngineContext)
+ const situation = useSelector(situationSelector)
const value =
(engine.evaluate({
valeur: target.dottedName,
unité: targetUnit,
arrondi: 'oui',
}).nodeValue as number) ?? undefined
- const blurValue = useInversionFail() && !isActiveOrFocused
-
+ const blurValue = useInversionFail() && !isFocused
+ const onSuggestionClick = useCallback(
+ (value) => {
+ dispatch(updateSituation(target.dottedName, value))
+ },
+ [target.dottedName, dispatch]
+ )
+ const isSituationEmpty = Object.keys(situation).length === 0
+ const isActive = target.dottedName in situation
const onChange = useCallback(
(evt) =>
dispatch(
@@ -228,54 +200,68 @@ function TargetInputOrValue({
[targetUnit, target, dispatch]
)
return (
-
- {target.question ? (
- <>
- {!isActiveOrFocused && }
- {
- setActive(true)
- }}
- language={language}
- />
-
- {formatValue(value, { language, displayedUnit: '€' })}
+ <>
+
+ {target.question ? (
+ <>
+ {!isFocused && }
+ {
+ setFocused(true)
+ }}
+ onBlur={() => setTimeout(() => setFocused(false), 100)}
+ language={language}
+ />
+ >
+ ) : (
+
+ {value && Number.isNaN(value) ? (
+ '—'
+ ) : (
+
+ {formatValue(value, { displayedUnit: '€', language })}
+
+ )}
- >
- ) : (
-
- {value && Number.isNaN(value) ? (
- '—'
- ) : (
-
- {formatValue(value, { displayedUnit: '€', language })}
-
- )}
-
+ )}
+ {target.dottedName.includes('prix du travail') && }
+ {target.dottedName === 'contrat salarié . rémunération . net' && (
+
+ )}
+
+ {(isActive || isFocused) && (
+
)}
- {target.dottedName.includes('prix du travail') && }
- {target.dottedName === 'contrat salarié . rémunération . net' && (
-
- )}
-
+ >
)
}
function TitreRestaurant() {
diff --git a/mon-entreprise/source/components/conversation/Conversation.tsx b/mon-entreprise/source/components/conversation/Conversation.tsx
index f053d08a8..c4845f38a 100644
--- a/mon-entreprise/source/components/conversation/Conversation.tsx
+++ b/mon-entreprise/source/components/conversation/Conversation.tsx
@@ -1,5 +1,5 @@
-import { stepAction, goToQuestion, updateSituation } from 'Actions/actions'
-import RuleInput, { RuleInputProps } from 'Components/conversation/RuleInput'
+import { goToQuestion, stepAction, updateSituation } from 'Actions/actions'
+import RuleInput, { InputProps } from 'Components/conversation/RuleInput'
import QuickLinks from 'Components/QuickLinks'
import * as Animate from 'Components/ui/animate'
import { EngineContext } from 'Components/utils/EngineContext'
@@ -41,7 +41,7 @@ export default function Conversation({ customEndMessages }: ConversationProps) {
dispatch(stepAction(currentQuestion, source))
}
- const onChange: RuleInputProps['onChange'] = (value) => {
+ const onChange: InputProps['onChange'] = (value) => {
dispatch(updateSituation(currentQuestion, value))
}
diff --git a/mon-entreprise/source/components/conversation/DateInput.tsx b/mon-entreprise/source/components/conversation/DateInput.tsx
index 4c9bd3ee9..99ad934dd 100644
--- a/mon-entreprise/source/components/conversation/DateInput.tsx
+++ b/mon-entreprise/source/components/conversation/DateInput.tsx
@@ -1,21 +1,8 @@
-import {
- InputCommonProps,
- RuleInputProps,
-} from 'Components/conversation/RuleInput'
-import { RuleNode } from 'publicodes'
+import { InputProps } from 'Components/conversation/RuleInput'
import { useCallback, useMemo } from 'react'
import styled from 'styled-components'
import InputSuggestions from './InputSuggestions'
-type DateInputProps = {
- onChange: InputCommonProps['onChange']
- id: InputCommonProps['id']
- onSubmit: RuleInputProps['onSubmit']
- value: InputCommonProps['value']
- suggestions: RuleNode['suggestions']
- required: RuleInputProps['required']
-}
-
export default function DateInput({
suggestions,
onChange,
@@ -23,7 +10,7 @@ export default function DateInput({
onSubmit,
required,
value,
-}: DateInputProps) {
+}: InputProps) {
const dateValue = useMemo(() => {
if (!value || typeof value !== 'string') return undefined
const [day, month, year] = value.split('/')
diff --git a/mon-entreprise/source/components/conversation/RuleInput.tsx b/mon-entreprise/source/components/conversation/RuleInput.tsx
index a9032e76b..c59d6ec7f 100644
--- a/mon-entreprise/source/components/conversation/RuleInput.tsx
+++ b/mon-entreprise/source/components/conversation/RuleInput.tsx
@@ -8,7 +8,7 @@ import ToggleSwitch from 'Components/ui/ToggleSwitch'
import { EngineContext } from 'Components/utils/EngineContext'
import { DottedName } from 'modele-social'
import Engine, { ASTNode, formatValue, reduceAST } from 'publicodes'
-import { Evaluation } from 'publicodes/dist/types/AST/types'
+import { EvaluatedNode, Evaluation } from 'publicodes/dist/types/AST/types'
import { RuleNode } from 'publicodes/dist/types/rule'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
@@ -17,30 +17,23 @@ import ParagrapheInput from './ParagrapheInput'
import SelectEuropeCountry from './select/SelectEuropeCountry'
import TextInput from './TextInput'
-type Value = any
-export type RuleInputProps = {
+export type Props = Omit<
+ React.HTMLAttributes,
+ 'onChange' | 'defaultValue'
+> & {
+ required?: boolean
dottedName: Name
- onChange: (value: Value | null) => void
+ onChange: (value: Parameters['evaluate']>[0]) => void
useSwitch?: boolean
isTarget?: boolean
- autoFocus?: boolean
- required?: boolean
- id?: string
- className?: string
onSubmit?: (source: string) => void
}
-export type InputCommonProps = Pick<
- RuleInputProps,
- 'onChange' | 'autoFocus' | 'className'
-> &
+export type InputProps = Props &
Pick & {
question: RuleNode['rawNode']['question']
- key: string
- id: string
- value: any //TODO EvaluatedRule['nodeValue']
+ value: EvaluatedNode['nodeValue']
missing: boolean
- required: boolean
}
export const binaryQuestion = [
@@ -56,30 +49,25 @@ export default function RuleInput({
dottedName,
onChange,
useSwitch = false,
- id,
isTarget = false,
- autoFocus = false,
- required = true,
- className,
onSubmit = () => null,
-}: RuleInputProps) {
+ ...props
+}: Props) {
const engine = useContext(EngineContext)
const rule = engine.getRule(dottedName)
const evaluation = engine.evaluate(dottedName)
const language = useTranslation().i18n.language
const value = evaluation.nodeValue
- const commonProps: InputCommonProps = {
- key: dottedName,
+ const commonProps: InputProps = {
+ dottedName,
value,
missing: !!evaluation.missingVariables[dottedName],
onChange,
- autoFocus,
- className,
- required,
title: rule.title,
- id: id ?? dottedName,
+ id: props.id ?? dottedName,
question: rule.rawNode.question,
suggestions: rule.suggestions,
+ ...props,
}
if (getVariant(engine.getRule(dottedName))) {
return (
@@ -149,12 +137,12 @@ export default function RuleInput({
return (
<>
onChange({ valeur: evt.target.value, unité })}
/>
>
diff --git a/mon-entreprise/source/pages/Simulateurs/AutoEntrepreneur.tsx b/mon-entreprise/source/pages/Simulateurs/AutoEntrepreneur.tsx
index 90c6b6c0c..5b6b5127d 100644
--- a/mon-entreprise/source/pages/Simulateurs/AutoEntrepreneur.tsx
+++ b/mon-entreprise/source/pages/Simulateurs/AutoEntrepreneur.tsx
@@ -1,6 +1,7 @@
import { updateSituation } from 'Actions/actions'
+import Conversation from 'Components/conversation/Conversation'
import { Condition } from 'Components/EngineValue'
-import RuleLink from 'Components/RuleLink'
+import SearchButton from 'Components/SearchButton'
import SimulateurWarning from 'Components/SimulateurWarning'
import { SimulationGoal, SimulationGoals } from 'Components/SimulationGoals'
import StackedBarChart from 'Components/StackedBarChart'
@@ -12,41 +13,47 @@ import { useDispatch } from 'react-redux'
import AidesCovid from '../../components/simulationExplanation/AidesCovid'
export default function AutoEntrepreneur() {
- const dispatch = useDispatch()
-
return (
<>
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
>
)
@@ -67,22 +75,37 @@ function ActivitéMixte() {
const defaultCheked = !!useEngine().evaluate('entreprise . activité . mixte')
.nodeValue
const dispatch = useDispatch()
+
return (
-
+
)
}
diff --git a/mon-entreprise/source/pages/Simulateurs/configs/auto-entrepreneur.yaml b/mon-entreprise/source/pages/Simulateurs/configs/auto-entrepreneur.yaml
index b8479c7c9..8e207eb6a 100644
--- a/mon-entreprise/source/pages/Simulateurs/configs/auto-entrepreneur.yaml
+++ b/mon-entreprise/source/pages/Simulateurs/configs/auto-entrepreneur.yaml
@@ -1,4 +1,7 @@
objectifs:
+ - dirigeant . auto-entrepreneur . chiffre d'affaires
+ - dirigeant . auto-entrepreneur . net de cotisations
+ - dirigeant . auto-entrepreneur . net après impôt
- dirigeant . auto-entrepreneur . cotisations et contributions
- dirigeant . auto-entrepreneur . net après impôt . impôt
@@ -23,5 +26,5 @@ questions:
- entreprise . chiffre d'affaires . prestations de service . BNC
unité par défaut: €/an
situation:
- entreprise . activité . mixte: oui
+ entreprise . activité . mixte: non
dirigeant: "'auto-entrepreneur'"
diff --git a/publicodes/core/source/parse.ts b/publicodes/core/source/parse.ts
index 168431932..04cabbb0d 100644
--- a/publicodes/core/source/parse.ts
+++ b/publicodes/core/source/parse.ts
@@ -150,11 +150,11 @@ ${e.message}`
const chainableMecanisms = [
applicable,
nonApplicable,
- parDéfaut,
arrondi,
unité,
plancher,
plafond,
+ parDéfaut,
situation,
abattement,
]