mirror of
https://github.com/betagouv/mon-entreprise
synced 2025-02-09 01:45:03 +00:00
Suppression des décorateurs. Problème : Les décorateurs que l'on utilisait correspondait à une ancienne version de la proposal tc39, encore en stage 1 (voir 0). La proposition a complètement évolué, pour ne plus du tout avoir la même forme que précédement. Au lieu de garder la version 'legacy', on choisit de se séparer des décorateur, étant donné que le nouveau use case n'a plus rien à voir, et que l'ancienne version peut être gérée de manière quasi équivalente avec des fonctions et des compose
321 lines
7.8 KiB
JavaScript
321 lines
7.8 KiB
JavaScript
import classNames from 'classnames'
|
|
import InputSuggestions from 'Components/conversation/InputSuggestions'
|
|
import withColours from 'Components/utils/withColours'
|
|
import withLanguage from 'Components/utils/withLanguage'
|
|
import { encodeRuleName, findRuleByDottedName } from 'Engine/rules'
|
|
import { compose, propEq } from 'ramda'
|
|
import React, { Component } from 'react'
|
|
import emoji from 'react-easy-emoji'
|
|
import { Trans, translate } from 'react-i18next'
|
|
import { connect } from 'react-redux'
|
|
import { withRouter } from 'react-router'
|
|
import { Link } from 'react-router-dom'
|
|
import { change, Field, formValueSelector, reduxForm } from 'redux-form'
|
|
import {
|
|
analysisWithDefaultsSelector,
|
|
blockingInputControlsSelector,
|
|
flatRulesSelector,
|
|
noUserInputSelector
|
|
} from 'Selectors/analyseSelectors'
|
|
import { mainTargetNames } from '../config'
|
|
import { normalizeBasePath } from '../utils'
|
|
import AnimatedTargetValue from './AnimatedTargetValue'
|
|
import Controls from './Controls'
|
|
import CurrencyInput from './CurrencyInput/CurrencyInput'
|
|
import ProgressCircle from './ProgressCircle'
|
|
import './TargetSelection.css'
|
|
|
|
let salaries = [
|
|
'contrat salarié . salaire . total',
|
|
'contrat salarié . salaire . brut de base',
|
|
'contrat salarié . salaire . net à payer'
|
|
]
|
|
|
|
let displayedTargetNames = [...salaries, 'contrat salarié . aides employeur']
|
|
export let popularTargetNames = [
|
|
...displayedTargetNames,
|
|
'contrat salarié . rémunération . net imposable'
|
|
]
|
|
|
|
const TargetSelection = compose(
|
|
translate(),
|
|
reduxForm({
|
|
form: 'conversation',
|
|
destroyOnUnmount: false
|
|
}),
|
|
withRouter,
|
|
connect(
|
|
state => ({
|
|
getTargetValue: dottedName =>
|
|
formValueSelector('conversation')(state, dottedName),
|
|
analysis: analysisWithDefaultsSelector(state),
|
|
blockingInputControls: blockingInputControlsSelector(state),
|
|
flatRules: flatRulesSelector(state),
|
|
noUserInput: noUserInputSelector(state),
|
|
conversationStarted: state.conversationStarted,
|
|
activeInput: state.activeTargetInput
|
|
}),
|
|
dispatch => ({
|
|
setFormValue: (field, name) =>
|
|
dispatch(change('conversation', field, name)),
|
|
setActiveInput: name =>
|
|
dispatch({ type: 'SET_ACTIVE_TARGET_INPUT', name })
|
|
})
|
|
)
|
|
)(
|
|
class TargetSelection extends Component {
|
|
render() {
|
|
let {
|
|
colours,
|
|
noUserInput,
|
|
blockingInputControls,
|
|
analysis: { controls }
|
|
} = this.props
|
|
return (
|
|
<div id="targetSelection">
|
|
{noUserInput && (
|
|
<p className="blockingControl">
|
|
<Trans i18nKey="enterSalary">
|
|
Entrez un salaire <b>mensuel</b>
|
|
</Trans>
|
|
</p>
|
|
)}
|
|
<Controls {...{ blockingInputControls, controls }} />
|
|
<section
|
|
id="targetsContainer"
|
|
style={{
|
|
color: colours.textColour,
|
|
background: `linear-gradient(
|
|
60deg,
|
|
${colours.darkColour} 0%,
|
|
${colours.colour} 100%
|
|
)`
|
|
}}>
|
|
{this.renderOutputList()}
|
|
</section>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
renderOutputList() {
|
|
let displayedTargets = mainTargetNames.map(target =>
|
|
findRuleByDottedName(this.props.flatRules, target)
|
|
),
|
|
{
|
|
conversationStarted,
|
|
activeInput,
|
|
setActiveInput,
|
|
analysis,
|
|
noUserInput,
|
|
blockingInputControls,
|
|
match
|
|
} = this.props,
|
|
targets = analysis ? analysis.targets : []
|
|
|
|
return (
|
|
<div>
|
|
<ul id="targets">
|
|
{displayedTargets.map(target => (
|
|
<li key={target.name}>
|
|
<div className="main">
|
|
<Header
|
|
{...{
|
|
match,
|
|
target,
|
|
conversationStarted,
|
|
isActiveInput: activeInput === target.dottedName,
|
|
blockingInputControls
|
|
}}
|
|
/>
|
|
<TargetInputOrValue
|
|
{...{
|
|
target,
|
|
targets,
|
|
activeInput,
|
|
setActiveInput,
|
|
setFormValue: this.props.setFormValue,
|
|
noUserInput,
|
|
blockingInputControls
|
|
}}
|
|
/>
|
|
</div>
|
|
{activeInput === target.dottedName && !conversationStarted && (
|
|
<InputSuggestions
|
|
suggestions={target.suggestions}
|
|
onFirstClick={value =>
|
|
this.props.setFormValue(target.dottedName, '' + value)
|
|
}
|
|
colouredBackground={true}
|
|
/>
|
|
)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)
|
|
}
|
|
}
|
|
)
|
|
|
|
let Header = ({
|
|
target,
|
|
conversationStarted,
|
|
isActiveInput,
|
|
blockingInputControls,
|
|
match
|
|
}) => {
|
|
const ruleLink =
|
|
normalizeBasePath(match.path).replace(/simulation\/$/, '') +
|
|
'règle/' +
|
|
encodeRuleName(target.dottedName)
|
|
return (
|
|
<span className="header">
|
|
{conversationStarted && !blockingInputControls && (
|
|
<ProgressCircle target={target} isActiveInput={isActiveInput} />
|
|
)}
|
|
|
|
<span className="texts">
|
|
{!conversationStarted && target.dottedName.includes('net après impôt') && (
|
|
<div>
|
|
<span id="labelNew">
|
|
<Trans>Janvier 2019</Trans>
|
|
</span>
|
|
</div>
|
|
)}
|
|
<span className="optionTitle">
|
|
<Link to={ruleLink}>{target.title || target.name}</Link>
|
|
</span>
|
|
{!conversationStarted && <p>{target['résumé']}</p>}
|
|
</span>
|
|
</span>
|
|
)
|
|
}
|
|
|
|
let CurrencyField = withColours(props => {
|
|
return (
|
|
<CurrencyInput
|
|
style={{
|
|
color: props.colours.textColour,
|
|
borderColor: props.colours.textColour
|
|
}}
|
|
className="targetInput"
|
|
autoFocus
|
|
{...props.input}
|
|
{...props}
|
|
/>
|
|
)
|
|
})
|
|
|
|
let TargetInputOrValue = withLanguage(
|
|
({
|
|
target,
|
|
targets,
|
|
activeInput,
|
|
setActiveInput,
|
|
language,
|
|
noUserInput,
|
|
blockingInputControls
|
|
}) => (
|
|
<span className="targetInputOrValue">
|
|
{activeInput === target.dottedName ? (
|
|
<Field
|
|
name={target.dottedName}
|
|
component={CurrencyField}
|
|
language={language}
|
|
/>
|
|
) : (
|
|
<TargetValue
|
|
{...{
|
|
targets,
|
|
target,
|
|
activeInput,
|
|
setActiveInput,
|
|
noUserInput,
|
|
blockingInputControls
|
|
}}
|
|
/>
|
|
)}
|
|
{target.dottedName.includes('rémunération . total') && <AidesGlimpse />}
|
|
</span>
|
|
)
|
|
)
|
|
|
|
const TargetValue = connect(
|
|
null,
|
|
dispatch => ({
|
|
setFormValue: (field, name) => dispatch(change('conversation', field, name))
|
|
})
|
|
)(
|
|
class TargetValue extends Component {
|
|
render() {
|
|
let { targets, target, noUserInput, blockingInputControls } = this.props
|
|
|
|
let targetWithValue =
|
|
targets && targets.find(propEq('dottedName', target.dottedName)),
|
|
value = targetWithValue && targetWithValue.nodeValue
|
|
|
|
return (
|
|
<div
|
|
className={classNames({
|
|
editable: target.question,
|
|
attractClick:
|
|
target.question && (noUserInput || blockingInputControls)
|
|
})}
|
|
tabIndex="0"
|
|
onClick={this.showField(value)}
|
|
onFocus={this.showField(value)}>
|
|
<AnimatedTargetValue value={value} />
|
|
</div>
|
|
)
|
|
}
|
|
showField(value) {
|
|
let { target, setFormValue, activeInput, setActiveInput } = this.props
|
|
return () => {
|
|
if (!target.question) return
|
|
if (value != null)
|
|
setFormValue(target.dottedName, Math.floor(value) + '')
|
|
|
|
if (activeInput) setFormValue(activeInput, '')
|
|
setActiveInput(target.dottedName)
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
const AidesGlimpse = compose(
|
|
withColours,
|
|
withRouter,
|
|
connect(state => ({ analysis: analysisWithDefaultsSelector(state) }))
|
|
)(
|
|
class AidesGlimpse extends Component {
|
|
render() {
|
|
let targets = this.props.analysis.targets,
|
|
aides =
|
|
targets &&
|
|
targets.find(
|
|
t => t.dottedName === 'contrat salarié . aides employeur'
|
|
)
|
|
if (!aides || !aides.nodeValue) return null
|
|
return (
|
|
<div id="aidesGlimpse">
|
|
{' '}
|
|
- <AnimatedTargetValue value={aides.nodeValue} />{' '}
|
|
<Link
|
|
to={
|
|
normalizeBasePath(this.props.match.path).replace(
|
|
/simulation\/$/,
|
|
''
|
|
) +
|
|
'règle/' +
|
|
encodeRuleName('contrat salarié . aides employeur')
|
|
}
|
|
style={{ color: this.props.colours.textColour }}>
|
|
<Trans>d'aides</Trans> {emoji(aides.icon)}
|
|
</Link>
|
|
</div>
|
|
)
|
|
}
|
|
}
|
|
)
|
|
|
|
export default TargetSelection
|