diff --git a/package.json b/package.json index a62b70f93..2a50d6660 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "npm": "^5.3.0", "ramda": "0.24.1", "react": "^16.0.0", + "react-addons-css-transition-group": "^15.6.2", "react-dom": "^16.0.0", "react-helmet": "^5.2.0", "react-redux": "^5.0.6", @@ -30,6 +31,7 @@ "react-scroll": "^1.5.4", "react-select": "^1.0.0-rc.10", "react-select-fast-filter-options": "^0.2.3", + "react-transition-group": "^2.2.1", "react-virtualized": "^9.10.1", "react-virtualized-select": "^3.1.0", "reduce-reducers": "^0.1.2", diff --git a/règles/rémunération-travail/entités/ok/CDD.yaml b/règles/rémunération-travail/entités/ok/CDD.yaml index fdb60f80e..5f7cfad3d 100644 --- a/règles/rémunération-travail/entités/ok/CDD.yaml +++ b/règles/rémunération-travail/entités/ok/CDD.yaml @@ -94,8 +94,6 @@ simulateur: titre: Simulateur CDD sous-titre: Découvrir le surcoût employeur du CDD par rapport au CDI - résultats: Le coût du travail faisant ressortir les cotisations spécifiques au CDD. - indice: Par mois introduction: notes: - icône: fa-handshake-o @@ -104,7 +102,6 @@ - icône: fa-balance-scale texte: Votre contrat ne peut donc avoir ni pour objet ni pour effet de pourvoir durablement un emploi lié à l'activité normale et permanente de l'entreprise. titre: Votre obligation - motivation: Découvrez en quelques clics le montant des obligations liées au CDD # CIF, majoration chômage, indemnité de fin de contrat, indemnité compensatrice des congés payés hypothèses: contrat salarié . type de contrat: CDD diff --git a/règles/rémunération-travail/entités/ok/contrat-salarié.yaml b/règles/rémunération-travail/entités/ok/contrat-salarié.yaml index 6e8b18564..d4ba353f7 100644 --- a/règles/rémunération-travail/entités/ok/contrat-salarié.yaml +++ b/règles/rémunération-travail/entités/ok/contrat-salarié.yaml @@ -194,8 +194,6 @@ titre: Simulateur de coût d'embauche sous-titre: Découvrir le coût d'embauche ou le salaire réel résultats: Le salaire net à partir du brut ou vice-versa, et les cotisations - introduction: - motivation: Découvrez le vrai coût du travail - espace: contrat salarié diff --git a/source/components/HomeEmbauche.js b/source/components/HomeEmbauche.js index b5d23e35c..89d1b81dc 100644 --- a/source/components/HomeEmbauche.js +++ b/source/components/HomeEmbauche.js @@ -34,7 +34,7 @@ export default class HomeEmbauche extends Component {
Nouveau - Simuler le surcoût CDD (beta) + Simuler le surcoût CDD (beta)
diff --git a/source/components/Results.css b/source/components/Results.css index 868478182..97b2e9786 100644 --- a/source/components/Results.css +++ b/source/components/Results.css @@ -1,51 +1,38 @@ - #results { - padding: .1em; - background: #333350; - font-size: 80%; - color: white; - padding: .6em 0; - text-align: center; - width: 100%; - height: 12em; position: fixed; - bottom: 0; - left: 0; - box-shadow: 1px -7px 20px 2px #ccc; + left: 50%; + bottom: 2.5%; + width: 90%; + max-width: 45em; + margin: 0 auto; + padding: 0; + + background: #2975D1; + color: white; + font-size: 120%; + box-shadow: 0px 0px 20px 2px rgba(0, 0, 0, 0.25); opacity: 0; - transform: translateY(12em); + transform: translate(-50%, 12em); transition: transform .5s; transition-delay: .3s; transition-timing-function: cubic-bezier(0, 1.01, 0.24, 1) } #results.show { - transform: translateY(0); + transform: translate(-50%, 0); opacity: 1; } -#results-actions, -#results-titles { - display: inline-block; - float: left; - width: 18%; - margin: 0; - padding: 0 0 0 2em; -} - #results-actions { - display: flex; - align-items: center; - justify-content: space-around; - height: 100%; + background: #333350; } #toSimulation { - font-size: 190%; + font-size: 150%; color: white; - background: #4A89DC; - padding: .6em .6em; + margin-left: .6em; + line-height: 1.8em; text-decoration: none; border-radius: .2em; position: relative; @@ -54,82 +41,46 @@ margin-right: .6em; } -#results-titles { - color: white; - line-height: 1.2em; - font-weight: 400; - font-size: 120%; - text-align: left; -} -#results-titles h2 { - font-size: 250%; - margin: .4em 0; -} -#results-titles p { - color: inherit; -} -#results-titles i { - margin: 0 .3em; -} -#resultText { +#results h2 { + margin: .6em; font-weight: 600; - font-size: 100%; + text-align: left; + font-size: 125%; } +#results h2 i { + margin-right: .6em; +} - - +#results h2 small { + opacity: 0.7; + font-size: calc(50% + .2vw); + font-weight: 400; +} +#results h2 span { + font-size: 70%; + margin: 0 .6em +} #results ul { - display: inline-flex; - justify-content: space-around; - height: 100%; - width: 80%; list-style: none; padding-left: 0; - margin: 0; + display: flex; + align-items: center; + flex-wrap: wrap; + height: 70%; + margin: .6em auto 1.2em; } +#results li { + margin: 0 1em 0 2em; + display: inline-block; + width: 100%; +} + @media (max-width: 1280px) { - #results .rule-type { - display: none; - } - #results { - padding: 0; - } - #results-titles { - width: 100%; - text-align: center; - margin-bottom: .6em; - } - #results-titles p { - margin: 0; - margin-right: 3em; - } - #results-titles h2 { - font-size: 150%; - display: none; - } - #results-titles #resultText { - font-size: 120% - } - #results h2 { - margin: 0.3em 1em 0 0; - display: inline-block; - } - #results-titles > p { - display: inline-block; - } - #results-titles #understandTip { - display: none; - } - - #results ul { - width: 100%; - font-size: 90%; - } } diff --git a/source/components/Results.js b/source/components/Results.js index 80d186787..4942d4988 100644 --- a/source/components/Results.js +++ b/source/components/Results.js @@ -34,9 +34,7 @@ export default class Results extends Component { if (!explanation) return null - let onRulePage = R.contains('/regle/')(location.pathname), - hint = analysedSituation.root.simulateur && analysedSituation.root.simulateur.indice - + let onRulePage = R.contains('/regle/')(location.pathname) return (
{onRulePage && conversationStarted ? @@ -46,15 +44,13 @@ export default class Results extends Component { :
-

{hint || "Vos résultats"}:

- {do {let text = R.path(['simulateur', 'résultats'])(analysedSituation.root) - text && -

{text}

- }} +

{explanation.length == 1 ? 'Votre résultat' : 'Vos résultats'}·Cliquez pour comprendre chaque calcul

}
) diff --git a/source/components/Simulateur.css b/source/components/Simulateur.css index 6e7d8771b..b6e8d3711 100644 --- a/source/components/Simulateur.css +++ b/source/components/Simulateur.css @@ -1,5 +1,5 @@ #sim { - padding: 3em 0; /* For the warning message */ + margin: 1% auto; /*background-image: radial-gradient(ellipse at center, white -160%, rgba(255,255,255,0) 100%);*/ /*background-image: radial-gradient(ellipse at center, #4A89DC -160%,#333350 70%);*/ color: #333350; @@ -7,6 +7,9 @@ height: 100%; padding-bottom: 10%; + padding: 1em; + max-width: 50em; + } #sim p { @@ -15,8 +18,7 @@ #sim > h1 { color: inherit; - margin-top: 0; - text-align: center; + margin: 0; font-size: 350%; font-weight: 800; } @@ -24,23 +26,14 @@ #simSubtitle { margin-top: -.5em; - text-align: center; - font-size: 110%; + font-size: 120%; font-weight: 300; margin-bottom: 2.5em; } -#sim .centered { - /*width: 40%;*/ - width: 50em; - max-width: 90%; - margin: 0 auto; -} - #sim .intro { font-style: italic; - font-size: 100%; - margin-bottom: 3%; + font-size: 110%; } #sim .intro > div { margin: 1em 0; @@ -57,13 +50,6 @@ width: 80%; } -#sim .remarks p { - opacity: .9; - padding-left: 1em; - border-left: 10px solid rgba(255, 255, 255, 0.2); - font-style: italic; -} - #sim .action { margin-top: 5%; margin-bottom: 3%; @@ -72,31 +58,30 @@ text-align: center; } -#sim .action button { +#sim .intro button { color: white; display: block; text-align: center; background: #4A89DC; - padding: .6em 1.2em; + padding: .3em 1em; font-size: 140%; - margin: 1em auto; - width: 12em; + margin: 2em auto; + width: 8em; border: none; - box-shadow: 0px 9px 14px 0px rgba(0, 0, 0, 0.1) + box-shadow: 0px 9px 14px 0px rgba(0, 0, 0, 0.1); + opacity: 0.95 } -#sim .action button:hover { +#sim .intro button:hover { box-shadow: none; - opacity: .95; + opacity: 1; } #conversation { - margin: 3em auto; - padding: 0 1em; + margin-top: 6%; font-size: 110%; line-height: normal; min-height: 10em; - max-width: 50em; } @@ -108,14 +93,13 @@ #foldedSteps .header { margin-bottom: 1em; - text-align: center; } #foldedSteps .header h3 { display: inline; } #foldedSteps .header button { font-size: 80%; - color: #4A89DC; + color: #2975D1; border: none; } #foldedSteps .header button i { @@ -126,21 +110,6 @@ #fin { - margin: 0 auto; - width: 80%; - display: flex; - align-items: flex-end; + width: 30em; font-style: italic; } -#fin-text { - width: 50%; - margin-left: 2em; - display: inline-block; -} -#fin p:first-of-type { - font-weight: bold -} -#fin img { - width: 25%; - display: inline-block; -} diff --git a/source/components/Simulateur.js b/source/components/Simulateur.js index 325ce3af6..335355d3e 100644 --- a/source/components/Simulateur.js +++ b/source/components/Simulateur.js @@ -14,7 +14,7 @@ import './Simulateur.css' import {capitalise0} from '../utils' import Conversation from './conversation/Conversation' -import ReactPiwik from './Tracker'; +import ReactPiwik from './Tracker' let situationSelector = formValueSelector('conversation') @@ -34,15 +34,18 @@ let situationSelector = formValueSelector('conversation') resetForm: () => dispatch(reset('conversation')) }) ) -export default class extends React.Component { +export default class extends Component { + state = { + started: false + } componentWillMount() { let { - match: { - params: { - name: encodedName + match: { + params: { + name: encodedName + } } - } - } = this.props, + } = this.props, name = decodeRuleName(encodedName), existingConversation = this.props.foldedSteps.length > 0 @@ -58,12 +61,12 @@ export default class extends React.Component { if (!this.rule.formule) return let - started = !this.props.match.params.intro, - {foldedSteps, extraSteps, unfoldedSteps, situation, situationGate} = this.props, + {started} = this.state, + {foldedSteps, extraSteps, unfoldedSteps, situation, situationGate, themeColours} = this.props, sim = path => R.path(R.unless(R.is(Array), R.of)(path))(this.rule.simulateur || {}), reinitalise = () => { - ReactPiwik.push(['trackEvent', 'restart', '']); + ReactPiwik.push(['trackEvent', 'restart', '']) this.props.resetForm(this.name) this.props.startConversation(this.name) }, @@ -80,8 +83,8 @@ export default class extends React.Component { {sim('sous-titre') &&
{sim('sous-titre')}
} - {sim(['introduction', 'notes']) && -
+ {!started && sim(['introduction', 'notes']) && +
{sim(['introduction', 'notes']).map( ({icône, texte, titre}) =>
@@ -90,27 +93,13 @@ export default class extends React.Component {
)} +
} - { - // Tant que le bouton 'C'est parti' n'est pas cliqué, on affiche l'intro - !started ? -
-
- {createMarkdownDiv(sim(['introduction', 'motivation'])) ||

Simulez cette règle en quelques clics

} - -
-
-

- N'hésitez pas à nous écrire - - ! La loi française est très ciblée, et donc complexe. Nous pouvons la rendre plus transparente. -

-
-
- : } + { (started || !sim(['introduction', 'notes'])) && + + }
) diff --git a/source/components/conversation/Conversation.js b/source/components/conversation/Conversation.js index 0b2bffa76..1818956df 100644 --- a/source/components/conversation/Conversation.js +++ b/source/components/conversation/Conversation.js @@ -11,7 +11,7 @@ import Scroll from 'react-scroll' }) export default class Conversation extends Component { render() { - let {foldedSteps, unfoldedSteps, extraSteps, reinitalise, situation, situationGate} = this.props + let {foldedSteps, unfoldedSteps, extraSteps, reinitalise, situation, situationGate, textColourOnWhite} = this.props Scroll.animateScroll.scrollToBottom() return ( @@ -21,7 +21,7 @@ export default class Conversation extends Component {

Vos réponses

- @@ -37,6 +37,8 @@ export default class Conversation extends Component { ))}
} + {unfoldedSteps.length == 0 && + } { !R.isEmpty(extraSteps) &&
@@ -64,8 +66,9 @@ export default class Conversation extends Component { /> }}
- {unfoldedSteps.length == 0 && - } + {R.isEmpty(unfoldedSteps) && + + }
@@ -73,22 +76,11 @@ export default class Conversation extends Component { } } - -class Conclusion extends Component { - render() { - return ( -
- -
-

- Votre simulation est terminée ! -

-

- N'hésitez pas à modifier vos réponses, ou cliquez sur vos résultats pour comprendre le calcul. -

- -
-
- ) - } -} +let Conclusion = ({ affiner }) => ( +
+

+ Vous pouvez maintenant modifier vos réponses{" "} + {affiner && "ou affiner votre situation"} : vos résultats ci-dessous seront mis à jour. +

+
+) diff --git a/source/components/conversation/Input.js b/source/components/conversation/Input.js index 9f8327feb..f93ae0de9 100644 --- a/source/components/conversation/Input.js +++ b/source/components/conversation/Input.js @@ -53,13 +53,13 @@ export default class Input extends Component { - {this.renderSuggestions()} + {this.renderSuggestions(themeColours)} {inputError && {error}} ) } - renderSuggestions(){ + renderSuggestions(themeColours){ let {setFormValue, submit, suggestions} = this.props.stepProps if (!suggestions) return null return ( @@ -69,7 +69,8 @@ export default class Input extends Component {
  • setFormValue('' + value) && submit() && e.preventDefault()} onMouseOver={() => setFormValue('' + value) && this.setState({suggestedInput: true})} - onMouseOut={() => setFormValue('') && this.setState({suggestedInput: false})}> + onMouseOut={() => setFormValue('') && this.setState({suggestedInput: false})} + style={{color: themeColours.colour}}> {text}
  • )} diff --git a/source/components/conversation/conversation.css b/source/components/conversation/conversation.css index 49507506c..d95880a89 100644 --- a/source/components/conversation/conversation.css +++ b/source/components/conversation/conversation.css @@ -147,7 +147,7 @@ } #foldedSteps { - margin: 2em 0 4em; + margin: 3em 0; } .step.question .variant { @@ -305,13 +305,10 @@ fieldset > .ignore { margin-left: .6em; } .step .inputSuggestions a { - color: #4A89DC; padding: .1em .6em; font-weight: 600; } .step .inputSuggestions a:hover { - background: #4A89DC; - color: white; text-decoration: none; } diff --git a/source/components/rule/RuleValueVignette.css b/source/components/rule/RuleValueVignette.css index 86c6a2486..3b8d72a6b 100644 --- a/source/components/rule/RuleValueVignette.css +++ b/source/components/rule/RuleValueVignette.css @@ -1,9 +1,4 @@ -.RuleValueVignette { - margin: 0 1em 0; - text-align: center; - width: 25%; -} .RuleValueVignette li a { text-decoration: none; @@ -11,84 +6,43 @@ .RuleValueVignette .rule-type { color: white; border: none; - font-size: 85%; line-height: 2em; font-weight: 600; margin: .6em 0 .1em; } - .RuleValueVignette .rule-box { - padding: .6em 1em; - color: #333350; - background: white; - border-radius: 3px; - white-space: nowrap; - height: 8em; display: flex; - flex-wrap: wrap; - align-items: center; - justify-content: center; + justify-content: space-between; +} +.RuleValueVignette .rule-box:hover { + background: rgba(255, 255, 255, 0.16) } -.RuleValueVignette .rule-name { - font-size: 175%; - font-weight: 600; +.RuleValueVignette .rule-box > span { + display: inline-block; } -.RuleValueVignette p { - margin: 0; - padding: 0 0; - font-size: 120%; - color: inherit; - width: 100%; +.RuleValueVignette .rule-value { + transition: background .8s; } -.RuleValueVignette.number p { - color: #4A89DC; - font-weight: bold; -} -.RuleValueVignette.unsatisfied p { +.RuleValueVignette .rule-value .unsatisfied { font-style: italic; } -.RuleValueVignette.irrelevant p { - font-weight: 600; +.RuleValueVignette .rule-value .irrelevant { + font-style: normal; } -.RuleValueVignette p .figure { - font-size: 250%; -} - - -.RuleValueVignette:not(.unsatisfied):not(.irrelevant) .rule-box { - border-bottom: .8em solid #4A89DC; -} - -.RuleValueVignette:hover .rule-box { - background: #ddd; -} -.RuleValueVignette.irrelevant .rule-box { - background: rgba(255, 255, 255, 0.35); +.RuleValueVignette .rule-value .figure { + font-weight: bold; } -.RuleValueVignette.irrelevant .rule-type { - color: rgba(255, 255, 255, 0.35); +/* Animation of summary figures changes : flash ! */ +.flash-enter { + background: rgba(255, 255, 255, 1); } -.RuleValueVignette.irrelevant .rule-name { - text-decoration: line-through; -} - - - - -@media (max-width: 1280px) { - - - .RuleValueVignette .rule-box p { - padding: 0.6em; - } - - .RuleValueVignette .rule-name { - font-size: 150%; - } +.flash-leave { + /* Completely hide the button while it's being animated and before it's removed from the DOM. */ + display: none; } diff --git a/source/components/rule/RuleValueVignette.js b/source/components/rule/RuleValueVignette.js index 91c7db0c0..7191e0e75 100644 --- a/source/components/rule/RuleValueVignette.js +++ b/source/components/rule/RuleValueVignette.js @@ -1,11 +1,13 @@ import React from "react" -import {Link} from 'react-router-dom' -import {encodeRuleName} from 'Engine/rules' -import classNames from 'classnames' -import {capitalise0} from '../../utils' -let fmt = new Intl.NumberFormat('fr-FR').format -export let humanFigure = decimalDigits => value => fmt(value.toFixed(decimalDigits)) -import './RuleValueVignette.css' +import { Link } from "react-router-dom" +import { encodeRuleName } from "Engine/rules" +import classNames from "classnames" +import { capitalise0 } from "../../utils" +let fmt = new Intl.NumberFormat("fr-FR").format +export let humanFigure = decimalDigits => value => + fmt(value.toFixed(decimalDigits)) +import "./RuleValueVignette.css" +import ReactCSSTransitionGroup from "react-addons-css-transition-group" export default ({ name, @@ -15,36 +17,49 @@ export default ({ nodeValue: ruleValue }) => do { - let - unsatisfied = ruleValue == null, + let unsatisfied = ruleValue == null, irrelevant = ruleValue == 0, - number = typeof ruleValue == 'number' && ruleValue > 0 - + number = typeof ruleValue == "number" && ruleValue > 0 ; -
    - {type} -
    +
    {type}
    -
    - {titre || capitalise0(name)} -
    -

    - {conversationStarted && - (irrelevant - ? "Vous n'êtes pas concerné" - : unsatisfied - ? "En attente de vos réponses..." - :

    - {humanFigure(2)(ruleValue) + "€"} - -

    Pourquoi ?

    -
    )} -

    + {titre || capitalise0(name)} +
    } + +let RuleValue = ({ unsatisfied, irrelevant, conversationStarted, ruleValue }) => + do { + let [className, text] = irrelevant + ? ["irrelevant", "Vous n'êtes pas concerné"] + : unsatisfied + ? ["unsatisfied", "En attente de vos réponses..."] + : ["figure", humanFigure(2)(ruleValue) + " €"] + + { + /*

    Pourquoi ?

    */ + } + + + + {" "} + {conversationStarted && {text}} + + + } diff --git a/source/components/themeColours.js b/source/components/themeColours.js index 612d3e698..77d708dc2 100644 --- a/source/components/themeColours.js +++ b/source/components/themeColours.js @@ -7,7 +7,7 @@ export default forcedThemeColour => { return script && script.getAttribute('couleur') }, // Use the default theme colour if the host page hasn't made a choice - defaultColour = '#4A89DC', + defaultColour = '#2975D1', colour = forcedThemeColour || scriptColour() || defaultColour, textColour = findContrastedTextColour(colour, true), // the 'simple' version feels better... inverseTextColour = textColour === '#ffffff' ? '#000' : '#fff', diff --git a/source/containers/Layout.css b/source/containers/Layout.css index 5a1335948..89ef2c88f 100644 --- a/source/containers/Layout.css +++ b/source/containers/Layout.css @@ -35,12 +35,6 @@ h1 { flex-direction: column; } -#ninetyPercent { - width: 100%; - flex-grow: 1; - overflow: auto; -} - #page-type { display: inline-block; position: fixed; diff --git a/source/containers/Layout.js b/source/containers/Layout.js index c09eeddf8..63591e561 100644 --- a/source/containers/Layout.js +++ b/source/containers/Layout.js @@ -25,7 +25,15 @@ const piwik = new ReactPiwik({ export default class Layout extends Component { history = createHistory() - + state = { + resultsHeight: 600 + } + componentDidMount(){ + let resultsEl = document.getElementById('results') + this.setState({ + resultsHeight: resultsEl ? resultsEl.clientHeight : 600 + }) + } render() { let displayWarning = ["/simu/", "/regle/", "/regles"].find( t => window.location.href.toString().indexOf(t) > -1 @@ -37,7 +45,7 @@ export default class Layout extends Component { return (
    -
    +
    +