[cdd] Affichage des • d'aide seulement quand l'aide existe

pull/6/head
Mael Thomas 2017-02-09 18:15:25 +01:00
parent 39c018ea54
commit 5427ac7181
16 changed files with 122 additions and 97 deletions

View File

@ -7,7 +7,9 @@
référence: https://fr.wikipedia.org/wiki/Contrat_de_travail_%C3%A0_dur%C3%A9e_d%C3%A9termin%C3%A9e_en_France
# TODO: règle de type : il faut q'un motif et une durée soient sélectionnés pour qu'un contrat soit un CDD. Cela revient à dire que les variables CDD et motif sont obligatoires *dans le contexte* de leur attache
- Variable: durée
- Variable: durée contrat
titre: durée du contrat
question: Quelle est la durée du contrat ?
attache: Salariat . CDD
contrainte: période
description: Durée du contrat de travail
@ -98,6 +100,7 @@
- Variable: événements
attache: Salariat . CDD
question: Pensez-vous être confronté à un de ces évéments ?
description: Certains événements impactent le prix d'un CDD
# au lieu de lister tous les cas, l'alternative est de simplement indiquer qu'ils sont exclusifs,
# et les identifier dynamiquement par leur attribut "attache" :
@ -141,6 +144,7 @@
- Variable: complément formation professionnelle employeur
titre: Complément de formation offert par l'employeur
titre: Complément de formation professionnelle offert par l'employeur
question: L'employeur s'engage-t-il à verser un complément de formation professionnelle ?
attache: Salariat . CDD
description: L'employeur s'engage à fournir une formation professionnelle, ce qui le dispense de la cotisation CIF CDD
description: L'employeur peut s'engager à fournir un complément de formation professionnelle. Cela le dispensera de l'obligation de payer la cotisation CIF CDD

View File

@ -1,6 +1,7 @@
- Variable: contrat aidé
attache: Salariat
question: Est-ce un contrat aidé ?
choix exclusifs:
- contrat unique insertion
- emploi avenir

View File

@ -11,6 +11,8 @@
- Variable: salaire de base
attache: Salariat
question: Quel est le salaire de base ?
description: Le salaire de base est le salaire régulier présent dans le contrat. Des primes viendront éventuellement le compléter, on parlera alors de salaire brut.
contrainte: nombre positif
- Variable: Salaire brut

View File

@ -7,7 +7,7 @@
description: Majoration des contributions patronales dassurance chômage pour les contrats à durée déterminée courts (CDD)
non applicable si:
l'une de ces conditions:
- Salariat . CDD . durée > 3
- Salariat . CDD . durée contrat > 3
- Salariat . CDD . événements . CDD poursuivi en CDI
formule:
linéaire:
@ -15,10 +15,10 @@
taux:
logique numérique:
Salariat . CDD . motif . accroissement temporaire activité:
Salariat . CDD . durée <= 1: 3% # TODO 1 mois, pas 1 rien, évidemment
Salariat . CDD . durée <= 3: 1.5%
Salariat . CDD . durée contrat <= 1: 3% # TODO 1 mois, pas 1 rien, évidemment
Salariat . CDD . durée contrat <= 3: 1.5%
Salariat . CDD . motif . usage:
Salariat . CDD . durée <= 3: 0.5%
Salariat . CDD . durée contrat <= 3: 0.5%

View File

@ -6,7 +6,7 @@ rules:
- 2
- unix
semi:
- 2
- 1
- never
no-unused-vars: 1
no-console: 1

View File

@ -29,4 +29,4 @@ export const CHANGE_THEME_COLOUR = 'CHANGE_THEME_COLOUR'
export function changeThemeColour(colour) {return {type: CHANGE_THEME_COLOUR, colour}}
export const EXPLAIN_TERM = 'EXPLAIN_TERM'
export const EXPLAIN_VARIABLE = 'EXPLAIN_VARIABLE'

39
source/components/Aide.js Normal file
View File

@ -0,0 +1,39 @@
import React, {Component} from 'react'
import {connect} from 'react-redux'
import {findRuleByName} from '../engine/rules'
@connect(
state =>
({explained: state.explainedVariable})
)
export default class Aide extends Component {
render() {
let {explained} = this.props
if (!explained) return <section id="help" />
let rule = findRuleByName(explained),
text = rule.description || rule.titre
let possibilities = rule['choix exclusifs']
return (
<section id="help" className="active">
<p>
{text}
</p>
{ possibilities &&
<p>
{possibilities.length} possibilités :
<ul>
{possibilities.map(p =>
<li key={p}>{p}</li>
)}
</ul>
</p>
}
</section>
)
}
}

View File

@ -35,6 +35,7 @@
}
#sim #help {
box-shadow: -1px 1px 15px 1px #eee;
border: 1px solid;
border-radius: 2px;
border-color: #ccc;

View File

@ -6,41 +6,9 @@ import {reduxForm, formValueSelector} from 'redux-form'
import {connect} from 'react-redux'
import './conversation/conversation.css'
import {START_CONVERSATION} from '../actions'
import {findRuleByName} from '../engine/rules'
import Aide from './Aide'
@connect(({form: {conversation}, steps, explainTerm}) => ({conversationState: conversation && conversation.values, steps, explainTerm}))
class Aide extends Component {
render() {
let {steps, conversationState, explainTerm} = this.props
if (!steps.length) return null
let [{dependencyOfVariables, helpText}] = steps
if (!explainTerm) return <section id="help" />
let rule = findRuleByName(explainTerm),
text = rule.description || rule.titre
let possibilities = rule['choix exclusifs']
return (
<section id="help" className="active">
<p>
{text}
</p>
{ possibilities &&
<p>
{possibilities.length} possibilités :
<ul>
{possibilities.map(p =>
<li key={p}>{p}</li>
)}
</ul>
</p>
}
</section>
)
}
}
let situationSelector = formValueSelector('conversation')
@reduxForm(

View File

@ -1,4 +1,4 @@
.term.defined .icon{
.explicable .icon{
text-align: center;
width: 1.3em;
line-height: 1.3em;
@ -9,12 +9,12 @@
border: 1px solid transparent;
}
.term.defined:hover .icon {
.explicable:hover .icon {
opacity: 1;
border-color: white;
}
.term.defined .icon:hover {
.explicable .icon:hover {
opacity: 1;
background: white;
color: #4A89DC;

View File

@ -0,0 +1,39 @@
import React from 'react'
import classNames from 'classnames'
import './Explicable.css'
import HoverDecorator from '../HoverDecorator'
import {connect} from 'react-redux'
import {EXPLAIN_VARIABLE} from '../../actions'
import {findRuleByName} from '../../engine/rules'
@connect(null, dispatch => ({
explain: variableName => dispatch({type: EXPLAIN_VARIABLE, variableName})
}))
@HoverDecorator
export default class Explicable extends React.Component {
render(){
let
{name, hover, label, explain} = this.props,
rule = findRuleByName(name)
// Rien à expliquer ici, ce n'est pas une règle
if (!rule) return <span>{label}</span>
let ruleLabel = rule.titre || rule.name
// Rien à expliquer ici, il n'y a pas de champ description dans la règle
if (!rule.description && !rule['choix exclusifs']) return <span>{ruleLabel}</span>
return (
<span
className={classNames('explicable')} >
{ruleLabel}
<span
className="icon"
onClick={e => {e.preventDefault(); e.stopPropagation(); explain(name)}}>
{ hover ? '' : '•' }</span>
</span>
)
}
}

View File

@ -1,32 +1,29 @@
import React, {Component} from 'react'
import {connect} from 'react-redux'
import {FormDecorator} from './FormDecorator'
import {answer, answered} from './userAnswerButtonStyle'
import HoverDecorator from '../HoverDecorator'
import Term from './Term'
import {EXPLAIN_TERM} from '../../actions'
import Explicable from './Explicable'
import R from 'ramda'
@connect(null, dispatch => ({
explainTerm: term => () => dispatch({type: EXPLAIN_TERM, term})
}))
@HoverDecorator
class RadioLabel extends Component {
render() {
let {choice: {value, label}, input, submit, hover, themeColours, explainTerm} = this.props,
let {value, label, input, submit, hover, themeColours} = this.props,
// value = R.when(R.is(Object), R.prop('value'))(choice),
labelStyle =
Object.assign(
(value === input.value || hover) ? answered(themeColours) : answer(themeColours),
)
return (
<label
<label key={value}
style={labelStyle}
className="radio" >
<input
type="radio" {...input} onClick={submit}
value={value} checked={value === input.value ? 'checked' : ''} />
<Term label={label} defined={true} explain={explainTerm(value)}/>
<Explicable name={value} label={label}/>
</label>
)
}
@ -46,8 +43,10 @@ export default class Question extends Component {
return (
<span>
{ choices.map((choice) =>
<RadioLabel key={choice.value} {...{choice, input, submit, themeColours}}/>
{ choices.map((choice) => do {
let {value, label} = R.is(String)(choice) ? {value: choice, label: null} : choice;
<RadioLabel key={value} {...{value, label, input, submit, themeColours}}/>
}
)}
</span>
)

View File

@ -1,22 +0,0 @@
import React from 'react'
import classNames from 'classnames'
import './Term.css'
import HoverDecorator from '../HoverDecorator'
@HoverDecorator
export default class Term extends React.Component {
render(){
let {label, defined, hover, explain} = this.props
return (
<span
className={classNames('term', {defined})}
>
{label}
<span
className="icon"
onClick={e => {e.preventDefault(); e.stopPropagation(); explain()}}>
{ hover ? '' : '•' }</span>
</span>
)
}
}

View File

@ -1,7 +1,7 @@
export let constructStepMeta = ({dottedName, name, description}) => ({
export let constructStepMeta = ({question, dottedName, name}) => ({
// name: dottedName.split(' . ').join('.'),
name: dottedName,
question: description || name,
question: question || name,
title: name,
dependencyOfVariables: ['chai pas'],
visible: true,

View File

@ -42,10 +42,10 @@ let [rules, entityRules] =
/****************************************
Méthodes de recherche d'une règle */
export let findRuleByName = search => console.log('search', search) ||
export let findRuleByName = search =>
[...rules, ...entityRules]
.map(enrichRule)
.find( ({name}) => console.log('name', name) ||
.find( ({name}) =>
name === search
)

View File

@ -9,7 +9,7 @@ import Question from './components/conversation/Question'
import Input from './components/conversation/Input'
import RhetoricalQuestion from './components/conversation/RhetoricalQuestion'
import { STEP_ACTION, UNSUBMIT_ALL, START_CONVERSATION, EXPLAIN_TERM} from './actions'
import { STEP_ACTION, UNSUBMIT_ALL, START_CONVERSATION, EXPLAIN_VARIABLE} from './actions'
import R from 'ramda'
import {findGroup, findRuleByDottedName, dottedName, parentName} from './engine/rules'
@ -35,9 +35,9 @@ function themeColours(state = computeThemeColours(), {type, colour}) {
let situationGate = state =>
name => formValueSelector('conversation')(state, name)
function explainTerm(state = null, {type, term}) {
if (type == EXPLAIN_TERM)
return term
function explainedVariable(state = null, {type, variableName}) {
if (type == EXPLAIN_VARIABLE)
return variableName
else return state
}
@ -54,7 +54,7 @@ export default reduceReducers(
themeColours,
explainTerm
explainedVariable
}),
// cross-cutting concerns because here `state` is the whole state tree
(state, action) => {
@ -122,17 +122,11 @@ export default reduceReducers(
constructStepMeta(group),
{
component: Question,
choices: group['choix exclusifs'].map(name => {
let rule = findRuleByDottedName(
group.dottedName + ' . ' + name
)
return {
value: rule.name,
label: rule && rule.titre || name
}
}).concat([{value: 'aucun', label: 'Aucun'}]),
choices:
group['choix exclusifs'].concat(
[{value: 'aucun', label: 'Aucun'}]
),
// defaultValue: 'Non',
helpText: 'Choisissez une réponse'
}
)]
])