Formatage des nombres dans les réponses aux questions

Fixes #683
pull/693/head
Maxime Quandalle 2019-09-24 16:31:39 +02:00
parent 38d2e12b64
commit 0fcade76e1
No known key found for this signature in database
GPG Key ID: 428641C03D29CA10
3 changed files with 104 additions and 5 deletions

View File

@ -5,6 +5,7 @@ import { getFormatersFromUnit } from 'Engine/format'
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { situationSelector } from 'Selectors/analyseSelectors'
import { useTranslation } from 'react-i18next'
/*
This higher order component wraps "Form" components (e.g. Question.js), that represent user inputs,
@ -15,9 +16,10 @@ to understand those precious higher order components.
*/
export const FormDecorator = formType => RenderField =>
function({ fieldName, question, inversion, unit, ...otherProps }) {
function FormStep({ fieldName, question, inversion, unit, ...otherProps }) {
const dispatch = useDispatch()
const situation = useSelector(situationSelector)
const { language } = useTranslation().i18n
const submit = source =>
dispatch({
@ -30,7 +32,7 @@ export const FormDecorator = formType => RenderField =>
dispatch(updateSituation(fieldName, normalize(value)))
}
const { format, normalize } = getFormatersFromUnit(unit)
const { format, normalize } = getFormatersFromUnit(unit, language)
const value = format(situation[fieldName])
return (
@ -48,6 +50,7 @@ export const FormDecorator = formType => RenderField =>
setFormValue={setFormValue}
submit={submit}
format={format}
normalize={normalize}
unit={unit}
{...otherProps}
/>

View File

@ -2,7 +2,7 @@ import classnames from 'classnames'
import { T } from 'Components'
import withColours from 'Components/utils/withColours'
import { compose } from 'ramda'
import React, { useCallback, useState } from 'react'
import React, { useCallback } from 'react'
import { usePeriod } from 'Selectors/analyseSelectors'
import { debounce } from '../../utils'
import { FormDecorator } from './FormDecorator'
@ -33,7 +33,7 @@ export default compose(
<InputSuggestions
suggestions={suggestions}
onFirstClick={value => {
setFormValue(format(value))
setFormValue(value)
}}
onSecondClick={() => submit('suggestion')}
rulePeriod={rulePeriod}
@ -45,7 +45,7 @@ export default compose(
type="text"
key={value}
autoFocus
defaultValue={value}
value={format(value)}
onChange={evt => {
debouncedSetFormValue(evt.target.value)
}}

96
source/engine/format.js Normal file
View File

@ -0,0 +1,96 @@
import { serialiseUnit } from 'Engine/units'
import { memoizeWith } from 'ramda'
export const formatCurrency = (value, language) => {
return value == null
? ''
: Intl.NumberFormat(language, {
style: 'currency',
currency: 'EUR',
maximumFractionDigits: 0,
minimumFractionDigits: 0
})
.format(value)
.replace(/^(-)?€/, '$1€\u00A0')
}
const sanitizeValue = language => value =>
language === 'fr' ? String(value).replace(',', '.') : value
export const formatPercentage = value => +(value * 100).toFixed(2)
export const normalizePercentage = value => value / 100
export const getFormatersFromUnit = (unit, language = 'en') => {
const serializedUnit = typeof unit == 'object' ? serialiseUnit(unit) : unit
const sanitize = sanitizeValue(language)
switch (serializedUnit) {
case '%':
return {
format: numberFormatter({ style: 'percent', language }).replace(
' %',
''
),
normalize: v => normalizePercentage(language)(sanitize(v))
}
default:
return {
format: x =>
Number(x)
? numberFormatter({ style: 'decimal', language })(Number(x))
: x,
normalize: x => sanitize(x)
}
}
}
const NumberFormat = memoizeWith(
(...args) => JSON.stringify(args),
Intl.NumberFormat
)
export let numberFormatter = ({
style,
maximumFractionDigits = 2,
minimumFractionDigits = 0,
language
}) => value =>
NumberFormat(language, {
style,
currency: 'EUR',
maximumFractionDigits,
minimumFractionDigits
}).format(value)
export function formatValue({
maximumFractionDigits,
minimumFractionDigits,
language,
unit,
value
}) {
const serializedUnit = typeof unit == 'object' ? serialiseUnit(unit) : unit
switch (serializedUnit) {
case '€':
return numberFormatter({
style: 'currency',
maximumFractionDigits,
minimumFractionDigits,
language
})(value)
case '%':
return numberFormatter({ style: 'percent', maximumFractionDigits })(value)
default:
if (typeof value !== 'number') {
return value
}
return (
numberFormatter({
style: 'decimal',
minimumFractionDigits,
maximumFractionDigits
})(value) +
(typeof serializedUnit === 'string' ? `\u00A0${serializedUnit}` : '')
)
}
}