2019-03-27 17:48:14 +00:00
|
|
|
import classNames from 'classnames'
|
|
|
|
import Controls from 'Components/Controls'
|
|
|
|
import InputSuggestions from 'Components/conversation/InputSuggestions'
|
|
|
|
import withColours from 'Components/utils/withColours'
|
|
|
|
import withLanguage from 'Components/utils/withLanguage'
|
|
|
|
import withSitePaths from 'Components/utils/withSitePaths'
|
|
|
|
import { encodeRuleName } from 'Engine/rules'
|
|
|
|
import { compose, isEmpty, isNil, propEq } from 'ramda'
|
|
|
|
import React, { Component, PureComponent } from 'react'
|
|
|
|
import { withTranslation } 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,
|
|
|
|
flatRulesSelector,
|
|
|
|
nextStepsSelector,
|
|
|
|
noUserInputSelector
|
|
|
|
} from 'Selectors/analyseSelectors'
|
|
|
|
import Animate from 'Ui/animate'
|
|
|
|
import AnimatedTargetValue from 'Ui/AnimatedTargetValue'
|
|
|
|
import { Progress } from '../sites/mycompanyinfrance.fr/layout/ProgressHeader/ProgressHeader'
|
|
|
|
import CurrencyInput from './CurrencyInput/CurrencyInput'
|
|
|
|
import QuickLinks from './QuickLinks'
|
|
|
|
import './TargetSelection.css'
|
2018-06-06 08:22:46 +00:00
|
|
|
|
2019-02-04 09:30:15 +00:00
|
|
|
const MAX_NUMBER_QUESTION = 18
|
2018-11-15 15:21:53 +00:00
|
|
|
export default compose(
|
2019-02-08 11:45:14 +00:00
|
|
|
withTranslation(),
|
2019-01-10 16:49:35 +00:00
|
|
|
withColours,
|
2018-11-14 15:51:37 +00:00
|
|
|
reduxForm({
|
|
|
|
form: 'conversation',
|
|
|
|
destroyOnUnmount: false
|
2018-02-28 16:45:13 +00:00
|
|
|
}),
|
2018-11-14 15:51:37 +00:00
|
|
|
withRouter,
|
|
|
|
connect(
|
|
|
|
state => ({
|
|
|
|
getTargetValue: dottedName =>
|
|
|
|
formValueSelector('conversation')(state, dottedName),
|
|
|
|
analysis: analysisWithDefaultsSelector(state),
|
|
|
|
flatRules: flatRulesSelector(state),
|
2019-02-04 09:30:15 +00:00
|
|
|
progress:
|
|
|
|
(100 * (MAX_NUMBER_QUESTION - nextStepsSelector(state))) /
|
|
|
|
MAX_NUMBER_QUESTION,
|
2018-11-14 15:51:37 +00:00
|
|
|
noUserInput: noUserInputSelector(state),
|
|
|
|
conversationStarted: state.conversationStarted,
|
2019-01-08 11:54:56 +00:00
|
|
|
activeInput: state.activeTargetInput,
|
2019-01-17 10:38:24 +00:00
|
|
|
objectifs: state.simulation?.config.objectifs || []
|
2018-11-14 15:51:37 +00:00
|
|
|
}),
|
|
|
|
dispatch => ({
|
|
|
|
setFormValue: (field, name) =>
|
|
|
|
dispatch(change('conversation', field, name)),
|
|
|
|
setActiveInput: name =>
|
|
|
|
dispatch({ type: 'SET_ACTIVE_TARGET_INPUT', name })
|
|
|
|
})
|
|
|
|
)
|
|
|
|
)(
|
2019-04-02 09:50:59 +00:00
|
|
|
class TargetSelection extends PureComponent {
|
2019-03-27 17:48:14 +00:00
|
|
|
componentDidMount() {
|
|
|
|
const props = this.props
|
|
|
|
const targets = props.analysis ? props.analysis.targets : []
|
|
|
|
// Initialize defaultValue for target that can't be computed
|
2019-04-02 09:50:59 +00:00
|
|
|
|
2019-03-27 17:48:14 +00:00
|
|
|
targets
|
|
|
|
.filter(
|
|
|
|
target =>
|
|
|
|
(!target.formule || isEmpty(target.formule)) &&
|
|
|
|
(!isNil(target.defaultValue) ||
|
|
|
|
!isNil(target.explanation?.defaultValue)) &&
|
|
|
|
!props.getTargetValue(target.dottedName)
|
|
|
|
)
|
|
|
|
|
|
|
|
.forEach(target => {
|
|
|
|
props.setFormValue(
|
|
|
|
target.dottedName,
|
|
|
|
!isNil(target.defaultValue)
|
|
|
|
? target.defaultValue
|
|
|
|
: target.explanation?.defaultValue
|
|
|
|
)
|
|
|
|
})
|
|
|
|
props.setActiveInput(null)
|
|
|
|
}
|
2018-11-14 15:51:37 +00:00
|
|
|
render() {
|
2019-03-04 13:21:15 +00:00
|
|
|
let { colours, noUserInput, analysis, progress } = this.props
|
2019-01-29 17:41:44 +00:00
|
|
|
|
2018-11-14 15:51:37 +00:00
|
|
|
return (
|
|
|
|
<div id="targetSelection">
|
2019-01-17 14:34:44 +00:00
|
|
|
<QuickLinks />
|
2019-03-04 13:21:15 +00:00
|
|
|
{!noUserInput && <Controls controls={analysis.controls} />}
|
2019-02-15 10:33:07 +00:00
|
|
|
<div style={{ height: '10px' }}>
|
|
|
|
<Progress percent={progress} />
|
|
|
|
</div>
|
2018-11-14 15:51:37 +00:00
|
|
|
<section
|
2019-01-23 17:04:22 +00:00
|
|
|
className="ui__ plain card"
|
2018-11-14 15:51:37 +00:00
|
|
|
style={{
|
|
|
|
color: colours.textColour,
|
|
|
|
background: `linear-gradient(
|
2019-02-15 15:01:09 +00:00
|
|
|
60deg,
|
|
|
|
${colours.darkColour} 0%,
|
|
|
|
${colours.colour} 100%
|
|
|
|
)`
|
2018-11-14 15:51:37 +00:00
|
|
|
}}>
|
|
|
|
{this.renderOutputList()}
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2017-11-15 09:49:55 +00:00
|
|
|
|
2018-11-14 15:51:37 +00:00
|
|
|
renderOutputList() {
|
2019-03-25 16:11:28 +00:00
|
|
|
let {
|
2018-11-14 15:51:37 +00:00
|
|
|
conversationStarted,
|
|
|
|
activeInput,
|
|
|
|
setActiveInput,
|
2019-01-08 20:18:04 +00:00
|
|
|
analysis,
|
2019-03-27 17:48:14 +00:00
|
|
|
|
2019-01-10 16:49:35 +00:00
|
|
|
match
|
2018-11-14 15:51:37 +00:00
|
|
|
} = this.props,
|
|
|
|
targets = analysis ? analysis.targets : []
|
2018-06-06 16:17:13 +00:00
|
|
|
|
2018-11-14 15:51:37 +00:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<ul id="targets">
|
2019-03-25 16:11:28 +00:00
|
|
|
{targets
|
|
|
|
.map(target => target.explanation || target)
|
|
|
|
.filter(target => {
|
2019-03-25 15:51:56 +00:00
|
|
|
return (
|
|
|
|
target.isApplicable !== false &&
|
2019-03-25 16:11:28 +00:00
|
|
|
(target.question || target.nodeValue)
|
2019-03-25 15:51:56 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.map(target => (
|
|
|
|
<li
|
|
|
|
key={target.name}
|
|
|
|
className={!target.question ? 'not-editable' : undefined}>
|
2019-03-25 16:11:28 +00:00
|
|
|
<Animate.appear alreadyPresent={!target.nodeValue}>
|
|
|
|
<div>
|
|
|
|
<div className="main">
|
|
|
|
<Header
|
|
|
|
{...{
|
|
|
|
match,
|
|
|
|
target,
|
|
|
|
conversationStarted,
|
|
|
|
isActiveInput: activeInput === target.dottedName
|
2019-03-25 15:51:56 +00:00
|
|
|
}}
|
|
|
|
/>
|
2019-03-25 16:11:28 +00:00
|
|
|
{!target.question && (
|
|
|
|
<span
|
|
|
|
style={{
|
|
|
|
flex: 1,
|
|
|
|
borderBottom: '1px dashed #ffffff91',
|
|
|
|
marginLeft: '1rem'
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<TargetInputOrValue
|
|
|
|
{...{
|
|
|
|
target,
|
|
|
|
targets,
|
|
|
|
activeInput,
|
|
|
|
setActiveInput,
|
2019-03-27 17:48:14 +00:00
|
|
|
setFormValue: this.props.setFormValue
|
2019-03-25 16:11:28 +00:00
|
|
|
}}
|
2019-03-25 15:51:56 +00:00
|
|
|
/>
|
2019-03-25 16:11:28 +00:00
|
|
|
</div>
|
|
|
|
{activeInput === target.dottedName &&
|
|
|
|
!conversationStarted && (
|
|
|
|
<Animate.fromTop>
|
|
|
|
<InputSuggestions
|
|
|
|
suggestions={target.suggestions}
|
|
|
|
onFirstClick={value =>
|
|
|
|
this.props.setFormValue(
|
|
|
|
target.dottedName,
|
|
|
|
'' + value
|
|
|
|
)
|
|
|
|
}
|
|
|
|
rulePeriod={target.période}
|
|
|
|
colouredBackground={true}
|
|
|
|
/>
|
|
|
|
</Animate.fromTop>
|
|
|
|
)}
|
|
|
|
</div>
|
2019-03-25 15:51:56 +00:00
|
|
|
</Animate.appear>
|
|
|
|
</li>
|
|
|
|
))}
|
2018-11-14 15:51:37 +00:00
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2017-11-15 09:49:55 +00:00
|
|
|
}
|
2018-11-14 15:51:37 +00:00
|
|
|
)
|
2018-04-06 10:39:45 +00:00
|
|
|
|
2019-01-21 18:19:49 +00:00
|
|
|
let Header = withSitePaths(({ target, conversationStarted, sitePaths }) => {
|
|
|
|
const ruleLink =
|
|
|
|
sitePaths.documentation.index + '/' + encodeRuleName(target.dottedName)
|
|
|
|
return (
|
|
|
|
<span className="header">
|
|
|
|
<span className="texts">
|
|
|
|
<span className="optionTitle">
|
|
|
|
<Link to={ruleLink}>{target.title || target.name}</Link>
|
2018-04-25 13:45:29 +00:00
|
|
|
</span>
|
2019-01-21 18:19:49 +00:00
|
|
|
{!conversationStarted && <p>{target['résumé']}</p>}
|
2018-04-06 10:39:45 +00:00
|
|
|
</span>
|
2019-01-21 18:19:49 +00:00
|
|
|
</span>
|
|
|
|
)
|
|
|
|
})
|
2018-04-06 10:39:45 +00:00
|
|
|
|
2018-07-31 17:26:04 +00:00
|
|
|
let CurrencyField = withColours(props => {
|
2018-04-27 13:51:31 +00:00
|
|
|
return (
|
|
|
|
<CurrencyInput
|
2018-07-31 17:26:04 +00:00
|
|
|
style={{
|
|
|
|
color: props.colours.textColour,
|
|
|
|
borderColor: props.colours.textColour
|
|
|
|
}}
|
2018-04-27 13:51:31 +00:00
|
|
|
className="targetInput"
|
|
|
|
{...props.input}
|
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
)
|
2018-07-31 17:26:04 +00:00
|
|
|
})
|
2018-03-22 10:04:47 +00:00
|
|
|
|
2018-04-27 13:51:31 +00:00
|
|
|
let TargetInputOrValue = withLanguage(
|
2019-02-12 14:59:01 +00:00
|
|
|
({ target, targets, activeInput, setActiveInput, language, noUserInput }) => (
|
2018-04-27 13:51:31 +00:00
|
|
|
<span className="targetInputOrValue">
|
2019-03-27 17:48:14 +00:00
|
|
|
{activeInput === target.dottedName ||
|
|
|
|
!target.formule ||
|
|
|
|
isEmpty(target.formule) ? (
|
2018-04-27 13:51:31 +00:00
|
|
|
<Field
|
|
|
|
name={target.dottedName}
|
2019-03-27 17:48:14 +00:00
|
|
|
{...(target.formule ? { autoFocus: true } : {})}
|
2018-04-27 13:51:31 +00:00
|
|
|
component={CurrencyField}
|
|
|
|
language={language}
|
|
|
|
/>
|
|
|
|
) : (
|
2018-06-06 16:17:13 +00:00
|
|
|
<TargetValue
|
2018-06-29 16:14:00 +00:00
|
|
|
{...{
|
|
|
|
targets,
|
|
|
|
target,
|
|
|
|
activeInput,
|
|
|
|
setActiveInput,
|
2019-02-12 14:59:01 +00:00
|
|
|
noUserInput
|
2018-06-29 16:14:00 +00:00
|
|
|
}}
|
2018-06-06 16:17:13 +00:00
|
|
|
/>
|
2018-04-27 13:51:31 +00:00
|
|
|
)}
|
|
|
|
</span>
|
|
|
|
)
|
|
|
|
)
|
2018-11-14 15:51:37 +00:00
|
|
|
|
|
|
|
const TargetValue = connect(
|
2019-01-10 16:49:35 +00:00
|
|
|
null,
|
2018-08-29 16:38:14 +00:00
|
|
|
dispatch => ({
|
|
|
|
setFormValue: (field, name) => dispatch(change('conversation', field, name))
|
|
|
|
})
|
2018-11-14 15:51:37 +00:00
|
|
|
)(
|
|
|
|
class TargetValue extends Component {
|
|
|
|
render() {
|
2019-03-27 17:48:14 +00:00
|
|
|
let { targets, target } = this.props
|
2019-01-10 16:49:35 +00:00
|
|
|
|
2018-11-14 15:51:37 +00:00
|
|
|
let targetWithValue =
|
|
|
|
targets && targets.find(propEq('dottedName', target.dottedName)),
|
2019-01-10 16:49:35 +00:00
|
|
|
value = targetWithValue && targetWithValue.nodeValue
|
|
|
|
|
2018-11-14 15:51:37 +00:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
className={classNames({
|
|
|
|
editable: target.question,
|
2019-03-27 17:48:14 +00:00
|
|
|
attractClick: target.question && isNil(target.nodeValue)
|
2018-11-14 15:51:37 +00:00
|
|
|
})}
|
|
|
|
tabIndex="0"
|
|
|
|
onClick={this.showField(value)}
|
|
|
|
onFocus={this.showField(value)}>
|
|
|
|
<AnimatedTargetValue value={value} />
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
showField(value) {
|
2019-01-10 16:49:35 +00:00
|
|
|
let { target, setFormValue, activeInput, setActiveInput } = this.props
|
2018-11-14 15:51:37 +00:00
|
|
|
return () => {
|
|
|
|
if (!target.question) return
|
|
|
|
if (value != null)
|
2019-03-27 17:48:14 +00:00
|
|
|
setFormValue(target.dottedName, Math.round(value) + '')
|
2018-07-05 15:33:49 +00:00
|
|
|
|
2019-01-10 16:49:35 +00:00
|
|
|
if (activeInput) setFormValue(activeInput, '')
|
2018-11-14 15:51:37 +00:00
|
|
|
setActiveInput(target.dottedName)
|
|
|
|
}
|
2018-07-05 15:33:49 +00:00
|
|
|
}
|
|
|
|
}
|
2018-11-14 15:51:37 +00:00
|
|
|
)
|
2019-03-27 17:48:14 +00:00
|
|
|
|
|
|
|
// let TargetInput = withLanguage(
|
|
|
|
// ({
|
|
|
|
// target,
|
|
|
|
// targets,
|
|
|
|
// activeInput,
|
|
|
|
// setActiveInput,
|
|
|
|
// language,
|
|
|
|
// setFormValue
|
|
|
|
// }) => (
|
|
|
|
// <span className="targetInputContainer">
|
|
|
|
// {!target.question ? (
|
|
|
|
// <Montant numFractionDigit={0}>{target.nodeValue}</Montant>
|
|
|
|
// ) : activeInput === target.dottedName || !target.formule ? (
|
|
|
|
// <Field
|
|
|
|
// name={target.dottedName}
|
|
|
|
// onFocus={() => {
|
|
|
|
// if (target.dottedName !== activeInput) {
|
|
|
|
// setActiveInput(target.dottedName)
|
|
|
|
// }
|
|
|
|
// }}
|
|
|
|
// component={CurrencyField}
|
|
|
|
// defaultValue={0}
|
|
|
|
// autoFocus={target.formule}
|
|
|
|
// className={classnames('targetInput', {
|
|
|
|
// active: target.dottedName === activeInput
|
|
|
|
// })}
|
|
|
|
// language={language}
|
|
|
|
// />
|
|
|
|
// ) : (
|
|
|
|
// <span style={{ position: 'relative' }}>
|
|
|
|
// <CurrencyInput
|
|
|
|
// onFocus={() => {
|
|
|
|
// if (!target.question) return
|
|
|
|
// if (target.nodeValue)
|
|
|
|
// setFormValue(
|
|
|
|
// target.dottedName,
|
|
|
|
// Math.round(target.nodeValue) + ''
|
|
|
|
// )
|
|
|
|
// const previousActiveTarget = targets.find(
|
|
|
|
// t => t.dottedName === activeInput
|
|
|
|
// )
|
|
|
|
// if (
|
|
|
|
// previousActiveTarget?.formule ||
|
|
|
|
// previousActiveTarget?.explanation?.formule
|
|
|
|
// ) {
|
|
|
|
// setFormValue(activeInput, '')
|
|
|
|
// }
|
|
|
|
// setActiveInput(target.dottedName)
|
|
|
|
// }}
|
|
|
|
// className={classnames('targetInput', {
|
|
|
|
// active: target.dottedName === activeInput
|
|
|
|
// })}
|
|
|
|
// language={language}
|
|
|
|
// value={Math.round(target.nodeValue) || ''}
|
|
|
|
// />
|
|
|
|
// <EvaporatingDifference value={target.nodeValue} />
|
|
|
|
// </span>
|
|
|
|
// )}
|
|
|
|
// </span>
|
|
|
|
// )
|
|
|
|
// )
|