diff --git a/source/components/TargetSelection.tsx b/source/components/TargetSelection.tsx index 1035b5da4..f47a8b611 100644 --- a/source/components/TargetSelection.tsx +++ b/source/components/TargetSelection.tsx @@ -180,13 +180,15 @@ const Target = ({ target, initialRender }) => { {isActiveInput && ( - { - dispatch(updateSituation(target.dottedName, value)) - }} - unit={target.defaultUnit} - /> +
+ { + dispatch(updateSituation(target.dottedName, value)) + }} + unit={target.defaultUnit} + /> +
)} diff --git a/source/components/conversation/Conversation.tsx b/source/components/conversation/Conversation.tsx index 91b4c59bb..17cf5f508 100644 --- a/source/components/conversation/Conversation.tsx +++ b/source/components/conversation/Conversation.tsx @@ -7,7 +7,11 @@ import emoji from 'react-easy-emoji' import { Trans } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' import { RootState } from 'Reducers/rootReducer' -import { currentQuestionSelector, flatRulesSelector, nextStepsSelector } from 'Selectors/analyseSelectors' +import { + currentQuestionSelector, + flatRulesSelector, + nextStepsSelector +} from 'Selectors/analyseSelectors' import * as Animate from 'Ui/animate' import Aide from './Aide' import './conversation.css' @@ -41,17 +45,15 @@ export default function Conversation({ customEndMessages }: ConversationProps) { } } const DecoratedInputComponent = FormDecorator(InputComponent) - return nextSteps.length ? ( + + return flatRules && nextSteps.length ? ( <>
{currentQuestion && ( - +
{previousAnswers.length > 0 && ( diff --git a/source/components/conversation/FormDecorator.tsx b/source/components/conversation/FormDecorator.tsx index 84b5523a1..73a0d434f 100644 --- a/source/components/conversation/FormDecorator.tsx +++ b/source/components/conversation/FormDecorator.tsx @@ -1,10 +1,13 @@ import { updateSituation } from 'Actions/actions' import Explicable from 'Components/conversation/Explicable' -import { serializeUnit } from 'Engine/units' +import { findRuleByDottedName } from 'Engine/rules' import React from 'react' import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' -import { situationSelector } from 'Selectors/analyseSelectors' +import { + flatRulesSelector, + situationSelector +} from 'Selectors/analyseSelectors' /* This higher order component wraps "Form" components (e.g. Question.js), that represent user inputs, @@ -15,43 +18,37 @@ to understand those precious higher order components. */ export default function FormDecorator(RenderField) { - return function FormStep({ - fieldName, - question, - inversion, - unit, - ...otherProps - }) { + return function FormStep({ dottedName }) { const dispatch = useDispatch() const situation = useSelector(situationSelector) + const flatRules = useSelector(flatRulesSelector) + const language = useTranslation().i18n.language const submit = source => dispatch({ type: 'STEP_ACTION', name: 'fold', - step: fieldName, + step: dottedName, source }) const setFormValue = value => { - dispatch(updateSituation(fieldName, value)) + dispatch(updateSituation(dottedName, value)) } return (
-
-

- {question} {!inversion && } -

-
+

+ {findRuleByDottedName(flatRules, dottedName).question}{' '} + +

diff --git a/source/components/conversation/Input.js b/source/components/conversation/Input.js index d09ae2418..f1bf48bc5 100644 --- a/source/components/conversation/Input.js +++ b/source/components/conversation/Input.js @@ -1,5 +1,6 @@ import { ThemeColorsContext } from 'Components/utils/colors' import { currencyFormat } from 'Engine/format' +import { serializeUnit } from 'Engine/units' import React, { useCallback, useContext } from 'react' import { useTranslation } from 'react-i18next' import NumberFormat from 'react-number-format' @@ -49,7 +50,7 @@ export default function Input({ autoComplete="off" /> {onSubmit && ( diff --git a/source/components/conversation/Question.css b/source/components/conversation/Question.css deleted file mode 100644 index e4fc34dcb..000000000 --- a/source/components/conversation/Question.css +++ /dev/null @@ -1,5 +0,0 @@ -.binaryQuestionList { - display: flex; - align-items: center; - justify-content: flex-end; -} diff --git a/source/components/conversation/Question.js b/source/components/conversation/Question.js index 3fd9a145f..1affaeeb4 100644 --- a/source/components/conversation/Question.js +++ b/source/components/conversation/Question.js @@ -1,10 +1,9 @@ import classnames from 'classnames' import { ThemeColorsContext } from 'Components/utils/colors' import { is } from 'ramda' -import React, { useCallback, useContext, useState } from 'react' +import React, { useCallback, useContext } from 'react' import { Trans } from 'react-i18next' import Explicable from './Explicable' -import './Question.css' import SendButton from './SendButton' /* Ceci est une saisie de type "radio" : l'utilisateur choisit une réponse dans une liste, ou une liste de listes. @@ -23,8 +22,6 @@ import SendButton from './SendButton' */ -// FormDecorator permet de factoriser du code partagé par les différents types de saisie, -// dont Question est un example export default function Question({ choices, onSubmit, @@ -33,34 +30,28 @@ export default function Question({ value: currentValue }) { const colors = useContext(ThemeColorsContext) - const [touched, setTouched] = useState(false) const handleChange = useCallback( value => { onChange(value) - setTouched(true) }, [onChange] ) const renderBinaryQuestion = () => { - return ( -
- {choices.map(({ value, label }) => ( - - ))} -
- ) + return choices.map(({ value, label }) => ( + + )) } const renderChildren = choices => { // seront stockées ainsi dans le state : @@ -122,7 +113,7 @@ export default function Question({ css="margin-top: 0.6rem; display: flex; align-items: center; flex-wrap: wrap;" > {choiceElements} - {onSubmit && } + {onSubmit && }
) } @@ -154,7 +145,9 @@ function RadioLabelContent({ key={value} style={labelStyle} css={css} - className={classnames('radio', 'userAnswerButton', { selected })} + className={classnames('radio', 'userAnswerButton', 'ui__', 'button', { + selected + })} > {label} getAction('accept')} diff --git a/source/components/conversation/conversation.css b/source/components/conversation/conversation.css index 13b171670..20b5c4374 100644 --- a/source/components/conversation/conversation.css +++ b/source/components/conversation/conversation.css @@ -1,86 +1,3 @@ -.scrollIndication { - margin: 0.6em 0; - font-size: 110%; -} - -.scrollIndication.down { - margin-bottom: 1em; -} - -#resultsScrollElement, -#myScrollToElement { - text-align: center; -} - -#foldedSteps { - padding: 1em 0; - margin-bottom: 1em; -} - -#foldedSteps .header button { - display: block; - margin: 0 auto 1em; -} -#foldedSteps button i { - margin-right: 0.3em; - font-size: 110%; - vertical-align: top; -} - -#foldedSteps button { - border: none; - font-weight: 500; -} - -#myScrollToElement { - padding-top: 0.3em; -} - -.step { - position: relative; -} - -.step { - opacity: 1; -} - -.step:first-child { - opacity: 1; -} - -.unfoldedHeader { - display: flex; - justify-content: space-between; - align-items: flex-start; -} - -.step.completed .edit:hover { - background: #333350; - color: white; -} - -/* Our little help icon */ -.help-button { - display: inline-block; - margin-top: 0.5em; - line-height: 1.1em; - border-radius: 1em; - font-size: 90%; - color: #777; - border: 1px solid; - background: none; - text-align: center; - cursor: pointer; - color: #aaa; - text-transform: uppercase; - font-size: 60%; - padding: 0.25em 0.6em; -} -.help-button:hover { - color: #333; - border: 1px solid #333; -} - .step fieldset { display: flex; justify-content: flex-end; @@ -92,8 +9,9 @@ list-style-type: none; } -.step fieldset > ul:not(.binaryQuestionList) { - width: 100%; +.step fieldset .step.question .variantLeaf, +.step fieldset .step.question { + justify-content: flex-end; } .step.question .variant { @@ -141,17 +59,6 @@ font-size: 120%; } -.resume { - transition: 1s display; -} - -.answer-ignored { - font-size: 80%; - opacity: 0.8; - margin-left: 0.4em; - vertical-align: middle; -} - .step.question input[type='radio'] { display: none; } @@ -203,175 +110,25 @@ outline: none; } -.help-box { - position: absolute; - width: 100%; - height: 100%; - z-index: 1; - text-align: center; -} - -.help-box p { - padding: 1em; - font-size: 90%; - font-style: italic; -} - -.close-help { - cursor: pointer; - position: absolute; - top: 0; - right: 0; - font-size: 105%; -} -.close-text { - text-transform: uppercase; - font-size: 60%; -} - -.close-text .icon { - font-size: 150%; - vertical-align: middle; -} - -.step .send { - padding: 0.1em 0.4em 0em 1em; - background: none; - cursor: pointer; - border: 1px solid; - border-radius: 0.4em; - line-height: 0em; -} - -.step .send:disabled { - opacity: 0.2; -} - -.step .send i { - margin: 0 0.3em; - font-size: 160%; -} - -.step .send .text { - text-transform: uppercase; - font-size: 135%; - line-height: 2em; -} - .answer { margin-top: 0.6rem; - display: flex; - flex-wrap: wrap; - align-items: center; -} - -.foldedQuestion .answer { - float: right; -} - -.step-input-error { - position: absolute; - right: 0; - bottom: -1.5em; - font-size: 0.8em; - font-style: italic; - color: #c0392b; - font-weight: 600; -} - -.step textarea { - vertical-align: middle; - margin-right: 1em; -} - -#share-link { - color: white; - padding: 0.3em 0.3em; - display: inline-block; - margin-top: 0.3em; - border-radius: 0.25em; -} -#share-icon { - font-size: 200%; - vertical-align: middle; - line-height: 0em; - margin-left: 0.3em; -} - -.info-zone { - font-size: 65%; - text-align: center; - font-style: italic; - color: #666; - line-height: 1.6em; -} - -.input-tip { - height: 2em; -} - -.input-tip p { - margin: 0.1em; -} - -#show-advanced { - font-weight: bold; -} - -/* Positioning the animated elements absolutely + transition-delay will make it possible -for the appearing element to appear without stacking up below the first one */ - -.input-tip { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; -} - -.foldedQuestion { - margin-left: 0em; -} - -.foldedQuestion .edit { - vertical-align: middle; - margin-left: 0.5em; - border: none; - padding-right: 0; -} - -.foldedQuestion .borderWrapper { - padding: 0.1em 0; - display: inline-block; - width: calc(100% - 8em); - border-bottom: 1px solid #eee; -} - -.foldedQuestion:last-of-type .borderWrapper { - border-bottom: none; -} - -.conversationContainer { - flex: 1; - padding-bottom: 1rem; - margin-bottom: 1rem; } .step label.userAnswerButton { - border: 1px solid var(--color); + border: 1px solid var(--color) !important; + text-transform: none !important; background-color: white; color: var(--textColorOnWhite); } .step label.userAnswerButton.selected { background: var(--color); border: 1px solid var(--color); - color: var(--textColor); } @media (hover) { - .step label.userAnswerButton:hover { + .step label.userAnswerButton:hover:not(.selected) { background: var(--color); border: 1px solid var(--color); color: var(--textColor); + transition: all 0.05s; } } diff --git a/source/components/conversation/select/SelectGéo.js b/source/components/conversation/select/SelectGéo.js index f46273fba..22ff2ce39 100644 --- a/source/components/conversation/select/SelectGéo.js +++ b/source/components/conversation/select/SelectGéo.js @@ -25,7 +25,7 @@ async function searchCommunes(input) { return json } -export default function Select({ setFormValue, submit }) { +export default function Select({ onChange, onSubmit }) { const [searchResults, setSearchResults] = useState() const [isLoading, setLoadingState] = useState(false) @@ -47,7 +47,7 @@ export default function Select({ setFormValue, submit }) { tauxVersementTransport(option.code) .then(({ taux }) => { // serialize to not mix our data schema and the API response's - setFormValue( + onChange( JSON.stringify({ ...option, ...(taux != undefined @@ -57,15 +57,15 @@ export default function Select({ setFormValue, submit }) { : {}) }) ) - submit() + onSubmit() }) .catch(error => { //eslint-disable-next-line no-console console.log( 'Erreur dans la récupération du taux de versement transport à partir du code commune', error - ) || setFormValue(JSON.stringify({ option })) - submit() // eslint-disable-line no-console + ) || onChange(JSON.stringify({ option })) + onSubmit() // eslint-disable-line no-console }) } diff --git a/source/components/conversation/select/SelectTauxRisque.js b/source/components/conversation/select/SelectTauxRisque.js index d4501848b..411bc6b33 100644 --- a/source/components/conversation/select/SelectTauxRisque.js +++ b/source/components/conversation/select/SelectTauxRisque.js @@ -3,12 +3,12 @@ import { Trans, useTranslation } from 'react-i18next' import Worker from 'worker-loader!./SelectTauxRisque.worker.js' const worker = new Worker() -function SelectComponent({ setFormValue, submit, options }) { +function SelectComponent({ onChange, onSubmit, options }) { const [searchResults, setSearchResults] = useState() let submitOnChange = option => { option.text = +option['Taux net'].replace(',', '.') - setFormValue(option.text) - submit() + onChange(option.text) + onSubmit() } const { t } = useTranslation() useEffect(() => { diff --git a/source/engine/InputComponent.js b/source/engine/InputComponent.js index aa8d2dd49..65f116cd2 100644 --- a/source/engine/InputComponent.js +++ b/source/engine/InputComponent.js @@ -14,8 +14,13 @@ export const binaryOptionChoices = [ // This function takes the unknown rule and finds which React component should be displayed to get a user input through successive if statements // That's not great, but we won't invest more time until we have more diverse input components and a better type system. -// eslint-disable-next-line react/display-name -export default ({ rules, dottedName, onChange, value }) => { +export default function InputComponent({ + rules, + dottedName, + onChange, + onSubmit, + value +}) { let rule = findRuleByDottedName(rules, dottedName) let commonProps = { @@ -23,6 +28,7 @@ export default ({ rules, dottedName, onChange, value }) => { fieldName: dottedName, value, onChange, + onSubmit, ...pick( ['dottedName', 'title', 'question', 'defaultValue', 'suggestions'], rule diff --git a/source/locales/en.yaml b/source/locales/en.yaml index a334ce04f..f663e43f2 100644 --- a/source/locales/en.yaml +++ b/source/locales/en.yaml @@ -678,6 +678,7 @@ path: sécuritéSociale: /social-security simulateurs: index: /simulators + dnrti: /dnrti assimilé-salarié: /assimile-salarie indépendant: /independant auto-entrepreneur: /auto-entrepreneur