👽 Modifier la langue des règles dynamiquement

pull/188/head
Laurent Bossavit 2018-03-29 13:38:55 +02:00 committed by Mael
parent b5b663c0dd
commit 76acc8ed27
9 changed files with 62 additions and 31 deletions

View File

@ -34,3 +34,4 @@ export function changeThemeColour(colour) {
}
export const EXPLAIN_VARIABLE = 'EXPLAIN_VARIABLE'
export const CHANGE_LANG = 'CHANGE_LANG'

View File

@ -8,10 +8,12 @@ import { withRouter } from 'react-router'
import './Results.css'
import RuleValueVignette from './rule/RuleValueVignette'
import ProgressTip from 'Components/ProgressTip'
import { findRuleByDottedName } from 'Engine/rules.js'
@withRouter
@connect(state => ({
analysis: state.analysis,
flatRules: state.flatRules,
targetName: state.targetName,
conversationStarted: !isEmpty(state.form),
conversationFirstAnswer: path(['form', 'conversation', 'values'])(state),
@ -22,7 +24,11 @@ import ProgressTip from 'Components/ProgressTip'
@translate()
export default class Results extends Component {
render() {
let { analysis, conversationStarted, done, themeColours } = this.props
let { flatRules, analysis, conversationStarted, done, themeColours } = this.props
let withFlatRule = rule => ({
...rule,
flatRule: findRuleByDottedName(flatRules, rule.dottedName)
})
if (!analysis) return null
@ -44,7 +50,7 @@ export default class Results extends Component {
{targets.map(rule => (
<li key={rule.nom} style={textStyle}>
<RuleValueVignette
{...rule}
{...withFlatRule(rule)}
conversationStarted={conversationStarted}
/>
</li>

View File

@ -18,7 +18,7 @@ import { Namespace } from './rule/Rule'
@connect(state => ({
situationGate: state.situationGate,
parsedRules: state.parsedRules,
flatRules: state.flatRules,
analysis: state.analysis
}))
export default class RulePage extends Component {
@ -35,23 +35,23 @@ export default class RulePage extends Component {
}
}
setRule(name) {
let { parsedRules, situationGate } = this.props,
let { flatRules, situationGate } = this.props,
decodedRuleName = decodeRuleName(name)
if (decodedRuleName.includes(' . ')) {
let rule = findRuleByDottedName(parsedRules, decodedRuleName)
let rule = findRuleByDottedName(flatRules, decodedRuleName)
this.rule =
rule &&
head(analyse(parsedRules, rule.dottedName)(situationGate).targets)
head(analyse(flatRules, rule.dottedName)(situationGate).targets)
this.multipleMatchingRules = false
return
}
let ruleName = nameLeaf(decodeRuleName(name)),
rules = findRulesByName(parsedRules, ruleName)
rules = findRulesByName(flatRules, ruleName)
if (!rules.length) return null
if (rules.length > 1) this.multipleMatchingRules = rules
this.rule = head(
analyse(parsedRules, head(rules).dottedName)(situationGate).targets
analyse(flatRules, head(rules).dottedName)(situationGate).targets
)
}
render() {

View File

@ -7,7 +7,6 @@ import { withRouter, Redirect } from 'react-router-dom'
import classNames from 'classnames'
import { START_CONVERSATION } from '../actions'
import {
rules,
findRuleByName,
findRule,
findRuleByDottedName,
@ -34,7 +33,8 @@ import Explanation from 'Components/Explanation'
done: state.done,
nextSteps: state.nextSteps,
inputInversions: formValueSelector('conversation')(state, 'inversions'),
analysis: state.analysis
analysis: state.analysis,
flatRules: state.flatRules
}),
dispatch => ({
startConversation: (targetNames, fromScratch = false) =>
@ -51,6 +51,7 @@ export default class extends Component {
let {
match: { params: { targets: encodedTargets } },
targetNames: pastTargetNames,
flatRules,
resetFormField
} = this.props,
targetNames = encodedTargets.split('+').map(decodeRuleName)
@ -58,7 +59,7 @@ export default class extends Component {
this.targetNames = targetNames
this.targetRules = reject(isNil)(
targetNames.map(name => findRule(rules, name))
targetNames.map(name => findRule(flatRules, name))
)
this.targetRules.map(({ dottedName }) => resetFormField(dottedName))
@ -74,6 +75,7 @@ export default class extends Component {
if (this.targetRules.length == 0) return <Redirect to="/404" />
let {
flatRules,
foldedSteps,
currentQuestion,
situationGate,
@ -105,13 +107,13 @@ export default class extends Component {
reinitalise,
currentQuestion:
currentQuestion &&
this.buildStep({ unfolded: true })(
this.buildStep({ unfolded: true, flatRules })(
situationGate,
this.targetNames,
inputInversions
)(currentQuestion),
foldedSteps: map(
this.buildStep({ unfolded: false })(
this.buildStep({ unfolded: false, flatRules })(
situationGate,
this.targetNames,
inputInversions
@ -133,18 +135,18 @@ export default class extends Component {
)
}
buildStep = ({ unfolded }) => (
buildStep = ({ unfolded, flatRules }) => (
situationGate,
targetNames,
inputInversions
) => question => {
let step = makeQuestion(rules, targetNames)(question)
let step = makeQuestion(flatRules, targetNames)(question)
let fieldName =
(inputInversions &&
path(step.dottedName.split('.'), inputInversions)) ||
step.dottedName,
fieldTitle = findRuleByDottedName(rules, fieldName).title
fieldTitle = findRuleByDottedName(flatRules, fieldName).title
return (
<step.component

View File

@ -9,7 +9,7 @@ import BlueButton from './BlueButton'
export let salaries = ['salaire net', 'salaire de base', 'salaire total']
@connect(state => ({
parsedRules: state.parsedRules,
flatRules: state.flatRules,
}))
@translate()
export default class TargetSelection extends Component {
@ -37,9 +37,9 @@ export default class TargetSelection extends Component {
}
renderOutputList() {
let { parsedRules } = this.props,
let { flatRules } = this.props,
popularTargets = [...salaries, 'aides employeur différées'].map(
curry(findRuleByName)(parsedRules)
curry(findRuleByName)(flatRules)
),
{ targets } = this.state,
textColourOnWhite = this.props.themeColours.textColourOnWhite,

View File

@ -6,6 +6,7 @@ import { Link } from 'react-router-dom'
import screenfull from 'screenfull'
import { connect } from 'react-redux'
import { withRouter } from 'react-router'
import { CHANGE_LANG } from '../../actions'
@withRouter
@connect(state => ({
@ -102,6 +103,12 @@ let Links = ({ toggle }) => (
@withRouter
@translate()
@connect(
state => {},
dispatch => ({
changeLanguage: (lang) => dispatch({ type: CHANGE_LANG, lang })
})
)
export class Footer extends Component {
static contextTypes = {
i18n: PropTypes.object.isRequired
@ -109,6 +116,7 @@ export class Footer extends Component {
render() {
let { i18n } = this.context
let changeLanguage = lng => {
this.props.changeLanguage(lng)
i18n.changeLanguage(lng)
}
let appMode = ['/simu', '/regle'].find(t =>

View File

@ -10,7 +10,7 @@ import Helmet from 'react-helmet'
import { createMarkdownDiv } from 'Engine/marked'
import Destinataire from './Destinataire'
import { Link } from 'react-router-dom'
import { findRuleByNamespace, encodeRuleName } from 'Engine/rules'
import { findRuleByNamespace, encodeRuleName, findRuleByDottedName } from 'Engine/rules'
import withColours from '../withColours'
import SearchButton from 'Components/SearchButton'
@ -18,14 +18,16 @@ import SearchButton from 'Components/SearchButton'
@connect(state => ({
form: state.form,
rules: state.parsedRules,
flatRules: state.flatRules,
currentExample: state.currentExample
}))
export default class Rule extends Component {
render() {
let { form, rule, currentExample, rules } = this.props,
let { form, rule, currentExample, rules, flatRules } = this.props,
flatRule = findRuleByDottedName(flatRules, rule.dottedName),
conversationStarted = !isEmpty(form)
let { type, name, title, description, question, ns } = rule,
let { type, name, title, description, question, ns } = flatRule,
namespaceRules = findRuleByNamespace(rules, rule.dottedName)
return (
@ -53,21 +55,21 @@ export default class Rule extends Component {
rule={rule}
showValues={conversationStarted || currentExample}
/>
{rule.note && (
{flatRule.note && (
<section id="notes">
<h3>Note: </h3>
{createMarkdownDiv(rule.note)}
{createMarkdownDiv(flatRule.note)}
</section>
)}
<Examples
currentExample={currentExample}
situationExists={conversationStarted}
rule={rule}
rule={flatRule}
/>
{!isEmpty(namespaceRules) && (
<NamespaceRulesList {...{ rule, namespaceRules }} />
<NamespaceRulesList {...{ flatRule, namespaceRules }} />
)}
{this.renderReferences(rule)}
{this.renderReferences(flatRule)}
</section>
<ReportError />
</div>

View File

@ -11,11 +11,12 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
export default ({
name,
type,
title,
conversationStarted,
flatRule,
nodeValue: ruleValue
}) =>
do {
debugger;
let unsatisfied = ruleValue == null,
irrelevant = ruleValue == 0,
number = typeof ruleValue == 'number' && ruleValue > 0
@ -29,7 +30,7 @@ export default ({
>
<Link to={'/règle/' + encodeRuleName(name)}>
<div className="rule-box">
<span className="rule-name">{title}</span>
<span className="rule-name">{flatRule.title}</span>
<RuleValue
{...{ unsatisfied, irrelevant, conversationStarted, ruleValue }}
/>

View File

@ -28,7 +28,8 @@ import {
STEP_ACTION,
START_CONVERSATION,
EXPLAIN_VARIABLE,
CHANGE_THEME_COLOUR
CHANGE_THEME_COLOUR,
CHANGE_LANG
} from './actions'
import { analyseMany, parseAll } from 'Engine/traverse'
@ -66,6 +67,16 @@ export let reduceSteps = (tracker, flatRules, answerSource) => (
state.parsedRules = parseAll(flatRules)
}
// TODO
if (action.type == CHANGE_LANG) {
if (action.lang == 'fr') { flatRules = rulesFr }
else flatRules = rules
return {
...state,
flatRules
}
}
if (
![START_CONVERSATION, STEP_ACTION, 'USER_INPUT_UPDATE'].includes(
action.type
@ -222,5 +233,5 @@ export default reduceReducers(
currentExample
}),
// cross-cutting concerns because here `state` is the whole state tree
reduceSteps(ReactPiwik, rules, formatInputs(rules, formValueSelector))
reduceSteps(ReactPiwik, rules, formatInputs(rulesFr, formValueSelector))
)