🐛 Les saisies numériques ont maintenant le bon format
Solution pratique mais pas élégantes aux formats d'entréepull/6/head
parent
465438ee1c
commit
4886f0ca1c
|
@ -26,7 +26,7 @@
|
|||
[Cliquez ici](https://www.service-public.fr/professionnels-entreprises/vosdroits/F31211) pour connaître la durée maximale d'un CDD.
|
||||
références:
|
||||
Durée maximale d'un CDD (service-public.fr): https://www.service-public.fr/professionnels-entreprises/vosdroits/F31211
|
||||
format: période
|
||||
format: mois
|
||||
suggestions:
|
||||
18 mois: 18
|
||||
1 an: 12
|
||||
|
@ -38,7 +38,7 @@
|
|||
titre: Congés non pris
|
||||
question: Combien de jours de congés ne seront pas pris ?
|
||||
description: Combien de jours de congés ne pourront être pris par l'employé, du fait de la durée de son CDD. En jours ouvrés, par rapport aux 25 jours de congés légaux annuels.
|
||||
format: nombre positif
|
||||
format: jours
|
||||
suggestions:
|
||||
3 / 25: 3
|
||||
10 / 25: 10
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
nom: salaire de base
|
||||
question: Quel est le salaire de base ?
|
||||
description: Le salaire de base est le salaire brut régulier inscrit dans le contrat. C'est le salaire de négociation entre le salarié et l'employeur. Des primes viendront éventuellement le compléter, on parlera alors de salaire brut.
|
||||
format: nombre positif
|
||||
format: euros
|
||||
suggestions:
|
||||
salaire médian: 2300
|
||||
SMIC: 1480
|
||||
|
@ -34,13 +34,13 @@
|
|||
nom: salaire brut
|
||||
titre: Salaire brut
|
||||
question: Quel est le salaire brut ?
|
||||
description: |
|
||||
description: |
|
||||
C'est le salaire de négociation du contrat de travail en France.
|
||||
|
||||
Il peut être vu comme :
|
||||
- la somme du salaire net et des cotisations sociales salariales retenues sur le bulletin de paie d'un salarié
|
||||
- ou comme les sommes perçues par le salarié au titre de son contrat de travail, avant retenues sociales et fiscales.
|
||||
format: nombre positif
|
||||
format: euros
|
||||
# TODO En attendant que l'UI devienne plus intelligente, c'est confondu avec le salaire de base.
|
||||
# intelligente : il faudrait demander : `salaire brut`, puis un bouton `qu'est-ce que c'est` pour nous guider et décortiquer la formule
|
||||
# formule:
|
||||
|
|
|
@ -1,100 +0,0 @@
|
|||
import React, {Component} from 'react'
|
||||
import './CDD.css'
|
||||
import Results from './Results'
|
||||
import {reduxForm, formValueSelector} from 'redux-form'
|
||||
import {connect} from 'react-redux'
|
||||
import './conversation/conversation.css'
|
||||
import {START_CONVERSATION} from '../actions'
|
||||
import Aide from './Aide'
|
||||
import PageTypeIcon from './PageTypeIcon'
|
||||
|
||||
let situationSelector = formValueSelector('conversation')
|
||||
|
||||
@reduxForm({form: 'conversation', destroyOnUnmount: false})
|
||||
@connect(
|
||||
state => ({
|
||||
situation: variableName => situationSelector(state, variableName),
|
||||
foldedSteps: state.foldedSteps,
|
||||
unfoldedSteps: state.unfoldedSteps,
|
||||
themeColours: state.themeColours,
|
||||
analysedSituation: state.analysedSituation,
|
||||
}),
|
||||
dispatch => ({
|
||||
startConversation: rootVariable => dispatch({type: START_CONVERSATION, rootVariable}),
|
||||
}),
|
||||
)
|
||||
export default class CDD extends Component {
|
||||
componentDidMount() {
|
||||
// C'est ici que la génération du formulaire, et donc la traversée des variables commence
|
||||
this.props.startConversation('surcoût CDD')
|
||||
}
|
||||
render() {
|
||||
let {foldedSteps, unfoldedSteps, situation} = this.props
|
||||
|
||||
return (
|
||||
<div id="sim">
|
||||
<PageTypeIcon type="simulation" />
|
||||
<h1>Simulateur CDD</h1>
|
||||
<div id="conversation">
|
||||
<div id="questions-answers">
|
||||
<div id="foldedSteps">
|
||||
{foldedSteps
|
||||
.map(step => (
|
||||
<step.component
|
||||
key={step.name}
|
||||
{...step}
|
||||
step={step}
|
||||
answer={situation(step.name)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div id="unfoldedSteps">
|
||||
{unfoldedSteps.map(step => (
|
||||
<step.component
|
||||
key={step.name}
|
||||
{...step}
|
||||
step={step}
|
||||
unfolded={true}
|
||||
answer={situation(step.name)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{unfoldedSteps.length == 0 &&
|
||||
<div id="fin">
|
||||
<img src={require('../images/fin.png')} />
|
||||
<p>
|
||||
Nous n'avons plus de questions : votre simulation est terminée.
|
||||
</p>
|
||||
<p>
|
||||
Cliquez sur les obligations en bas pour comprendre vos résultats.
|
||||
</p>
|
||||
<p>
|
||||
Une remarque ?
|
||||
<a href="mailto:contact@embauche.beta.gouv.fr">
|
||||
Écrivez-nous
|
||||
</a>
|
||||
{' '}
|
||||
<i
|
||||
style={{cursor: 'pointer'}}
|
||||
className="fa fa-envelope-o"
|
||||
/>
|
||||
{' '}
|
||||
!
|
||||
</p>
|
||||
</div>}
|
||||
</div>
|
||||
<Aide />
|
||||
</div>
|
||||
<Results {...this.props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO Problèmes à résoudre :
|
||||
|
||||
- exprimer la justification du CDD d'usage au delà des secteurs.
|
||||
" l'usage exclut le recours au CDI en raison de la nature de l'activité et du caractère temporaire de ces emplois."
|
||||
+ interdictions explicites (grève et travaux dangereux)
|
||||
|
||||
*/
|
|
@ -1,90 +0,0 @@
|
|||
import React, {Component} from 'react'
|
||||
import './CDD.css'
|
||||
import Results from './Results'
|
||||
import {reduxForm, formValueSelector} from 'redux-form'
|
||||
import {connect} from 'react-redux'
|
||||
import './conversation/conversation.css'
|
||||
import {START_CONVERSATION} from '../actions'
|
||||
import Aide from './Aide'
|
||||
import PageTypeIcon from './PageTypeIcon'
|
||||
|
||||
//TODO fusionner SimulationCDD & SimulationNet
|
||||
|
||||
let situationSelector = formValueSelector('conversation')
|
||||
|
||||
@reduxForm({form: 'conversation', destroyOnUnmount: false})
|
||||
@connect(
|
||||
state => ({
|
||||
situation: variableName => situationSelector(state, variableName),
|
||||
foldedSteps: state.foldedSteps,
|
||||
unfoldedSteps: state.unfoldedSteps,
|
||||
themeColours: state.themeColours,
|
||||
analysedSituation: state.analysedSituation,
|
||||
}),
|
||||
dispatch => ({
|
||||
startConversation: rootVariable => dispatch({type: START_CONVERSATION, rootVariable}),
|
||||
}),
|
||||
)
|
||||
export default class SimulationNet extends Component {
|
||||
componentDidMount() {
|
||||
// C'est ici que la génération du formulaire, et donc la traversée des variables commence
|
||||
this.props.startConversation('salaire net')
|
||||
}
|
||||
render() {
|
||||
let {foldedSteps, unfoldedSteps, situation} = this.props
|
||||
|
||||
return (
|
||||
<div id="sim">
|
||||
<PageTypeIcon type="simulation" />
|
||||
<h1>Simulateur salaire net</h1>
|
||||
<div id="conversation">
|
||||
<div id="questions-answers">
|
||||
<div id="foldedSteps">
|
||||
{foldedSteps
|
||||
.map(step => (
|
||||
<step.component
|
||||
key={step.name}
|
||||
{...step}
|
||||
step={step}
|
||||
answer={situation(step.name)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div id="unfoldedSteps">
|
||||
{unfoldedSteps.map(step => (
|
||||
<step.component
|
||||
key={step.name}
|
||||
{...step}
|
||||
step={step}
|
||||
unfolded={true}
|
||||
answer={situation(step.name)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{unfoldedSteps.length == 0 &&
|
||||
<div id="fin">
|
||||
<img src={require('../images/fin.png')} />
|
||||
<p>
|
||||
Nous n'avons plus de questions : votre simulation est terminée.
|
||||
</p><p>
|
||||
Une remarque ?
|
||||
<a href="mailto:contact@embauche.beta.gouv.fr">
|
||||
Écrivez-nous
|
||||
</a>
|
||||
{' '}
|
||||
<i
|
||||
style={{cursor: 'pointer'}}
|
||||
className="fa fa-envelope-o"
|
||||
/>
|
||||
{' '}
|
||||
!
|
||||
</p>
|
||||
</div>}
|
||||
</div>
|
||||
<Aide />
|
||||
</div>
|
||||
<Results {...this.props} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
import React, {Component} from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import Question from '../components/Forms/Question'
|
||||
import Input from '../components/Forms/Input'
|
||||
import SelectCommune from '../components/Forms/SelectCommune'
|
||||
import SelectTauxRisque from '../components/Forms/SelectTauxRisque'
|
||||
import RhetoricalQuestion from '../components/Forms/RhetoricalQuestion'
|
||||
import TextArea from '../components/Forms/TextArea'
|
||||
import Group from '../components/Group'
|
||||
import ResultATMP from '../components/ResultATMP'
|
||||
import {reduxForm, formValueSelector} from 'redux-form'
|
||||
import { percentage } from '../formValueTypes.js'
|
||||
import validate from '../conversation-validate'
|
||||
|
||||
let advancedInputSelector = formValueSelector('advancedQuestions'),
|
||||
basicInputSelector = formValueSelector('basicInput')
|
||||
|
||||
@reduxForm({
|
||||
form: 'advancedQuestions',
|
||||
validate,
|
||||
})
|
||||
@connect(state => ({
|
||||
formValue: (field, simple) => simple ? basicInputSelector(state, field): advancedInputSelector(state, field),
|
||||
steps: state.steps,
|
||||
themeColours: state.themeColours
|
||||
}))
|
||||
class Conversation extends Component {
|
||||
render() {
|
||||
let { formValue, steps, themeColours: {colour, textColour}} = this.props
|
||||
let effectifEntreprise = formValue('effectifEntreprise', 'basicInput')
|
||||
|
||||
/* C'est ici qu'est définie la suite de questions à poser. */
|
||||
return (
|
||||
<div id="conversation">
|
||||
<SelectCommune
|
||||
visible={effectifEntreprise >= 10}
|
||||
title="Commune"
|
||||
question="Quelle est la commune de l'embauche ?"
|
||||
name="codeINSEE" />
|
||||
<Input
|
||||
title="Complémentaire santé"
|
||||
question="Quel est le montant total par salarié de la complémentaire santé obligatoire de l'entreprise ?"
|
||||
visible={effectifEntreprise < 10 || steps.get('codeINSEE')}
|
||||
name="mutuelle" />
|
||||
<Group
|
||||
text="Risques professionnels"
|
||||
visible={steps.get('mutuelle')}
|
||||
foldTrigger="tauxRisque"
|
||||
valueType={percentage}
|
||||
>
|
||||
<Question
|
||||
visible={true}
|
||||
title="Taux de risque connu"
|
||||
question="Connaissez-vous votre taux de risque AT/MP ?"
|
||||
name="tauxRisqueConnu" />
|
||||
<Input
|
||||
title="Taux de risque"
|
||||
question="Entrez votre taux de risque"
|
||||
visible={formValue('tauxRisqueConnu') == 'Oui'}
|
||||
name="tauxRisque" />
|
||||
<Group name="tauxInconnu" visible={formValue('tauxRisqueConnu')== 'Non'}>
|
||||
<SelectTauxRisque
|
||||
visible={true}
|
||||
title="Code de risque sélectionné"
|
||||
question="Quelle est la catégorie de risque de votre entreprise ?"
|
||||
name="selectTauxRisque" />
|
||||
<ResultATMP
|
||||
name="resultATMP"
|
||||
selectedTauxRisque={formValue('selectTauxRisque')}
|
||||
formValue={formValue}
|
||||
{...{steps}}
|
||||
effectif={formValue('effectifEntreprise', 'basicInput')} />
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
<Input
|
||||
title="Pourcentage d'alternants"
|
||||
question="Quel est le pourcentage d'alternants dans votre entreprise ?"
|
||||
visible={effectifEntreprise >= 249 && steps.get('tauxRisque')}
|
||||
name="pourcentage_alternants" />
|
||||
|
||||
<Question
|
||||
visible={
|
||||
(effectifEntreprise < 249 && steps.get('tauxRisque'))
|
||||
|| steps.get('pourcentage_alternants')}
|
||||
title="Régime Alsace-Moselle"
|
||||
question="Le salarié est-il affilié au régime d'Alsace-Moselle ?"
|
||||
name="alsaceMoselle" />
|
||||
|
||||
<Question
|
||||
title="Pénibilité du travail"
|
||||
question="Le salarié est-il exposé à des facteurs de pénibilité au-delà des seuils d'exposition ?"
|
||||
visible={steps.get('alsaceMoselle')}
|
||||
name="penibilite" />
|
||||
|
||||
<Question
|
||||
title="Exonération Jeune Entreprise Innovante"
|
||||
question="Profitez-vous du statut Jeune Entreprise Innovante pour cette embauche ?"
|
||||
visible={steps.get('penibilite')}
|
||||
name="jei" />
|
||||
|
||||
<Question
|
||||
title="Votre avis"
|
||||
question="Votre estimation est terminée. En êtes-vous satisfait ?"
|
||||
visible={steps.get('jei')}
|
||||
name="serviceUtile" />
|
||||
<RhetoricalQuestion
|
||||
visible={formValue('serviceUtile') === ':-)'}
|
||||
name="partage"
|
||||
question={<span>
|
||||
Merci. N'hésitez pas à partager le simulateur !
|
||||
</span>
|
||||
} />
|
||||
<TextArea
|
||||
visible={formValue('serviceUtile') === ':-|'}
|
||||
name="remarque"
|
||||
title="Votre remarque"
|
||||
question={'Que pouvons-nous faire pour l\'améliorer ?'}
|
||||
/>
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
|
||||
export default Conversation
|
|
@ -1,23 +1,36 @@
|
|||
import { number } from './validators'
|
||||
import { number, int } from './validators'
|
||||
|
||||
/*
|
||||
Here are common formats that can be attached to Form components
|
||||
*/
|
||||
|
||||
export let percentage = {
|
||||
let pourcentage = {
|
||||
suffix: '%',
|
||||
human: value => value + ' ' + '%',
|
||||
validator: number
|
||||
}
|
||||
|
||||
export let euro = {
|
||||
let euros = {
|
||||
suffix: '€',
|
||||
human: value => value + ' ' + '€',
|
||||
validator: number
|
||||
}
|
||||
|
||||
export let months = {
|
||||
let mois = {
|
||||
suffix: 'mois',
|
||||
human: value => value + ' ' + 'mois',
|
||||
validator: number
|
||||
validator: int
|
||||
}
|
||||
|
||||
let jours = {
|
||||
suffix: 'jours',
|
||||
human: value => value + ' ' + 'jours',
|
||||
validator: int
|
||||
}
|
||||
|
||||
export default {
|
||||
pourcentage,
|
||||
euros,
|
||||
mois,
|
||||
jours
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import Explicable from '../components/conversation/Explicable'
|
|||
import R from 'ramda'
|
||||
import Question from '../components/conversation/Question'
|
||||
import Input from '../components/conversation/Input'
|
||||
import {euro, months} from '../components/conversation/formValueTypes'
|
||||
import formValueTypes from '../components/conversation/formValueTypes'
|
||||
import {analyseSituation} from './traverse'
|
||||
import {formValueSelector} from 'redux-form'
|
||||
import { STEP_ACTION, START_CONVERSATION} from '../actions'
|
||||
|
@ -189,6 +189,7 @@ export let generateGridQuestions = missingVariables => R.pipe(
|
|||
// )(variant['une possibilité'])
|
||||
// }
|
||||
)
|
||||
|
||||
export let generateSimpleQuestions = missingVariables => R.pipe(
|
||||
R.values, //TODO exploiter ici les groupes de questions de type 'record' (R.keys): elles pourraient potentiellement êtres regroupées visuellement dans le formulaire
|
||||
R.unnest,
|
||||
|
@ -197,10 +198,10 @@ export let generateSimpleQuestions = missingVariables => R.pipe(
|
|||
if (rule == null) console.log(dottedName)
|
||||
return Object.assign(
|
||||
constructStepMeta(rule),
|
||||
rule.format == 'nombre positif' || rule.format == 'période'
|
||||
rule.format != null
|
||||
? {
|
||||
component: Input,
|
||||
valueType: rule.format == 'nombre positif' ? euro : months,
|
||||
valueType: formValueTypes[rule.format],
|
||||
attributes: {
|
||||
inputMode: 'numeric',
|
||||
placeholder: 'votre réponse',
|
||||
|
@ -220,34 +221,3 @@ export let generateSimpleQuestions = missingVariables => R.pipe(
|
|||
)
|
||||
})
|
||||
)
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// Pas de groupe trouvé : ce sont des variables individuelles
|
||||
[R.isNil, () => variables.map(dottedName => {
|
||||
let rule = findRuleByDottedName(dottedName)
|
||||
return Object.assign(constructStepMeta(rule),
|
||||
rule.format == 'nombre positif' ||
|
||||
rule.format == 'période' ?
|
||||
{
|
||||
component: Input,
|
||||
valueType: rule.format == 'nombre positif' ? euro : months,
|
||||
attributes: {
|
||||
inputMode: 'numeric',
|
||||
placeholder: 'votre réponse'
|
||||
},
|
||||
suggestions: rule.suggestions
|
||||
} : {
|
||||
component: Question,
|
||||
choices: [
|
||||
{value: 'non', label: 'Non'},
|
||||
{value: 'oui', label: 'Oui'}
|
||||
]
|
||||
},
|
||||
{
|
||||
objectives: missingVariables[dottedName]
|
||||
}
|
||||
)})],
|
||||
|
||||
*/
|
||||
|
|
|
@ -23,7 +23,7 @@ let evaluateBottomUp = situationGate => startingFragments => {
|
|||
export let evaluateVariable = (situationGate, variableName, format) => {
|
||||
// test rec
|
||||
let value = situationGate(variableName)
|
||||
return R.contains(format)(['nombre positif', 'période'])
|
||||
? (value == undefined ? null : value)
|
||||
return format != null ?
|
||||
(value == undefined ? null : value)
|
||||
: evaluateBottomUp(situationGate)(splitName(variableName))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue