ajoute un nouveau parcours gérer mon entreprise

pull/640/head
Johan Girod 2019-10-11 16:00:22 +02:00
parent 936d436f43
commit 73c79e4b81
44 changed files with 799 additions and 1593 deletions

View File

@ -33,17 +33,18 @@ export default function CompanyDetails({ siren, denomination }) {
<small>({siren})</small>
</>
) : (
<Skeleton width={400} />
)}
<Skeleton width={400} />
)}
</h3>
<small>
<p className="ui__ notice">
<T>Crée le</T>{' '}
<strong>
{company ? (
DateFormatter.format(new Date(company.date_creation))
) : (
<Skeleton width={80} />
)}
<Skeleton width={80} />
)}
</strong>
, <T>domiciliée à</T>{' '}
{company ? (
@ -52,9 +53,10 @@ export default function CompanyDetails({ siren, denomination }) {
{company.etablissement_siege.code_postal})
</>
) : (
<Skeleton width={100} />
)}
</small>
<Skeleton width={100} />
)}
</p>
</>
)
}

View File

@ -13,7 +13,7 @@ export default function Search() {
const [isLoading, setLoadingState] = useState(false)
const handleSearch = useCallback(
function(value) {
function (value) {
searchDenominationOrSiren(value).then(results => {
setLoadingState(false)
setSearchResults(results)
@ -77,7 +77,7 @@ export default function Search() {
css={`
text-align: left;
width: 100%;
padding: 0.4rem;
padding: 0 0.4rem;
border-radius: 0.3rem;
:hover,
:focus {

View File

@ -5,6 +5,7 @@
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.9);
overflow: auto;
z-index: 1;
}
#overlayContent {

View File

@ -1,9 +1,17 @@
import FocusTrap from 'focus-trap-react'
import React from 'react'
import React, { useEffect } from 'react'
import * as animate from 'Ui/animate'
import { LinkButton } from 'Ui/Button'
import './Overlay.css'
export default function Overlay({ onClose, children, ...otherProps }) {
useEffect(() => {
const body = document.getElementsByTagName('body')[0]
body.classList.add('no-scroll');
return () => {
body.classList.remove('no-scroll')
}
}
, [])
return (
<div id="overlayWrapper">
<animate.fromBottom>

View File

@ -4,11 +4,7 @@ import withColours from 'Components/utils/withColours'
import withSitePaths from 'Components/utils/withSitePaths'
import Value from 'Components/Value'
import knownMecanisms from 'Engine/known-mecanisms.yaml'
import {
encodeRuleName,
findRuleByDottedName,
findRuleByNamespace
} from 'Engine/rules'
import { encodeRuleName, findRuleByDottedName, findRuleByNamespace } from 'Engine/rules'
import { compose, isEmpty } from 'ramda'
import React, { Suspense, useState } from 'react'
import emoji from 'react-easy-emoji'
@ -16,12 +12,7 @@ import { Helmet } from 'react-helmet'
import { Trans, useTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import {
exampleAnalysisSelector,
flatRulesSelector,
noUserInputSelector,
ruleAnalysisSelector
} from 'Selectors/analyseSelectors'
import { exampleAnalysisSelector, flatRulesSelector, noUserInputSelector, ruleAnalysisSelector } from 'Selectors/analyseSelectors'
import Animate from 'Ui/animate'
import { AttachDictionary } from '../AttachDictionary'
import RuleLink from '../RuleLink'
@ -96,37 +87,37 @@ export default compose(
</Suspense>
</>
) : (
<div id="rule">
<Animate.fromBottom>
<Helmet
title={title}
meta={[
{
name: 'description',
content: description
}
]}
/>
<RuleHeader
{...{
dottedName,
type,
description,
question,
flatRule,
flatRules,
name,
acronyme,
title,
icon,
valuesToShow
}}
/>
<div id="rule">
<Animate.fromBottom>
<Helmet
title={title}
meta={[
{
name: 'description',
content: description
}
]}
/>
<RuleHeader
{...{
dottedName,
type,
description,
question,
flatRule,
flatRules,
name,
acronyme,
title,
icon,
valuesToShow
}}
/>
<section id="rule-content">
<div
id="ruleValue"
css={`
<section id="rule-content">
<div
id="ruleValue"
css={`
display: flex;
justify-content: center;
flex-wrap: wrap;
@ -141,85 +132,85 @@ export default compose(
margin: 0 0.6em;
}
`}>
<Value
{...displayedRule}
nilValueSymbol={
displayedRule.parentDependency?.nodeValue == false
? '-'
: null
}
/>
<Period
period={flatRule['période']}
valuesToShow={valuesToShow}
/>
</div>
{displayedRule.defaultValue != null && (
<div id="ruleDefault">
par défaut :{' '}
<Value
{...displayedRule}
nodeValue={displayedRule.defaultValue}
nilValueSymbol={
displayedRule.parentDependency ?.nodeValue == false
? '-'
: null
}
/>
<Period
period={flatRule['période']}
valuesToShow={valuesToShow}
/>
</div>
)}
{!valuesToShow && (
<div style={{ textAlign: 'center', marginTop: '1em' }}>
<Link
className="ui__ cta plain button"
target="_parent"
to={
dottedName.includes('contrat salarié')
? sitePaths.sécuritéSociale.salarié
: dottedName.includes('auto-entrepreneur')
? sitePaths.sécuritéSociale['auto-entrepreneur']
: dottedName.includes('indépendant')
? sitePaths.sécuritéSociale.indépendant
: // otherwise
sitePaths.sécuritéSociale.index
}>
<T>Faire une simulation</T>
</Link>
</div>
)}
<Algorithm
rule={displayedRule}
showValues={valuesToShow || currentExample}
/>
{displayedRule['rend non applicable'] && (
<section id="non-applicable">
<h3>
<T>Rend non applicable les règles suivantes</T> :{' '}
</h3>
<ul>
{displayedRule['rend non applicable'].map(ruleName => (
<li key={ruleName}>
<RuleLink dottedName={ruleName} />
</li>
))}
</ul>
</section>
)}
{flatRule.note && (
<section id="notes">
<h3>Note : </h3>
<Markdown source={flatRule.note} />
</section>
)}
<Examples
currentExample={currentExample}
situationExists={valuesToShow}
rule={displayedRule}
/>
{!isEmpty(namespaceRules) && (
<NamespaceRulesList {...{ namespaceRules }} />
)}
{renderReferences(flatRule)}
</section>
{renderToggleSourceButton()}
</Animate.fromBottom>
</div>
)}
{displayedRule.defaultValue != null && (
<div id="ruleDefault">
par défaut :{' '}
<Value
{...displayedRule}
nodeValue={displayedRule.defaultValue}
/>
</div>
)}
{!valuesToShow && (
<div style={{ textAlign: 'center', marginTop: '1em' }}>
<Link
className="ui__ cta plain button"
target="_parent"
to={
dottedName.includes('contrat salarié')
? sitePaths.simulateurs.salarié
: dottedName.includes('auto-entrepreneur')
? sitePaths.simulateurs['auto-entrepreneur']
: dottedName.includes('indépendant')
? sitePaths.simulateurs.indépendant
: // otherwise
sitePaths.simulateurs.index
}>
<T>Faire une simulation</T>
</Link>
</div>
)}
<Algorithm
rule={displayedRule}
showValues={valuesToShow || currentExample}
/>
{displayedRule['rend non applicable'] && (
<section id="non-applicable">
<h3>
<T>Rend non applicable les règles suivantes</T> :{' '}
</h3>
<ul>
{displayedRule['rend non applicable'].map(ruleName => (
<li key={ruleName}>
<RuleLink dottedName={ruleName} />
</li>
))}
</ul>
</section>
)}
{flatRule.note && (
<section id="notes">
<h3>Note : </h3>
<Markdown source={flatRule.note} />
</section>
)}
<Examples
currentExample={currentExample}
situationExists={valuesToShow}
rule={displayedRule}
/>
{!isEmpty(namespaceRules) && (
<NamespaceRulesList {...{ namespaceRules }} />
)}
{renderReferences(flatRule)}
</section>
{renderToggleSourceButton()}
</Animate.fromBottom>
</div>
)}
</>
)
})
@ -260,13 +251,13 @@ let Period = ({ period, valuesToShow }) =>
valuesToShow && period === 'flexible' ? (
<PeriodSwitch />
) : (
<span className="inlineMecanism">
<span
className="name"
data-term-definition="période"
style={{ background: '#8e44ad' }}>
{period}
<span className="inlineMecanism">
<span
className="name"
data-term-definition="période"
style={{ background: '#8e44ad' }}>
{period}
</span>
</span>
</span>
)
)
) : null

View File

@ -93,7 +93,7 @@
}
.ui__.button.cta,
.ui__.inverted-button.cta {
margin: 1rem;
margin: 1rem 0;
display: inline-block;
align-self: center;
font-size: 120%;
@ -203,27 +203,14 @@
padding: 0.4rem 0.8rem;
border-radius: 0.3rem;
}
.ui__.button-choice:first-of-type {
margin-top: 2rem;
}
.ui__.button-choice:last-of-type {
margin-bottom: 2rem;
}
.ui__.button-choice {
display: flex;
padding-top: 1rem;
padding-bottom: 1rem;
align-items: baseline;
color: inherit;
line-height: 2rem;
padding-bottom: 1rem;
margin: 1rem 0;
position: relative;
text-decoration: none;
font-size: 1.15rem;
}
.ui__.button-choice small {
margin-left: 0.2rem;
flex-grow: 1;
}
.ui__.button-choice--soon {
@ -240,20 +227,6 @@
filter: saturate(0%);
}
.ui__.button-choice img {
margin-right: 2rem !important;
margin-left: 0.5rem !important;
transform: scale(1.5) translateY(0.1em);
}
@media (min-width: 600px) {
.ui__.button-choice:not(.button-choice--soon)::after {
content: '';
position: absolute;
right: 20px;
font-size: 2rem;
}
}
@keyframes push-button-down {
from {

View File

@ -75,10 +75,16 @@ button {
}
p,
a,
ul {
line-height: 1.7rem;
}
p, ul {
margin: 0 0 0.6rem;
}
p.ui__.lead {
font-size: 120%;
line-height: 2rem;
@ -127,4 +133,5 @@ small,
color: rgba(0, 0, 0, 0.6);
color: var(--lighterTextColour);
font-size: 85%;
line-height: 1.2rem;
}

View File

@ -64,6 +64,12 @@ blockquote {
flex-wrap: wrap;
}
@media (max-width: 850px) {
.ui__.hide-mobile {
display: none;
}
}
section {
padding: 1rem 0;
}
@ -104,3 +110,7 @@ span.ui__.enumeration:not(:last-of-type)::after {
border-radius: 0.3rem;
text-align: center;
}
.no-scroll {
overflow: hidden;
}

View File

@ -2,33 +2,33 @@
import React, { Component, createContext } from 'react'
import i18n from '../../i18n'
const SitePathsContext: React$Context<SitePaths> = createContext({})
export const SitePathsContext: React$Context<SitePaths> = createContext({})
export const SitePathProvider = SitePathsContext.Provider
export default function withSitePaths<Props: { sitePaths: SitePaths }>(
export default function withSitePaths<Props: { sitePaths: SitePaths }> (
WrappedComponent: React$ComponentType<Props>
): React$ComponentType<$Diff<Props, { sitePaths: SitePaths }>> {
class WithSitePaths extends Component<
$Diff<Props, { sitePaths: SitePaths }>
): React$ComponentType < $Diff < Props, { sitePaths: SitePaths } >> {
class WithSitePaths extends Component <
$Diff < Props, { sitePaths: SitePaths }>
> {
displayName = `withSitePaths(${WrappedComponent.displayName || ''})`
displayName = `withSitePaths(${WrappedComponent.displayName || ''})`
constructor(props) {
super(props)
i18n.on('languageChanged', () => {
this.forceUpdate()
})
}
super(props)
i18n.on('languageChanged', () => {
this.forceUpdate()
})
}
render() {
return (
<SitePathsContext.Consumer>
{sitePaths => (
<WrappedComponent {...this.props} sitePaths={sitePaths} />
)}
</SitePathsContext.Consumer>
)
}
}
return WithSitePaths
return (
<SitePathsContext.Consumer>
{sitePaths => (
<WrappedComponent {...this.props} sitePaths={sitePaths} />
)}
</SitePathsContext.Consumer>
)
}
}
return WithSitePaths
}
export type SitePaths = Object

View File

@ -502,26 +502,28 @@ path:
statutDirigeant: '/directors-status'
nombreAssociés: '/multiple-associates'
autoEntrepreneur: '/auto-entrepreneur'
sécuritéSociale:
index: '/social-security'
gérer:
index: '/manage'
embaucher: '/hiring'
selection: '/social-scheme-selection'
sécuritéSociale: '/social-security'
simulateurs:
index: /simulators
assimilé-salarié: '/assimilated-salaried'
indépendant: '/self-employed'
auto-entrepreneur: '/auto-entrepreneur'
salarié: '/salaried'
selection: '/social-scheme-selection'
comparaison: '/social-scheme-comparaison'
démarcheEmbauche:
index: '/hiring-process'
documentation:
exemples: '/examples'
privacy:
index: '/privacy'
integration:
index: '/integration'
iframe: '/iframe'
library: '/library'
économieCollaborative:
index: '/sharing-economy'
votreSituation: '/your-situation'
Auto-entrepreneur en EIRL: Auto-entrepreneur with EIRL option
auto-entrepreneur-EIRL: auto-entrepreneur-EIRL

View File

@ -1,5 +1,6 @@
import Route404 from 'Components/Route404'
import withSitePaths from 'Components/utils/withSitePaths'
import { rules as baseRulesEn, rulesFr as baseRulesFr } from 'Engine/rules'
import 'iframe-resizer'
import { compose } from 'ramda'
import createRavenMiddleware from 'raven-for-redux'
@ -10,21 +11,12 @@ import { useTranslation } from 'react-i18next'
import { Route, Switch } from 'react-router-dom'
import 'Ui/index.css'
import Provider from '../../Provider'
import {
persistEverything,
retrievePersistedState
} from '../../storage/persistEverything'
import {
persistSimulation,
retrievePersistedSimulation
} from '../../storage/persistSimulation'
import { persistEverything, retrievePersistedState } from '../../storage/persistEverything'
import { persistSimulation, retrievePersistedSimulation } from '../../storage/persistSimulation'
import Tracker, { devTracker } from '../../Tracker'
import { inIframe, getSessionStorage } from '../../utils'
import { getSessionStorage, inIframe } from '../../utils'
import './App.css'
import Footer from './layout/Footer/Footer'
import { PrivacyContent } from './layout/Footer/Privacy'
import Header from './layout/Header/Header'
import Navigation from './layout/Navigation/Navigation'
import trackSimulatorActions from './middlewares/trackSimulatorActions'
import CompanyIndex from './pages/Company'
import Couleur from './pages/Dev/Couleur'
@ -32,14 +24,15 @@ import IntegrationTest from './pages/Dev/IntegrationTest'
import Personas from './pages/Dev/Personas'
import Sitemap from './pages/Dev/Sitemap'
import Documentation from './pages/Documentation'
import HiringProcess from './pages/HiringProcess'
import Gérer from './pages/Gérer'
import Iframes from './pages/Iframes'
import Landing from './pages/Landing/Landing.js'
import Integration from './pages/integration/index'
import SocialSecurity from './pages/SocialSecurity'
import Landing from './pages/Landing/Landing.js'
import Simulateurs from './pages/Simulateurs'
import ÉconomieCollaborative from './pages/ÉconomieCollaborative'
import { constructLocalizedSitePath } from './sitePaths'
import { rules as baseRulesEn, rulesFr as baseRulesFr } from 'Engine/rules'
if (process.env.NODE_ENV === 'production') {
Raven.config(
@ -59,7 +52,7 @@ const middlewares = [
function InFranceRoute({ basename, language }) {
useEffect(() => {
getSessionStorage()?.setItem('lang', language)
getSessionStorage() ?.setItem('lang', language)
}, [language])
const paths = constructLocalizedSitePath(language)
const rules = language === 'en' ? baseRulesEn : baseRulesFr
@ -87,7 +80,6 @@ function InFranceRoute({ basename, language }) {
let RouterSwitch = () => {
return (
<>
{!inIframe() && <Navigation location={location} />}
<Switch>
<Route exact path="/" component={Landing} />
<Route path="/iframes" component={Iframes} />
@ -105,29 +97,28 @@ const App = compose(withSitePaths)(({ sitePaths }) => {
{/* Passing location down to prevent update blocking */}
<div className="app-content">
{!inIframe() && <Header />}
<div className="ui__ container" style={{ flexGrow: 1, flexShrink: 0 }}>
<Switch>
<Route path={sitePaths.entreprise.index} component={CompanyIndex} />
<Route
path={sitePaths.sécuritéSociale.index}
component={SocialSecurity}
/>
<Route
path={sitePaths.démarcheEmbauche.index}
component={HiringProcess}
path={sitePaths.gérer.index}
component={Gérer}
/>
<Route
path={sitePaths.économieCollaborative.index}
component={ÉconomieCollaborative}
/>
<Route
path={sitePaths.simulateurs.index}
component={Simulateurs}
/>
<Route
path={sitePaths.documentation.index}
component={Documentation}
/>
<Route path={sitePaths.privacy.index} component={PrivacyContent} />
<Route path={sitePaths.integration.index} component={Integration} />
<Route exact path="/dev/sitemap" component={Sitemap} />
<Route
exact

View File

@ -20,20 +20,20 @@ type OwnProps = {}
const feedbackBlacklist = [
['index'],
['entreprise', 'statutJuridique', 'index'],
['sécuritéSociale', 'indépendant'],
['sécuritéSociale', 'auto-entrepreneur'],
['sécuritéSociale', 'assimilé-salarié'],
['sécuritéSociale', 'salarié']
['simulateurs', 'indépendant'],
['simulateurs', 'auto-entrepreneur'],
['simulateurs', 'assimilé-salarié'],
['simulateurs', 'salarié']
].map(lensPath)
const Footer = ({ sitePaths }) => {
const hrefLink =
hrefLangLink[i18n.language][
decodeURIComponent(
(process.env.NODE_ENV === 'production'
? window.location.protocol + '//' + window.location.host
: '') + window.location.pathname
).replace(/\/$/, '')
decodeURIComponent(
(process.env.NODE_ENV === 'production'
? window.location.protocol + '//' + window.location.host
: '') + window.location.pathname
).replace(/\/$/, '')
] || []
return (
<div className="footer-container">
@ -108,8 +108,8 @@ const Footer = ({ sitePaths }) => {
) : hrefLang === 'en' ? (
<> Switch to English {emoji('🇬🇧')}</>
) : (
hrefLang
)}
hrefLang
)}
</a>
))}
</p>

View File

@ -1,63 +0,0 @@
.steps-header {
margin: 0.6rem 0 1rem;
margin-left: 2.5rem; /* Let some space for the menu button */
}
.steps-header nav {
max-width: 100%;
display: flex;
margin: auto;
justify-content: space-between;
background: white;
}
.steps-header a {
display: flex;
padding-right: 0.8rem;
text-decoration: none;
flex-shrink: 0;
text-align: center;
align-items: center;
}
.steps-header a:focus {
outline: none;
}
.steps-header a:last-child {
margin-right: 0;
}
.steps-header a img {
height: 3rem;
}
.steps-header a {
border-bottom: 2px solid;
transition: border-bottom 0.2s;
}
.steps-header a > * {
transition: transform 0.2s;
will-change: transform;
}
.steps-header a:hover > * {
/* padding-bottom: 3px; */
transform: translateY(-3px);
}
.steps-header a.active {
font-weight: 500;
}
.steps-header a:not(.active) {
border-color: transparent;
}
@media (max-width: 850px) {
.steps-header a > img {
display: none;
}
.steps-header a > div {
max-width: 4.5em;
}
.steps-header a {
padding: 0 0.8rem;
}
}

View File

@ -1,64 +0,0 @@
/* @flow */
import { React, T } from 'Components'
import withSitePaths from 'Components/utils/withSitePaths'
import withTracker from 'Components/utils/withTracker'
import companySvg from 'Images/company.svg'
import estimateSvg from 'Images/estimate.svg'
import hiringSvg from 'Images/hiring.svg'
import { compose } from 'ramda'
import { NavLink } from 'react-router-dom'
import './Header.css'
import type { Tracker } from 'Components/utils/withTracker'
type OwnProps = {}
type Props = OwnProps & {
tracker: Tracker,
sitePaths: Object
}
const StepsHeader = ({ tracker, sitePaths }: Props) => (
<header className="steps-header">
<nav className="ui__ container">
<NavLink
to={sitePaths.entreprise.index}
activeClassName="active"
onClick={() =>
tracker.push(['trackEvent', 'Header', 'click', 'Your company'])
}>
<img src={companySvg} />
<div>
<T>Mon entreprise</T>
</div>
</NavLink>
<NavLink
to={sitePaths.sécuritéSociale.index}
activeClassName="active"
onClick={() =>
tracker.push(['trackEvent', 'Header', 'click', 'Social security'])
}>
<img src={estimateSvg} />
<div>
<T>Protection sociale</T>
</div>
</NavLink>
<NavLink
to={sitePaths.démarcheEmbauche.index}
activeClassName="active"
onClick={() =>
tracker.push(['trackEvent', 'Header', 'click', 'Hiring process'])
}>
<img src={hiringSvg} />
<div>
<T>Embauche</T>
</div>
</NavLink>
</nav>
</header>
)
export default (compose(
withTracker,
withSitePaths
)(StepsHeader): React$ComponentType<OwnProps>)

View File

@ -1,124 +0,0 @@
/* @flow */
import classnames from 'classnames'
import withTracker from 'Components/utils/withTracker'
import { compose } from 'ramda'
import React, { Component } from 'react'
import { withRouter } from 'react-router'
import { NavLink } from 'react-router-dom'
import type { Tracker } from 'Components/utils/withTracker'
import type { Location } from 'react-router-dom'
import type { ChildrenArray, Node, Element } from 'react'
type OwnProps = {
children: ChildrenArray<Element<any>>,
to?: ?string,
title: Node
}
type Props = OwnProps & {
location: Location,
tracker: Tracker
}
type State = {
opened: boolean,
previousLocation: Location,
controlled: boolean
}
const containsActiveChildren = (
children: ChildrenArray<Element<any>>,
currentLocation: Location
) =>
React.Children.toArray(children).some(child => {
if (!React.isValidElement(child)) {
return false
}
if (child.props.to === currentLocation.pathname) {
return true
}
return containsActiveChildren(child.props.children, currentLocation)
})
class NavOpener extends Component<Props, State> {
constructor(props) {
super(props)
const containingActiveChildren = containsActiveChildren(
props.children,
props.location
)
this.state = {
opened: containingActiveChildren,
previousLocation: props.location,
controlled: false
}
}
static getDerivedStateFromProps(props, state) {
const containingActiveChildren = containsActiveChildren(
props.children,
props.location
)
return state.previousLocation !== props.location
? {
previousLocation: props.location,
opened: state.opened || containingActiveChildren
}
: null
}
handleToggle = event => {
this.props.tracker.push([
'trackEvent',
'Sidebar',
'click',
event.target.textContent
])
this.setState(({ opened }) => ({ opened: !opened, controlled: true }))
}
render() {
const parentClassNames = {
opened: this.state.controlled
? this.state.opened
: containsActiveChildren(this.props.children, this.props.location),
active: this.props.location.pathname === this.props.to
}
return (
<>
<span className={classnames('navigation__item', parentClassNames)}>
<button
className="ui__ text-button navigation__caret"
onClick={this.handleToggle}>
</button>
{this.props.to ? (
<NavLink
to={this.props.to}
onClick={event =>
this.props.tracker.push([
'trackEvent',
'Sidebar',
'click',
event.target.textContent
])
}
exact
className="ui__ text-button">
{this.props.title}
</NavLink>
) : (
<button
className={classnames('ui__', 'text-button', parentClassNames)}
onClick={this.handleToggle}>
{this.props.title}
</button>
)}
</span>
{this.props.children}
</>
)
}
}
export default (compose(
withTracker,
withRouter
)(NavOpener): React$ComponentType<OwnProps>)

View File

@ -1,118 +0,0 @@
.navigation .progress {
height: 2px;
position: absolute;
bottom: 5px;
background: rgba(41, 117, 209, 0.2);
border-radius: 0.1rem;
width: 100%;
}
.navigation .progress .bar {
transition: width 0.3s;
background-color: rgb(41, 117, 209);
height: 100%;
}
.navigation__container {
display: flex;
flex-direction: column;
align-items: flex-end;
flex-shrink: 0;
min-height: 100%;
background-color: rgb(227, 237, 249);
background-color: var(--lighterColour);
}
.navigation {
padding: 1rem 2rem 3rem 0.6rem;
flex: 1;
min-width: 20rem;
}
.navigation ul {
list-style: none;
margin: 0;
padding-left: 1.2rem;
}
.navigation li {
padding: 0;
}
.navigation > ul > li > ul {
visibility: visible !important;
height: auto !important;
}
.navigation__item:not(.opened) + ul {
visibility: hidden;
height: 0;
}
.navigation__item:hover {
opacity: 0.8;
}
.navigation__item:hover * {
opacity: 1 !important;
}
.navigation__caret {
width: 30px;
text-align: center !important;
transition: transform 0.2s;
font-size: 120% !important;
}
.navigation__item.opened .navigation__caret {
transform: rotate(90deg) translateX(1px) translateY(-1px);
}
.navigation__item {
left: -30px;
white-space: nowrap;
position: relative;
}
.navigation__item.active {
color: rgb(41, 117, 209);
color: var(--colour);
}
.navigation li > :first-child {
position: relative;
display: inline-block;
text-decoration: none;
width: 100%;
padding: 0.2rem 0;
}
.navigation > ul > li ul > li > :first-child:not(.active):not(:hover) {
opacity: 0.6;
}
.navigation a:not(.active) {
color: inherit;
}
.navigation a:hover {
text-decoration: underline;
}
.navigation > ul > li > :first-child,
.navigation > ul > li > :first-child * {
text-decoration: none !important;
line-height: 2rem;
font-family: 'Montserrat', sans-serif;
font-weight: 600;
color: var(--darkColour);
font-size: 1.3rem;
}
.navigation > ul > li > :first-child .navigation__caret {
visibility: hidden;
}
.navigation > ul > li > .navigation__item.opened {
color: var(--colour);
color: rgb(41, 117, 209);
}
.navigation__container .mobile__menu {
display: none;
height: 48px;
width: 48px;
}
@media (max-width: 500px) {
.navigation__container header {
background: transparent;
}
.navigation__container {
margin-right: 1rem;
}
}

View File

@ -1,286 +0,0 @@
/* @flow */
import { React, T } from 'Components'
import withSitePaths from 'Components/utils/withSitePaths'
import companySvg from 'Images/company.svg'
import estimateSvg from 'Images/estimate.svg'
import hiringSvg from 'Images/hiring.svg'
import { compose } from 'ramda'
import { useTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { NavLink } from 'react-router-dom'
import './Navigation.css'
import NavOpener from './NavOpener'
import SideBar from './SideBar'
type OwnProps = {}
type Props = OwnProps & {
companyProgress: number,
estimationProgress: number,
sitePaths: Object,
hiringProgress: number,
companyStatusChoice: string
}
const Navigation = ({ sitePaths, companyStatusChoice }: Props) => {
const { t } = useTranslation()
return (
<SideBar>
<div className="navigation__container">
<nav className="navigation">
<ul>
<li>
<NavLink to="/" exact className="navigationItem">
<T>Accueil</T>
</NavLink>
</li>
<li>
<NavOpener
to={sitePaths.entreprise.index}
exact={false}
title={
<>
<T>Mon entreprise</T>
<img
style={{ height: '2.5rem', marginBottom: '-0.8rem' }}
src={companySvg}
/>
</>
}>
<ul>
<li>
<NavOpener title={t('Créer mon entreprise')}>
<ul>
<li>
<NavOpener
to={sitePaths.entreprise.statutJuridique}
title={t('Guide du statut juridique')}>
<ul>
<li>
<NavLink
to={
sitePaths.entreprise.statutJuridique
.multipleAssociates
}>
<T k="associés.titre">Nombre d'associés</T>
</NavLink>
</li>
<li>
<NavLink
to={
sitePaths.entreprise.statutJuridique
.directorStatus
}>
<T k="statut du dirigeant.titre">
Statut du dirigeant
</T>
</NavLink>
</li>
<li>
<NavLink
to={
sitePaths.entreprise.statutJuridique
.soleProprietorship
}>
<T k="responsabilité.titre">Responsabilité</T>
</NavLink>
</li>
<li>
<NavLink
to={
sitePaths.entreprise.statutJuridique
.minorityDirector
}>
<T k="gérant minoritaire.titre">
Gérant majoritaire ou minoritaire
</T>
</NavLink>
</li>
<li>
<NavLink
to={
sitePaths.entreprise.statutJuridique
.autoEntrepreneur
}>
<T k="autoentrepreneur.titre">
Auto-entrepreneur ou EI
</T>
</NavLink>
</li>
<li>
<NavLink
to={
sitePaths.entreprise.statutJuridique.liste
}>
<T>Liste des statuts</T>
</NavLink>
</li>
</ul>
</NavOpener>
</li>
<li>
{/* Todo remove when no choice */}
<NavOpener
to={
companyStatusChoice
? sitePaths.entreprise.créer(
companyStatusChoice
)
: null
}
title={t('Démarches de création')}>
<ul>
<li>
<NavLink
to={sitePaths.entreprise.créer(
'auto-entrepreneur'
)}>
<T>Auto-entrepreneur</T>
</NavLink>
</li>
<li>
<NavLink to={sitePaths.entreprise.créer('EI')}>
EI
</NavLink>
</li>
<li>
<NavLink
to={sitePaths.entreprise.créer('EIRL')}>
EIRL
</NavLink>
</li>
<li>
<NavLink
to={sitePaths.entreprise.créer('EURL')}>
EURL
</NavLink>
</li>
<li>
<NavLink to={sitePaths.entreprise.créer('SA')}>
SA
</NavLink>
</li>
<li>
<NavLink
to={sitePaths.entreprise.créer('SARL')}>
SARL
</NavLink>
</li>
<li>
<NavLink to={sitePaths.entreprise.créer('SAS')}>
SAS
</NavLink>
</li>
<li>
<NavLink
to={sitePaths.entreprise.créer('SASU')}>
SASU
</NavLink>
</li>
</ul>
</NavOpener>
</li>
<li>
<NavLink to={sitePaths.entreprise.après}>
<T k="entreprise.tâches.ensuite">
Après la création
</T>
</NavLink>
</li>
</ul>
</NavOpener>
</li>
</ul>
</NavOpener>
</li>
<li>
<NavOpener
exact
to={sitePaths.sécuritéSociale.index}
title={
<>
<T>Protection sociale</T>
<img
style={{ height: '2.5rem', marginBottom: '-0.8rem' }}
src={estimateSvg}
/>
</>
}>
<ul>
<li>
<NavOpener
to={sitePaths.sécuritéSociale.selection}
title={<T>Rémunération du dirigeant</T>}>
<ul>
<li>
<NavLink
exact
to={sitePaths.sécuritéSociale['assimilé-salarié']}>
<T>Assimilé salarié</T>
</NavLink>
</li>
<li>
<NavLink
exact
to={sitePaths.sécuritéSociale.indépendant}>
<T>Indépendant</T>
</NavLink>
</li>
<li>
<NavLink
exact
to={sitePaths.sécuritéSociale['auto-entrepreneur']}>
<T>Auto-entrepreneur</T>
</NavLink>
</li>
<li>
<NavLink
exact
to={sitePaths.sécuritéSociale.comparaison}>
<T>Comparer les régimes</T>
</NavLink>
</li>
</ul>
</NavOpener>
</li>
<li>
<NavLink exact to={sitePaths.sécuritéSociale.salarié}>
<T>Simulateur de salaire</T>
</NavLink>
</li>
<li>
<NavLink exact to={sitePaths.documentation.exemples}>
<T>Exemples de simulation de salaire</T>
</NavLink>
</li>
</ul>
</NavOpener>
</li>
<li>
<NavLink to={sitePaths.démarcheEmbauche.index}>
<T>Embauche</T>
<img
style={{ height: '2.5rem', marginBottom: '-0.8rem' }}
src={hiringSvg}
/>
</NavLink>
</li>
<li>
<NavLink to={sitePaths.documentation.index}>
<T>Documentation</T>
</NavLink>
</li>
</ul>
</nav>
</div>
</SideBar>
)
}
export default (compose(
withSitePaths,
connect(
state => ({
companyStatusChoice: state.inFranceApp.companyStatusChoice
}),
{}
)
)(Navigation): React$ComponentType<OwnProps>)

View File

@ -1,59 +0,0 @@
.sidebar__container {
height: 100%;
position: absolute;
left: 0;
top: 0;
transform: translate(-100%);
/* let the browser know we plan to animate
each view in and out */
will-change: transform;
transition: transform 0.3s cubic-bezier(0.465, 0.183, 0.153, 0.946);
z-index: 1;
}
.sidebar__container.opened {
transform: translate(0%);
}
.sidebar__container + * {
will-change: transform;
transition: transform 0.3s cubic-bezier(0.465, 0.183, 0.153, 0.946);
}
.sidebar__container.opened + * {
transform: translateX(100%);
overflow: hidden;
}
.menu__button {
position: absolute;
top: 0;
height: 2.5rem;
padding: 0.6rem;
width: 2.5rem;
right: calc(-2.5rem);
background: radial-gradient(
circle,
rgba(255, 255, 255, 1) 50%,
rgba(255, 255, 255, 0) 70%
);
}
.menu__button:hover {
opacity: 0.8;
}
.menu__button img {
height: 100%;
}
.sidebar {
overflow: auto;
height: 100%;
}
@media (min-width: 500px) {
.sidebar__container.opened + * {
transform: none;
}
}
@media (max-width: 1500px) {
.sidebar__container.opened + * {
opacity: 0.5;
pointer-events: none;
}
}

View File

@ -1,91 +0,0 @@
/* @flow */
import classnames from 'classnames'
import withTracker from 'Components/utils/withTracker'
import { compose } from 'ramda'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useLocation } from 'react-router'
import backSvg from './back.svg'
import mobileMenuSvg from './mobile-menu.svg'
import './SideBar.css'
import type Tracker from '../../../../Tracker'
type OwnProps = {|
children: React$Node
|}
type Props = OwnProps & {
tracker: Tracker
}
const bigScreen = window.matchMedia('(min-width: 1500px)')
const isParent = (parentNode, children) => {
if (children === parentNode) {
return true
}
if (!children) {
return false
}
return isParent(parentNode, children.parentNode)
}
function SideBar({ tracker, children }: Props) {
const location = useLocation()
const [opened, setOpened] = useState(false)
const [sticky, setSticky] = useState(bigScreen.matches)
const [previousLocation, setPreviousLocation] = useState(location)
const ref = useRef()
useEffect(() => {
const handleClick = event => {
if (!sticky && !isParent(ref.current, event.target) && opened) {
handleClose()
}
}
window.addEventListener('click', handleClick)
bigScreen.addListener(handleMediaQueryChange)
return () => {
window.removeEventListener('click', handleClick)
bigScreen.removeListener(handleMediaQueryChange)
}
}, [handleClose, opened, sticky])
useEffect(() => {
if (!sticky && previousLocation !== location) {
setOpened(false)
}
setPreviousLocation(location)
}, [sticky, previousLocation, location])
const handleMediaQueryChange = () => {
setSticky(bigScreen.matches)
}
const handleClose = useCallback(() => {
tracker.push(['trackEvent', 'Sidebar', 'close'])
setOpened(false)
}, [tracker])
const handleOpen = () => {
tracker.push(['trackEvent', 'Sidebar', 'open'])
setOpened(true)
}
return (
<div
css="transform: translate(-100%)" // prevent FOUC effect
className={classnames('sidebar__container', {
opened: opened
})}
ref={ref}>
<div className="sidebar">{children}</div>
<button
className="menu__button"
onClick={opened ? handleClose : handleOpen}>
<img src={opened ? backSvg : mobileMenuSvg} />
</button>
</div>
)
}
export default (compose(withTracker)(SideBar): React$ComponentType<OwnProps>)

View File

@ -1 +0,0 @@
<svg preserveAspectRatio="xMidYMid meet" height="1em" width="1em" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="currentColor" class="_13gjrqj"><g><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></g></svg>

Before

Width:  |  Height:  |  Size: 339 B

View File

@ -1 +0,0 @@
<svg preserveAspectRatio="xMidYMid meet" height="1em" width="1em" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="currentColor" class="_13gjrqj"><g><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></g></svg>

Before

Width:  |  Height:  |  Size: 379 B

View File

@ -3,11 +3,11 @@ import { React, T } from 'Components'
import { ScrollToTop } from 'Components/utils/Scroll'
import withSitePaths from 'Components/utils/withSitePaths'
import { compose } from 'ramda'
import { useTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import Animate from 'Ui/animate'
import siret from './siret.jpg'
import { useTranslation } from 'react-i18next'
type OwnProps = {}
type Props = {
@ -70,7 +70,7 @@ const AfterRegistration = ({ companyStatusChoice, sitePaths }: Props) => {
<span
style={
companyStatusChoice &&
companyStatusChoice.match(/auto-entrepreneur|EI/)
companyStatusChoice.match(/auto-entrepreneur|EI/)
? { display: 'none' }
: {}
}>
@ -119,11 +119,6 @@ const AfterRegistration = ({ companyStatusChoice, sitePaths }: Props) => {
className="ui__ simple skip button left">
<T k="après.actions.retour">Démarche de création</T>
</Link>
<Link
to={sitePaths.sécuritéSociale.index}
className="ui__ plain button">
<T k="après.actions.avance">Estimez vos cotisations </T>
</Link>
</p>
</Animate.fromBottom>
)

View File

@ -31,8 +31,8 @@ const StatusButton = withSitePaths(
{status.includes('auto-entrepreneur') ? (
<T>Devenir</T>
) : (
<T>Créer une</T>
)}{' '}
<T>Créer une</T>
)}{' '}
{t(status)}
</Link>
</div>
@ -126,11 +126,6 @@ const SetMainStatus = ({
className="ui__ simple small skip button left">
<T>Précédent</T>
</button>
<Link
to={sitePaths.sécuritéSociale.index}
className="ui__ simple small skip button">
<T>Choisir plus tard</T>
</Link>
</div>
</>
)

View File

@ -0,0 +1,213 @@
/* @flow */
import { checkHiringItem, initializeHiringChecklist } from 'Actions/hiringChecklistAction'
import { React, T } from 'Components'
import withSitePaths from 'Components/utils/withSitePaths'
import { compose } from 'ramda'
import { Helmet } from 'react-helmet'
import { withTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import Animate from 'Ui/animate'
import { CheckItem, Checklist } from 'Ui/Checklist'
const Embaucher = ({
onChecklistInitialization,
sitePaths,
onItemCheck,
hiringChecklist,
t
}) => (
<Animate.fromBottom>
<Helmet>
<title>
{t(['embauche.tâches.page.titre', `Les formalités pour embaucher`])}
</title>
<meta
name="description"
content={t(
'embauche.tâches.page.description',
`Toutes les démarches nécessaires à l'embauche de votre premier salarié.`
)}
/>
</Helmet>
<h1>
<T k="embauche.tâches.titre">Les formalités pour embaucher</T>
</h1>
<p>
<T k="embauche.tâches.description">
Toutes les étapes nécessaires à l'embauche de votre premier employé.
</T>
</p>
<Checklist
onInitialization={onChecklistInitialization}
onItemCheck={onItemCheck}
defaultChecked={hiringChecklist}>
<CheckItem
name="contract"
title={
<T k="embauche.tâches.contrat.titre">
Signer un contrat de travail avec votre employé
</T>
}
explanations={
<p>
<a
className="ui__ button"
href="https://www.service-public.fr/particuliers/vosdroits/N19871"
target="_blank">
{' '}
<T>Plus d'informations</T>
</a>
</p>
}
/>
<CheckItem
name="dpae"
title={
<T k="embauche.tâches.dpae.titre">
Déclarer l'embauche à l'administration sociale
</T>
}
explanations={
<p>
<T k="embauche.tâches.dpae.description">
Ceci peut être fait par le biais du formulaire appelé DPAE, doit
être complété dans les 8 jours avant toute embauche, et peut{' '}
<a href="https://www.due.urssaf.fr" target="_blank">
être effectué en ligne
</a>
.
</T>
</p>
}
/>
<CheckItem
name="paySoftware"
title={
<T k="embauche.tâches.logiciel de paie.titre">
Choisir un logiciel de paie
</T>
}
explanations={
<p>
<T k="embauche.tâches.logiciel de paie.description">
Les fiches de paie et les déclarations peuvent être traitées en
ligne gratuitement par le{' '}
<a href="http://www.letese.urssaf.fr" target="_blank">
Tese
</a>
. Vous pouvez aussi utiliser un{' '}
<a
href="http://www.dsn-info.fr/convention-charte.htm"
target="_blank">
logiciel de paie privé.
</a>
</T>
</p>
}
/>
<CheckItem
name="registre"
title={
<T k="embauche.tâches.registre.titre">
Tenir un registre des employés à jour
</T>
}
explanations={
<p>
<a
href="https://www.service-public.fr/professionnels-entreprises/vosdroits/F1784"
className="ui__ button"
target="_blank">
<T>Plus d'informations</T>
</a>
</p>
}
/>
<CheckItem
name="complementaryPension"
title={
<T k="embauche.tâches.pension.titre">
Prendre contact avec l'institution de prévoyance complémentaire
obligatoire qui vous est assignée
</T>
}
explanations={
<p>
<a
href="https://www.espace-entreprise.agirc-arrco.fr/simape/#/donneesDep"
className="ui__ button"
target="_blank">
<T k="embauche.tâches.pension.description">
Trouver mon institution de prévoyance
</T>
</a>
{/* // The AGIRC-ARRCO complementary pension is mandatory. Those are only federations,{' '} */}
</p>
}
/>
<CheckItem
name="complementaryHealth"
title={
<T k="embauche.tâches.complémentaire santé.titre">
Choisir une complémentaire santé
</T>
}
explanations={
<p>
<T k="embauche.tâches.complémentaire santé.description">
Vous devez couvrir vos salariés avec l'assurance complémentaire
santé privée de votre choix (aussi appelée "mutuelle"), pour
autant qu'elle offre un ensemble de garanties minimales.
L'employeur doit payer au moins la moitié du forfait.
</T>
</p>
}
/>
<CheckItem
name="workMedicine"
title={
<T k="embauche.tâches.medecine.titre">
S'inscrire à un bureau de médecine du travail
</T>
}
explanations={
<p>
<T k="embauche.tâches.medecine.description">
N'oubliez pas de planifier un rendez-vous initial pour chaque
nouvelle embauche.{' '}
<a href="https://www.service-public.fr/particuliers/vosdroits/F2211">
Plus d'infos.
</a>
</T>
</p>
}
/>
</Checklist>
<T k="embauche.chaque mois">
<h2>Tous les mois</h2>
<ul>
<li>
Utiliser un logiciel de paie pour calculer les cotisations sociales et
les transmettre via la déclaration sociale nominative (DSN)
</li>
<li>Remettre la fiche de paie à votre employé</li>
</ul>
<Link className="ui__ button" to={sitePaths.simulateurs.salarié}>
Obtenir un exemple de fiche de paie
</Link>
</T>
</Animate.fromBottom>
)
export default compose(
withTranslation(),
withSitePaths,
connect(
state => ({ hiringChecklist: state.inFranceApp.hiringChecklist }),
{
onChecklistInitialization: initializeHiringChecklist,
onItemCheck: checkHiringItem
}
)
)(Embaucher)

View File

@ -0,0 +1,214 @@
import { resetEntreprise, specifyIfAutoEntrepreneur } from 'Actions/existingCompanyActions';
import { React, T } from 'Components';
import CompanyDetails from 'Components/CompanyDetails';
import FindCompany from 'Components/FindCompany';
import Overlay from 'Components/Overlay';
import { ScrollToTop } from 'Components/utils/Scroll';
import { SitePathsContext } from 'Components/utils/withSitePaths';
import { useContext, useEffect, useRef, useState } from 'react';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import * as Animate from 'Ui/animate';
import businessPlan from './businessPlan.svg';
const infereRégimeFromCompanyDetails = (
company
) => {
if (!company) {
return null
}
if (company.isAutoEntrepreneur) {
return 'auto-entrepreneur'
}
if (['EI', 'EURL'].includes(company.statutJuridique)) {
return 'indépendant'
}
if (['SASU', 'SAS'].includes(company.statutJuridique)) {
return 'assimilé-salarié'
}
return null
}
export default function SocialSecurity() {
const { t } = useTranslation()
const company = useSelector(state => state.inFranceApp.existingCompany)
const sitePaths = useContext(SitePathsContext)
const régime = infereRégimeFromCompanyDetails(company)
return (
<>
<Helmet>
<title>
{t('gérer.index.page.titre', 'Gérer mon activité')}
</title>
</Helmet>
<ScrollToTop />
<Animate.fromBottom>
<h1>
<T k="gérer.index.page.titre">
Gérer mon activité
</T>
</h1>
<div css="display: flex; align-items: flex-start; justify-content: space-between">
<div>{!company && <p className="ui__ lead" >
<T k="gérer.index.content.entreprise">
Vous souhaitez vous verser un revenu ou embaucher ? <br />
Vous aurez à payer des cotisations et des impôts. <br />
Pour anticiper leur montant, nous avons conçu des simulateurs adaptés à votre situation.
</T>
</p>}
<CompanySection company={company} />
</div>
<img
className="ui__ hide-mobile"
src={businessPlan}
css="max-width: 30%; transform: translateX(1.5rem) scale(1.5);" />
</div>
<>
<h2>Simulateurs</h2>
{!!régime && <Link
className="ui__ interactive card button-choice light-bg"
css="width: 100%"
to={
régime && sitePaths.simulateurs[régime]
}>
<p><T k='sécu.choix.dirigeant2'>
Calculer mon revenu net
</T></p>
<small>
Estimez précisément le montant de vos cotisations grâce au simulateur {régime} de lURSSAF
</small>
</Link>
}
{régime !== 'auto-entrepreneur' && <Link
className="ui__ interactive card button-choice light-bg "
css="width: 100%"
to={sitePaths.simulateurs.salarié}>
<p><T k="sécu.choix.employé">Estimer le montant dune embauche</T></p>
<small>Découvrez le montant total dépensé par lentreprise pour rémunérer votre prochain employé</small>
</Link>}
<h2>Liens utiles</h2>
<Link
className="ui__ interactive card button-choice light-bg"
css={`
width: 50%;
@media (max-width: 850px) {
width: 100%;
}
`}
to={sitePaths.gérer.embaucher}
>
<p>Découvrir les démarches dembauche </p>
<small>La liste des choses à faire pour être sûr de ne rien oublier lors de lembauche dun nouveau salarié</small>
</Link>
</>
}
</Animate.fromBottom>
</>
)
}
const CompanySection = ({ company }) => {
const [searchModal, showSearchModal] = useState(false)
const [autoEntrepreneurModal, showAutoEntrepreneurModal] = useState(false)
const companyRef = useRef(null)
useEffect(() => {
if (companyRef.current !== company) {
companyRef.current = company
if (searchModal && company) {
showSearchModal(false)
}
if (
company ?.statutJuridique === 'EI' &&
company ?.isAutoEntrepreneur == null
) {
showAutoEntrepreneurModal(true)
}
}
}, [company, searchModal])
const dispatch = useDispatch(company)
const handleAnswerAutoEntrepreneur = isAutoEntrepreneur => {
dispatch(specifyIfAutoEntrepreneur(isAutoEntrepreneur))
showAutoEntrepreneurModal(false)
}
return (
<>
{autoEntrepreneurModal && (
<>
<ScrollToTop />
<Overlay>
<h2> Êtes-vous auto-entrepreneur ? </h2>
<div className="ui__ answer-group">
<button
className="ui__ button"
onClick={() => handleAnswerAutoEntrepreneur(true)}>
Oui
</button>
<button
className="ui__ button"
onClick={() => handleAnswerAutoEntrepreneur(false)}>
Non
</button>
</div>
</Overlay>
</>
)}
{searchModal && (
<>
<ScrollToTop />
<Overlay onClose={() => showSearchModal(false)}>
<FindCompany />
</Overlay>
</>
)}
{company ? (
<>
<CompanyDetails siren={company.siren} />
<p> {company.statutJuridique !== 'NON_IMPLÉMENTÉ' &&
<>
<span className="ui__ label">
{company.isAutoEntrepreneur ?
'Auto-entrepreneur'
:
company.statutJuridique}
</span>
</>
}
</p>
<button
className="ui__ simple small button"
onClick={() => {
dispatch(resetEntreprise())
showSearchModal(true)
}}>
<T>Changer l'entreprise sélectionnée</T>
</button>
</>
) : (
<p>
<button
onClick={() => showSearchModal(true)}
className="ui__ plain cta button">
<T>Renseigner mon entreprise</T>
</button>
</p>
)}
</>
)
}

View File

@ -21,7 +21,7 @@ const SchemeChoice = compose(
</h1>
<p>
<Link
to={sitePaths.sécuritéSociale['assimilé-salarié']}
to={sitePaths.simulateurs['assimilé-salarié']}
className="ui__ interactive card light-bg button-choice">
{emoji('☂')}
<span>
@ -36,7 +36,7 @@ const SchemeChoice = compose(
</span>
</Link>
<Link
to={sitePaths.sécuritéSociale.indépendant}
to={sitePaths.simulateurs.indépendant}
className="ui__ interactive card light-bg button-choice">
{emoji('👩‍🔧')}
<span>
@ -51,7 +51,7 @@ const SchemeChoice = compose(
</span>
</Link>
<Link
to={sitePaths.sécuritéSociale['auto-entrepreneur']}
to={sitePaths.simulateurs['auto-entrepreneur']}
className="ui__ interactive card light-bg button-choice">
{emoji('🚶‍♂️')}
Auto-entrepreneur
@ -65,7 +65,7 @@ const SchemeChoice = compose(
<p style={{ textAlign: 'center', marginTop: '1rem' }}>
<Link
className="ui__ plain cta button"
to={sitePaths.sécuritéSociale.comparaison}>
to={sitePaths.simulateurs.comparaison}>
<T k="selectionRégime.comparer.cta">Comparer les régimes</T>
</Link>
</p>

View File

@ -0,0 +1,42 @@
import { React, T } from 'Components'
import { Helmet } from 'react-helmet'
import { useTranslation } from 'react-i18next'
import * as Animate from 'Ui/animate'
import Video from './Video'
export function SocialSecurity() {
const { t } = useTranslation()
return (
<>
<Helmet>
<title>
{t('sécu.page.titre', "Sécurité sociale")}
</title>
<meta name="description" content={t('sécu.page.description')} />
</Helmet>
<Animate.fromBottom>
<T k="sécu.content">
<h1>Protection sociale </h1>
<p>
En France, tous les travailleurs bénéficient d'une protection
sociale de qualité. Ce système obligatoire repose sur la solidarité
et vise à assurer le{' '}
<strong>bien-être général de la population</strong>.
</p>
<p>
En contrepartie du paiement de{' '}
<strong>contributions sociales</strong>, le cotisant est couvert sur
la maladie, les accidents du travail, chômage ou encore la retraite.
</p>
</T>
<section style={{ marginTop: '2rem' }}>
<Video />
</section>
</Animate.fromBottom>
</>
)
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,32 @@
import { ScrollToTop } from 'Components/utils/Scroll'
import { SitePathsContext } from 'Components/utils/withSitePaths'
import React, { useContext } from 'react'
import { Route, Switch } from 'react-router'
import Embaucher from './Embaucher'
import Home from './Home'
import SchemeSelection from './SchemeSelection'
import SécuritéSociale from './SécuritéSociale'
export default function Gérer() {
const sitePaths = useContext(SitePathsContext);
return (
<>
<ScrollToTop />
<Switch>
<Route exact path={sitePaths.gérer.index} component={Home} />
<Route
path={sitePaths.gérer.selection}
component={SchemeSelection}
/>
<Route
path={sitePaths.gérer.sécuritéSociale}
component={SécuritéSociale}
/>
<Route path={sitePaths.gérer.embaucher} component={Embaucher} />
</Switch>
</>
);
}

View File

@ -1,216 +0,0 @@
/* @flow */
import {
checkHiringItem,
initializeHiringChecklist
} from 'Actions/hiringChecklistAction'
import { React, T } from 'Components'
import withSitePaths from 'Components/utils/withSitePaths'
import { compose } from 'ramda'
import { Helmet } from 'react-helmet'
import { withTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import Animate from 'Ui/animate'
import { CheckItem, Checklist } from 'Ui/Checklist'
const HiringProcess = ({
onChecklistInitialization,
sitePaths,
onItemCheck,
hiringChecklist,
t
}) => (
<Animate.fromBottom>
<Helmet>
<title>
{t(['embauche.tâches.page.titre', `Les formalités pour embaucher`])}
</title>
<meta
name="description"
content={t(
'embauche.tâches.page.description',
`Toutes les démarches nécessaires à l'embauche de votre premier salarié.`
)}
/>
</Helmet>
<h1>
<T k="embauche.tâches.titre">Les formalités pour embaucher</T>
</h1>
<p>
<T k="embauche.tâches.description">
Toutes les étapes nécessaires à l'embauche de votre premier employé.
</T>
</p>
<Checklist
onInitialization={onChecklistInitialization}
onItemCheck={onItemCheck}
defaultChecked={hiringChecklist}>
<CheckItem
name="contract"
title={
<T k="embauche.tâches.contrat.titre">
Signer un contrat de travail avec votre employé
</T>
}
explanations={
<p>
<a
className="ui__ button"
href="https://www.service-public.fr/particuliers/vosdroits/N19871"
target="_blank">
{' '}
<T>Plus d'informations</T>
</a>
</p>
}
/>
<CheckItem
name="dpae"
title={
<T k="embauche.tâches.dpae.titre">
Déclarer l'embauche à l'administration sociale
</T>
}
explanations={
<p>
<T k="embauche.tâches.dpae.description">
Ceci peut être fait par le biais du formulaire appelé DPAE, doit
être complété dans les 8 jours avant toute embauche, et peut{' '}
<a href="https://www.due.urssaf.fr" target="_blank">
être effectué en ligne
</a>
.
</T>
</p>
}
/>
<CheckItem
name="paySoftware"
title={
<T k="embauche.tâches.logiciel de paie.titre">
Choisir un logiciel de paie
</T>
}
explanations={
<p>
<T k="embauche.tâches.logiciel de paie.description">
Les fiches de paie et les déclarations peuvent être traitées en
ligne gratuitement par le{' '}
<a href="http://www.letese.urssaf.fr" target="_blank">
Tese
</a>
. Vous pouvez aussi utiliser un{' '}
<a
href="http://www.dsn-info.fr/convention-charte.htm"
target="_blank">
logiciel de paie privé.
</a>
</T>
</p>
}
/>
<CheckItem
name="registre"
title={
<T k="embauche.tâches.registre.titre">
Tenir un registre des employés à jour
</T>
}
explanations={
<p>
<a
href="https://www.service-public.fr/professionnels-entreprises/vosdroits/F1784"
className="ui__ button"
target="_blank">
<T>Plus d'informations</T>
</a>
</p>
}
/>
<CheckItem
name="complementaryPension"
title={
<T k="embauche.tâches.pension.titre">
Prendre contact avec l'institution de prévoyance complémentaire
obligatoire qui vous est assignée
</T>
}
explanations={
<p>
<a
href="https://www.espace-entreprise.agirc-arrco.fr/simape/#/donneesDep"
className="ui__ button"
target="_blank">
<T k="embauche.tâches.pension.description">
Trouver mon institution de prévoyance
</T>
</a>
{/* // The AGIRC-ARRCO complementary pension is mandatory. Those are only federations,{' '} */}
</p>
}
/>
<CheckItem
name="complementaryHealth"
title={
<T k="embauche.tâches.complémentaire santé.titre">
Choisir une complémentaire santé
</T>
}
explanations={
<p>
<T k="embauche.tâches.complémentaire santé.description">
Vous devez couvrir vos salariés avec l'assurance complémentaire
santé privée de votre choix (aussi appelée "mutuelle"), pour
autant qu'elle offre un ensemble de garanties minimales.
L'employeur doit payer au moins la moitié du forfait.
</T>
</p>
}
/>
<CheckItem
name="workMedicine"
title={
<T k="embauche.tâches.medecine.titre">
S'inscrire à un bureau de médecine du travail
</T>
}
explanations={
<p>
<T k="embauche.tâches.medecine.description">
N'oubliez pas de planifier un rendez-vous initial pour chaque
nouvelle embauche.{' '}
<a href="https://www.service-public.fr/particuliers/vosdroits/F2211">
Plus d'infos.
</a>
</T>
</p>
}
/>
</Checklist>
<T k="embauche.chaque mois">
<h2>Tous les mois</h2>
<ul>
<li>
Utiliser un logiciel de paie pour calculer les cotisations sociales et
les transmettre via la déclaration sociale nominative (DSN)
</li>
<li>Remettre la fiche de paie à votre employé</li>
</ul>
<Link className="ui__ button" to={sitePaths.sécuritéSociale.salarié}>
Obtenir un exemple de fiche de paie
</Link>
</T>
</Animate.fromBottom>
)
export default compose(
withTranslation(),
withSitePaths,
connect(
state => ({ hiringChecklist: state.inFranceApp.hiringChecklist }),
{
onChecklistInitialization: initializeHiringChecklist,
onItemCheck: checkHiringItem
}
)
)(HiringProcess)

View File

@ -5,9 +5,9 @@ import urssafSvg from 'Images/urssaf.svg'
import React, { useEffect, useState } from 'react'
import emoji from 'react-easy-emoji'
import { Trans } from 'react-i18next'
import { Link } from 'react-router-dom'
import screenfull from 'screenfull'
import { isIE } from '../../../../utils'
import Privacy from '../../layout/Footer/Privacy'
export default function IframeFooter() {
const [isFullscreen, setIsFullscreen] = useState(screenfull.isFullscreen)
@ -62,9 +62,7 @@ export default function IframeFooter() {
{emoji('🖨')}
<Trans>Imprimer</Trans>
</button>
<Link to="/vie-privée" target="_top">
<Trans>Vie privée</Trans>
</Link>
<Privacy />
</div>
</>
)

View File

@ -4,7 +4,7 @@ import { compose } from 'ramda'
import React from 'react'
import { Helmet } from 'react-helmet'
import { connect } from 'react-redux'
import { SalarySimulation } from '../SocialSecurity/Salarié'
import { SalarySimulation } from '../Simulateurs/Salarié'
export default compose(
withSitePaths,
@ -15,7 +15,7 @@ export default compose(
return (
<>
<Helmet>
<link rel="canonical" href={sitePaths.sécuritéSociale.salarié} />
<link rel="canonical" href={sitePaths.simulateurs.salarié} />
</Helmet>
{showMonEntrepriseLink && (
<Banner icon="✨">

View File

@ -1,9 +1,9 @@
import { IsEmbeddedContext } from 'Components/utils/embeddedContext'
import React from 'react'
import { Route } from 'react-router'
import SimulateurAssimiléSalarié from '../SocialSecurity/AssimiléSalarié'
import SimulateurAutoEntrepreneur from '../SocialSecurity/AutoEntrepreneur'
import SimulateurIndépendant from '../SocialSecurity/Indépendant'
import SimulateurAssimiléSalarié from '../Simulateurs/AssimiléSalarié'
import SimulateurAutoEntrepreneur from '../Simulateurs/AutoEntrepreneur'
import SimulateurIndépendant from '../Simulateurs/Indépendant'
import IframeFooter from './IframeFooter'
import SimulateurEmbauche from './SimulateurEmbauche'

View File

@ -85,7 +85,7 @@ export default withSitePaths(({ sitePaths }: Props) => {
</Link>
<Link
className="ui__ interactive card box "
to={sitePaths.sécuritéSociale.index}>
to={sitePaths.gérer.index}>
<div className="ui__ big box-icon">{emoji('💶')}</div>
<T k="landing.choice.manage">
<h3>Gérer mon activité</h3>

View File

@ -0,0 +1,38 @@
import { ScrollToTop } from 'Components/utils/Scroll'
import { SitePathsContext } from 'Components/utils/withSitePaths'
import React, { useContext } from 'react'
import { Route, Switch } from 'react-router'
import AssimiléSalarié from './AssimiléSalarié'
import AutoEntrepreneur from './AutoEntrepreneur'
import Indépendant from './Indépendant'
import Salarié from './Salarié'
import SchemeComparaison from './SchemeComparaison'
export default function Simulateurs() {
const sitePaths = useContext(SitePathsContext);
return (
<>
<ScrollToTop />
<Switch>
{/* <Route exact path={sitePaths.simulateurs.index} component={Home} /> */}
<Route path={sitePaths.simulateurs.salarié} component={Salarié} />
<Route
path={sitePaths.simulateurs.comparaison}
component={SchemeComparaison}
/>
<Route
path={sitePaths.simulateurs['assimilé-salarié']}
component={AssimiléSalarié}
/>
<Route
path={sitePaths.simulateurs.indépendant}
component={Indépendant}
/>
<Route
path={sitePaths.simulateurs['auto-entrepreneur']}
component={AutoEntrepreneur}
/>
</Switch>
</>
)
}

View File

@ -1,240 +0,0 @@
/* @flow */
import {
resetEntreprise,
specifyIfAutoEntrepreneur
} from 'Actions/existingCompanyActions'
import { React, T } from 'Components'
import CompanyDetails from 'Components/CompanyDetails'
import FindCompany from 'Components/FindCompany'
import Overlay from 'Components/Overlay'
import { ScrollToTop } from 'Components/utils/Scroll'
import withSitePaths from 'Components/utils/withSitePaths'
import { useEffect, useRef, useState } from 'react'
import emoji from 'react-easy-emoji'
import { Helmet } from 'react-helmet'
import { useTranslation } from 'react-i18next'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import * as Animate from 'Ui/animate'
import Video from './Video'
import type { Match, Location } from 'react-router'
const infereRégimeFromCompanyDetails = (
company
): 'indépendant' | 'assimilé-salarié' | 'auto-entrepreneur' | null => {
if (!company) {
return null
}
if (company.isAutoEntrepreneur) {
return 'auto-entrepreneur'
}
if (['EI', 'EURL'].includes(company.statutJuridique)) {
return 'indépendant'
}
if (['SASU', 'SAS'].includes(company.statutJuridique)) {
return 'assimilé-salarié'
}
return null
}
type Props = {
match: Match,
location: Location,
showFindYourCompanyLink: boolean,
legalStatus: string,
régime: 'indépendant' | 'assimilé-salarié' | 'auto-entrepreneur' | null,
sitePaths: Object
}
function SocialSecurity({ sitePaths }: Props) {
const { t } = useTranslation()
const company = useSelector(state => state.inFranceApp.existingCompany)
const régime = infereRégimeFromCompanyDetails(company)
return (
<>
<Helmet>
<title>
{t('sécu.page.titre', "Sécurité sociale et coût d'embauche")}
</title>
<meta name="description" content={t('sécu.page.description')} />
</Helmet>
<ScrollToTop />
<Animate.fromBottom>
<T k="sécu.content">
<h1>Protection sociale </h1>
<p>
En France, tous les travailleurs bénéficient d'une protection
sociale de qualité. Ce système obligatoire repose sur la solidarité
et vise à assurer le{' '}
<strong>bien-être général de la population</strong>.
</p>
<p>
En contrepartie du paiement de{' '}
<strong>contributions sociales</strong>, le cotisant est couvert sur
la maladie, les accidents du travail, chômage ou encore la retraite.
</p>
</T>
<CompanySection company={company} />
<section
style={{ marginTop: '2rem' }}
className="ui__ full-width light-bg">
<div className="ui__ container">
{régime === 'auto-entrepreneur' ? (
<Link
className="ui__ interactive card button-choice "
to={sitePaths.sécuritéSociale['auto-entrepreneur']}>
{emoji('🚶')}{' '}
<T k="sécu.choix.auto-entrepreneur">
Estimer ma rémunération en tant qu'auto-entrepreneur
</T>
</Link>
) : (
<>
<h2>
<T k="sécu.choix.titre">Que souhaitez-vous estimer ?</T>
</h2>
<Link
className="ui__ interactive card button-choice "
to={
régime
? sitePaths.sécuritéSociale[régime]
: sitePaths.sécuritéSociale.selection
}>
{emoji('💰')}{' '}
{company?.statutJuridique &&
company.statutJuridique !== 'NON_IMPLÉMENTÉ'
? t(
[
'sécu.choix.dirigeant1',
`Mon revenu en tant que dirigeant de {{legalStatus}}`
],
{ legalStatus: t(company.statutJuridique) }
)
: t(
'sécu.choix.dirigeant2',
`Mon revenu en tant que chef d'entreprise`
)}
</Link>
<Link
className="ui__ interactive card button-choice "
to={sitePaths.sécuritéSociale.salarié}>
{emoji('👥')}{' '}
<T k="sécu.choix.employé">Le salaire d'un employé</T>
</Link>
</>
)}
</div>
</section>
<section style={{ marginTop: '2rem' }}>
<Video />
</section>
</Animate.fromBottom>
</>
)
}
const CompanySection = ({ company }) => {
const [searchModal, showSearchModal] = useState(false)
const [autoEntrepreneurModal, showAutoEntrepreneurModal] = useState(false)
const companyRef = useRef(null)
useEffect(() => {
if (companyRef.current !== company) {
companyRef.current = company
if (searchModal && company) {
showSearchModal(false)
}
if (
company?.statutJuridique === 'EI' &&
company?.isAutoEntrepreneur == null
) {
showAutoEntrepreneurModal(true)
}
}
}, [company, searchModal])
const dispatch = useDispatch(company)
const handleAnswerAutoEntrepreneur = isAutoEntrepreneur => {
dispatch(specifyIfAutoEntrepreneur(isAutoEntrepreneur))
showAutoEntrepreneurModal(false)
}
return (
<>
{autoEntrepreneurModal && (
<>
<ScrollToTop />
<Overlay>
<h2> Êtes-vous auto-entrepreneur ? </h2>
<div className="ui__ answer-group">
<button
className="ui__ button"
onClick={() => handleAnswerAutoEntrepreneur(true)}>
Oui
</button>
<button
className="ui__ button"
onClick={() => handleAnswerAutoEntrepreneur(false)}>
Non
</button>
</div>
</Overlay>
</>
)}
{searchModal && (
<>
<ScrollToTop />
<Overlay onClose={() => showSearchModal(false)}>
<FindCompany />
</Overlay>
</>
)}
{company ? (
<>
<h2>
<T>Votre entreprise</T>
</h2>
<CompanyDetails siren={company.siren} />
<br />
<button
className="ui__ simple small button"
onClick={() => {
dispatch(resetEntreprise())
showSearchModal(true)
}}>
<T>Changer</T>
</button>
</>
) : (
<>
<h2>
<T>Simulations personnalisées</T>
</h2>
<p>
<T k="sécu.entrepriseCrée">
Si vous possédez déjà une entreprise, nous pouvons{' '}
<strong>automatiquement personnaliser</strong> vos simulations à
votre situation.
</T>
</p>
<div style={{ textAlign: 'center' }}>
<button
onClick={() => showSearchModal(true)}
className="ui__ button plain">
<T>Renseigner mon entreprise</T>
</button>
</div>
</>
)}
</>
)
}
export default withSitePaths(SocialSecurity)

View File

@ -1,43 +0,0 @@
import { ScrollToTop } from 'Components/utils/Scroll'
import withSitePaths from 'Components/utils/withSitePaths'
import React from 'react'
import { Route, Switch } from 'react-router'
import AssimiléSalarié from './AssimiléSalarié'
import AutoEntrepreneur from './AutoEntrepreneur'
import Home from './Home'
import Indépendant from './Indépendant'
import Salarié from './Salarié'
import SchemeComparaison from './SchemeComparaison'
import SchemeSelection from './SchemeSelection'
const SocialSecurityRoutes = ({ sitePaths }) => (
<>
<ScrollToTop />
<Switch>
<Route exact path={sitePaths.sécuritéSociale.index} component={Home} />
<Route path={sitePaths.sécuritéSociale.salarié} component={Salarié} />
<Route
path={sitePaths.sécuritéSociale.comparaison}
component={SchemeComparaison}
/>
<Route
path={sitePaths.sécuritéSociale['assimilé-salarié']}
component={AssimiléSalarié}
/>
<Route
path={sitePaths.sécuritéSociale.indépendant}
component={Indépendant}
/>
<Route
path={sitePaths.sécuritéSociale.selection}
component={SchemeSelection}
/>
<Route
path={sitePaths.sécuritéSociale['auto-entrepreneur']}
component={AutoEntrepreneur}
/>
</Switch>
</>
)
export default withSitePaths(SocialSecurityRoutes)

View File

@ -31,28 +31,28 @@ export const constructLocalizedSitePath = (language: string) => {
créer: (companyStatus: LegalStatus | ':status') =>
companyStatus === ':status'
? [
t('path.entreprise.créer', '/créer-une-{{companyStatus}}', {
companyStatus: ':status'
}),
t(
'path.entreprise.devenirAutoEntrepreneur',
'/devenir-{{autoEntrepreneur}}',
{
autoEntrepreneur: ':status'
}
)
]
t('path.entreprise.créer', '/créer-une-{{companyStatus}}', {
companyStatus: ':status'
}),
t(
'path.entreprise.devenirAutoEntrepreneur',
'/devenir-{{autoEntrepreneur}}',
{
autoEntrepreneur: ':status'
}
)
]
: companyStatus.includes('auto-entrepreneur')
? t(
? t(
'path.entreprise.devenirAutoEntrepreneur',
'/devenir-{{autoEntrepreneur}}',
{
autoEntrepreneur: companyStatus
}
)
: t('path.entreprise.créer', '/créer-une-{{companyStatus}}', {
)
: t('path.entreprise.créer', '/créer-une-{{companyStatus}}', {
companyStatus
}),
}),
après: t('path.entreprise.après', '/après-la-création'),
statutJuridique: {
@ -80,26 +80,28 @@ export const constructLocalizedSitePath = (language: string) => {
)
}
},
sécuritéSociale: {
index: t('path.sécuritéSociale.index', '/sécurité-sociale'),
gérer: {
index: t('path.gérer.index', '/gérer'),
embauche: t('path.gérer.embaucher', '/embaucher'),
selection: t('path.gérer.selection', '/sélection-du-régime'),
sécuritéSociale: t('path.gérer.selection', '/sécurité-sociale'),
},
simulateurs: {
index: t('path.simulateurs.index', '/simulateurs'),
'assimilé-salarié': t(
'path.sécuritéSociale.assimilé-salarié',
'path.simulateurs.assimilé-salarié',
'/assimilé-salarié'
),
indépendant: t('path.sécuritéSociale.indépendant', '/indépendant'),
indépendant: t('path.simulateurs.indépendant', '/indépendant'),
'auto-entrepreneur': t(
'path.sécuritéSociale.auto-entrepreneur',
'path.simulateurs.auto-entrepreneur',
'/auto-entrepreneur'
),
comparaison: t(
'path.sécuritéSociale.comparaison',
'path.simulateurs.comparaison',
'/comparaison-régimes-sociaux'
),
selection: t('path.sécuritéSociale.selection', '/sélection-du-régime'),
salarié: t('path.sécuritéSociale.salarié', '/salarié')
},
démarcheEmbauche: {
index: t('path.démarcheEmbauche.index', '/démarches-embauche')
salarié: t('path.simulateurs.salarié', '/salarié')
},
économieCollaborative: {
index: t('path.économieCollaborative.index', '/économie-collaborative'),
@ -112,9 +114,6 @@ export const constructLocalizedSitePath = (language: string) => {
exemples: t('path.documentation.exemples', '/exemples'),
index: t('path.documentation.index', '/documentation')
},
privacy: {
index: t('path.privacy.index', '/vie-privée')
},
integration: {
index: t('path.integration.index', '/intégration'),
iframe: t('path.integration.iframe', '/iframe'),