diff --git a/package.json b/package.json index 52654a0b4..bcaf0e6ff 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,9 @@ "react-json-tree": "^0.10.0", "react-redux": "^4.4.5", "react-router": "^2.6.1", + "reduce-reducers": "^0.1.2", "redux": "^3.5.2", + "redux-form": "^6.4.3", "redux-saga": "^0.10.5", "reselect": "^2.5.2", "whatwg-fetch": "^1.0.0" diff --git a/règles/rémunération-travail/cdd/simples/CIF.yaml b/règles/rémunération-travail/cdd/simples/CIF.yaml index 6d75c3c7e..5003b2c85 100644 --- a/règles/rémunération-travail/cdd/simples/CIF.yaml +++ b/règles/rémunération-travail/cdd/simples/CIF.yaml @@ -10,9 +10,10 @@ - CDD poursuivi en CDI # Types de CDD - CDD type saisonnier - - contrat jeune vacances - - contrat aidé # voir la définition précise dans indemnité de fin de contrat - - apprentissage + # TODO Commentés pour le développement de la démo CDD seulement + # - contrat jeune vacances + # - contrat aidé # voir la définition précise dans indemnité de fin de contrat + # - apprentissage formule: linéaire: diff --git a/règles/rémunération-travail/rémunérations-salarié.brouillon.yaml b/règles/rémunération-travail/rémunérations-salarié.brouillon.yaml index 1486cd50d..b3530648d 100644 --- a/règles/rémunération-travail/rémunérations-salarié.brouillon.yaml +++ b/règles/rémunération-travail/rémunérations-salarié.brouillon.yaml @@ -10,6 +10,6 @@ - Variable: assiette cotisations sociales description: L'assiette de la plupart des cotisations sociales pour le calcul des cotisations sociales sur le travail salarié. formule: - somme: ? # donc type numérique + somme: ? # juste pour le type numérique # - salaire brut # - primes etc. diff --git a/source/actions.js b/source/actions.js index e69de29bb..c13d97e0e 100644 --- a/source/actions.js +++ b/source/actions.js @@ -0,0 +1,29 @@ +// The input "conversation" is composed of "steps" +// The state keeps track of which of them have been submitted +// The user can also come back to one of his answers and edit it +export const STEP_ACTION = 'STEP_ACTION' +export function stepAction(name, newState) { + return {type: STEP_ACTION, name, newState} +} + +export const START_CONVERSATION = 'START_CONVERSATION' + +// Reset the form +export const UNSUBMIT_ALL = 'UNSUBMIT_ALL' + + +// Collect the input information from the forms, send them to the simulation engine API +// then update the results in the UI +export const SIMULATION_UPDATE_REQUEST = 'SIMULATION_UPDATE_REQUEST' +export const SIMULATION_UPDATE_SUCCESS = 'SIMULATION_UPDATE_SUCCESS' +export const SIMULATION_UPDATE_FAILURE = 'SIMULATION_UPDATE_FAIL' + +// Modify the UI parts displayed to the user +export const TOGGLE_TOP_SECTION = 'TOGGLE_TOP_SECTION' +export const TOGGLE_ADVANCED_SECTION = 'TOGGLE_ADVANCED_SECTION' + +// The initial request triggers the display of results based on default input information (not filled by the user) +export const INITIAL_REQUEST = 'INITIAL_REQUEST' + +export const CHANGE_THEME_COLOUR = 'CHANGE_THEME_COLOUR' +export function changeThemeColour(colour) {return {type: CHANGE_THEME_COLOUR, colour}} diff --git a/source/components/CDD.css b/source/components/CDD.css index 7dce93847..a0b137309 100644 --- a/source/components/CDD.css +++ b/source/components/CDD.css @@ -2,20 +2,22 @@ padding: 2em; } - #sim section { padding: 2em; } #conversation { + margin: 3em auto; + font-size: 120%; + line-height: normal; display: flex; justify-content: space-around; min-height: 10em; margin: 3em 0; + max-width: 80%; } #questions-answers { - background: blue; min-width: 50%; } @@ -25,6 +27,16 @@ } #results { - width: 100%; + width: 90%; background: purple; } + +#results ul { + list-style: none; +} + +#results li { + display: inline-block; + border: 1px solid; + padding: .6em 2em; +} diff --git a/source/components/CDD.js b/source/components/CDD.js index 63cf3cb03..a9f377a63 100644 --- a/source/components/CDD.js +++ b/source/components/CDD.js @@ -1,47 +1,55 @@ import React, { Component } from 'react' -import {analyseSituation, variableType} from '../traverse' import './CDD.css' +import IntroCDD from './IntroCDD' +import Results from './Results' +import {reduxForm, formValueSelector} from 'redux-form' +import {connect} from 'react-redux' +import './conversation/conversation.css' +import {START_CONVERSATION} from '../actions' +@connect(({form: {conversation}}) => ({conversationState: conversation && conversation.values})) +class Aide extends Component { + render() { + return
+ {JSON.stringify(this.props.conversationState)} +
+ } +} +let situationSelector = formValueSelector('conversation') + +@reduxForm( + {form: 'conversation'} +) +@connect(state => ({ + situation: variableName => situationSelector(state, variableName), + steps: state.steps, + themeColours: state.themeColours, + analysedSituation: state.analysedSituation +}), dispatch => ({ + startConversation: () => dispatch({type: START_CONVERSATION}) +})) export default class CDD extends Component { - state = { - situation: {} + componentDidMount() { + this.props.startConversation() } render() { - let [missingVariable] = analyseSituation(this.state.situation) - let type = variableType(missingVariable) + let {steps} = this.props + + let conversation = steps.map(step => + + ) return (
-
-

- Le CDD en France est un contrat d'exception au CDI. On y a donc recours sous certaines conditions seulement. Cet outil vous aidera à respecter ces conditions et à calculer le prix mensuel de l'embauche, qui en dépend, en vous proposant une suite de questions. - - Ici, vous avez le droit de ne pas savoir : certaines questions sont complexes, elles seront toujours accompagnées d'une aide contextuelle. Si ce n'est pas le cas, engueulez-nous* ! -

-

- *: écrivez à contact@contact.contact (on fera mieux après). La loi française est complexe, souvent à raison. Nous ne la changerons pas, mais pouvons la rendre plus transparente. -

-
+
-
e.preventDefault()}> - - -
-
-
- Aide + {conversation}
+
-
- Résultats -
+
) } diff --git a/source/components/HoverDecorator.js b/source/components/HoverDecorator.js new file mode 100644 index 000000000..2d192285d --- /dev/null +++ b/source/components/HoverDecorator.js @@ -0,0 +1,15 @@ +import React, {Component} from 'react' + +export default DecoratedComponent => + class extends Component { + state = { + hover: false, + } + toggleHover = () => + this.setState({hover: !this.state.hover}) + render() { + return + + + } + } diff --git a/source/components/IntroCDD.js b/source/components/IntroCDD.js new file mode 100644 index 000000000..a5cd18c79 --- /dev/null +++ b/source/components/IntroCDD.js @@ -0,0 +1,13 @@ +import React from 'react' + +export default () => +
+

+ Le CDD en France est un contrat d'exception au CDI. On y a donc recours sous certaines conditions seulement. Cet outil vous aidera à respecter ces conditions et à calculer le prix mensuel de l'embauche, qui en dépend, en vous proposant une suite de questions. + + Ici, vous avez le droit de ne pas savoir : certaines questions sont complexes, elles seront toujours accompagnées d'une aide contextuelle. Si ce n'est pas le cas, engueulez-nous* ! +

+

+ *: écrivez à contact@contact.contact (on fera mieux après). La loi française est complexe, souvent à raison. Nous ne la changerons pas, mais pouvons la rendre plus transparente. +

+
diff --git a/source/components/Results.js b/source/components/Results.js new file mode 100644 index 000000000..d664777ca --- /dev/null +++ b/source/components/Results.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' + +export default class Results extends Component { + render() { + let {analysedSituation} = this.props + return ( +
+

Cotisations

+ +
+ ) + } +} diff --git a/source/components/SelectedVariable.css b/source/components/SelectedVariable.css deleted file mode 100644 index 71bbaa475..000000000 --- a/source/components/SelectedVariable.css +++ /dev/null @@ -1,50 +0,0 @@ -#calculable-items>li { - margin-top: 4em; - padding-bottom: 2em; - border-bottom: 1px solid #eee; -} - -.item .left { - display: inline-block; - width: 30%; -} -.item .right { - display: inline-block; - width: 40%; -} -/* Display formulas */ - -.calc { - text-align: center; -} -.calc h3 { - font-weight: 300; - font-size: 100%; - color: #666; - text-transform: uppercase; -} -.linear { - font-size: 130%; -} -.linear .label { - font-size: 70%; - color: #333; - color: #2980b9; -} - -.linear .operator { - margin: 0 1em; - color: #2980b9; - font-size: 150%; -} - -.linear .limit { - margin-top: 1em; -} -.linear .limit .label { - margin-right: 1em; -} - -.linear .base, .calc .rate { - display: inline-block; -} diff --git a/source/components/SelectedVariable.js b/source/components/SelectedVariable.js deleted file mode 100644 index 9dcf75ba5..000000000 --- a/source/components/SelectedVariable.js +++ /dev/null @@ -1,106 +0,0 @@ -import React, { Component } from 'react' -import './SelectedVariable.css' -import TagMap from './TagMap' -import R from 'ramda' - -export default class SelectedVariable extends Component { - render() { - let { - variable: { - name, - first: { - description - }, - tags, - calculable - }, - selectedTags - } = this.props, - - tagsList = R.pluck('tags', calculable), - commonTags = R.tail(tagsList).reduce( - (result, next) => R.intersection(result, R.toPairs(next)), - R.toPairs(R.head(tagsList)) - ), - itemsWithUniqueTags = R.map(item => [item, R.fromPairs(R.difference(R.toPairs(item.tags), commonTags))], calculable) - - - return ( -
-

{name}

-

{description}

- - {/* -
    - {Object.keys(tags) - .filter(name => !selectedTags.find(([n]) => name == n)) - .map(name => -
  • - {name + ': ' + tags[name]} -
  • - )} -
- */} - -
) - } -} - -class Items extends Component { - render() { - let {itemsWithUniqueTags} = this.props - - return ( - - ) - } -} - -let Item = ({item: {linear, marginalRateTaxScale}, tags}) => -
  • -
    - -
    -
    - { linear && - || marginalRateTaxScale && - } -
    -
  • - - -let Linear = ({data: { - base, - limit, - historique -}}) =>
    -

    Calcul linéaire

    -
    -
    -
    base
    -
    {base}
    -
    - - ✕ - -
    -
    Taux
    -
    { - historique[(Object.keys(historique).sort()[0])] - }
    -
    - { limit != null &&
    - dans la limite de : - {limit} -
    } -
    -
    - -let TaxScale = ({data}) =>
    -

    Règle de calcul: barème

    - {JSON.stringify(data)} -
    diff --git a/source/components/TagMap.js b/source/components/TagMap.js deleted file mode 100644 index b84639aa0..000000000 --- a/source/components/TagMap.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react' -import R from 'ramda' - -let TagMap = ({data}) => - - -export default TagMap diff --git a/source/components/TagNavigation.js b/source/components/TagNavigation.js deleted file mode 100644 index 35ce89208..000000000 --- a/source/components/TagNavigation.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react' -import TagMap from './TagMap' - -export default class TagNavigation extends React.Component { - render(){ - let {tagsToSelect, selectedTags, selectTag, resetTags} = this.props - return ( -
    -

    ☛ Explorez par catégorie

    -
    - {selectedTags.length > 0 && -
    - - -
    - } -
      - {tagsToSelect.map(tag => - - )} -
    -
    -
    - ) - } -} - -class Tag extends React.Component { - render(){ - let {tag: {name, choices, number}, selectTag} = this.props - return (
  • - - {name} - - ({number} variable{number > 1 ? 's' : ''}) - - - -
  • ) - } -} - diff --git a/source/components/Variables.js b/source/components/Variables.js deleted file mode 100644 index 72c49e02c..000000000 --- a/source/components/Variables.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react' - -import SelectedVariable from './SelectedVariable' -import colors from './variable-colors.yaml' -console.log(colors.length); -import R from 'ramda' - -function convertHex(hex,opacity){ - let r = parseInt(hex.substring(0,2), 16), - g = parseInt(hex.substring(2,4), 16), - b = parseInt(hex.substring(4,6), 16), - result =`rgba(${r},${g},${b},${opacity})` - - return result -} - -const Variable = ({color, name, selectVariable}) => -
  • selectVariable(name)} > -

    {name}

    -
  • - -export default class Variables extends React.Component { - render(){ - let {variables, selectedTags, selectedVariable, selectVariable} = this.props - console.log('variables prop in set.add(variable), new Set()), // get unique variable names - // variableColors = [...variableSet].reduce((correspondance, v, i) => Object.assign(correspondance, {[v]: colors[i]}), {}) - - console.log('selectedVariable',selectedVariable) - if (selectedVariable != null) - return - - return
      - {variables.map((v, i) => - - )} -
    - } -} diff --git a/source/components/conversation/Conversation.js b/source/components/conversation/Conversation.js new file mode 100644 index 000000000..1df51e339 --- /dev/null +++ b/source/components/conversation/Conversation.js @@ -0,0 +1,124 @@ +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 ( +
    + = 10} + title="Commune" + question="Quelle est la commune de l'embauche ?" + name="codeINSEE" /> + + + + + + + + + + + = 249 && steps.get('tauxRisque')} + name="pourcentage_alternants" /> + + + + + + + + + + Merci. N'hésitez pas à partager le simulateur ! + + } /> +