Instaure un nouveau moteur pour le choix du status
Le but est d'arriver au résultat en un minimum de question. Le moteur pose les questions les plus importantes (qui départagent le plus de status) en premier. Si la question peut aboutir à une absence de status concordant, elle n'est pas posée. Le moteur permet aussi de commencer par n'importe quelle question. Dans le cadre du référencement direct, cela signifie que l'on peut arriver sur la page liability par exemple via une recherche / lien et continuer à partir de ce point d'entrée.pull/294/head
parent
336266b2b3
commit
fce23e51a4
|
@ -45,6 +45,7 @@
|
|||
"reduce-reducers": "^0.1.2",
|
||||
"redux": "^3.7.2",
|
||||
"redux-form": "^7.4.2",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"reselect": "^3.0.1",
|
||||
"screenfull": "^3.3.2"
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Provider } from 'react-redux'
|
|||
import { Router } from 'react-router-dom'
|
||||
import reducers from 'Reducers/rootReducer'
|
||||
import { applyMiddleware, compose, createStore } from 'redux'
|
||||
import thunk from 'redux-thunk'
|
||||
import computeThemeColours from 'Ui/themeColours'
|
||||
import trackDomainActions from './middlewares/trackDomainActions'
|
||||
import {
|
||||
|
@ -43,10 +44,7 @@ let initialStore = {
|
|||
}
|
||||
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
|
||||
let enhancer = composeEnhancers(applyMiddleware(trackDomainActions(tracker)))
|
||||
|
||||
let store = createStore(reducers, initialStore, enhancer)
|
||||
persistSimulation(store)
|
||||
if (process.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker
|
||||
|
@ -61,17 +59,27 @@ if (process.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
|||
}
|
||||
|
||||
export default class Layout extends PureComponent {
|
||||
state = {
|
||||
history: createHistory({
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.history = createHistory({
|
||||
basename: process.env.NODE_ENV === 'production' ? '' : this.props.basename
|
||||
})
|
||||
const storeEnhancer = composeEnhancers(
|
||||
applyMiddleware(
|
||||
// Allows us to painlessly do route transition in action creators
|
||||
thunk.withExtraArgument(this.history),
|
||||
trackDomainActions(tracker)
|
||||
)
|
||||
)
|
||||
this.store = createStore(reducers, initialStore, storeEnhancer)
|
||||
persistSimulation(this.store)
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Provider store={this.store}>
|
||||
<TrackerProvider value={tracker}>
|
||||
<I18nextProvider i18n={i18next}>
|
||||
<Router history={tracker.connectToHistory(this.state.history)}>
|
||||
<Router history={tracker.connectToHistory(this.history)}>
|
||||
<>{this.props.children}</>
|
||||
</Router>
|
||||
</I18nextProvider>
|
||||
|
|
|
@ -2,34 +2,47 @@
|
|||
import type {
|
||||
ChooseCompanyLiabilityAction,
|
||||
CompanyLiability,
|
||||
CompanyHaveMultipleAssociateAction,
|
||||
CompanyHaveMultipleAssociatesAction,
|
||||
DirectorStatus,
|
||||
CompanyIsMicroenterpriseAction,
|
||||
DefineDirectorStatusAction
|
||||
} from 'Types/companyStatusTypes'
|
||||
import type { RouterHistory } from 'react-router'
|
||||
import { nextQuestionUrlSelector } from 'Selectors/companyStatusSelectors'
|
||||
|
||||
export function chooseCompanyLiability(
|
||||
setup: CompanyLiability
|
||||
): ChooseCompanyLiabilityAction {
|
||||
return {
|
||||
const thenGoToNextQuestion = actionCreator => (...args: any) => (
|
||||
dispatch: any => void,
|
||||
getState: () => any,
|
||||
history: RouterHistory
|
||||
) => {
|
||||
dispatch(actionCreator(...args))
|
||||
history.push(nextQuestionUrlSelector(getState()))
|
||||
}
|
||||
|
||||
export const chooseCompanyLiability = thenGoToNextQuestion(
|
||||
(setup: ?CompanyLiability): ChooseCompanyLiabilityAction => ({
|
||||
type: 'CHOOSE_COMPANY_LEGAL_SETUP',
|
||||
setup
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
export function defineDirectorStatus(
|
||||
status: DirectorStatus
|
||||
): DefineDirectorStatusAction {
|
||||
return {
|
||||
export const defineDirectorStatus = thenGoToNextQuestion(
|
||||
(status: ?DirectorStatus): DefineDirectorStatusAction => ({
|
||||
type: 'DEFINE_DIRECTOR_STATUS',
|
||||
status
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
export function companyHaveMultipleAssociate(
|
||||
multipleAssociate: boolean
|
||||
): CompanyHaveMultipleAssociateAction {
|
||||
return {
|
||||
type: 'COMPANY_HAVE_MULTIPLE_ASSOCIATE',
|
||||
multipleAssociate
|
||||
}
|
||||
}
|
||||
export const companyHaveMultipleAssociates = thenGoToNextQuestion(
|
||||
(multipleAssociates: ?boolean): CompanyHaveMultipleAssociatesAction => ({
|
||||
type: 'COMPANY_HAVE_MULTIPLE_ASSOCIATES',
|
||||
multipleAssociates
|
||||
})
|
||||
)
|
||||
|
||||
export const companyIsMicroenterprise = thenGoToNextQuestion(
|
||||
(microenterprise: ?boolean): CompanyIsMicroenterpriseAction => ({
|
||||
type: 'COMPANY_IS_MICROENTERPRISE',
|
||||
microenterprise
|
||||
})
|
||||
)
|
||||
|
|
|
@ -32,12 +32,12 @@
|
|||
border-color: rgb(41, 117, 209);
|
||||
color: rgb(41, 117, 209);
|
||||
background: linear-gradient(
|
||||
45deg,
|
||||
50deg,
|
||||
rgba(39, 69, 195, 0.87) 5%,
|
||||
rgba(41, 117, 209, 1) 50%,
|
||||
rgba(255, 255, 255, 0.52) 55%
|
||||
);
|
||||
background-size: 250%;
|
||||
background-size: 260%;
|
||||
background-position-x: 99%;
|
||||
}
|
||||
.ui__.button:not(:disabled):hover,
|
||||
|
|
|
@ -17,8 +17,10 @@ function companyLegalStatus(
|
|||
|
||||
case 'DEFINE_DIRECTOR_STATUS':
|
||||
return { ...state, directorStatus: action.status }
|
||||
case 'COMPANY_HAVE_MULTIPLE_ASSOCIATE':
|
||||
return { ...state, multipleAssociate: action.multipleAssociate }
|
||||
case 'COMPANY_HAVE_MULTIPLE_ASSOCIATES':
|
||||
return { ...state, multipleAssociates: action.multipleAssociates }
|
||||
case 'COMPANY_IS_MICROENTERPRISE':
|
||||
return { ...state, microenterprise: action.microenterprise }
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
|
|
@ -1,74 +1,150 @@
|
|||
/* @flow */
|
||||
|
||||
import type {
|
||||
State,
|
||||
CompanyLegalStatus,
|
||||
DirectorStatus
|
||||
} from 'Types/companyStatusTypes'
|
||||
import { map, whereEq } from 'ramda'
|
||||
import type { State, CompanyLegalStatus } from 'Types/companyStatusTypes'
|
||||
import {
|
||||
add,
|
||||
countBy,
|
||||
difference,
|
||||
filter,
|
||||
map,
|
||||
pick,
|
||||
sortBy,
|
||||
whereEq
|
||||
} from 'ramda'
|
||||
|
||||
const LEGAL_STATUS_DETAILS: { [status: string]: CompanyLegalStatus } = {
|
||||
Microenterprise: {
|
||||
liability: 'SOLE_PROPRIETORSHIP',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociates: false,
|
||||
microenterprise: true,
|
||||
},
|
||||
'Microenterprise (option EIRL)': {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociates: false,
|
||||
microenterprise: true
|
||||
},
|
||||
EI: {
|
||||
liability: 'SOLE_PROPRIETORSHIP',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociate: false
|
||||
multipleAssociates: false,
|
||||
microenterprise: false
|
||||
},
|
||||
EURL: {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociate: false
|
||||
multipleAssociates: false,
|
||||
microenterprise: false
|
||||
},
|
||||
EIRL: {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociate: false
|
||||
multipleAssociates: false,
|
||||
microenterprise: false
|
||||
},
|
||||
SARL: {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociate: true
|
||||
multipleAssociates: true,
|
||||
microenterprise: false
|
||||
},
|
||||
SAS: {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SALARIED',
|
||||
multipleAssociate: true
|
||||
multipleAssociates: true,
|
||||
microenterprise: false
|
||||
},
|
||||
SA: {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SALARIED',
|
||||
multipleAssociate: true
|
||||
multipleAssociates: true,
|
||||
microenterprise: false
|
||||
},
|
||||
SNC: {
|
||||
liability: 'SOLE_PROPRIETORSHIP',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociate: true
|
||||
multipleAssociates: true,
|
||||
microenterprise: false
|
||||
},
|
||||
SASU: {
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociate: false
|
||||
directorStatus: 'SALARIED',
|
||||
multipleAssociates: false,
|
||||
microenterprise: false
|
||||
}
|
||||
}
|
||||
export type LegalStatus = $Keys<typeof LEGAL_STATUS_DETAILS>
|
||||
const possibleStatus = (
|
||||
companyLegalStatus: CompanyLegalStatus
|
||||
): { [LegalStatus]: boolean } =>
|
||||
// $FlowFixMe
|
||||
map(whereEq(companyLegalStatus), LEGAL_STATUS_DETAILS)
|
||||
map(
|
||||
// $FlowFixMe
|
||||
whereEq(filter(x => x !== null, companyLegalStatus)),
|
||||
LEGAL_STATUS_DETAILS
|
||||
)
|
||||
|
||||
export const possibleStatusSelector = (state: {
|
||||
inFranceApp: State
|
||||
}): { [LegalStatus]: boolean } =>
|
||||
possibleStatus(state.inFranceApp.companyLegalStatus)
|
||||
|
||||
export const disabledDirectorStatusSelector = (state: {
|
||||
type Question = $Keys<CompanyLegalStatus>
|
||||
|
||||
const QUESTION_LIST: Array<Question> = Object.keys(LEGAL_STATUS_DETAILS.SA);
|
||||
export const nextQuestionSelector = (state: {
|
||||
inFranceApp: State
|
||||
}): Array<DirectorStatus> =>
|
||||
['SALARIED', 'SELF_EMPLOYED'].filter(directorStatus =>
|
||||
Object.values(
|
||||
possibleStatus({
|
||||
...state.inFranceApp.companyLegalStatus,
|
||||
directorStatus
|
||||
})
|
||||
).every(x => x === false)
|
||||
}): ?Question => {
|
||||
const companyLegalStatus = state.inFranceApp.companyLegalStatus
|
||||
const questionAnswered = Object.keys(companyLegalStatus)
|
||||
const possibleStatusList = pick(
|
||||
Object.keys(filter(Boolean, possibleStatus(companyLegalStatus))),
|
||||
LEGAL_STATUS_DETAILS
|
||||
)
|
||||
|
||||
const unansweredQuestions = difference(QUESTION_LIST, questionAnswered)
|
||||
const shannonEntropyByQuestion = unansweredQuestions.map(question => {
|
||||
const answerPopulation = Object.values(possibleStatusList).map(
|
||||
// $FlowFixMe
|
||||
status => status[question]
|
||||
)
|
||||
const frequencyOfAnswers = Object.values(
|
||||
countBy(x => x, answerPopulation)
|
||||
).map(
|
||||
numOccurrence =>
|
||||
// $FlowFixMe
|
||||
numOccurrence / answerPopulation.length
|
||||
)
|
||||
const shannonEntropy = -frequencyOfAnswers
|
||||
.map(p => p * Math.log2(p))
|
||||
// $FlowFixMe
|
||||
.reduce(add, 0)
|
||||
return [question, shannonEntropy]
|
||||
})
|
||||
const sortedPossibleNextQuestions = sortBy(
|
||||
([, entropy]) => -entropy,
|
||||
shannonEntropyByQuestion.filter(([, entropy]) => entropy !== 0)
|
||||
).map(([question]) => question)
|
||||
if (sortedPossibleNextQuestions.length === 0) {
|
||||
return null
|
||||
}
|
||||
return sortedPossibleNextQuestions[0]
|
||||
}
|
||||
|
||||
export const nextQuestionUrlSelector = (state: { inFranceApp: State }) => {
|
||||
const nextQuestion = nextQuestionSelector(state)
|
||||
if (!nextQuestion) {
|
||||
return '/register/pick-legal-status'
|
||||
}
|
||||
return (
|
||||
'/register/' +
|
||||
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()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,5 +2,46 @@ import React from 'react'
|
|||
import { render } from 'react-dom'
|
||||
import App from './App'
|
||||
|
||||
// Avoid `console` errors in browsers that lack a console.
|
||||
;(function() {
|
||||
var method
|
||||
var noop = function() {}
|
||||
var methods = [
|
||||
'assert',
|
||||
'clear',
|
||||
'count',
|
||||
'debug',
|
||||
'dir',
|
||||
'dirxml',
|
||||
'error',
|
||||
'exception',
|
||||
'group',
|
||||
'groupCollapsed',
|
||||
'groupEnd',
|
||||
'info',
|
||||
'log',
|
||||
'markTimeline',
|
||||
'profile',
|
||||
'profileEnd',
|
||||
'table',
|
||||
'time',
|
||||
'timeEnd',
|
||||
'timeStamp',
|
||||
'trace',
|
||||
'warn'
|
||||
]
|
||||
var length = methods.length
|
||||
var console = (window.console = window.console || {})
|
||||
|
||||
while (length--) {
|
||||
method = methods[length]
|
||||
|
||||
// Only stub undefined methods.
|
||||
if (!console[method]) {
|
||||
console[method] = noop
|
||||
}
|
||||
}
|
||||
})()
|
||||
|
||||
let anchor = document.querySelector('#js')
|
||||
render(<App />, anchor)
|
||||
|
|
|
@ -1,27 +1,14 @@
|
|||
/* @flow */
|
||||
import { defineDirectorStatus } from 'Actions/companyStatusActions'
|
||||
import { equals } from 'ramda'
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { disabledDirectorStatusSelector } from 'Selectors/companyStatusSelectors'
|
||||
import { SkipButton } from 'Ui/Button'
|
||||
import type { DirectorStatus } from 'Types/companyStatusTypes'
|
||||
import type { RouterHistory } from 'react-router'
|
||||
|
||||
type Props = {
|
||||
history: RouterHistory,
|
||||
defineDirectorStatus: DirectorStatus => void,
|
||||
disabledDirectorStatus: Array<DirectorStatus>
|
||||
defineDirectorStatus: (?DirectorStatus) => void
|
||||
}
|
||||
|
||||
const goToNextStep = (history: RouterHistory) => {
|
||||
history.push('/register/set-legal-status')
|
||||
}
|
||||
|
||||
const DefineDirectorStatus = ({
|
||||
history,
|
||||
defineDirectorStatus,
|
||||
disabledDirectorStatus
|
||||
}: Props) => (
|
||||
const DefineDirectorStatus = ({ defineDirectorStatus }: Props) => (
|
||||
<>
|
||||
<h2>Defining the director's status </h2>
|
||||
<p>
|
||||
|
@ -47,39 +34,27 @@ const DefineDirectorStatus = ({
|
|||
professional income as reported to the tax authorities.
|
||||
</li>
|
||||
</ul>
|
||||
{!!disabledDirectorStatus.length && (
|
||||
<p>
|
||||
Because of your previous choices, you only have the following
|
||||
possibility for the director status:
|
||||
</p>
|
||||
)}
|
||||
<div className="ui__ answer-group">
|
||||
{!disabledDirectorStatus.find(equals('SALARIED')) && (
|
||||
<button
|
||||
className="ui__ button"
|
||||
onClick={() => {
|
||||
defineDirectorStatus('SALARIED')
|
||||
goToNextStep(history)
|
||||
}}>
|
||||
Salaried
|
||||
</button>
|
||||
)}
|
||||
{!disabledDirectorStatus.find(equals('SELF-EMPLOYED')) && (
|
||||
<button
|
||||
className="ui__ button"
|
||||
onClick={() => {
|
||||
defineDirectorStatus('SELF_EMPLOYED')
|
||||
goToNextStep(history)
|
||||
}}>
|
||||
Self-employed
|
||||
</button>
|
||||
)}
|
||||
<SkipButton onClick={() => goToNextStep(history)} />
|
||||
<button
|
||||
className="ui__ button"
|
||||
onClick={() => {
|
||||
defineDirectorStatus('SALARIED')
|
||||
}}>
|
||||
Salaried
|
||||
</button>
|
||||
<button
|
||||
className="ui__ button"
|
||||
onClick={() => {
|
||||
defineDirectorStatus('SELF_EMPLOYED')
|
||||
}}>
|
||||
Self-employed
|
||||
</button>
|
||||
<SkipButton onClick={() => defineDirectorStatus(null)} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
export default connect(
|
||||
state => ({ disabledDirectorStatus: disabledDirectorStatusSelector(state) }),
|
||||
null,
|
||||
{ defineDirectorStatus }
|
||||
)(DefineDirectorStatus)
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
/* @flow */
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { nextQuestionUrlSelector } from 'Selectors/companyStatusSelectors'
|
||||
import type { Match } from 'react-router'
|
||||
|
||||
type Props = {
|
||||
match: Match
|
||||
match: Match,
|
||||
nextQuestionUrl: string
|
||||
}
|
||||
const CreateMyCompany = ({ match }: Props) => (
|
||||
const CreateMyCompany = ({ match, nextQuestionUrl }: Props) => (
|
||||
<>
|
||||
<h1 className="question__title">Register a company</h1>
|
||||
<Link className="ui__ link-button" to="/register/find">
|
||||
|
@ -21,7 +23,7 @@ const CreateMyCompany = ({ match }: Props) => (
|
|||
</p>
|
||||
{match.isExact && (
|
||||
<div className="ui__ answer-group">
|
||||
<Link className="ui__ button" to={match.path + '/choose-liability'}>
|
||||
<Link className="ui__ button" to={nextQuestionUrl}>
|
||||
Choose the legal status
|
||||
</Link>
|
||||
<Link to={'/social-security'} className="ui__ skip-button">
|
||||
|
@ -32,4 +34,7 @@ const CreateMyCompany = ({ match }: Props) => (
|
|||
</>
|
||||
)
|
||||
|
||||
export default CreateMyCompany
|
||||
export default connect(
|
||||
state => ({ nextQuestionUrl: nextQuestionUrlSelector(state) }),
|
||||
null
|
||||
)(CreateMyCompany)
|
||||
|
|
|
@ -3,19 +3,15 @@ import { chooseCompanyLiability } from 'Actions/companyStatusActions'
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { SkipButton } from 'Ui/Button'
|
||||
import type { Match, RouterHistory } from 'react-router'
|
||||
import type { Match } from 'react-router'
|
||||
import type { CompanyLiability } from 'Types/companyStatusTypes'
|
||||
|
||||
type Props = {
|
||||
match: Match,
|
||||
history: RouterHistory,
|
||||
chooseCompanyLiability: CompanyLiability => void
|
||||
chooseCompanyLiability: (?CompanyLiability) => void
|
||||
}
|
||||
|
||||
const goToNextStep = (history: RouterHistory) => {
|
||||
history.push('/register/number-of-associate')
|
||||
}
|
||||
const Liability = ({ chooseCompanyLiability, history }: Props) => (
|
||||
const Liability = ({ chooseCompanyLiability }: Props) => (
|
||||
<>
|
||||
<h2>Choosing the liability </h2>
|
||||
<p>
|
||||
|
@ -40,7 +36,6 @@ const Liability = ({ chooseCompanyLiability, history }: Props) => (
|
|||
<div className="ui__ answer-group">
|
||||
<button
|
||||
onClick={() => {
|
||||
goToNextStep(history)
|
||||
chooseCompanyLiability('SOLE_PROPRIETORSHIP')
|
||||
}}
|
||||
className="ui__ button">
|
||||
|
@ -49,12 +44,11 @@ const Liability = ({ chooseCompanyLiability, history }: Props) => (
|
|||
<button
|
||||
onClick={() => {
|
||||
chooseCompanyLiability('LIMITED_LIABILITY')
|
||||
goToNextStep(history)
|
||||
}}
|
||||
className="ui__ button">
|
||||
Limited liability
|
||||
</button>
|
||||
<SkipButton onClick={() => goToNextStep(history)} />
|
||||
<SkipButton onClick={() => chooseCompanyLiability(null)} />
|
||||
</div>
|
||||
{/* this is an economic activity conducted by a single natural person, in his own name ; */}
|
||||
{/* Company : This is an economic activity conducted by a single partner - single member company with limited liability (EURL) - or several partners (limited liability company (SARL), public limited company (SA), simplified joint-stock company (SAS)...). */}
|
||||
|
@ -63,7 +57,5 @@ const Liability = ({ chooseCompanyLiability, history }: Props) => (
|
|||
|
||||
export default connect(
|
||||
null,
|
||||
{
|
||||
chooseCompanyLiability
|
||||
}
|
||||
{ chooseCompanyLiability }
|
||||
)(Liability)
|
||||
|
|
|
@ -13,6 +13,7 @@ type Props = {
|
|||
setMainStatus: LegalStatus => void
|
||||
}
|
||||
|
||||
|
||||
const StatusButton = ({ status }: { status: LegalStatus }) => (
|
||||
<Link to={`/register/register-${status}`} className="ui__ button">
|
||||
Create {status}
|
||||
|
@ -20,25 +21,16 @@ const StatusButton = ({ status }: { status: LegalStatus }) => (
|
|||
)
|
||||
|
||||
const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
||||
const atLeastOneStatus = Object.values(possibleStatus).some(x => x)
|
||||
return (
|
||||
const uniqStatus = (Object.values(possibleStatus).filter(Boolean).length === 1);
|
||||
return (
|
||||
<>
|
||||
<h2>Choosing a legal status</h2>
|
||||
{atLeastOneStatus ? (
|
||||
<p>
|
||||
Based on your previous answers, you can choose between the following
|
||||
statuses:
|
||||
</p>
|
||||
) : (
|
||||
<p>
|
||||
{' '}
|
||||
We didn't find any status matching your need. You can go back and
|
||||
change your needs, or choose a status manually from the following
|
||||
list:
|
||||
</p>
|
||||
)}
|
||||
<h2>Your legal status</h2>
|
||||
{uniqStatus? <p>The following status seems to be the perfect match for your need:</p> : <p>
|
||||
Based on your previous answers, you can choose between the following statuses:
|
||||
</p>}
|
||||
|
||||
<ul>
|
||||
{(!atLeastOneStatus || possibleStatus.EI) && (
|
||||
{possibleStatus.EI && (
|
||||
<li>
|
||||
<strong>
|
||||
EI - Entreprise individuelle (Individual business):{' '}
|
||||
|
@ -48,7 +40,7 @@ const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
|||
wealth are one.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.EIRL) && (
|
||||
{possibleStatus.EIRL && (
|
||||
<li>
|
||||
<strong>
|
||||
EIRL - Entrepreneur individuel à responsabilité limitée
|
||||
|
@ -58,7 +50,7 @@ const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
|||
heritage necessary for the activity.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.EURL) && (
|
||||
{possibleStatus.EURL && (
|
||||
<li>
|
||||
<strong>
|
||||
EURL - Entreprise unipersonnelle à responsabilité limitée (Limited
|
||||
|
@ -68,7 +60,7 @@ const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
|||
its contribution to the capital.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.SARL) && (
|
||||
{possibleStatus.SARL && (
|
||||
<li>
|
||||
<strong>
|
||||
SARL - Société à responsabilité limitée (Limited corporation):{' '}
|
||||
|
@ -78,7 +70,7 @@ const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
|||
capital is freely fixed in the statutes.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.SAS) && (
|
||||
{possibleStatus.SAS && (
|
||||
<li>
|
||||
<strong>
|
||||
SAS - Société par actions simplifiées (Simplified joint stock
|
||||
|
@ -89,7 +81,7 @@ const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
|||
the statutes.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.SASU) && (
|
||||
{possibleStatus.SASU && (
|
||||
<li>
|
||||
<strong>
|
||||
SASU - Société par action simplifiée unipersonnelle (Simplified
|
||||
|
@ -99,24 +91,36 @@ const SetMainStatus = ({ history, possibleStatus }: Props) => {
|
|||
capital. The minimum capital is freely fixed in the statutes.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.SA) && (
|
||||
{possibleStatus.SA && (
|
||||
<li>
|
||||
<strong>SA - Société anonyme (Anonymous company):</strong>Company
|
||||
composed of at least 2 shareholders if it is not listed.
|
||||
composed of at least 2 shareholders. The only status that allows you to be listed on the stock exchange. The minimum share capital is €37.000.
|
||||
</li>
|
||||
)}
|
||||
{(!atLeastOneStatus || possibleStatus.SNC) && (
|
||||
{possibleStatus.SNC && (
|
||||
<li>
|
||||
<strong>SNC - Société en nom collectif (Partnership):</strong>The
|
||||
partners are liable indefinitely and severally for the debts of the
|
||||
company.
|
||||
</li>
|
||||
)}
|
||||
|
||||
{possibleStatus['Microenterprise (option EIRL)'] && (
|
||||
<li>
|
||||
<strong>Microenterprise (option EIRL):</strong> The micro-enterprise is a sole proprietorship company, subject to a flat-rate scheme for the calculation of taxes and the payment of social security contributions. With the EIRL option, you have limited liability on your losses.
|
||||
</li>
|
||||
)}
|
||||
|
||||
{possibleStatus.Microenterprise && (
|
||||
<li>
|
||||
<strong>Microenterprise:</strong> The micro-enterprise is a sole proprietorship subject to a flat-rate scheme for the calculation of taxes and the payment of social security contributions.
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
<div className="ui__ answer-group">
|
||||
{/* $FlowFixMe */}
|
||||
{(Object.entries(possibleStatus): Array<[LegalStatus, boolean]>)
|
||||
.filter(([, statusIsVisible]) => statusIsVisible || !atLeastOneStatus)
|
||||
.filter(([, statusIsVisible]) => statusIsVisible)
|
||||
.map(([status]) => (
|
||||
<StatusButton key={status} status={status} history={history} />
|
||||
))}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/* @flow */
|
||||
import { companyIsMicroenterprise } from 'Actions/companyStatusActions'
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { SkipButton } from 'Ui/Button'
|
||||
|
||||
type Props = {
|
||||
companyIsMicroenterprise: (?boolean) => void
|
||||
}
|
||||
|
||||
const Microenterprise = ({ companyIsMicroenterprise }: Props) => (
|
||||
<>
|
||||
<h2>Microenterprise or Individual Business</h2>
|
||||
<p>
|
||||
The Micro entreprise is a simplified scheme of declaration and payment, whose tax and social contributions are based on the turnover achieved each month. Available for
|
||||
companies whose annual turnover does not exceed (for the past year) 70 000 € for services providers or 170 000 € for micro-entrepreneurs whose main activity is the sale of goods, catering or the provision of housing.
|
||||
</p><p>This is a interesting choice if you do not need lot of capital for your activity, you plan it to be small, and you want the minimum amount of paperwork to get started. </p>
|
||||
<p>For all other case, it is advised to choose the standard status, which is Individual Business.</p>
|
||||
|
||||
<div className="ui__ answer-group">
|
||||
<button
|
||||
onClick={() => {
|
||||
companyIsMicroenterprise(true)
|
||||
}}
|
||||
className="ui__ button">
|
||||
Microenterprise
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
companyIsMicroenterprise(false)
|
||||
}}
|
||||
className="ui__ button">
|
||||
Individual Business
|
||||
</button>
|
||||
<SkipButton onClick={() => companyIsMicroenterprise(null)} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
{ companyIsMicroenterprise }
|
||||
)(Microenterprise)
|
|
@ -1,23 +1,14 @@
|
|||
/* @flow */
|
||||
import { companyHaveMultipleAssociate } from 'Actions/companyStatusActions'
|
||||
import { companyHaveMultipleAssociates } from 'Actions/companyStatusActions'
|
||||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { SkipButton } from 'Ui/Button'
|
||||
import type { RouterHistory } from 'react-router'
|
||||
|
||||
type Props = {
|
||||
history: RouterHistory,
|
||||
companyHaveMultipleAssociate: boolean => void
|
||||
companyHaveMultipleAssociates: (?boolean) => void
|
||||
}
|
||||
|
||||
const goToNextStep = (history: RouterHistory) => {
|
||||
history.push('/register/define-director-status')
|
||||
}
|
||||
|
||||
const NumberOfAssociate = ({
|
||||
history,
|
||||
companyHaveMultipleAssociate
|
||||
}: Props) => (
|
||||
const NumberOfAssociate = ({ companyHaveMultipleAssociates }: Props) => (
|
||||
<>
|
||||
<h2>Number of associates </h2>
|
||||
<p>
|
||||
|
@ -28,26 +19,24 @@ const NumberOfAssociate = ({
|
|||
<div className="ui__ answer-group">
|
||||
<button
|
||||
onClick={() => {
|
||||
companyHaveMultipleAssociate(false)
|
||||
goToNextStep(history)
|
||||
companyHaveMultipleAssociates(false)
|
||||
}}
|
||||
className="ui__ button">
|
||||
Only one associate
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
companyHaveMultipleAssociate(true)
|
||||
goToNextStep(history)
|
||||
companyHaveMultipleAssociates(true)
|
||||
}}
|
||||
className="ui__ button">
|
||||
Multiple partners
|
||||
</button>
|
||||
<SkipButton onClick={() => goToNextStep(history)} />
|
||||
<SkipButton onClick={() => companyHaveMultipleAssociates(null)} />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
{ companyHaveMultipleAssociate }
|
||||
{ companyHaveMultipleAssociates }
|
||||
)(NumberOfAssociate)
|
||||
|
|
|
@ -1,75 +1,64 @@
|
|||
/* @flow */
|
||||
import Checklist from 'Components/Checklist'
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import siret from './siret.jpg'
|
||||
import type { Match } from 'react-router'
|
||||
|
||||
export default (match: Match) =>
|
||||
Checklist({
|
||||
name: 'register',
|
||||
title: `Checklist to register a ${match.params.status || ''}`,
|
||||
subtitle: `
|
||||
This checklist will guide you thoughout all the necessary steps to
|
||||
register your company with the French administration.
|
||||
`,
|
||||
items: {
|
||||
legalStatus: 'Choose the legal status',
|
||||
corporateName: (
|
||||
<p>
|
||||
Find a corporate name (<em>raison sociale</em>, the legal name of your
|
||||
company)
|
||||
</p>
|
||||
),
|
||||
tradeName: 'Find a trade name (for commercial purposes)',
|
||||
space: 'Find a space (or work at home)',
|
||||
registerCfe: (
|
||||
<span>
|
||||
Register your company online on{' '}
|
||||
<a target="_blank" href="https://www.guichet-entreprises.fr/en/">
|
||||
Guichet-entreprises.fr (english)
|
||||
</a>
|
||||
</span>
|
||||
),
|
||||
newspaper: `Have the company's creation published in
|
||||
a newspaper of legal announcements such as the Bodacc (Bulletin officiel
|
||||
des annonces civiles et commerciales)`,
|
||||
bankAccount:
|
||||
'Open a business bank account and follow the capital deposit procedure if needed',
|
||||
accountant: 'Choose a certified accountant',
|
||||
insurance: 'Check out needs of professional insurance'
|
||||
},
|
||||
|
||||
conclusion: (
|
||||
<>
|
||||
<p>
|
||||
Once your business has been officially registered, you will receive :
|
||||
</p>
|
||||
<ul>
|
||||
<li>your Siren number, which identifies your company ;</li>
|
||||
<li>
|
||||
the Siret number, which identifies each place of business operated
|
||||
by the same company.
|
||||
</li>
|
||||
</ul>
|
||||
<img src={siret} alt="Siret and siren number" />
|
||||
<p>
|
||||
It also assigns the APE code for the business sector to which your
|
||||
company or you as a self-employed worker belong. The APE code is used
|
||||
to classify your company’s main operations in relation to the french
|
||||
business nomenclature system (« NAF » code). It also determines the
|
||||
applicable collective agreement as well as the industrial accident
|
||||
rate in the field to which you or your company belong.
|
||||
</p>
|
||||
<p>
|
||||
Now that you have a properly registered company, the next steps is to{' '}
|
||||
<strong>hire your first employee</strong>
|
||||
</p>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Link className="ui__ button" to="/social-security">
|
||||
Simulate hiring cost in France
|
||||
</Link>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
})
|
||||
import type { Match, RouterHistory } from 'react-router'
|
||||
type Props = {
|
||||
history: RouterHistory,
|
||||
match: Match
|
||||
}
|
||||
const Register = ({ match, history }: Props) => (
|
||||
<>
|
||||
<h1>Create a {match.params.status} </h1>
|
||||
<p>
|
||||
<Link to="/register">
|
||||
Not sure about this status? Take our guide to help you choose.
|
||||
</Link>{' '}
|
||||
</p>
|
||||
<p>
|
||||
Register your company to the French administration is the first thing to
|
||||
do. It can be done online with the following data :
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>The corporate name</strong>, also called "raison sociale" in
|
||||
french, is the legal name of your company, written on all of your
|
||||
administrative papers. It can be different from the trade name (used for
|
||||
commercial purpose).
|
||||
</li>
|
||||
<li>
|
||||
<strong>The corporate purpose of the company</strong>, also called
|
||||
"object social" is a short phrase describing the activity of your
|
||||
company. As it is legally binding it must be composed with care,
|
||||
possibly with the help of a lawyer.
|
||||
</li>
|
||||
<li>
|
||||
<strong>The social security number of the director</strong>. In case you
|
||||
don't have yet a french social security number...
|
||||
</li>
|
||||
<li>
|
||||
<strong>The address</strong>, the physical space where your company will
|
||||
be incorporated. In certain areas, you can benefit from substantial
|
||||
government aid (exemption from charges, taxes, etc.).
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
If you don't know where your going to open your company, you can discover
|
||||
the French territories in our <a>incoporation simulator</a>.
|
||||
</p>
|
||||
{/* <p>If the company director is not part of the EU, you'll need a specific visa https://www.economie.gouv.fr/entreprises/etranger-comment-creer-votre-entreprise-france </p> */}
|
||||
<p style={{ textAlign: 'right' }}>
|
||||
<a
|
||||
onClick={() => history.push('/register/registration-pending')}
|
||||
className="ui__ button"
|
||||
href="https://translate.google.com/translate?depth=1&hl=en&rurl=translate.google.com&sl=fr&sp=nmt4&tl=en&u=https://www.guichet-entreprises.fr/en/how-to-create-your-business/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank">
|
||||
Register my company online
|
||||
</a>
|
||||
<Link to={'/social-security'} className="ui__ skip-button">
|
||||
Do it later ›
|
||||
</Link>
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
export default Register
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import siret from './siret.jpg'
|
||||
|
||||
const DuringRegistration = () => (
|
||||
<>
|
||||
<h1>Registration pending</h1>
|
||||
<p>
|
||||
<a>If you have trouble completing your application, we can help.</a>
|
||||
</p>
|
||||
<p>
|
||||
While your application is being processed, you can focus on the following
|
||||
tasks:{' '}
|
||||
</p>
|
||||
<ul className="ui__ no-bullet">
|
||||
<li>
|
||||
<label>
|
||||
<input type="checkbox" />Open a business bank account and follow the
|
||||
capital deposit procedure if needed
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label>
|
||||
<input type="checkbox" />Choose a certified accountant
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<label>
|
||||
<input type="checkbox" />Check out needs of professional insurance
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
You can also{' '}
|
||||
<Link to="/social-security">
|
||||
learn more about social security system and simulate your first employee
|
||||
</Link>
|
||||
</p>
|
||||
<h2>Application status</h2>
|
||||
<p>Once your business has been officially registered, you will receive:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Your Siret number</strong>
|
||||
, which identifies your company
|
||||
</li>
|
||||
<li>
|
||||
<strong>Your APE code</strong>
|
||||
, which defines your business sector
|
||||
</li>
|
||||
<li>
|
||||
<strong>Your K-bis extract</strong>
|
||||
, which certifies that your company is properly registrated
|
||||
</li>
|
||||
</ul>
|
||||
<a className="ui__ button">I've received my SIRET number</a>
|
||||
<h3>Siren and Siret</h3>
|
||||
<p>
|
||||
The Siren number identifies your company while the Siret number identifies
|
||||
each place of business operated by the same company.
|
||||
</p>
|
||||
<img src={siret} alt="Siret and siren number" />
|
||||
<h3>APE Code</h3>
|
||||
<p>
|
||||
The APE code for the business sector to which your company belong. The APE
|
||||
code is used to classify your company’s main operations in relation to the
|
||||
french business nomenclature system (« NAF » code). It also determines the
|
||||
applicable collective agreement as well as the industrial accident rate in
|
||||
the field to which you or your company belong.
|
||||
</p>
|
||||
<h3>Kbis extract</h3>
|
||||
</>
|
||||
)
|
||||
|
||||
export default DuringRegistration
|
|
@ -7,6 +7,8 @@ import Find from './Find'
|
|||
import Home from './Home'
|
||||
import Liability from './Liability'
|
||||
import MainStatus from './MainStatus'
|
||||
import Microenterprise from './Microenterprise'
|
||||
import RegistrationPending from './RegistrationPending'
|
||||
import NumberOfAssociate from './NumberOfAssociate'
|
||||
import Register from './Register'
|
||||
|
||||
|
@ -16,8 +18,9 @@ const CreateMyCompany = ({ match, location }) => (
|
|||
<Switch>
|
||||
<Route
|
||||
path={match.path + '/register-:status'}
|
||||
component={Register(match)}
|
||||
component={Register}
|
||||
/>
|
||||
<Route path={match.path + '/registration-pending'} component={RegistrationPending} />
|
||||
|
||||
<Route path={match.path + '/find'} component={Find} />
|
||||
<Route path={match.path} component={Home} />
|
||||
|
@ -42,7 +45,7 @@ const CreateMyCompany = ({ match, location }) => (
|
|||
{style => (
|
||||
<Switch location={location}>
|
||||
<Route
|
||||
path={match.path + '/choose-liability'}
|
||||
path={match.path + '/liability'}
|
||||
render={props => (
|
||||
<animated.div style={style}>
|
||||
<Liability {...props} />
|
||||
|
@ -50,7 +53,7 @@ const CreateMyCompany = ({ match, location }) => (
|
|||
)}
|
||||
/>
|
||||
<Route
|
||||
path={match.path + '/define-director-status'}
|
||||
path={match.path + '/director-status'}
|
||||
render={props => (
|
||||
<animated.div style={style}>
|
||||
<DefineDirectorStatus {...props} />
|
||||
|
@ -58,7 +61,15 @@ const CreateMyCompany = ({ match, location }) => (
|
|||
)}
|
||||
/>
|
||||
<Route
|
||||
path={match.path + '/number-of-associate'}
|
||||
path={match.path + '/microenterprise'}
|
||||
render={props => (
|
||||
<animated.div style={style}>
|
||||
<Microenterprise {...props} />
|
||||
</animated.div>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={match.path + '/multiple-associates'}
|
||||
render={props => (
|
||||
<animated.div style={style}>
|
||||
<NumberOfAssociate {...props} />
|
||||
|
@ -66,7 +77,7 @@ const CreateMyCompany = ({ match, location }) => (
|
|||
)}
|
||||
/>
|
||||
<Route
|
||||
path={match.path + '/set-legal-status'}
|
||||
path={match.path + '/pick-legal-status'}
|
||||
render={props => (
|
||||
<animated.div style={style}>
|
||||
<MainStatus {...props} />
|
||||
|
|
|
@ -21,11 +21,16 @@ class Hiring extends Component<Props, {}> {
|
|||
designed to ensure the{' '}
|
||||
<strong>general welfare of its people</strong>.
|
||||
</p>
|
||||
<p>
|
||||
This easy access to health care and other services ensures that
|
||||
companies can put healthy, highly skilled, and productive
|
||||
employees to work in an attractive market in the heart of Europe.
|
||||
</p>
|
||||
<p>
|
||||
As soon as you declare and pay your employees, you automatically
|
||||
entitle them to all of France’s health, maternity, disability, old
|
||||
age, unemployment, occupational accidents and occupational illness
|
||||
insurance programs.
|
||||
entitle them to the general scheme of French Social Security
|
||||
(health, maternity, disability, old age, occupational illness,
|
||||
accident at work) and unemployment insurance.
|
||||
</p>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<iframe
|
||||
|
|
|
@ -3,19 +3,25 @@
|
|||
export type CompanyLiability = 'LIMITED_LIABILITY' | 'SOLE_PROPRIETORSHIP'
|
||||
export type ChooseCompanyLiabilityAction = {
|
||||
type: 'CHOOSE_COMPANY_LEGAL_SETUP',
|
||||
setup: CompanyLiability
|
||||
setup: ?CompanyLiability
|
||||
}
|
||||
|
||||
export type DirectorStatus = 'SALARIED' | 'SELF_EMPLOYED'
|
||||
|
||||
export type DefineDirectorStatusAction = {
|
||||
type: 'DEFINE_DIRECTOR_STATUS',
|
||||
status: DirectorStatus
|
||||
status: ?DirectorStatus
|
||||
}
|
||||
|
||||
export type CompanyHaveMultipleAssociateAction = {
|
||||
type: 'COMPANY_HAVE_MULTIPLE_ASSOCIATE',
|
||||
multipleAssociate: boolean
|
||||
export type CompanyHaveMultipleAssociatesAction = {
|
||||
type: 'COMPANY_HAVE_MULTIPLE_ASSOCIATES',
|
||||
multipleAssociates: ?boolean
|
||||
}
|
||||
|
||||
|
||||
export type CompanyIsMicroenterpriseAction = {
|
||||
type: 'COMPANY_IS_MICROENTERPRISE',
|
||||
microenterprise: ?boolean
|
||||
}
|
||||
|
||||
export type ChangeChecklistItemAction = {
|
||||
|
@ -32,9 +38,15 @@ export type SaveExistingCompanyDetailsAction = {
|
|||
|
||||
export type State = {|
|
||||
+companyLegalStatus: {
|
||||
+liability?: CompanyLiability,
|
||||
+directorStatus?: DirectorStatus,
|
||||
+multipleAssociate?: boolean
|
||||
/*
|
||||
Note on the meanings of null / undefined value:
|
||||
If the key exists and the value is null, the question have been asked, but skipped by the user.
|
||||
If the key does not exists, the question still hasn't been asked.
|
||||
*/
|
||||
+liability?: ?CompanyLiability,
|
||||
+directorStatus?: ?DirectorStatus,
|
||||
+multipleAssociates?: ?boolean,
|
||||
+microenterprise?: ?boolean
|
||||
},
|
||||
+existingCompanyDetails: ?{ [string]: string },
|
||||
+checklists: {
|
||||
|
@ -48,6 +60,7 @@ export type CompanyLegalStatus = $PropertyType<State, 'companyLegalStatus'>
|
|||
export type Action =
|
||||
| ChooseCompanyLiabilityAction
|
||||
| DefineDirectorStatusAction
|
||||
| CompanyHaveMultipleAssociateAction
|
||||
| CompanyIsMicroenterpriseAction
|
||||
| CompanyHaveMultipleAssociatesAction
|
||||
| SaveExistingCompanyDetailsAction
|
||||
| ChangeChecklistItemAction
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* @flow */
|
||||
import { map } from 'ramda'
|
||||
|
||||
export let capitalise0 = (name: string) => name[0].toUpperCase() + name.slice(1)
|
||||
|
||||
|
@ -45,3 +46,13 @@ export function isIE() {
|
|||
) != null)
|
||||
)
|
||||
}
|
||||
|
||||
export const mapDispatchWithRouter = (actionCreators: Object) => (
|
||||
dispatch: (...any) => void,
|
||||
ownProps: Object
|
||||
) =>
|
||||
map(
|
||||
actionCreator => (...args) =>
|
||||
dispatch(actionCreator(...args, ownProps.router)),
|
||||
actionCreators
|
||||
)
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/* @flow */
|
||||
|
||||
import { expect } from 'chai'
|
||||
import { nextQuestionSelector } from 'Selectors/companyStatusSelectors'
|
||||
const state = companyLegalStatus => ({
|
||||
inFranceApp: {
|
||||
companyLegalStatus,
|
||||
existingCompanyDetails: null,
|
||||
checklists: { register: {}, hire: {} }
|
||||
}
|
||||
})
|
||||
describe('company status selectors', function() {
|
||||
describe('nextQuestionSelector', function() {
|
||||
it('should return null there is only one status possible', () => {
|
||||
const nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
liability: 'SOLE_PROPRIETORSHIP',
|
||||
directorStatus: 'SELF_EMPLOYED',
|
||||
multipleAssociates: true
|
||||
})
|
||||
)
|
||||
expect(nextQuestion).to.be.equal(null)
|
||||
})
|
||||
it('should not return null if no questions have been answered yet', () => {
|
||||
const nextQuestion = nextQuestionSelector(state({}))
|
||||
expect(nextQuestion).not.to.be.equal(null)
|
||||
})
|
||||
it('should return null if all the questions have been answered', () => {
|
||||
const nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
liability: null,
|
||||
directorStatus: null,
|
||||
microenterprise: null,
|
||||
multipleAssociates: null
|
||||
})
|
||||
)
|
||||
expect(nextQuestion).to.be.equal(null)
|
||||
})
|
||||
it('should always return a question that have not been answered yet', () => {
|
||||
let nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
directorStatus: null,
|
||||
multipleAssociates: null
|
||||
})
|
||||
)
|
||||
expect(['directorStatus', 'multipleAssociates']).not.to.contain(
|
||||
nextQuestion
|
||||
)
|
||||
|
||||
nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
directorStatus: 'SALARIED',
|
||||
liability: 'LIMITED_LIABILITY'
|
||||
})
|
||||
)
|
||||
expect(['directorStatus', 'liability']).not.to.contain(nextQuestion)
|
||||
|
||||
nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
multipleAssociates: true,
|
||||
liability: 'LIMITED_LIABILITY'
|
||||
})
|
||||
)
|
||||
expect(['multipleAssociates', 'liability']).not.to.contain(nextQuestion)
|
||||
})
|
||||
it('should not return a question which can lead to no matching status', () => {
|
||||
const nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
liability: 'SOLE_PROPRIETORSHIP',
|
||||
multipleAssociates: null,
|
||||
microenterprise: null,
|
||||
})
|
||||
)
|
||||
expect(nextQuestion).to.be.equal(null)
|
||||
})
|
||||
it('should return a question if it can help to shrink down the possibilities', () => {
|
||||
const nextQuestion = nextQuestionSelector(
|
||||
state({
|
||||
liability: 'LIMITED_LIABILITY',
|
||||
directorStatus: 'SALARIED'
|
||||
})
|
||||
)
|
||||
expect(nextQuestion).not.to.be.equal(null)
|
||||
})
|
||||
|
||||
it('should first return the question which convey the most information (which eliminates the most statuses ) ', () => {
|
||||
const nextQuestion = nextQuestionSelector(state({}))
|
||||
expect(nextQuestion).to.be.equal('multipleAssociates')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -6851,6 +6851,10 @@ redux-form@^7.4.2:
|
|||
prop-types "^15.6.1"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
redux-thunk@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
|
||||
|
||||
redux@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
|
||||
|
|
Loading…
Reference in New Issue