2017-11-15 09:49:55 +00:00
|
|
|
import React, { Component } from 'react'
|
2018-03-29 07:58:20 +00:00
|
|
|
import { Trans, translate } from 'react-i18next'
|
2018-03-21 11:02:24 +00:00
|
|
|
import formValueTypes from 'Components/conversation/formValueTypes'
|
2018-04-25 13:45:29 +00:00
|
|
|
import { findRuleByName } from 'Engine/rules'
|
|
|
|
import { propEq, curry } from 'ramda'
|
2017-11-16 17:11:42 +00:00
|
|
|
import './TargetSelection.css'
|
2018-01-10 16:51:35 +00:00
|
|
|
import BlueButton from './BlueButton'
|
2018-03-21 17:35:15 +00:00
|
|
|
import { Field, reduxForm, formValueSelector, change } from 'redux-form'
|
2018-03-29 09:50:34 +00:00
|
|
|
import { Link } from 'react-router-dom'
|
2018-02-28 16:45:13 +00:00
|
|
|
import { connect } from 'react-redux'
|
|
|
|
import { RuleValue } from './rule/RuleValueVignette'
|
2018-03-14 17:20:09 +00:00
|
|
|
import classNames from 'classnames'
|
2018-04-25 13:55:17 +00:00
|
|
|
import ProgressCircle from './ProgressCircle/ProgressCircle'
|
2018-04-26 15:15:08 +00:00
|
|
|
import InputSuggestions from 'Components/conversation/InputSuggestions'
|
2018-03-21 11:02:24 +00:00
|
|
|
import { buildValidationFunction } from './conversation/FormDecorator'
|
2018-03-15 11:18:21 +00:00
|
|
|
export let salaries = ['salaire total', 'salaire de base', 'salaire net']
|
2018-03-12 15:22:16 +00:00
|
|
|
export let popularTargetNames = [...salaries, 'aides employeur']
|
2017-12-07 14:19:51 +00:00
|
|
|
|
2018-03-29 07:58:20 +00:00
|
|
|
@translate()
|
2018-02-28 16:45:13 +00:00
|
|
|
@reduxForm({
|
2018-04-06 13:26:03 +00:00
|
|
|
form: 'conversation',
|
|
|
|
destroyOnUnmount: false
|
2018-02-28 16:45:13 +00:00
|
|
|
})
|
|
|
|
@connect(
|
|
|
|
state => ({
|
|
|
|
getTargetValue: dottedName =>
|
|
|
|
formValueSelector('conversation')(state, dottedName),
|
|
|
|
targets: state.analysis ? state.analysis.targets : [],
|
2018-03-29 17:26:35 +00:00
|
|
|
flatRules: state.flatRules,
|
|
|
|
conversationStarted: state.conversationStarted,
|
2018-04-05 15:08:04 +00:00
|
|
|
activeInput: state.activeTargetInput
|
2018-02-28 16:45:13 +00:00
|
|
|
}),
|
|
|
|
dispatch => ({
|
2018-03-22 10:04:47 +00:00
|
|
|
setFormValue: (field, name) =>
|
|
|
|
dispatch(change('conversation', field, name)),
|
2018-04-05 15:08:04 +00:00
|
|
|
startConversation: () => dispatch({ type: 'START_CONVERSATION' }),
|
|
|
|
setActiveInput: name => dispatch({ type: 'SET_ACTIVE_TARGET_INPUT', name })
|
2018-02-28 16:45:13 +00:00
|
|
|
})
|
|
|
|
)
|
2017-11-15 09:49:55 +00:00
|
|
|
export default class TargetSelection extends Component {
|
|
|
|
render() {
|
2018-04-25 13:22:58 +00:00
|
|
|
let { targets, conversationStarted, colours, activeInput } = this.props
|
|
|
|
this.firstEstimationComplete = activeInput && targets.length > 0
|
2017-11-15 09:49:55 +00:00
|
|
|
return (
|
2018-03-14 17:20:09 +00:00
|
|
|
<div id="targetSelection">
|
2018-03-12 09:38:29 +00:00
|
|
|
<section
|
2018-03-14 17:20:09 +00:00
|
|
|
id="targetsContainer"
|
2018-03-12 09:38:29 +00:00
|
|
|
style={{
|
2018-03-29 10:10:09 +00:00
|
|
|
background: colours.colour,
|
|
|
|
color: colours.textColour
|
2018-03-29 17:26:35 +00:00
|
|
|
}}>
|
2018-03-12 09:38:29 +00:00
|
|
|
{this.renderOutputList()}
|
|
|
|
</section>
|
2018-04-24 16:30:16 +00:00
|
|
|
{!this.firstEstimationComplete && (
|
|
|
|
<h1>
|
|
|
|
<Trans i18nKey="enterSalary">Entrez un salaire mensuel</Trans>
|
|
|
|
</h1>
|
|
|
|
)}
|
2018-02-28 16:45:13 +00:00
|
|
|
|
2018-03-29 17:26:35 +00:00
|
|
|
{this.firstEstimationComplete &&
|
|
|
|
!conversationStarted && (
|
|
|
|
<div id="action">
|
|
|
|
<p>
|
2018-04-24 16:30:16 +00:00
|
|
|
<b>
|
|
|
|
<Trans>Estimation approximative</Trans>
|
|
|
|
</b>{' '}
|
|
|
|
<br />
|
2018-04-30 15:11:32 +00:00
|
|
|
<Trans i18nKey="defaults">pour un CDI non cadre</Trans>
|
2018-03-29 17:26:35 +00:00
|
|
|
</p>
|
|
|
|
<BlueButton onClick={this.props.startConversation}>
|
2018-04-24 08:29:40 +00:00
|
|
|
<Trans>Affiner le calcul</Trans>
|
2018-03-29 17:26:35 +00:00
|
|
|
</BlueButton>
|
|
|
|
</div>
|
|
|
|
)}
|
2018-03-14 17:20:09 +00:00
|
|
|
</div>
|
2017-11-15 09:49:55 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
renderOutputList() {
|
2018-03-29 17:26:35 +00:00
|
|
|
let popularTargets = popularTargetNames.map(
|
2018-04-12 16:25:30 +00:00
|
|
|
curry(findRuleByName)(this.props.flatRules)
|
2018-03-29 17:26:35 +00:00
|
|
|
),
|
2018-04-25 13:45:29 +00:00
|
|
|
{ conversationStarted, activeInput, setActiveInput, targets } = this.props
|
2017-12-20 16:49:58 +00:00
|
|
|
|
2017-11-15 09:49:55 +00:00
|
|
|
return (
|
2017-11-16 17:11:42 +00:00
|
|
|
<div>
|
2018-03-22 17:54:19 +00:00
|
|
|
<ul id="targets">
|
2018-04-25 13:45:29 +00:00
|
|
|
{popularTargets.map(target => (
|
|
|
|
<li key={target.name}>
|
2018-04-26 15:15:08 +00:00
|
|
|
<div className="main">
|
|
|
|
<Header
|
|
|
|
{...{
|
|
|
|
target,
|
|
|
|
conversationStarted,
|
|
|
|
isActiveInput: activeInput === target.dottedName
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<TargetInputOrValue
|
|
|
|
{...{
|
|
|
|
target,
|
|
|
|
targets,
|
|
|
|
firstEstimationComplete: this.firstEstimationComplete,
|
|
|
|
activeInput,
|
|
|
|
setActiveInput,
|
|
|
|
setFormValue: this.props.setFormValue
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
{activeInput === target.dottedName &&
|
|
|
|
!conversationStarted && (
|
|
|
|
<InputSuggestions
|
|
|
|
suggestions={target.suggestions}
|
|
|
|
onFirstClick={value =>
|
|
|
|
this.props.setFormValue(target.dottedName, '' + value)
|
|
|
|
}
|
|
|
|
colouredBackground={true}
|
|
|
|
/>
|
|
|
|
)}
|
2018-03-22 17:54:19 +00:00
|
|
|
</li>
|
2017-12-19 16:09:17 +00:00
|
|
|
))}
|
2018-03-22 17:54:19 +00:00
|
|
|
</ul>
|
2017-11-16 17:11:42 +00:00
|
|
|
</div>
|
2017-11-15 09:49:55 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2018-04-06 10:39:45 +00:00
|
|
|
|
2018-04-25 13:45:29 +00:00
|
|
|
let Header = ({ target, conversationStarted, isActiveInput }) => {
|
2018-04-24 16:30:16 +00:00
|
|
|
return (
|
2018-04-25 13:45:29 +00:00
|
|
|
<span className="header">
|
|
|
|
{conversationStarted && (
|
|
|
|
<ProgressCircle target={target} isActiveInput={isActiveInput} />
|
2018-04-24 16:30:16 +00:00
|
|
|
)}
|
2018-04-09 12:19:48 +00:00
|
|
|
|
2018-04-25 13:45:29 +00:00
|
|
|
<span className="texts">
|
|
|
|
<span className="optionTitle">
|
|
|
|
<Link to={'/règle/' + target.dottedName}>
|
|
|
|
{target.title || target.name}
|
|
|
|
</Link>
|
|
|
|
</span>
|
|
|
|
{!conversationStarted && <p>{target['résumé']}</p>}
|
2018-04-06 10:39:45 +00:00
|
|
|
</span>
|
|
|
|
</span>
|
2018-04-25 13:45:29 +00:00
|
|
|
)
|
|
|
|
}
|
2018-04-06 10:39:45 +00:00
|
|
|
|
2018-03-21 15:12:13 +00:00
|
|
|
let validate = buildValidationFunction(formValueTypes['euros'])
|
2018-03-21 11:02:24 +00:00
|
|
|
let InputComponent = ({ input, meta: { dirty, error } }) => (
|
|
|
|
<span>
|
2018-03-21 15:12:13 +00:00
|
|
|
{dirty && error && <span className="input-error">{error}</span>}
|
2018-03-21 15:21:18 +00:00
|
|
|
<input type="number" {...input} autoFocus />
|
2018-03-21 11:02:24 +00:00
|
|
|
</span>
|
|
|
|
)
|
2018-03-21 17:35:15 +00:00
|
|
|
let TargetInputOrValue = ({
|
2018-04-25 13:45:29 +00:00
|
|
|
target,
|
2018-03-21 11:02:24 +00:00
|
|
|
targets,
|
|
|
|
firstEstimationComplete,
|
|
|
|
activeInput,
|
2018-04-09 12:19:48 +00:00
|
|
|
setActiveInput
|
2018-03-21 11:02:24 +00:00
|
|
|
}) => (
|
|
|
|
<span className="targetInputOrValue">
|
2018-04-25 13:45:29 +00:00
|
|
|
{activeInput === target.dottedName ? (
|
2018-03-21 15:12:13 +00:00
|
|
|
<Field
|
2018-04-25 13:45:29 +00:00
|
|
|
name={target.dottedName}
|
2018-03-21 15:12:13 +00:00
|
|
|
component={InputComponent}
|
|
|
|
type="text"
|
|
|
|
validate={validate}
|
|
|
|
/>
|
2018-03-21 11:02:24 +00:00
|
|
|
) : (
|
2018-04-25 13:45:29 +00:00
|
|
|
<TargetValue {...{ targets, target, activeInput, setActiveInput }} />
|
|
|
|
)}
|
|
|
|
{(firstEstimationComplete || target.question) && (
|
|
|
|
<span className="unit">€</span>
|
2018-03-21 11:02:24 +00:00
|
|
|
)}
|
|
|
|
</span>
|
|
|
|
)
|
2018-03-22 10:04:47 +00:00
|
|
|
|
|
|
|
@connect(
|
|
|
|
() => ({}),
|
|
|
|
dispatch => ({
|
|
|
|
setFormValue: (field, name) => dispatch(change('conversation', field, name))
|
|
|
|
})
|
|
|
|
)
|
|
|
|
class TargetValue extends Component {
|
|
|
|
render() {
|
2018-04-25 13:45:29 +00:00
|
|
|
let {
|
|
|
|
targets,
|
|
|
|
target,
|
|
|
|
setFormValue,
|
|
|
|
activeInput,
|
|
|
|
setActiveInput
|
|
|
|
} = this.props,
|
|
|
|
targetWithValue = targets.find(propEq('dottedName', target.dottedName)),
|
|
|
|
value = targetWithValue && targetWithValue.nodeValue,
|
2018-03-22 10:04:47 +00:00
|
|
|
humanValue = value != null && value.toFixed(0)
|
|
|
|
|
|
|
|
return (
|
|
|
|
<span
|
|
|
|
className={classNames({
|
2018-04-25 13:45:29 +00:00
|
|
|
editable: target.question,
|
|
|
|
attractClick: target.question && targets.length === 0
|
2018-03-22 10:04:47 +00:00
|
|
|
})}
|
|
|
|
onClick={() => {
|
2018-04-25 13:45:29 +00:00
|
|
|
if (!target.question) return
|
2018-03-22 10:04:47 +00:00
|
|
|
if (value != null) {
|
2018-04-25 13:45:29 +00:00
|
|
|
setFormValue(target.dottedName, humanValue + '')
|
2018-03-22 10:04:47 +00:00
|
|
|
setFormValue(activeInput, '')
|
|
|
|
}
|
|
|
|
|
2018-04-25 13:45:29 +00:00
|
|
|
setActiveInput(target.dottedName)
|
2018-03-29 17:26:35 +00:00
|
|
|
}}>
|
2018-03-22 10:04:47 +00:00
|
|
|
<RuleValue value={value} />
|
|
|
|
</span>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|