diff --git a/source/actions/companyStatusActions.js b/source/actions/companyStatusActions.js index 821f3757e..da952097a 100644 --- a/source/actions/companyStatusActions.js +++ b/source/actions/companyStatusActions.js @@ -11,6 +11,7 @@ import type { } from 'Types/companyTypes' import type { RouterHistory } from 'react-router' import { nextQuestionUrlSelector } from 'Selectors/companyStatusSelectors' +import sitePaths from '../sites/mycompanyinfrance.fr/sitePaths'; const thenGoToNextQuestion = actionCreator => (...args: any) => ( dispatch: any => void, @@ -66,5 +67,5 @@ export const goToCompanyStatusChoice = () => ( type: 'RESET_COMPANY_STATUS_CHOICE' }: ResetCompanyStatusAction) ) - history.push('/company') + history.push(sitePaths().entreprise.index) } diff --git a/source/components/Controls.js b/source/components/Controls.js index 040811037..9fec97cfe 100644 --- a/source/components/Controls.js +++ b/source/components/Controls.js @@ -1,12 +1,13 @@ -import React from 'react' -import './Controls.css' -import emoji from 'react-easy-emoji' -import { connect } from 'react-redux' -import { startConversation, hideControl } from 'Actions/actions' +import { hideControl, startConversation } from 'Actions/actions' +import withLanguage from 'Components/utils/withLanguage' import { makeJsx } from 'Engine/evaluation' import { createMarkdownDiv } from 'Engine/marked' +import { compose } from 'ramda' +import React from 'react' +import emoji from 'react-easy-emoji' +import { connect } from 'react-redux' +import './Controls.css' import withColours from './utils/withColours' -import withLanguage from 'Components/utils/withLanguage' function Controls({ blockingInputControls, @@ -41,7 +42,9 @@ function Controls({
  • + style={{ + background: colours.lighterColour + }}> {emoji(level == 'avertissement' ? '⚠️' : 'ℹ️')}
    {message && createMarkdownDiv(message)} @@ -79,14 +82,18 @@ function Controls({ ) } -export default connect( - (state, props) => ({ - foldedSteps: state.conversationSteps.foldedSteps, - key: props.language, - hiddenControls: state.hiddenControls - }), - dispatch => ({ - startConversation: cible => dispatch(startConversation(cible)), - hideControl: id => dispatch(hideControl(id)) - }) -)(withColours(withLanguage(Controls))) +export default compose( + connect( + (state, props) => ({ + foldedSteps: state.conversationSteps.foldedSteps, + key: props.language, + hiddenControls: state.hiddenControls + }), + dispatch => ({ + startConversation: cible => dispatch(startConversation(cible)), + hideControl: id => dispatch(hideControl(id)) + }) + ), + withColours, + withLanguage +)(Controls) diff --git a/source/components/Simu.js b/source/components/Simu.js index 82ee1f6a3..cbfe4c934 100644 --- a/source/components/Simu.js +++ b/source/components/Simu.js @@ -15,6 +15,7 @@ import { validInputEnteredSelector } from 'Selectors/analyseSelectors' import * as Animate from 'Ui/animate' +import sitePaths from '../sites/mycompanyinfrance.fr/sitePaths' import { normalizeBasePath } from '../utils' import Conversation from './conversation/Conversation' import Distribution from './Distribution' @@ -118,7 +119,9 @@ class Simulation extends Component {

    {this.props.displayHiringProcedures && (
    - + Connaître les démarches diff --git a/source/components/ui/themeColours.js b/source/components/ui/themeColours.js index 012102313..d952abde1 100644 --- a/source/components/ui/themeColours.js +++ b/source/components/ui/themeColours.js @@ -10,6 +10,7 @@ export default forcedThemeColour => { colour = forcedThemeColour || defaultColour, lightColour = lightenColour(colour, 10), darkColour = lightenColour(colour, -10), + lighterColour = lightenColour(colour, 45), lightestColour = lightenColour(colour, 100), darkestColour = lightenColour(colour, -100), textColour = findContrastedTextColour(colour, true), // the 'simple' version feels better... @@ -22,14 +23,14 @@ export default forcedThemeColour => { return { colour, - lightenColour: amount => lightenColour(colour, amount), textColour, inverseTextColour, lighterTextColour, lighterInverseTextColour, textColourOnWhite, - lightColour, darkColour, + lightColour, + lighterColour, lightestColour, darkestColour } diff --git a/source/i18n.js b/source/i18n.js index 862f7483b..2c9261bb0 100644 --- a/source/i18n.js +++ b/source/i18n.js @@ -34,4 +34,4 @@ i18next.init( } ) -export default lang +export default i18next diff --git a/source/locales/en.yaml b/source/locales/en.yaml index 71ddf75da..aee84b021 100644 --- a/source/locales/en.yaml +++ b/source/locales/en.yaml @@ -403,8 +403,12 @@ après: retour: Creation checklist avance: Go to social security -sécu: | - <0>Social protection: costs and benefits<1>France has chosen to provide its citizens with a high-quality social safety net. This mandatory system is based on solidarity and designed to ensure the general welfare of its people.<2>Easy access to health care and other services ensures that companies can put healthy, productive and highly skilled employees to work in an attractive market in the heart of Europe.<3>As soon as you declare and pay your employees, you automatically entitle them to the general scheme of French Social Security (health, maternity, disability, old age, occupational illness and accidents) and unemployment insurance.<4><0><5>How much does it cost to hire ? +sécu: + page: + titre: 'Social security in France: costs and benefits' + description: Découvrez les coûts et avantages de la sécurité sociale française en simulant un cas concret d'embauche dans votre entreprise. + content: | + <0>Social protection: costs and benefits<1>France has chosen to provide its citizens with a high-quality social safety net. This mandatory system is based on solidarity and designed to ensure the general welfare of its people.<2>Easy access to health care and other services ensures that companies can put healthy, productive and highly skilled employees to work in an attractive market in the heart of Europe.<3>As soon as you declare and pay your employees, you automatically entitle them to the general scheme of French Social Security (health, maternity, disability, old age, occupational illness and accidents) and unemployment insurance.<4><0><5>How much does it cost to hire ? Votre entreprise: Your company Protection sociale: Social security @@ -480,3 +484,23 @@ embauche: Guide du status juridique: Legal status guide Démarches de création: Creation process checklist + +path: + entreprise: + index: '/company' + monEntreprise: '/my-company' + créer: '/create-a-{{companyStatus}}' + trouver: '/find' + après: '/after-registration' + statusJuridique: + index: '/legal-status' + liste: '/list' + gérantMinoritaire: '/chairman-or-managing-director' + responsabilité: '/liability' + statusDirigeant: '/directors-status' + nombreAssociés: '/multiple-associates' + microEntreprise: '/micro-enterprise-or-individual-business' + sécurité sociale: + index: '/social-security' + démarche embauche: + index: '/hiring-process' diff --git a/source/reducers/rootReducer.js b/source/reducers/rootReducer.js index f8bd01831..286df0c60 100644 --- a/source/reducers/rootReducer.js +++ b/source/reducers/rootReducer.js @@ -17,7 +17,7 @@ import { combineReducers } from 'redux' import { reducer as formReducer } from 'redux-form' import computeThemeColours from 'Ui/themeColours' import { simulationTargetNames } from '../config.js' -import defaultLang from '../i18n' +import i18n from '../i18n' import inFranceAppReducer from './inFranceAppReducer' import storageReducer from './storageReducer' import type { Action } from 'Types/ActionsTypes' @@ -66,7 +66,7 @@ function activeTargetInput(state = null, { type, name }) { } } -function lang(state = defaultLang, { type, lang }) { +function lang(state = i18n.language, { type, lang }) { switch (type) { case 'SWITCH_LANG': return lang diff --git a/source/selectors/companyStatusSelectors.js b/source/selectors/companyStatusSelectors.js index d5efcccab..58cf6b586 100644 --- a/source/selectors/companyStatusSelectors.js +++ b/source/selectors/companyStatusSelectors.js @@ -12,6 +12,7 @@ import { pick, sortBy } from 'ramda' +import sitePaths from '../sites/mycompanyinfrance.fr/sitePaths' const LEGAL_STATUS_DETAILS: { [status: string]: CompanyLegalStatus } = { 'Micro-enterprise': { @@ -169,24 +170,10 @@ export const nextQuestionSelector = (state: { } export const nextQuestionUrlSelector = (state: { inFranceApp: State }) => { - const questionToUrl = { - multipleAssociates: 'number-of-associates' - } + const paths = sitePaths() const nextQuestion = nextQuestionSelector(state) if (!nextQuestion) { - return '/company/legal-status/list' + return paths.entreprise.statusJuridique.liste } - return `/company/legal-status/${ - nextQuestion in questionToUrl - ? // $FlowFixMe - questionToUrl[nextQuestion] - : nextQuestion - .replace(/[^a-zA-Z0-9]+/g, '-') - .replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2') - .replace(/([a-z])([A-Z])/g, '$1-$2') - .replace(/([0-9])([^0-9])/g, '$1-$2') - .replace(/([^0-9])([0-9])/g, '$1-$2') - .replace(/-+/g, '-') - .toLowerCase() - }` + return paths.entreprise.statusJuridique[nextQuestion] } diff --git a/source/sites/mycompanyinfrance.fr/App.js b/source/sites/mycompanyinfrance.fr/App.js index f6e2dd618..7394b7a8b 100644 --- a/source/sites/mycompanyinfrance.fr/App.js +++ b/source/sites/mycompanyinfrance.fr/App.js @@ -21,6 +21,7 @@ import CompanyIndex from './pages/Company' import HiringProcess from './pages/HiringProcess' import Landing from './pages/Landing' import SocialSecurity from './pages/SocialSecurity' +import sitePaths from './sitePaths' if (process.env.NODE_ENV === 'production') { Raven.config( @@ -66,24 +67,35 @@ class InFranceRoute extends Component { } } -let RouterSwitch = translate()(() => ( - - -
    - {/* Passing location down to prevent update blocking */} - -
    - -
    - - - +let RouterSwitch = translate()(() => { + const paths = sitePaths() + return ( + + +
    + {/* Passing location down to prevent update blocking */} + +
    + +
    + + + +
    +
    -
    -
    - -)) + + ) +}) let ExportedApp = InFranceRoute diff --git a/source/sites/mycompanyinfrance.fr/layout/Navigation/Navigation.js b/source/sites/mycompanyinfrance.fr/layout/Navigation/Navigation.js index 4cc5a7271..60a62b5df 100644 --- a/source/sites/mycompanyinfrance.fr/layout/Navigation/Navigation.js +++ b/source/sites/mycompanyinfrance.fr/layout/Navigation/Navigation.js @@ -9,6 +9,7 @@ import selectors from 'Selectors/progressSelectors' import companySvg from '../../images/company.svg' import estimateSvg from '../../images/estimate.svg' import hiringSvg from '../../images/hiring.svg' +import sitePaths from '../../sitePaths' import './Navigation.css' import NavOpener from './NavOpener' import SideBar from './SideBar' @@ -44,7 +45,7 @@ const StepsHeader = ({
    • @@ -62,36 +63,59 @@ const StepsHeader = ({
        • - + Nombre d'associés
        • - + Status du dirigeant
        • - + Responsabilité
        • - + Gérant majoritaire ou minoritaire
        • - + Micro-entreprise ou EI
        • - + Liste des status
        • @@ -103,45 +127,70 @@ const StepsHeader = ({
          • - + Micro-entreprise
          • - EI + + EI +
          • - EIRL + + EIRL +
          • - EURL + + EURL +
          • - SA + + SA +
          • - SARL + + SARL +
          • - SAS + + SAS +
          • - SASU + + SASU +
          • - SNC + + SNC +
        • - + Après la création
        • @@ -149,7 +198,7 @@ const StepsHeader = ({
        • - + Trouver mon entreprise
        • @@ -157,7 +206,7 @@ const StepsHeader = ({
        • - + Protection sociale
        • - + Embauche (
          @@ -38,7 +39,7 @@ const StepsHeader = ({
        - + Choose later ›
        diff --git a/source/sites/mycompanyinfrance.fr/pages/Company/YourCompany.js b/source/sites/mycompanyinfrance.fr/pages/Company/YourCompany.js index 00ecc8915..99079f0f6 100644 --- a/source/sites/mycompanyinfrance.fr/pages/Company/YourCompany.js +++ b/source/sites/mycompanyinfrance.fr/pages/Company/YourCompany.js @@ -1,11 +1,13 @@ /* @flow */ +import { React, T } from 'Components' import withLanguage from 'Components/utils/withLanguage' import { toPairs } from 'ramda' -import { React, T } from 'Components' import { connect } from 'react-redux' import { Link, Redirect } from 'react-router-dom' +import sitePaths from '../../sitePaths' import type { ResetExistingCompanyDetailsAction } from 'Types/companyTypes' + let companyDataSelection = { l1_normalisee: 'Name', libelle_activite_principale: 'Main activity', @@ -57,18 +59,18 @@ export const CompanyDetails = (data: { [string]: string }) => { const YourCompany = ({ companyDetails, resetCompanyDetails }) => ( <> - {!companyDetails && } + {!companyDetails && }

        Your company

        - + This is not my company

        - + Simulate hiring costs

        diff --git a/source/sites/mycompanyinfrance.fr/pages/Company/index.js b/source/sites/mycompanyinfrance.fr/pages/Company/index.js index b75ac15dd..211908a4c 100644 --- a/source/sites/mycompanyinfrance.fr/pages/Company/index.js +++ b/source/sites/mycompanyinfrance.fr/pages/Company/index.js @@ -1,8 +1,10 @@ import React from 'react' +import { translate } from 'react-i18next' import { connect } from 'react-redux' import { Redirect, Route, Switch } from 'react-router' import * as Animate from 'Ui/animate' import { ScrollToElement } from '../../../../components/utils/Scroll' +import sitePaths from '../../sitePaths' import AfterRegistration from './AfterRegistration' import CreationChecklist from './CreationChecklist' import DefineDirectorStatus from './DirectorStatus' @@ -14,8 +16,6 @@ import MinorityDirector from './MinorityDirector' import NumberOfAssociate from './NumberOfAssociate' import PickLegalStatus from './PickLegalStatus' import YourCompany from './YourCompany' -import { translate } from 'react-i18next' - const withAnimation = Component => { const AnimateRouteComponent = (...props) => ( @@ -32,63 +32,77 @@ const CreateMyCompany = ({ location, companyStatusChoice, existingCompany -}) => ( - <> - - - - - - - - {existingCompany && ( - - )} - {companyStatusChoice ? ( - { + const paths = sitePaths() + return ( + <> + + + - ) : ( - - )} - - - - - - - - - - - -) + + + + + {existingCompany && ( + + )} + {companyStatusChoice ? ( + + ) : ( + + )} + + + + + + + + + + + + ) +} export default connect(state => ({ companyStatusChoice: state.inFranceApp.companyStatusChoice, diff --git a/source/sites/mycompanyinfrance.fr/pages/HiringProcess.js b/source/sites/mycompanyinfrance.fr/pages/HiringProcess.js index 8d61bf8ce..eca4ee42a 100644 --- a/source/sites/mycompanyinfrance.fr/pages/HiringProcess.js +++ b/source/sites/mycompanyinfrance.fr/pages/HiringProcess.js @@ -11,6 +11,7 @@ import { connect } from 'react-redux' import { Link } from 'react-router-dom' import Animate from 'Ui/animate' import { CheckItem, Checklist } from 'Ui/Checklist' +import sitePaths from '../sitePaths' const HiringProcess = ({ onChecklistInitialization, @@ -197,7 +198,7 @@ const HiringProcess = ({
      • Remettre la fiche de paie à votre employé
      - + Obtenir un exemple de fiche de paie diff --git a/source/sites/mycompanyinfrance.fr/pages/Landing.js b/source/sites/mycompanyinfrance.fr/pages/Landing.js index 7d50b55f4..eee4a5706 100644 --- a/source/sites/mycompanyinfrance.fr/pages/Landing.js +++ b/source/sites/mycompanyinfrance.fr/pages/Landing.js @@ -5,14 +5,14 @@ import marianneSvg from 'Images/marianne.svg' import urssafSvg from 'Images/urssaf.svg' import React from 'react' import emoji from 'react-easy-emoji' +import { Trans, translate } from 'react-i18next' import { Link } from 'react-router-dom' import companySvg from '../images/company.svg' import estimateSvg from '../images/estimate.svg' import hiringSvg from '../images/hiring.svg' import Footer from '../layout/Footer/Footer' +import sitePaths from '../sitePaths' import './Landing.css' -import { Trans } from 'react-i18next' -import { translate } from 'react-i18next' export default translate()( withColours(({ colours: { colour } }) => ( @@ -35,7 +35,7 @@ export default translate()(

      Commencer @@ -70,7 +70,9 @@ export default translate()(

    - + Créez votre entreprise › @@ -97,7 +99,9 @@ export default translate()(

    - + Découvrez le coût et les avantages › @@ -126,7 +130,9 @@ export default translate()(

    - + Découvrez le proccessus d'embauche diff --git a/source/sites/mycompanyinfrance.fr/pages/SocialSecurity/Home.js b/source/sites/mycompanyinfrance.fr/pages/SocialSecurity/Home.js index 7e8e82b03..25f87bece 100644 --- a/source/sites/mycompanyinfrance.fr/pages/SocialSecurity/Home.js +++ b/source/sites/mycompanyinfrance.fr/pages/SocialSecurity/Home.js @@ -1,25 +1,32 @@ /* @flow */ +import { Component, React, T } from 'Components' import Simulateur from 'Components/Simu' import { ScrollToTop } from 'Components/utils/Scroll' -import { React, Component, T } from 'Components' import Helmet from 'react-helmet' +import { translate } from 'react-i18next' import * as Animate from 'Ui/animate' import type { Match, Location } from 'react-router' - +import type { TFunction } from 'react-i18next' type Props = { match: Match, - location: Location + location: Location, + t: TFunction } class SocialSecurity extends Component { render() { return ( <> - Social security in France: costs and benefits + + {this.props.t( + 'sécu.page.titre', + "Sécurité sociale et coût d'embauche" + )} + @@ -75,4 +82,4 @@ class SocialSecurity extends Component { } } -export default SocialSecurity +export default translate()(SocialSecurity) diff --git a/source/sites/mycompanyinfrance.fr/sitePaths.js b/source/sites/mycompanyinfrance.fr/sitePaths.js new file mode 100644 index 000000000..ac509d073 --- /dev/null +++ b/source/sites/mycompanyinfrance.fr/sitePaths.js @@ -0,0 +1,74 @@ +/* @flow */ +import { map } from 'ramda' +import i18n from '../../i18n' +const constructLocalizedSitePath = () => + constructSitePaths('', { + index: '', + entreprise: { + index: i18n.t('path.entreprise.index', '/entreprise'), + monEntreprise: i18n.t('path.entreprise.monEntreprise', '/mon-entreprise'), + créer: (companyStatus: string) => + i18n.t(['path.entreprise.créer', '/créer-une-{{companyStatus}}'], { + companyStatus + }), + trouver: i18n.t('path.entreprise.trouver', '/retrouver-mon-entreprise'), + après: i18n.t('path.entreprise.après', '/après-la-création'), + statusJuridique: { + index: i18n.t( + 'path.entreprise.statusJuridique.index', + '/status-juridique' + ), + liste: i18n.t('path.entreprise.statusJuridique.liste', '/liste'), + liability: i18n.t( + 'path.entreprise.statusJuridique.responsabilité', + '/responsabilité' + ), + directorStatus: i18n.t( + 'path.entreprise.statusJuridique.statusDirigeant', + '/status-du-dirigeant' + ), + microEnterprise: i18n.t( + 'path.entreprise.statusJuridique.microEntreprise', + '/micro-entreprise-ou-entreprise-individuelle' + ), + multipleAssociates: i18n.t( + 'path.entreprise.statusJuridique.nombreAssociés', + '/nombre-associés' + ), + minorityDirector: i18n.t( + 'path.entreprise.statusJuridique.gérantMinoritaire', + '/gérant-majoritaire-ou-minoritaire' + ) + } + }, + sécuritéSociale: { + index: i18n.t('path.sécuritéSociale', '/sécurité-sociale'), + simulation: '/simulation' + }, + démarcheEmbauche: { + index: i18n.t('path.démarcheEmbauche', '/démarches-embauche') + } + }) + +const constructSitePaths = ( + root: string, + { index, ...sitePaths }: { index: string } +) => ({ + index: root + index, + ...map( + value => + typeof value === 'string' + ? root + index + value + : typeof value === 'function' + ? (...args) => root + index + value(...args) + : constructSitePaths(root + index, value), + sitePaths + ) +}) + +let sitePath = constructLocalizedSitePath() +i18n.on('languageChanged', () => { + sitePath = constructLocalizedSitePath() +}) + +export default () => sitePath