diff --git a/source/components/PeriodSwitch.js b/source/components/PeriodSwitch.js index c7f6670596..e0225cc412 100644 --- a/source/components/PeriodSwitch.js +++ b/source/components/PeriodSwitch.js @@ -11,15 +11,12 @@ export default function PeriodSwitch() { state => state.simulation?.config?.situation?.période || 'année' ) const currentPeriod = situation.période - let periods = ['mois', 'année'] + let periods = ['année', 'mois'] const updatePeriod = toPeriod => dispatch({ type: 'UPDATE_PERIOD', toPeriod }) if (!currentPeriod) { updatePeriod(defaultPeriod) } - if (defaultPeriod === 'année') { - periods.reverse() - } return ( diff --git a/source/components/TargetSelection.css b/source/components/TargetSelection.css index 63783d9ebc..f9ef880718 100644 --- a/source/components/TargetSelection.css +++ b/source/components/TargetSelection.css @@ -106,8 +106,8 @@ text-decoration: none; } -#targetSelection .targetInputOrValue > :not(.targetInput):not(.attractClick) { - margin: 0.2rem 0.6rem; +#targetSelection .targetInputOrValue > :not(.targetInput) { + margin: 0 0.6rem; } #targetSelection input { @@ -136,11 +136,9 @@ #targetSelection .targetInputBottomBorder { margin: 0; - padding: 0; + padding: 0 2px; height: 0; overflow: hidden; - position: relative; - top: -6px; } #targetSelection .editableTarget + .targetInputBottomBorder { diff --git a/source/components/TargetSelection.js b/source/components/TargetSelection.js index e781539d17..7f7f9c0ffa 100644 --- a/source/components/TargetSelection.js +++ b/source/components/TargetSelection.js @@ -1,13 +1,11 @@ import { updateSituation } from 'Actions/actions' import { T } from 'Components' import InputSuggestions from 'Components/conversation/InputSuggestions' -import PercentageField from 'Components/PercentageField' import PeriodSwitch from 'Components/PeriodSwitch' import RuleLink from 'Components/RuleLink' import { ThemeColoursContext } from 'Components/utils/withColours' import withSitePaths from 'Components/utils/withSitePaths' import { encodeRuleName } from 'Engine/rules' -import { serialiseUnit } from 'Engine/units' import { isEmpty, isNil } from 'ramda' import React, { useEffect, useState, useContext } from 'react' import emoji from 'react-easy-emoji' @@ -221,36 +219,9 @@ export const formatCurrency = (value, language) => { .replace(/^€/, '€ ') } -let clickableField = Input => - function WrappedClickableField({ value, ...otherProps }) { - const colors = useContext(ThemeColoursContext) - const { language } = useTranslation().i18n - return ( - <> - - - - {formatCurrency(value, language)} - - - ) - } - -let unitToComponent = { - '€': clickableField(CurrencyInput), - '%': clickableField(PercentageField) -} - let TargetInputOrValue = ({ target, isActiveInput, isSmallTarget }) => { const { i18n } = useTranslation() + const colors = useContext(ThemeColoursContext) const dispatch = useDispatch() const situationValue = useSituationValue(target.dottedName) const targetWithValue = useTarget(target.dottedName) @@ -259,39 +230,50 @@ let TargetInputOrValue = ({ target, isActiveInput, isSmallTarget }) => { state => analysisWithDefaultsSelector(state)?.cache.inversionFail ) const blurValue = inversionFail && !isActiveInput && value - const Component = unitToComponent[serialiseUnit(target.unit)] + return ( {target.question ? ( - - dispatch(updateSituation(target.dottedName, evt.target.value)) - } - onBlur={event => event.preventDefault()} - // We use onMouseDown instead of onClick because that's when the browser moves the cursor - onMouseDown={() => { - if (isSmallTarget) return - dispatch({ - type: 'SET_ACTIVE_TARGET_INPUT', - name: target.dottedName - }) - // TODO: This shouldn't be necessary: we don't need to recalculate the situation - // when the user just focus another field. Removing this line is almost working - // however there is a weird bug in the selection of the next question. - if (value) { - dispatch(updateSituation(target.dottedName, '' + value)) + <> + {!isActiveInput && } + + dispatch(updateSituation(target.dottedName, evt.target.value)) } - }} - {...(isActiveInput ? { autoFocus: true } : {})} - language={i18n.language} - /> + onBlur={event => event.preventDefault()} + // We use onMouseDown instead of onClick because that's when the browser moves the cursor + onMouseDown={() => { + if (isSmallTarget) return + dispatch({ + type: 'SET_ACTIVE_TARGET_INPUT', + name: target.dottedName + }) + // TODO: This shouldn't be necessary: we don't need to recalculate the situation + // when the user just focus another field. Removing this line is almost working + // however there is a weird bug in the selection of the next question. + if (value) { + dispatch(updateSituation(target.dottedName, '' + value)) + } + }} + {...(isActiveInput ? { autoFocus: true } : {})} + language={i18n.language} + /> + + {formatCurrency(value, i18n.language)} + + ) : ( {Number.isNaN(value) ? '—' : formatCurrency(value, i18n.language)} diff --git a/source/components/ui/AnimatedTargetValue.js b/source/components/ui/AnimatedTargetValue.js index 0efd1eae5a..8a90d9a640 100644 --- a/source/components/ui/AnimatedTargetValue.js +++ b/source/components/ui/AnimatedTargetValue.js @@ -1,29 +1,36 @@ /* @flow */ -import React, { useEffect, useState } from 'react' +import React, { useRef } from 'react' import ReactCSSTransitionGroup from 'react-addons-css-transition-group' import { useTranslation } from 'react-i18next' import './AnimatedTargetValue.css' -import { formatCurrency } from 'Components/TargetSelection' type Props = { value: ?number } +function formatDifference(difference, language) { + const prefix = difference > 0 ? '+' : '' + const formatedValue = Intl.NumberFormat(language, { + style: 'currency', + currency: 'EUR', + maximumFractionDigits: 0, + minimumFractionDigits: 0 + }).format(difference) + return prefix + formatedValue +} + export default function AnimatedTargetValue({ value, children }: Props) { - const [difference, setDifference] = useState(0) - const [previousValue, setPreviousValue] = useState() - useEffect(() => { - if (previousValue === value || Number.isNaN(value)) { - return - } - setDifference((value || 0) - (previousValue || 0)) - setPreviousValue(value) - }, [previousValue, value]) - const { i18n } = useTranslation() + const previousValue = useRef() + const { language } = useTranslation().i18n - const formattedDifference = formatCurrency(difference, i18n.language) + const difference = + previousValue.current === value || Number.isNaN(value) + ? null + : (value || 0) - (previousValue.current || 0) + previousValue.current = value const shouldDisplayDifference = - Math.abs(difference) > 1 && value != null && !Number.isNaN(value) + difference !== null && Math.abs(difference) > 1 + return ( <> @@ -33,7 +40,7 @@ export default function AnimatedTargetValue({ value, children }: Props) { color: difference > 0 ? 'chartreuse' : 'red', pointerEvents: 'none' }}> - {(difference > 0 ? '+' : '') + formattedDifference} + {formatDifference(difference, language)} )}{' '} {children}