Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
mquandalle committed Sep 12, 2019
1 parent 5129f83 commit fd21cfe
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 167 deletions.
127 changes: 22 additions & 105 deletions 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 (
<span id="PeriodSwitch">
<span className="base ui__ small toggle">
<label>
<Field
<input
name="période"
component="input"
type="radio"
value="année"
onChange={() =>
updateSituation(
'année',
batchPeriodChange,
situation,
rules,
updatePeriod
)
}
onChange={() => updatePeriod('année')}
checked={period === 'année'}
/>
<span>
<Trans>année</Trans>
</span>
</label>
<label>
<Field
<input
name="période"
component="input"
type="radio"
value="mois"
onChange={() =>
updateSituation(
'mois',
batchPeriodChange,
situation,
rules,
updatePeriod
)
}
onChange={() => updatePeriod('mois')}
checked={period === 'mois'}
/>
<span>
<Trans>mois</Trans>
Expand All @@ -100,42 +55,4 @@ export default compose(
</span>
</span>
)
})

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)
}
31 changes: 16 additions & 15 deletions source/components/SalaryExplanation.js
Expand Up @@ -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 {
Expand Down Expand Up @@ -89,20 +89,21 @@ export default compose(
)
})

const PaySlipSection = connect(state => ({
period: formValueSelector('conversation')(state, 'période')
}))(({ period }) => (
<section>
<h2>
<Trans>
{period === 'mois'
? 'Fiche de paie mensuelle'
: 'Détail annuel des cotisations'}
</Trans>
</h2>
<PaySlip />
</section>
))
function PaySlipSection() {
const period = usePeriod()
return (
<section>
<h2>
<Trans>
{period === 'mois'
? 'Fiche de paie mensuelle'
: 'Détail annuel des cotisations'}
</Trans>
</h2>
<PaySlip />
</section>
)
}

const DistributionSection = () => (
<section>
Expand Down
11 changes: 6 additions & 5 deletions 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,
Expand All @@ -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',
Expand Down Expand Up @@ -50,12 +53,10 @@ export const FormDecorator = formType => RenderField =>
<Field
component={RenderField}
name={fieldName}
value={situation[fieldName]}
setFormValue={(value, name = fieldName) =>
setFormValue(name, value)
}
onChange={(evt, value) => {
dispatch({ type: 'UPDATE_SITUATION', fieldName, value })
}}
{...stepProps}
/>
</fieldset>
Expand Down
31 changes: 10 additions & 21 deletions source/components/conversation/Input.js
Expand Up @@ -2,42 +2,36 @@ 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'
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 (
<>
<div css="width: 100%">
<InputSuggestions
suggestions={suggestions}
onFirstClick={value => setFormValue('' + value)}
onFirstClick={value => setFormValue(value)}
onSecondClick={() => submit('suggestion')}
rulePeriod={rulePeriod}
/>
Expand All @@ -46,13 +40,10 @@ export default compose(
<div className="answer">
<input
type="text"
key={input.value}
key={value}
autoFocus
defaultValue={input.value}
onChange={e => {
e.persist()
debouncedOnChange(e)
}}
defaultValue={value}
onChange={debouncedOnChange}
className={classnames({ suffixed })}
id={'step-' + dottedName}
inputMode="numeric"
Expand All @@ -78,8 +69,6 @@ export default compose(
)}
<SendButton {...{ disabled: submitDisabled, error, submit }} />
</div>

{inputError && <span className="step-input-error">{error}</span>}
</>
)
})
17 changes: 6 additions & 11 deletions 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
Expand Down Expand Up @@ -45,4 +40,4 @@ export default compose(
})}
</div>
)
})
}
2 changes: 1 addition & 1 deletion source/reducers/rootReducer.js
Expand Up @@ -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
}
Expand Down
15 changes: 6 additions & 9 deletions source/selectors/analyseSelectors.js
Expand Up @@ -6,7 +6,6 @@ import {
collectDefaults,
disambiguateExampleSituation,
findRuleByDottedName,
nestedSituationToPathMap,
rules as baseRulesEn,
rulesFr as baseRulesFr
} from 'Engine/rules'
Expand All @@ -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'
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit fd21cfe

Please sign in to comment.