feat(rgcp): ajout de champs pour gérer les mois incomplets

pull/3258/head
Alice Dahan 2024-12-06 16:54:25 +01:00 committed by liliced
parent b52009bd6f
commit 08b90703a2
4 changed files with 298 additions and 65 deletions

View File

@ -208,8 +208,9 @@ describe(
.should('have.length', 12)
.first()
.click()
cy.get('div[id="options-janvier"]').should('be.visible')
cy.get('div[id="options-janvier"] input').type('{selectall}28,15')
cy.get('input[id="option-heures-sup-janvier"]')
.should('be.visible')
.type('{selectall}28,15')
cy.get(
'#salarié___cotisations___exonérations___réduction_générale-janvier'

View File

@ -1490,14 +1490,30 @@ pages:
caption: "General discount month by month :"
options:
description: Adds fields to modulate employee activity
heures-sup:
popover: "<0>The number of hours of overtime and complementary work is used to
calculate the general reduction: gross remuneration is compared with
the SMIC increased by this number of hours.</0>"
label:
heures-complémentaires: Overtime
heures-supplémentaires: Overtime
popover: "<0>The number of hours of overtime or complementary work is used to
calculate the general reduction: gross remuneration is compared with
the SMIC increased by this number of hours.</0><1>If you have answered
the question on overtime or complementary hours, the value will be
overwritten by the value you enter month by month.</1>"
heures-complémentaires: Number of overtime hours
heures-supplémentaires: Number of overtime hours
rémunération-etp: Basic remuneration for a full month
rémunération-heures-complémentaires: Overtime pay
rémunération-heures-supplémentaires: Overtime pay
rémunération-primes: Remuneration not affected by the incomplete month
mois-incomplet:
description: Adds fields to handle incomplete months
rémunération-etp:
popover: <0>Indicate here the remuneration that would have been paid for a full
month, <2>excluding</2>:<4><0>bonuses and other remuneration not
affected by the absence ;</0><1>remuneration for overtime or
additional hours worked.</1></4></0>
rémunération-heures-sup:
popover: <0>Indicate here the remuneration relating to the payment of overtime
or complementary hours.</0>
rémunération-primes:
popover: <0>Indicate here any elements of remuneration not affected by the
absence, such as bonuses.</0>
régularisation:
annuelle: Annual adjustment
progressive: Progressive regularization

View File

@ -1584,15 +1584,30 @@ pages:
caption: "Réduction générale mois par mois :"
options:
description: Ajoute des champs pour moduler l'activité du salarié
heures-sup:
popover: "<0>Le nombre d'heures supplémentaires et complémentaires est utilisé
dans le calcul de la réduction générale : la rémunération brute est
comparée au montant du SMIC majoré de ce nombre d'heures.</0>"
label:
heures-complémentaires: Heures complémentaires
heures-supplémentaires: Heures supplémentaires
popover: "<0>Le nombre d'heures supplémentaires et complémentaires est utilisé
dans le calcul de la réduction générale : la rémunération brute est
comparée au montant du SMIC majoré de ce nombre d'heures.</0><1>Si
vous avez répondu à la question sur les heures supplémentaires ou
complémentaires, la valeur sera écrasée par celle que vous saisissez
mois par mois.</1>"
heures-complémentaires: Nombre d'heures complémentaires
heures-supplémentaires: Nombre d'heures supplémentaires
rémunération-etp: Rémunération de base mois complet
rémunération-heures-complémentaires: Rémunération des heures complémentaires
rémunération-heures-supplémentaires: Rémunération des heures supplémentaires
rémunération-primes: Rémunération non affectée par le mois incomplet
mois-incomplet:
description: Ajoute des champs pour gérer le cas d'un mois incomplet
rémunération-etp:
popover: <0>Indiquez ici la rémunération qui aurait été versée pour un mois
complet, <2>en excluant</2> :<4><0>les primes et autres éléments de
rémunération non affectés par l'absence ;</0><1>la rémunération des
heures supplémentaires ou complémentaires.</1></4></0>
rémunération-heures-sup:
popover: <0>Indiquez ici la rémunération afférente au paiement des heures
supplémentaires ou complémentaires.</0>
rémunération-primes:
popover: <0>Indiquez ici les éléments de rémunération non affectés par
l'absence, comme les primes.</0>
régularisation:
annuelle: Régularisation annuelle
progressive: Régularisation progressive

View File

@ -1,9 +1,10 @@
import { useState } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { styled } from 'styled-components'
import { Appear } from '@/components/ui/animate'
import { useEngine } from '@/components/utils/EngineContext'
import { Message, NumberField } from '@/design-system'
import { NumberField } from '@/design-system'
import { HelpButtonWithPopover } from '@/design-system/buttons'
import {
StyledInput,
@ -11,7 +12,13 @@ import {
StyledSuffix,
} from '@/design-system/field/TextField'
import { FlexCenter } from '@/design-system/global-style'
import { RotatingChevronIcon } from '@/design-system/icons'
import { Grid } from '@/design-system/layout'
import { baseTheme } from '@/design-system/theme'
import { Strong } from '@/design-system/typography'
import { Li, Ul } from '@/design-system/typography/list'
import { Body, SmallBody } from '@/design-system/typography/paragraphs'
import { useMediaQuery } from '@/hooks/useMediaQuery'
import { Options } from '../utils'
@ -30,91 +37,275 @@ export default function MonthOptions({
}: Props) {
const { t } = useTranslation()
const engine = useEngine()
const [isMoisIncompletVisible, setMoisIncompletVisible] = useState(false)
const isDesktop = useMediaQuery(
`(min-width: ${baseTheme.breakpointsWidth.md})`
)
const isTempsPartiel = engine.evaluate(
'salarié . contrat . temps de travail . temps partiel'
).nodeValue as boolean
const additionalHours = isTempsPartiel ? 'complémentaires' : 'supplémentaires'
const additionalHours = isTempsPartiel
? 'heuresComplémentaires'
: 'heuresSupplémentaires'
const additionalHoursLabels = {
supplémentaires: t(
heuresSupplémentaires: t(
'pages.simulateurs.réduction-générale.options.label.heures-supplémentaires',
'Heures supplémentaires'
"Nombre d'heures supplémentaires"
),
complémentaires: t(
heuresComplémentaires: t(
'pages.simulateurs.réduction-générale.options.label.heures-complémentaires',
'Heures complémentaires'
"Nombre d'heures complémentaires"
),
}
const additionalHoursRémunérationLabels = {
heuresSupplémentaires: t(
'pages.simulateurs.réduction-générale.options.label.rémunération-heures-supplémentaires',
'Rémunération des heures supplémentaires'
),
heuresComplémentaires: t(
'pages.simulateurs.réduction-générale.options.label.rémunération-heures-complémentaires',
'Rémunération des heures complémentaires'
),
}
const onChange = (value?: number) => {
const options = {
const onHeuresSupChange = (value?: number) => {
const newOptions = {
...options,
heuresSupplémentaires: 0,
heuresComplémentaires: 0,
}
if (isTempsPartiel) {
options.heuresComplémentaires = value ?? 0
newOptions.heuresComplémentaires = value ?? 0
} else {
options.heuresSupplémentaires = value ?? 0
newOptions.heuresSupplémentaires = value ?? 0
}
onOptionsChange(index, options)
onOptionsChange(index, newOptions)
}
const onRémunérationETPChange = (value?: number) => {
const newOptions = {
...options,
rémunérationETP: value ?? 0,
}
onOptionsChange(index, newOptions)
}
const onRémunérationPrimesChange = (value?: number) => {
const newOptions = {
...options,
rémunérationPrimes: value ?? 0,
}
onOptionsChange(index, newOptions)
}
const onRémunérationHeuresSupChange = (value?: number) => {
const newOptions = {
...options,
rémunérationHeuresSup: value ?? 0,
}
onOptionsChange(index, newOptions)
}
return (
<Appear>
<InputContainer id={`options-${month}`}>
<FlexDiv>
<StyledSmallBody id={`heures-${additionalHours}-label`}>
{additionalHoursLabels[additionalHours]}
</StyledSmallBody>
<HelpButtonWithPopover
type="info"
title={additionalHoursLabels[additionalHours]}
>
<HeuresSupplémentairesPopoverContent />
</HelpButtonWithPopover>
</FlexDiv>
<Grid container columnSpacing={4} style={{ alignItems: 'center' }}>
<Grid item>
<FlexDiv>
<StyledLabel id={`heures-sup-label`}>
{additionalHoursLabels[additionalHours]}
</StyledLabel>
<HelpButtonWithPopover
type="info"
title={additionalHoursLabels[additionalHours]}
>
<HeuresSupplémentairesPopoverContent />
</HelpButtonWithPopover>
</FlexDiv>
</Grid>
<Grid item>
<NumberFieldContainer>
<NumberField
id={`option-heures-sup-${month}`}
small={true}
value={options[additionalHours]}
onChange={onHeuresSupChange}
aria-labelledby={`heures-sup-label`}
displayedUnit="heures"
/>
</NumberFieldContainer>
</Grid>
</Grid>
<NumberFieldContainer>
<NumberField
small={true}
value={
isTempsPartiel
? options.heuresComplémentaires
: options.heuresSupplémentaires
}
onChange={onChange}
aria-labelledby={`heures-${additionalHours}-label`}
displayedUnit="heures"
/>
</NumberFieldContainer>
</InputContainer>
<StyledButton
role="button"
onClick={() => setMoisIncompletVisible(!isMoisIncompletVisible)}
aria-describedby="options-mois-incomplet-description"
aria-expanded={isMoisIncompletVisible}
aria-controls={`options-mois-incomplet-${month}`}
aria-label={!isMoisIncompletVisible ? t('Déplier') : t('Replier')}
>
Mois incomplet {isDesktop && '(embauche, absences, départ...)'}{' '}
<RotatingChevronIcon aria-hidden $isOpen={isMoisIncompletVisible} />
</StyledButton>
<span id="options-mois-incomplet-description" className="sr-only">
{t(
'pages.simulateurs.réduction-générale.options.mois-incomplet.description',
"Ajoute des champs pour gérer le cas d'un mois incomplet"
)}
</span>
{isMoisIncompletVisible && (
<Grid
container
columnSpacing={4}
style={{ alignItems: 'center' }}
id={`options-mois-incomplet-${month}`}
>
<Grid item>
<FlexDiv>
<StyledLabel id={`rémunération-etp-label`}>
{t(
'pages.simulateurs.réduction-générale.options.label.rémunération-etp',
'Rémunération de base mois complet'
)}
</StyledLabel>
<HelpButtonWithPopover
type="info"
title={t(
'pages.simulateurs.réduction-générale.options.label.rémunération-etp',
'Rémunération de base mois complet'
)}
>
<RémunérationETPPopoverContent />
</HelpButtonWithPopover>
</FlexDiv>
</Grid>
<Grid item>
<NumberFieldContainer>
<NumberField
id={`option-rémunération-etp-${month}`}
small={true}
value={options.rémunérationETP}
onChange={onRémunérationETPChange}
aria-labelledby={`rémunération-etp-label`}
displayedUnit="€"
/>
</NumberFieldContainer>
</Grid>
<Grid item>
<FlexDiv>
<StyledLabel id={`rémunération-primes-label`}>
{t(
'pages.simulateurs.réduction-générale.options.label.rémunération-primes',
'Rémunération non affectée par le mois incomplet'
)}
</StyledLabel>
<HelpButtonWithPopover
type="info"
title={t(
'pages.simulateurs.réduction-générale.options.label.rémunération-primes',
'Rémunération non affectée par le mois incomplet'
)}
>
<RémunérationPrimesPopoverContent />
</HelpButtonWithPopover>
</FlexDiv>
</Grid>
<Grid item>
<NumberFieldContainer>
<NumberField
id={`option-rémunération-primes-${month}`}
small={true}
value={options.rémunérationPrimes}
onChange={onRémunérationPrimesChange}
aria-labelledby={`rémunération-primes-label`}
displayedUnit="€"
/>
</NumberFieldContainer>
</Grid>
<Grid item>
<FlexDiv>
<StyledLabel id={`rémunération-heures-sup-label`}>
{additionalHoursRémunérationLabels[additionalHours]}
</StyledLabel>
<HelpButtonWithPopover
type="info"
title={additionalHoursRémunérationLabels[additionalHours]}
>
<RémunérationHeuresSupPopoverContent />
</HelpButtonWithPopover>
</FlexDiv>
</Grid>
<Grid item>
<NumberFieldContainer>
<NumberField
id={`option-rémunération-heures-sup-${month}`}
small={true}
value={options.rémunérationHeuresSup}
onChange={onRémunérationHeuresSupChange}
aria-labelledby={`rémunération-heures-sup-label`}
displayedUnit="€"
/>
</NumberFieldContainer>
</Grid>
</Grid>
)}
</Appear>
)
}
const HeuresSupplémentairesPopoverContent = () => (
<Trans i18nKey="pages.simulateurs.réduction-générale.options.popover">
<Trans i18nKey="pages.simulateurs.réduction-générale.options.heures-sup.popover">
<Body>
Le nombre d'heures supplémentaires et complémentaires est utilisé dans le
calcul de la réduction générale : la rémunération brute est comparée au
montant du SMIC majoré de ce nombre d'heures.
</Body>
<Message type="info">
Si vous avez répondu à la question sur les heures supplémentaires ou
complémentaires, la valeur sera écrasée par celle que vous saisissez mois
par mois.
</Message>
</Trans>
)
const InputContainer = styled.div`
${FlexCenter}
gap: ${({ theme }) => theme.spacings.md};
`
const RémunérationETPPopoverContent = () => (
<Trans i18nKey="pages.simulateurs.réduction-générale.options.rémunération-etp.popover">
<Body>
Indiquez ici la rémunération qui aurait été versée pour un mois complet,{' '}
<Strong>en excluant</Strong> :
<Ul>
<Li>
les primes et autres éléments de rémunération non affectés par
l'absence ;
</Li>
<Li>la rémunération des heures supplémentaires ou complémentaires.</Li>
</Ul>
</Body>
</Trans>
)
const RémunérationPrimesPopoverContent = () => (
<Trans i18nKey="pages.simulateurs.réduction-générale.options.rémunération-primes.popover">
<Body>
Indiquez ici les éléments de rémunération non affectés par l'absence,
comme les primes.
</Body>
</Trans>
)
const RémunérationHeuresSupPopoverContent = () => (
<Trans i18nKey="pages.simulateurs.réduction-générale.options.rémunération-heures-sup.popover">
<Body>
Indiquez ici la rémunération afférente au paiement des heures
supplémentaires ou complémentaires.
</Body>
</Trans>
)
const FlexDiv = styled.div`
${FlexCenter}
justify-content: end;
`
const StyledSmallBody = styled(SmallBody)`
const StyledLabel = styled(SmallBody)`
margin: 0;
color: ${({ theme }) => theme.colors.bases.primary[800]};
`
@ -131,3 +322,13 @@ const NumberFieldContainer = styled.div`
}
}
`
const StyledButton = styled(SmallBody)`
cursor: pointer;
font-weight: bold;
color: ${({ theme }) => theme.colors.bases.primary[800]};
margin-top: ${({ theme }) => theme.spacings.xs};
margin-bottom: 0;
svg {
fill: ${({ theme }) => theme.colors.bases.primary[800]} !important;
}
`