Skip to content

Commit

Permalink
🐛 Correction formatage de l'AnimatedValue
Browse files Browse the repository at this point in the history
Suppression de l'AnimatedValue pour l'objectif courant
Simplification du code de TargetSelection
Corrections CSS
  • Loading branch information
mquandalle committed Sep 18, 2019
1 parent 0ddc2d0 commit 7a965e6
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 81 deletions.
5 changes: 1 addition & 4 deletions source/components/PeriodSwitch.js
Expand Up @@ -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 (
<span id="PeriodSwitch">
Expand Down
8 changes: 3 additions & 5 deletions source/components/TargetSelection.css
Expand Up @@ -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 {
Expand Down Expand Up @@ -136,11 +136,9 @@

#targetSelection .targetInputBottomBorder {
margin: 0;
padding: 0;
padding: 0 2px;
height: 0;
overflow: hidden;
position: relative;
top: -6px;
}

#targetSelection .editableTarget + .targetInputBottomBorder {
Expand Down
96 changes: 39 additions & 57 deletions 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'
Expand Down Expand Up @@ -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 (
<>
<AnimatedTargetValue value={value} />
<Input
value={value}
debounce={600}
style={{
color: colors.textColour,
borderColor: colors.textColour
}}
{...otherProps}
/>
<span className="targetInputBottomBorder">
{formatCurrency(value, language)}
</span>
</>
)
}

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)
Expand All @@ -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 (
<span
className="targetInputOrValue"
style={blurValue ? { filter: 'blur(3px)' } : {}}>
{target.question ? (
<Component
name={target.dottedName}
value={situationValue || value}
className={
isActiveInput || isNil(value) ? 'targetInput' : 'editableTarget'
}
onChange={evt =>
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 && <AnimatedTargetValue value={value} />}
<CurrencyInput
style={{
color: colors.textColour,
borderColor: colors.textColour
}}
debounce={600}
name={target.dottedName}
value={situationValue || value}
className={
isActiveInput || isNil(value) ? 'targetInput' : 'editableTarget'
}
onChange={evt =>
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}
/>
<span className="targetInputBottomBorder">
{formatCurrency(value, i18n.language)}
</span>
</>
) : (
<span>
{Number.isNaN(value) ? '—' : formatCurrency(value, i18n.language)}
Expand Down
37 changes: 22 additions & 15 deletions 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 (
<>
<span className="Rule-value">
Expand All @@ -33,7 +40,7 @@ export default function AnimatedTargetValue({ value, children }: Props) {
color: difference > 0 ? 'chartreuse' : 'red',
pointerEvents: 'none'
}}>
{(difference > 0 ? '+' : '') + formattedDifference}
{formatDifference(difference, language)}
</Evaporate>
)}{' '}
{children}
Expand Down

0 comments on commit 7a965e6

Please sign in to comment.