Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suppression de redux-form #671

Merged
merged 7 commits into from Sep 23, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions .eslintrc.yaml
@@ -1,7 +1,4 @@
rules:
linebreak-style:
- 2
- unix
quotes:
- 1 # While https://github.com/eslint/eslint/issues/9662#issuecomment-353958854 we don't enforce this
- single
Expand All @@ -14,10 +11,13 @@ rules:
react/jsx-no-target-blank: 0
react/no-unescaped-entities: 0
react/display-name: 1
react-hooks/rules-of-hooks: error
react-hooks/exhaustive-deps: warn
parser: babel-eslint

plugins:
- react
- react-hooks
- flowtype
env:
browser: true
Expand Down
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -57,8 +57,6 @@
"react-virtualized-select": "^3.1.3",
"reduce-reducers": "^0.1.2",
"redux": "^3.7.2",
"redux-batched-actions": "^0.4.1",
"redux-form": "^8.2.0",
"redux-thunk": "^2.3.0",
"regenerator-runtime": "^0.13.3",
"reselect": "^4.0.0",
Expand Down Expand Up @@ -125,6 +123,7 @@
"eslint-config-prettier": "^4.0.0",
"eslint-plugin-flowtype": "^3.2.1",
"eslint-plugin-react": "^7.12.4",
"eslint-plugin-react-hooks": "^2.0.1",
"express": "^4.16.3",
"file-loader": "^1.1.11",
"flow-bin": "^0.92.0",
Expand Down
7 changes: 1 addition & 6 deletions source/Provider.js
Expand Up @@ -9,7 +9,6 @@ import { Provider as ReduxProvider } from 'react-redux'
import { Router } from 'react-router-dom'
import reducers from 'Reducers/rootReducer'
import { applyMiddleware, compose, createStore } from 'redux'
import { enableBatching } from 'redux-batched-actions'
import thunk from 'redux-thunk'
import { getIframeOption, inIframe } from './utils'

Expand Down Expand Up @@ -54,11 +53,7 @@ export default class Provider extends PureComponent {
if (this.props.initialStore)
this.props.initialStore.lang = this.props.language
}
this.store = createStore(
enableBatching(reducers),
this.props.initialStore,
storeEnhancer
)
this.store = createStore(reducers, this.props.initialStore, storeEnhancer)
this.props.onStoreCreated && this.props.onStoreCreated(this.store)

// Remove loader
Expand Down
13 changes: 9 additions & 4 deletions source/actions/actions.js
Expand Up @@ -7,8 +7,6 @@ import type {
SetSimulationConfigAction,
SetSituationBranchAction
} from 'Types/ActionsTypes'
// $FlowFixMe
import { change, reset } from 'redux-form'
import { deletePersistedSimulation } from '../storage/persistSimulation'
import type { Thunk } from 'Types/ActionsTypes'

Expand All @@ -18,18 +16,19 @@ export const resetSimulation = () => (dispatch: any => void): void => {
type: 'RESET_SIMULATION'
}: ResetSimulationAction)
)
dispatch(reset('conversation'))
}

export const goToQuestion = (question: string): StepAction => ({
type: 'STEP_ACTION',
name: 'unfold',
step: question
})

export const validateStepWithValue = (
dottedName,
value: any
): Thunk<StepAction> => dispatch => {
dispatch(change('conversation', dottedName, value))
dispatch(updateSituation(dottedName, value))
dispatch({
type: 'STEP_ACTION',
name: 'fold',
Expand Down Expand Up @@ -62,6 +61,12 @@ export const deletePreviousSimulation = () => (
deletePersistedSimulation()
}

export const updateSituation = (fieldName, value) => ({
type: 'UPDATE_SITUATION',
fieldName,
value
})

// $FlowFixMe
export function setExample(name, situation, dottedName) {
return { type: 'SET_EXAMPLE', name, situation, dottedName }
Expand Down
1 change: 1 addition & 0 deletions source/components/AttachDictionary.js
Expand Up @@ -8,6 +8,7 @@ import Overlay from './Overlay'
// Il suffit à la section d'appeler une fonction fournie en lui donnant du JSX
export let AttachDictionary = dictionary => Decorated =>
function withDictionary(props) {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [{ explanation, term }, setState] = useState({
term: null,
explanation: null
Expand Down
36 changes: 19 additions & 17 deletions source/components/CurrencyInput/CurrencyInput.js
@@ -1,5 +1,5 @@
import classnames from 'classnames'
import React, { useEffect, useRef, useState } from 'react'
import React, { useRef, useState } from 'react'
import NumberFormat from 'react-number-format'
import { debounce } from '../../utils'
import './CurrencyInput.css'
Expand All @@ -22,23 +22,27 @@ let currencyFormat = language => ({
})

export default function CurrencyInput({
value: valueArg,
value: valueProp = '',
debounce: debounceTimeout,
onChange,
language,
className,
...forwardedProps
}) {
const [currentValue, setCurrentValue] = useState(valueArg)
const [initialValue] = useState(valueArg)
// When the component is rendered with a new "value" argument, we update our local state
useEffect(() => {
setCurrentValue(valueArg)
}, [valueArg])
const nextValue = useRef(null)
const [initialValue, setInitialValue] = useState(valueProp)
const [currentValue, setCurrentValue] = useState(valueProp)
const onChangeDebounced = useRef(
debounceTimeout ? debounce(debounceTimeout, onChange) : onChange
)
// We need some mutable reference because the <NumberFormat /> component doesn't provide
// the DOM `event` in its custom `onValueChange` handler
const nextValue = useRef(null)

// When the component is rendered with a new "value" prop, we reset our local state
if (valueProp !== initialValue) {
setCurrentValue(valueProp)
setInitialValue(valueProp)
}

const handleChange = event => {
// Only trigger the `onChange` event if the value has changed -- and not
Expand All @@ -61,19 +65,17 @@ export default function CurrencyInput({
thousandSeparator,
decimalSeparator
} = currencyFormat(language)

// We display negative numbers iff this was the provided value (but we allow the user to enter them)
// We display negative numbers iff this was the provided value (but we disallow the user to enter them)
const valueHasChanged = currentValue !== initialValue

// Autogrow the input
const valueLength = (currentValue || '').toString().length
const valueLength = currentValue.toString().length
const width = `${5 + (valueLength - 5) * 0.75}em`

return (
<div
className={classnames(className, 'currencyInput__container')}
{...(valueLength > 5
? { style: { width: `${5 + (valueLength - 5) * 0.75}em` } }
: {})}>
{...(valueLength > 5 ? { style: { width } } : {})}>
{isCurrencyPrefixed && '€'}
<NumberFormat
{...forwardedProps}
Expand All @@ -84,10 +86,10 @@ export default function CurrencyInput({
inputMode="numeric"
onValueChange={({ value }) => {
setCurrentValue(value)
nextValue.current = value.toString().replace(/^\-/, '')
nextValue.current = value.toString().replace(/^-/, '')
}}
onChange={handleChange}
value={(currentValue || '').toString().replace('.', decimalSeparator)}
value={currentValue.toString().replace('.', decimalSeparator)}
/>
{!isCurrencyPrefixed && <>&nbsp;€</>}
</div>
Expand Down
25 changes: 12 additions & 13 deletions source/components/PercentageField.js
@@ -1,23 +1,22 @@
import React, { useState } from 'react'
import React, { useCallback, useState } from 'react'
import './PercentageField.css'

export default function PercentageField({ input, debounce }) {
const [localValue, setLocalValue] = useState(input?.value)

const debouncedOnChange = debounce
? debounce(debounce, input.onChange)
: input.onChange

const onChange = value => {
setLocalValue(value)
debouncedOnChange(value)
}
export default function PercentageField({ onChange, value, debounce }) {
const [localValue, setLocalValue] = useState(value)
const debouncedOnChange = useCallback(
debounce ? debounce(debounce, onChange) : onChange,
[debounce, onChange]
)

return (
<div>
<input
className="range"
onChange={e => onChange(e.target.value)}
onChange={e => {
const value = e.target.value
setLocalValue(value)
debouncedOnChange(value)
}}
type="range"
value={localValue}
name="volume"
Expand Down
140 changes: 39 additions & 101 deletions source/components/PeriodSwitch.js
@@ -1,116 +1,54 @@
import { findRuleByDottedName, nestedSituationToPathMap } from 'Engine/rules'
import { compose, filter, map, toPairs } from 'ramda'
import React, { useEffect } from 'react'
import { findRuleByDottedName } from 'Engine/rules'
import React, { useCallback, useEffect } from 'react'
import { Trans } from 'react-i18next'
import { connect } 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
situationSelector
} 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))
})
export default function PeriodSwitch() {
const dispatch = useDispatch()
const rules = useSelector(flatRulesSelector)
mquandalle marked this conversation as resolved.
Show resolved Hide resolved
const situation = useSelector(situationSelector)
const initialPeriod = useSelector(
state => state.simulation?.config?.situation?.période
)
)(function PeriodSwitch({
situation,
rules,
batchPeriodChange,
initialPériode
}) {
const currentPeriod = situation.période
useEffect(() => {
!situation.période &&
updateSituation(
initialPériode || 'année',
batchPeriodChange,
situation,
rules
)
return
})
!currentPeriod && updatePeriod(initialPeriod || 'année')
}, [currentPeriod, initialPeriod, updatePeriod])
const updatePeriod = useCallback(
toPeriod => {
const needConversion = Object.keys(situation).filter(dottedName => {
const rule = findRuleByDottedName(rules, dottedName)
return rule?.période === 'flexible'
})
dispatch({ type: 'UPDATE_PERIOD', toPeriod, needConversion })
},
[dispatch, rules, situation]
)
const periods = ['mois', 'année']

return (
<span id="PeriodSwitch">
<span className="base ui__ small toggle">
<label>
<Field
name="période"
component="input"
type="radio"
value="année"
onChange={() =>
updateSituation('année', batchPeriodChange, situation, rules)
}
/>
<span>
<Trans>année</Trans>
</span>
</label>
<label>
<Field
name="période"
component="input"
type="radio"
value="mois"
onChange={() =>
updateSituation('mois', batchPeriodChange, situation, rules)
}
/>
<span>
<Trans>mois</Trans>
</span>
</label>
{periods.map(period => (
<label key={period}>
<input
name="période"
type="radio"
value={period}
onChange={() => updatePeriod(period)}
checked={currentPeriod === period}
/>
<span>
<Trans>{period}</Trans>
</span>
</label>
))}
</span>
</span>
)
})

let updateSituation = (toPeriod, batchPeriodChange, situation, rules) => {
let needConvertion = filter(([dottedName, value]) => {
let rule = findRuleByDottedName(rules, dottedName)
return value != null && rule?.période === 'flexible'
})(toPairs(situation))
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)
}