}
{children}
@@ -162,7 +158,7 @@ const Underlay = styled.div`
right: 0;
bottom: 0;
left: 0;
- overflow: auto;
+ overflow: visible;
z-index: 200; // to be in front of the menu of the Publicodes doc
background: rgba(0, 0, 0, 0.5);
animation: ${appear} 0.2s;
diff --git a/site/source/design-system/popover/PopoverConfirm.tsx b/site/source/design-system/popover/PopoverConfirm.tsx
index 1be192f66..be4cadee5 100644
--- a/site/source/design-system/popover/PopoverConfirm.tsx
+++ b/site/source/design-system/popover/PopoverConfirm.tsx
@@ -35,9 +35,10 @@ export default function PopoverConfirm({
return (
{(closePopover) => (
-
-
{title}
- {children}
+
+ {title &&
{title}
}
+
+
{children}
@@ -56,7 +57,7 @@ export default function PopoverConfirm({
-
+
)}
)
@@ -68,7 +69,3 @@ const StyledGrid = styled(Grid)`
gap: ${({ theme }) => theme.spacings.md};
margin-top: ${({ theme }) => theme.spacings.xl};
`
-
-const StyledContainer = styled.div`
- padding: ${({ theme }) => theme.spacings.xxl};
-`
diff --git a/site/source/design-system/tag/index.tsx b/site/source/design-system/tag/index.tsx
index 70cdec28d..3efc35aa4 100644
--- a/site/source/design-system/tag/index.tsx
+++ b/site/source/design-system/tag/index.tsx
@@ -1,12 +1,47 @@
import styled from 'styled-components'
-export const Tag = styled.div`
+import { baseTheme, getColorGroup } from '../theme'
+
+export type TagType = keyof typeof baseTheme.colors.bases &
+ keyof typeof baseTheme.colors.extended &
+ keyof typeof baseTheme.colors.publics
+
+type SizeType = 'sm' | 'md' | 'lg'
+
+const lightColors = ['grey']
+
+export const Tag = styled.div<{ $color?: TagType; $size?: SizeType }>`
font-family: ${({ theme }) => theme.fonts.main};
- background-color: ${({ theme }) => theme.colors.bases.primary[100]};
+
display: flex;
+ align-items: center;
width: fit-content;
- padding: 0.25rem 1rem;
+ padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
- color: ${({ theme }) => theme.colors.extended.grey[800]};
font-weight: 500;
+ background-color: ${({ theme, $color }) =>
+ $color
+ ? theme.colors[getColorGroup($color)][$color][
+ lightColors.includes($color) ? 300 : 100
+ ]
+ : theme.colors.bases.primary[100]};
+ color: ${({ theme, $color }) =>
+ $color
+ ? theme.colors[getColorGroup($color)][$color][600]
+ : theme.colors.extended.grey[800]};
+ font-size: ${({ $size }) => {
+ switch ($size) {
+ case 'sm':
+ return '0.75rem'
+ case 'md':
+ default:
+ return '1rem'
+ }
+ }};
+ svg {
+ fill: ${({ theme, $color }) =>
+ $color
+ ? theme.colors[getColorGroup($color)][$color][600]
+ : theme.colors.extended.grey[800]};
+ }
`
diff --git a/site/source/design-system/theme.ts b/site/source/design-system/theme.ts
index 37bdc7a2e..709b7667e 100644
--- a/site/source/design-system/theme.ts
+++ b/site/source/design-system/theme.ts
@@ -1,6 +1,8 @@
import { Theme } from '@/types/styled'
-const baseTheme = {
+import { TagType } from './tag'
+
+export const baseTheme = {
colors: {
bases: {
primary: {
@@ -183,6 +185,19 @@ const baseTheme = {
},
}
+export type ColorGroups = Array
+
+export const getColorGroup = (color: TagType) => {
+ const colorGroups: ColorGroups = Object.keys(baseTheme.colors).map(
+ (colorGroup) => colorGroup as keyof typeof baseTheme.colors
+ )
+
+ return colorGroups.find(
+ (colorGroup: keyof typeof baseTheme.colors) =>
+ !!baseTheme.colors[colorGroup]?.[color]
+ ) as keyof typeof baseTheme.colors
+}
+
// We use the Grid from material-ui, we need to uniformise
// breakpoints and spacing with the Urssaf design system
export type SpacingKey = keyof typeof baseTheme.breakpointsWidth
diff --git a/site/source/design-system/tooltip/Tooltip.tsx b/site/source/design-system/tooltip/Tooltip.tsx
new file mode 100644
index 000000000..af5d4c787
--- /dev/null
+++ b/site/source/design-system/tooltip/Tooltip.tsx
@@ -0,0 +1,54 @@
+import React, { ReactNode } from 'react'
+import { Tooltip as RTooltip } from 'react-tooltip'
+
+import 'react-tooltip/dist/react-tooltip.css'
+
+import styled from 'styled-components'
+
+export const Tooltip = ({
+ children,
+ tooltip,
+ className,
+ id,
+}: {
+ children: ReactNode
+ tooltip: ReactNode
+ className?: string
+ // A11y : préciser un aria-describedby sur l'élément visé par le tooltip
+ id: string
+}) => {
+ return (
+
+ {React.Children.map(children, (child) => {
+ if (React.isValidElement(child)) {
+ return React.cloneElement(child, { id } as {
+ id: string
+ })
+ }
+ })}
+
+ {tooltip}
+
+
+ )
+}
+
+const StyledRTooltip = styled(RTooltip)`
+ max-width: 20rem;
+ font-size: 0.75rem;
+`
+const StyledSpan = styled.span`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ .react-tooltip {
+ opacity: 1 !important;
+ background: ${({ theme }) => theme.colors.extended.grey[800]};
+ color: ${({ theme }) => theme.colors.extended.grey[100]};
+ z-index: 100;
+ }
+`
diff --git a/site/source/design-system/tooltip/index.stories.tsx b/site/source/design-system/tooltip/index.stories.tsx
new file mode 100644
index 000000000..6aade290f
--- /dev/null
+++ b/site/source/design-system/tooltip/index.stories.tsx
@@ -0,0 +1,31 @@
+import { ComponentMeta, ComponentStory } from '@storybook/react'
+
+import { Tooltip } from '@/design-system/tooltip'
+
+// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
+export default {
+ component: Tooltip,
+ // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
+ argTypes: {
+ children: {
+ type: 'string',
+ },
+ tooltip: {
+ type: 'string',
+ },
+ id: {
+ type: 'string',
+ },
+ },
+} as ComponentMeta
+
+// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args
+const Template: ComponentStory = (args) =>
+
+export const Basic = Template.bind({})
+// More on args: https://storybook.js.org/docs/react/writing-stories/args
+Basic.args = {
+ children: 'Passez la souris sur moi',
+ tooltip: 'Coucou !',
+ id: 'test-tooltip',
+}
diff --git a/site/source/design-system/tooltip/index.ts b/site/source/design-system/tooltip/index.ts
new file mode 100644
index 000000000..1a0b4fb06
--- /dev/null
+++ b/site/source/design-system/tooltip/index.ts
@@ -0,0 +1 @@
+export { Tooltip } from './Tooltip'
diff --git a/site/source/hooks/useSaveAndRestoreScrollPosition.ts b/site/source/hooks/useSaveAndRestoreScrollPosition.ts
index 68e530bc5..386badde1 100644
--- a/site/source/hooks/useSaveAndRestoreScrollPosition.ts
+++ b/site/source/hooks/useSaveAndRestoreScrollPosition.ts
@@ -4,6 +4,7 @@ import { useLocation, useNavigationType } from 'react-router-dom'
import { debounce, getSessionStorage } from '@/utils'
const POP_ACTION_LABEL = 'POP'
+const REPLACE_ACTION_LABEL = 'REPLACE'
const sessionStorage = getSessionStorage()
export const useSaveAndRestoreScrollPosition = () => {
@@ -13,7 +14,11 @@ export const useSaveAndRestoreScrollPosition = () => {
useEffect(() => {
const scrollPosition = sessionStorage?.getItem(location.pathname)
- if (scrollPosition && navigationType === POP_ACTION_LABEL) {
+ if (
+ scrollPosition &&
+ (navigationType === POP_ACTION_LABEL ||
+ navigationType === REPLACE_ACTION_LABEL)
+ ) {
window.scrollTo(0, parseInt(scrollPosition))
}
}, [location, navigationType])
diff --git a/site/source/locales/rules-en.yaml b/site/source/locales/rules-en.yaml
index 037e0caaf..fc026a045 100644
--- a/site/source/locales/rules-en.yaml
+++ b/site/source/locales/rules-en.yaml
@@ -5202,48 +5202,6 @@ protection sociale:
formation professionnelle et le transport.
titre.en: social welfare
titre.fr: protection sociale
-protection sociale . accidents du travail et maladies professionnelles:
- description.en: >
- [automatic] Occupational injury and disease insurance is the
- oldest branch of Social Security: it is based on principles dating back to
- 1898 and included in the law of December 31, 1946.
-
-
- [🎞️ See the video](https://www.youtube.com/watch?v=NaGI_deZJD8 )
-
-
- The AT/MP contribution covers the risks of accidents at work, commuting accidents and occupational diseases for employees under the general scheme.
-
-
- To find out about occupational risks and set up prevention actions, the [AT/MP account](https://www.ameli.fr/entreprise/votre-entreprise/compte-atmp/ouvrir-compte-atmp) is a service open to all companies under the general Social Security scheme.
-
-
- In the event of an occupational injury, medical and surgical care is fully reimbursed within the limits of the Social Security rates.
- description.fr: >
- L’assurance AT/MP (accident du travail et maladie
- professionnelle) est la plus ancienne branche de la Sécurité sociale : elle
- relève de principes qui remontent à l’année 1898 et qui ont été repris dans
- la loi du 31 décembre 1946.
-
-
- [🎞️ Voir la vidéo](https://www.youtube.com/watch?v=NaGI_deZJD8 )
-
-
- La cotisation AT/MP couvre les risques accidents du travail, accidents de trajet et maladies professionnelles pour les salariés relevant du régime général.
-
-
- Pour connaître les risques professionnels et mettre en place des actions de prévention, le [compte AT/MP](https://www.ameli.fr/entreprise/votre-entreprise/compte-atmp/ouvrir-compte-atmp) est un service ouvert à toutes les entreprises du régime général de la Sécurité sociale.
-
-
- En cas d’AT/MP, les soins médicaux et chirurgicaux sont remboursés intégralement dans la limite des tarifs de la Sécurité sociale.
- note.en: |
- [automatic] The rate is 80% from the 29th day of the stoppage.
- note.fr: |
- Le taux est de 80% à partir du 29e jour d'arrêt.
- résumé.en: Provides comprehensive coverage for occupational diseases or accidents.
- résumé.fr: Offre une couverture complète des maladies ou accidents du travail.
- titre.en: Work accidents / occupational diseases
- titre.fr: accidents du travail et maladies professionnelles
protection sociale . assurance chômage:
description.en: >
Since 1958, the Unemployment Insurance has been protecting all
@@ -5408,9 +5366,33 @@ protection sociale . maladie:
des maladies graves comme les séjours à l'hôpital.
titre.en: '[automatic] health insurance'
titre.fr: assurance maladie
-protection sociale . maladie . ATMP:
- titre.en: '[automatic] Workplace injury and occupational disease'
- titre.fr: Accident du travail et maladie professionnelle
+protection sociale . maladie . accidents du travail et maladies professionnelles:
+ description.en: >
+ [automatic] Have you suffered an accident at work or an
+ occupational disease?
+
+ Your medical expenses are covered at 100%.
+
+
+ To compensate for your loss of salary, you can receive a daily allowance.
+
+ If you are declared unfit as a result of your accident/illness, you may receive a temporary incapacity benefit.
+ description.fr: >
+ Vous avez subi un accident du travail ou êtes atteint d’une
+ maladie professionnelle ?
+
+ Vos frais médicaux sont pris en charge à 100 %.
+
+
+ Pour compenser votre perte de salaire, vous pouvez percevoir des indemnités journalières.
+
+ Si vous êtes déclaré inapte suite à votre accident / maladie, vous pouvez recevoir une indemnité temporaire d'inaptitude.
+ résumé.en:
+ '[automatic] Provides comprehensive coverage for work-related illness
+ or injury.'
+ résumé.fr: Offre une couverture complète des maladies ou accidents du travail.
+ titre.en: '[automatic] work accidents and occupational diseases'
+ titre.fr: accidents du travail et maladies professionnelles
protection sociale . maladie . arrêt maladie:
description.en: >-
[automatic] If you are off work due to illness, you are entitled
@@ -5432,6 +5414,9 @@ protection sociale . maladie . arrêt maladie . indépendant:
protection sociale . maladie . arrêt maladie . salarié:
titre.en: '[automatic] employee'
titre.fr: salarié
+protection sociale . maladie . maternité paternité adoption:
+ titre.en: '[automatic] maternity and paternity leave benefits'
+ titre.fr: indemnités congé maternité paternité adoption
protection sociale . retraite:
description.en: >
[automatic] ### A mandatory system ...
@@ -5544,9 +5529,9 @@ protection sociale . retraite . base:
This estimate of your retirement pension is calculated based on the following principles:
- - Your earnings are calculated on the basis of your best 25 years
+ - The earnings calculated in the simulator correspond to your best 25 years
- - You have contributed enough quarters and you leave at the age required to benefit from the full rate
+ - You have contributed enough quarters and you are leaving at the age required to benefit from the full rate
description.fr: >
Le montant de votre pension pour la retraite de base est calculé
à partir la moyenne de vos revenus des 25 meilleures années.
@@ -5554,7 +5539,7 @@ protection sociale . retraite . base:
Cet estimation de votre pension de retraite est calculée en se basant sur les principes suivants :
- - La rémunération calculée correspond à celle de vos 25 meilleures années
+ - La rémunération calculée dans le simulateur correspond à celle de vos 25 meilleures années
- Vous avez cotisé suffisement de trimestres et vous partez à l'âge requis pour bénéficier du taux plein
résumé.en: '[automatic] Full basic retirement pension assuming your earnings
diff --git a/site/source/locales/ui-en.yaml b/site/source/locales/ui-en.yaml
index da6b74525..63095aa5c 100644
--- a/site/source/locales/ui-en.yaml
+++ b/site/source/locales/ui-en.yaml
@@ -191,6 +191,8 @@ Mois non concerné: Month not concerned
Mon entreprise: My company
Mon revenu: My income
Montant: Amount
+Montant annuel: Yearly amount
+Montant mensuel: Monthly amount
Montant de l'impôt sur les sociétés: Amount of corporate income tax
Montant de l’exonération sociale liée à la crise sanitaire pour les cotisations de l’année 2021: Amount of the health crisis exemption for contributions in 2021
Montant de l’exonération sociale liée à la crise sanitaire sur l’année 2021: Amount of the social exemption related to the health crisis in 2021
diff --git a/site/source/locales/ui-fr.yaml b/site/source/locales/ui-fr.yaml
index aaa13df0a..ffed9e5c6 100644
--- a/site/source/locales/ui-fr.yaml
+++ b/site/source/locales/ui-fr.yaml
@@ -137,6 +137,8 @@ Modifier l'entreprise: Modifier l'entreprise
Modifier mes réponses: Modifier mes réponses
Mois non concerné: Mois non concerné
Mon entreprise: Mon entreprise
+Montant annuel: Montant annuel
+Montant mensuel: Montant mensuel
Montant de l'impôt sur les sociétés: Montant de l'impôt sur les sociétés
Montant de l’exonération sociale liée à la crise sanitaire pour les cotisations de l’année 2021:
Montant de l’exonération sociale liée à la crise sanitaire pour les
diff --git a/site/source/pages/Landing/Landing.tsx b/site/source/pages/Landing/Landing.tsx
index 506bf370c..ad220fe95 100644
--- a/site/source/pages/Landing/Landing.tsx
+++ b/site/source/pages/Landing/Landing.tsx
@@ -86,7 +86,7 @@ export default function Landing() {
>
-
+ , Engine, Engine]
+}) => {
+ const defaultValueImpot = useEngine().evaluate(
+ DOTTEDNAME_SOCIETE_IMPOT
+ ).nodeValue
+ const defaultValueVersementLiberatoire = autoEntrepreneurEngine.evaluate(
+ DOTTEDNAME_SOCIETE_VERSEMENT_LIBERATOIRE
+ ).nodeValue
+ const defaultValueACRE = assimiléEngine.evaluate(DOTTEDNAME_ACRE).nodeValue
+
+ const [impotValue, setImpotValue] = useState(
+ `'${String(defaultValueImpot)}'` || "'IS'"
+ )
+ const [versementLiberatoireValue, setVersementLiberatoireValue] = useState(
+ defaultValueVersementLiberatoire
+ )
+ const [acreValue, setAcreValue] = useState(defaultValueACRE)
+ const { isAutoEntrepreneurACREEnabled, setIsAutoEntrepreneurACREEnabled } =
+ useCasParticuliers()
+
+ const [AEAcreValue, setAEAcreValue] = useState(null)
+
+ const { t } = useTranslation()
+
+ const dispatch = useDispatch()
+
+ return (
+ void }) => (
+
+ Aller plus loin
+
+ )}
+ confirmLabel="Enregistrer les options"
+ onConfirm={() => {
+ dispatch(
+ answerQuestion(
+ DOTTEDNAME_SOCIETE_IMPOT,
+ impotValue as PublicodesExpression
+ )
+ )
+
+ const versementLibératoireValuePassed =
+ versementLiberatoireValue === null
+ ? defaultValueVersementLiberatoire
+ : versementLiberatoireValue
+ dispatch(
+ answerQuestion(
+ DOTTEDNAME_SOCIETE_VERSEMENT_LIBERATOIRE,
+ versementLibératoireValuePassed ? 'oui' : 'non'
+ )
+ )
+
+ const acreValuePassed =
+ acreValue === null ? defaultValueACRE : acreValue
+ dispatch(
+ answerQuestion(DOTTEDNAME_ACRE, acreValuePassed ? 'oui' : 'non')
+ )
+
+ if (AEAcreValue !== null) {
+ setIsAutoEntrepreneurACREEnabled(AEAcreValue)
+ }
+ }}
+ onCancel={() => {
+ setAcreValue(null)
+ setVersementLiberatoireValue(null)
+ }}
+ >
+ <>
+
+ Aller plus loin sur les revenus
+
+
+ Calculer vos revenus
+
+
+
+ {t(
+ 'comparateur.allerPlusLoin.tableCaption',
+ "Tableau affichant le détail du calcul du revenu net pour la SASU, l'entreprise individuelle (EI) et l'auto-entreprise (AE)."
+ )}
+
+
+
+
Type de structure
+
+
+ SASU
+
+
+
+
+
+
+ EI
+
+
+
+
+
+
+
+ AE
+
+
+
+
+
+
+
+
+
+ -
+ {' '}
+ Chiffre d'affaires
+
+
+
+
+
+
+
+
+
+ -Charges
+
+
+
+
+
+
+
+
+
+ -{' '}
+ Cotisations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -Impôts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ {' '}
+
+ Revenu net
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Bénéficier de l'ACRE
+
+
+
+
+ L'aide à la création ou à la reprise d'une entreprise (Acre) consiste
+ en une exonération partielle de charges sociales,
+ dite exonération de début d'activité pendant 12 mois.
+
+ {
+ // TODO : décommenter une fois le simulateur créé
+
+ En savoir plus
+
+ }
+
Choisir mon option de simulation
+
+
+ setAcreValue(value)}
+ defaultSelected={defaultValueACRE as boolean}
+ />
+
+
+
+ {(acreValue || defaultValueACRE) && (
+ <>
+
+ Les{' '}
+
+ conditions d'accès
+ {' '}
+ à l'ACRE sont plus restrictives pour les auto-entrepreneurs.
+
+
+ setAEAcreValue(value)}
+ defaultSelected={isAutoEntrepreneurACREEnabled}
+ />
+
+
+ >
+ )}
+
+
+
+
+ Impôt sur le revenu, impôt sur les sociétés : que choisir ?
+
+
+ L’EI et la SASU permettent de{' '}
+
+ choisir entre l’imposition sur les sociétés et sur le revenu
+ {' '}
+ durant les 5 premières années. En auto-entreprise (AE), c’est l’
+ impôt sur le revenu qui est appliqué automatiquement
+ ; dans certaines situations, vous pouvez aussi opter pour le{' '}
+
+
+ versement libératoire
+
+
+ .
+
+
Choisir mon option de simulation (pour EI)
+
+
+
+
+
+
+
+
+ À ce jour, ce comparateur ne prend pas en compte le calcul de
+ l'impôt sur le revenu pour les SASU. La modification du
+ paramètre ci-dessous influera donc uniquement les calculs liés
+ au statut d'entreprise individuelle (EI).
+
+
+
+
+
+ {
+ setImpotValue(String(value))
+ }}
+ key="imposition"
+ aria-labelledby="questionHeader"
+ engine={indépendantEngine}
+ />
+
+