From fd21cfe390e8d8f68006d52495384944fcdc20ef Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Thu, 12 Sep 2019 18:17:59 +0200 Subject: [PATCH] WIP --- source/components/PeriodSwitch.js | 127 +++--------------- source/components/SalaryExplanation.js | 31 ++--- .../components/conversation/FormDecorator.js | 11 +- source/components/conversation/Input.js | 31 ++--- .../conversation/InputSuggestions.js | 17 +-- source/reducers/rootReducer.js | 2 +- source/selectors/analyseSelectors.js | 15 +-- 7 files changed, 67 insertions(+), 167 deletions(-) diff --git a/source/components/PeriodSwitch.js b/source/components/PeriodSwitch.js index 0a618dd6b5..62d34e0e63 100644 --- a/source/components/PeriodSwitch.js +++ b/source/components/PeriodSwitch.js @@ -1,97 +1,52 @@ -import { findRuleByDottedName, nestedSituationToPathMap } from 'Engine/rules' -import { compose, filter, map, toPairs } from 'ramda' +import { findRuleByDottedName } from 'Engine/rules' import React, { useEffect } from 'react' import { Trans } from 'react-i18next' -import { connect, useDispatch } from 'react-redux' -import { batchActions } from 'redux-batched-actions' -import { change, Field, reduxForm } from 'redux-form' +import { useDispatch, useSelector } from 'react-redux' import { flatRulesSelector, - situationSelector, - situationsWithDefaultsSelector + formattedSituationSelector } from 'Selectors/analyseSelectors' import './PeriodSwitch.css' -export default compose( - reduxForm({ - form: 'conversation', - destroyOnUnmount: false - }), - connect( - state => { - let situation = situationsWithDefaultsSelector(state) - if (Array.isArray(situation)) { - situation = situation[0] - } - - return { - rules: flatRulesSelector(state), - situation: nestedSituationToPathMap(situationSelector(state)), - initialPériode: situation.période - } - }, - dispatch => ({ - batchPeriodChange: actions => dispatch(batchActions(actions)) - }) - ) -)(function PeriodSwitch({ - situation, - rules, - batchPeriodChange, - initialPériode -}) { +export default function PeriodSwitch() { const dispatch = useDispatch() + const rules = useSelector(flatRulesSelector) + const situation = useSelector(formattedSituationSelector) + const period = situation.période useEffect(() => { - !situation.période && - updateSituation( - initialPériode || 'année', - batchPeriodChange, - situation, - rules, - updatePeriod - ) + !situation.période && updatePeriod('année') return - }) - const updatePeriod = (toPeriod, needConvertion) => + }, []) + const updatePeriod = toPeriod => { + const needConvertion = Object.keys(situation).filter(dottedName => { + const rule = findRuleByDottedName(rules, dottedName) + return rule?.période === 'flexible' + }) dispatch({ type: 'UPDATE_PERIOD', toPeriod, needConvertion }) + } + return ( ) -}) - -let updateSituation = ( - toPeriod, - batchPeriodChange, - situation, - rules, - updatePeriod -) => { - let needConvertion = filter(([dottedName, value]) => { - let rule = findRuleByDottedName(rules, dottedName) - return value != null && rule?.période === 'flexible' - })(toPairs(situation)) - - updatePeriod(toPeriod, needConvertion.map(([fieldName]) => fieldName)) - - let actions = [ - ...map( - ([dottedName, value]) => - change( - 'conversation', - dottedName, - Math.round( - situation.période === 'mois' && toPeriod === 'année' - ? value * 12 - : situation.période === 'année' && toPeriod === 'mois' - ? value / 12 - : (function() { - throw new Error('Oups, changement de période invalide') - })() - ) + '' - ), - needConvertion - ), - change('conversation', 'période', toPeriod) - ] - - batchPeriodChange(actions) } diff --git a/source/components/SalaryExplanation.js b/source/components/SalaryExplanation.js index c6b955ea03..f452a4a18b 100644 --- a/source/components/SalaryExplanation.js +++ b/source/components/SalaryExplanation.js @@ -6,7 +6,7 @@ import React, { useRef } from 'react' import emoji from 'react-easy-emoji' import { Trans } from 'react-i18next' import { connect } from 'react-redux' -import { formValueSelector } from 'redux-form' +import { usePeriod } from 'Selectors/analyseSelectors' import * as Animate from 'Ui/animate' class ErrorBoundary extends React.Component { @@ -89,20 +89,21 @@ export default compose( ) }) -const PaySlipSection = connect(state => ({ - period: formValueSelector('conversation')(state, 'période') -}))(({ period }) => ( -
-

- - {period === 'mois' - ? 'Fiche de paie mensuelle' - : 'Détail annuel des cotisations'} - -

- -
-)) +function PaySlipSection() { + const period = usePeriod() + return ( +
+

+ + {period === 'mois' + ? 'Fiche de paie mensuelle' + : 'Détail annuel des cotisations'} + +

+ +
+ ) +} const DistributionSection = () => (
diff --git a/source/components/conversation/FormDecorator.js b/source/components/conversation/FormDecorator.js index f1abebc47a..a95b418f4e 100644 --- a/source/components/conversation/FormDecorator.js +++ b/source/components/conversation/FormDecorator.js @@ -1,8 +1,9 @@ import classNames from 'classnames' import Explicable from 'Components/conversation/Explicable' import React from 'react' -import { useDispatch } from 'react-redux' -import { Field } from 'redux-form' +import { useDispatch, useSelector } from 'react-redux' +import { change, Field } from 'redux-form' +import { formattedSituationSelector } from 'Selectors/analyseSelectors' /* This higher order component wraps "Form" components (e.g. Question.js), that represent user inputs, @@ -15,6 +16,8 @@ to understand those precious higher order components. export const FormDecorator = formType => RenderField => function({ fieldName, question, inversion, unit, ...otherProps }) { const dispatch = useDispatch() + const situation = useSelector(formattedSituationSelector) + const submit = source => dispatch({ type: 'STEP_ACTION', @@ -50,12 +53,10 @@ export const FormDecorator = formType => RenderField => setFormValue(name, value) } - onChange={(evt, value) => { - dispatch({ type: 'UPDATE_SITUATION', fieldName, value }) - }} {...stepProps} /> diff --git a/source/components/conversation/Input.js b/source/components/conversation/Input.js index 45e1cd2cb9..bd2f80e2a8 100644 --- a/source/components/conversation/Input.js +++ b/source/components/conversation/Input.js @@ -2,8 +2,7 @@ import classnames from 'classnames' import { React, T } from 'Components' import withColours from 'Components/utils/withColours' import { compose } from 'ramda' -import { connect } from 'react-redux' -import { formValueSelector } from 'redux-form' +import { usePeriod } from 'Selectors/analyseSelectors' import { debounce } from '../../utils' import { FormDecorator } from './FormDecorator' import InputSuggestions from './InputSuggestions' @@ -11,33 +10,28 @@ import SendButton from './SendButton' export default compose( FormDecorator('input'), - withColours, - connect(state => ({ - period: formValueSelector('conversation')(state, 'période') - })) + withColours )(function Input({ - input, suggestions, setFormValue, submit, rulePeriod, dottedName, - meta: { dirty, error }, + value, colours, - period, unit }) { - const debouncedOnChange = debounce(750, input.onChange) + const period = usePeriod() + const debouncedOnChange = debounce(750, setFormValue) let suffixed = unit != null, - inputError = dirty && error, - submitDisabled = !dirty || inputError + submitDisabled = value === undefined return ( <>
setFormValue('' + value)} + onFirstClick={value => setFormValue(value)} onSecondClick={() => submit('suggestion')} rulePeriod={rulePeriod} /> @@ -46,13 +40,10 @@ export default compose(
{ - e.persist() - debouncedOnChange(e) - }} + defaultValue={value} + onChange={debouncedOnChange} className={classnames({ suffixed })} id={'step-' + dottedName} inputMode="numeric" @@ -78,8 +69,6 @@ export default compose( )}
- - {inputError && {error}} ) }) diff --git a/source/components/conversation/InputSuggestions.js b/source/components/conversation/InputSuggestions.js index 3e547ec127..ad0a3de81e 100644 --- a/source/components/conversation/InputSuggestions.js +++ b/source/components/conversation/InputSuggestions.js @@ -1,21 +1,16 @@ -import { compose, toPairs } from 'ramda' +import { toPairs } from 'ramda' import React, { useState } from 'react' import { useTranslation } from 'react-i18next' -import { connect } from 'react-redux' -import { formValueSelector } from 'redux-form' +import { usePeriod } from 'Selectors/analyseSelectors' -export default compose( - connect(state => ({ - period: formValueSelector('conversation')(state, 'période') - })) -)(function InputSuggestions({ +export default function InputSuggestions({ suggestions, onSecondClick, onFirstClick, - rulePeriod, - period + rulePeriod }) { const [suggestion, setSuggestion] = useState(null) + const period = usePeriod() const { t } = useTranslation() if (!suggestions) return null @@ -45,4 +40,4 @@ export default compose( })}
) -}) +} diff --git a/source/reducers/rootReducer.js b/source/reducers/rootReducer.js index cd373fcd03..4a07691ba3 100644 --- a/source/reducers/rootReducer.js +++ b/source/reducers/rootReducer.js @@ -102,7 +102,7 @@ function conversationSteps( } function updatePeriod(situation, { toPeriod, needConvertion }) { - const currentPeriod = situation['période'] || 'mois' + const currentPeriod = situation['période'] if (currentPeriod === toPeriod) { return situation } diff --git a/source/selectors/analyseSelectors.js b/source/selectors/analyseSelectors.js index 90fbdf928d..f03c55d95c 100644 --- a/source/selectors/analyseSelectors.js +++ b/source/selectors/analyseSelectors.js @@ -6,7 +6,6 @@ import { collectDefaults, disambiguateExampleSituation, findRuleByDottedName, - nestedSituationToPathMap, rules as baseRulesEn, rulesFr as baseRulesFr } from 'Engine/rules' @@ -33,6 +32,7 @@ import { takeWhile, zipWith } from 'ramda' +import { useSelector } from 'react-redux' import { getFormValues } from 'redux-form' import { createSelector, createSelectorCreator, defaultMemoize } from 'reselect' import { mapOrApply } from '../utils' @@ -87,16 +87,13 @@ export let situationSelector = createDeepEqualSelector( ) export let formattedSituationSelector = createSelector( - [situationSelector, state => state.simulation?.situation], - (reduxFormsituation, situation) => { - const formatedReduxFormSituation = nestedSituationToPathMap( - reduxFormsituation - ) - console.log(formatedReduxFormSituation, situation) - return formatedReduxFormSituation - } + [state => state.simulation?.situation], + situation => situation ) +export const usePeriod = () => + useSelector(state => state.simulation?.situation?.['période']) + export let noUserInputSelector = createSelector( [formattedSituationSelector], situation => !situation || isEmpty(dissoc('période', situation))