feat(site): Ajoute la sélection d'entreprise en 1ère étape des simulateurs.
parent
dfdeaf818f
commit
76419766be
|
@ -1,12 +1,19 @@
|
|||
import { Trans } from 'react-i18next'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
import Conversation, {
|
||||
ConversationProps,
|
||||
} from '@/components/conversation/Conversation'
|
||||
import Progress from '@/components/ui/Progress'
|
||||
import { Button } from '@/design-system/buttons'
|
||||
import { H3 } from '@/design-system/typography/heading'
|
||||
import { Body } from '@/design-system/typography/paragraphs'
|
||||
import { useSimulationProgress } from '@/hooks/useSimulationProgress'
|
||||
import { entrepriseEstSélectionnéeSelector } from '@/store/selectors/entrepriseEstSélectionnée.selector'
|
||||
|
||||
import EntrepriseInput from '../conversation/EntrepriseInput'
|
||||
|
||||
const QuestionsContainer = styled.div`
|
||||
padding: ${({ theme }) => ` ${theme.spacings.xs} ${theme.spacings.lg}`};
|
||||
|
@ -29,21 +36,74 @@ export function Questions({
|
|||
customEndMessages?: ConversationProps['customEndMessages']
|
||||
}) {
|
||||
const { numberCurrentStep, numberSteps } = useSimulationProgress()
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
const [companySelectionStep, setCompanySelectionStep] = useState(true)
|
||||
const entrepriseEstSélectionnée = useSelector(
|
||||
entrepriseEstSélectionnéeSelector
|
||||
)
|
||||
|
||||
const handleGoToNext = useCallback(() => {
|
||||
setCompanySelectionStep(false)
|
||||
}, [])
|
||||
|
||||
return companySelectionStep ? (
|
||||
<>
|
||||
<QuestionsContainer>
|
||||
<div className="print-hidden">
|
||||
<Notice>
|
||||
{t(
|
||||
'simulateurs.précision.company',
|
||||
'Améliorez votre simulation en sélectionnant votre entreprise :'
|
||||
)}
|
||||
</Notice>
|
||||
</div>
|
||||
<H3 id="questionHeader" as="h2">
|
||||
{t('Votre entreprise')}
|
||||
</H3>
|
||||
<legend className="sr-only">
|
||||
{t('Sélectionnez votre entreprise afin de préciser votre résultat.')}
|
||||
</legend>
|
||||
<EntrepriseInput aria-labelledby="questionHeader" />
|
||||
<Button
|
||||
size="XS"
|
||||
onPress={handleGoToNext}
|
||||
light={!entrepriseEstSélectionnée ? true : undefined}
|
||||
aria-label={
|
||||
entrepriseEstSélectionnée
|
||||
? t(
|
||||
"Suivant, passer aux questions avec l'entreprise sélectionnée"
|
||||
)
|
||||
: t("Passer, passer aux questions sans sélectionner d'entreprise")
|
||||
}
|
||||
>
|
||||
{entrepriseEstSélectionnée ? (
|
||||
<Trans>Suivant</Trans>
|
||||
) : (
|
||||
<Trans>Passer</Trans>
|
||||
)}{' '}
|
||||
<span aria-hidden>→</span>
|
||||
</Button>
|
||||
</QuestionsContainer>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Progress progress={numberCurrentStep} maxValue={numberSteps + 1} />
|
||||
<QuestionsContainer>
|
||||
<div className="print-hidden">
|
||||
{numberCurrentStep < numberSteps && (
|
||||
<Notice>
|
||||
<Trans i18nKey="simulateurs.précision.défaut">
|
||||
Améliorez votre simulation en répondant aux questions :
|
||||
</Trans>
|
||||
{t(
|
||||
'simulateurs.précision.défaut',
|
||||
'Améliorez votre simulation en répondant aux questions :'
|
||||
)}
|
||||
</Notice>
|
||||
)}
|
||||
</div>
|
||||
<Conversation customEndMessages={customEndMessages} />
|
||||
<Conversation
|
||||
customEndMessages={customEndMessages}
|
||||
setCompanySelectionStep={setCompanySelectionStep}
|
||||
/>
|
||||
</QuestionsContainer>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -11,6 +11,14 @@ import { Body } from '@/design-system/typography/paragraphs'
|
|||
import SeeAnswersButton from '../conversation/SeeAnswersButton'
|
||||
import Value from '../EngineValue/Value'
|
||||
|
||||
const StyledCompanyContainer = styled(Message).attrs({ border: false })``
|
||||
|
||||
const StyledH4 = styled(H4)`
|
||||
& span {
|
||||
color: ${({ theme }) => theme.colors.bases.primary[700]};
|
||||
}
|
||||
`
|
||||
|
||||
export function CompanyDetails({
|
||||
showSituation = false,
|
||||
headingTag = 'h3',
|
||||
|
@ -62,11 +70,3 @@ export function CompanyDetails({
|
|||
</StyledCompanyContainer>
|
||||
)
|
||||
}
|
||||
|
||||
const StyledCompanyContainer = styled(Message).attrs({ border: false })``
|
||||
|
||||
const StyledH4 = styled(H4)`
|
||||
& span {
|
||||
color: ${({ theme }) => theme.colors.bases.primary[700]};
|
||||
}
|
||||
`
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { Trans } from 'react-i18next'
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
import { Strong } from '@/design-system/typography'
|
||||
import { H4 } from '@/design-system/typography/heading'
|
||||
import { Body } from '@/design-system/typography/paragraphs'
|
||||
|
||||
import Value from '../EngineValue/Value'
|
||||
|
||||
const StyledH4 = styled(H4)`
|
||||
margin: ${({ theme }) => theme.spacings.xxs} 0;
|
||||
`
|
||||
const StyledBody = styled(Body)`
|
||||
margin: ${({ theme }) => theme.spacings.xxs} 0;
|
||||
`
|
||||
const StyledEntrepriseContainer = styled.div`
|
||||
padding: 0 ${({ theme }) => theme.spacings.xs};
|
||||
`
|
||||
|
||||
export default function SelectedEntrepriseDetails() {
|
||||
return (
|
||||
<StyledEntrepriseContainer>
|
||||
<StyledH4>
|
||||
<Value expression="entreprise . nom" linkToRule={false} />{' '}
|
||||
<Value expression="entreprise . SIREN" linkToRule={false} />
|
||||
</StyledH4>
|
||||
<StyledBody>
|
||||
<Trans>
|
||||
Entreprise créée le{' '}
|
||||
<Strong>
|
||||
<Value
|
||||
expression="entreprise . date de création"
|
||||
linkToRule={false}
|
||||
/>
|
||||
</Strong>{' '}
|
||||
et domiciliée à{' '}
|
||||
<Strong>
|
||||
<Value expression="établissement . commune" linkToRule={false} />
|
||||
</Strong>
|
||||
</Trans>
|
||||
</StyledBody>
|
||||
</StyledEntrepriseContainer>
|
||||
)
|
||||
}
|
|
@ -11,11 +11,13 @@ import { useNavigateQuestions } from './useNavigateQuestions'
|
|||
export type ConversationProps = {
|
||||
customEndMessages?: React.ReactNode
|
||||
customSituationVisualisation?: React.ReactNode
|
||||
setCompanySelectionStep?: (isCompanySelectionStep: boolean) => void
|
||||
}
|
||||
|
||||
export default function Conversation({
|
||||
customEndMessages,
|
||||
customSituationVisualisation,
|
||||
setCompanySelectionStep,
|
||||
}: ConversationProps) {
|
||||
const previousAnswers = useSelector(
|
||||
questionsRéponduesEncoreApplicablesNomsSelector
|
||||
|
@ -42,6 +44,7 @@ export default function Conversation({
|
|||
<QuestionEnCours
|
||||
previousAnswers={previousAnswers}
|
||||
customSituationVisualisation={customSituationVisualisation}
|
||||
setCompanySelectionStep={setCompanySelectionStep}
|
||||
/>
|
||||
) : (
|
||||
<VousAvezComplétéCetteSimulation
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
import { useEffect } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
import { EntrepriseSearchField } from '@/components/company/SearchField'
|
||||
import { useEngine } from '@/components/utils/EngineContext'
|
||||
import { Spacing } from '@/design-system/layout'
|
||||
import { Entreprise } from '@/domaine/Entreprise'
|
||||
import { useEntreprisesRepository } from '@/hooks/useRepositories'
|
||||
import { useSetEntreprise } from '@/hooks/useSetEntreprise'
|
||||
import { getCookieValue } from '@/storage/readCookie'
|
||||
import { resetCompany } from '@/store/actions/companyActions'
|
||||
|
||||
import SelectedEntrepriseDetails from '../company/SelectedEntrepriseDetails'
|
||||
|
||||
export default function EntrepriseInput() {
|
||||
const companySIREN = useEngine().evaluate('entreprise . SIREN').nodeValue
|
||||
useSetEntrepriseFromUrssafConnection()
|
||||
const setEntreprise = useSetEntreprise()
|
||||
const dispatch = useDispatch()
|
||||
const handleCompanySubmit = (établissement: Entreprise | null) => {
|
||||
setEntreprise(établissement)
|
||||
}
|
||||
const handleCompanyClear = () => {
|
||||
dispatch(resetCompany())
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<EntrepriseSearchField
|
||||
onSubmit={handleCompanySubmit}
|
||||
onClear={handleCompanyClear}
|
||||
selectedValue={companySIREN ? <SelectedEntrepriseDetails /> : null}
|
||||
/>
|
||||
<Spacing md />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function useSetEntrepriseFromUrssafConnection() {
|
||||
const setEntreprise = useSetEntreprise()
|
||||
const siret = siretFromUrssafFrConnection()
|
||||
const companySIREN = useEngine().evaluate('entreprise . SIREN').nodeValue
|
||||
const entreprisesRepository = useEntreprisesRepository()
|
||||
|
||||
useEffect(() => {
|
||||
if (siret && !companySIREN) {
|
||||
entreprisesRepository
|
||||
.rechercheTexteLibre(siret)
|
||||
.then((results) => {
|
||||
if (results?.length !== 1) {
|
||||
return
|
||||
}
|
||||
setEntreprise(results[0])
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
console.log(`Could not fetch company details for ${siret}`)
|
||||
})
|
||||
}
|
||||
}, [siret, companySIREN])
|
||||
}
|
||||
|
||||
// We can read cookies set on the urssaf.fr domain, which contain informations
|
||||
// such as the SIRET number. The cookie format could change at any time so we
|
||||
// wrap its read access in a `try / catch`.
|
||||
function siretFromUrssafFrConnection(): string | null {
|
||||
try {
|
||||
// Note: The `ctxUrssaf` contains more informations, but currently we only
|
||||
// need to retreive the SIRET which is slightly more easy to read from the
|
||||
// `EnLigne` cookie.
|
||||
const cookieValue = decodeURIComponent(getCookieValue('EnLigne'))
|
||||
const siret = cookieValue.match('siret=([0-9]{14})')?.pop()
|
||||
|
||||
return siret ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -28,11 +28,13 @@ import { evaluateQuestion } from '@/utils/publicodes'
|
|||
interface Props {
|
||||
previousAnswers: DottedName[]
|
||||
customSituationVisualisation?: React.ReactNode
|
||||
setCompanySelectionStep?: (isCompanySelectionStep: boolean) => void
|
||||
}
|
||||
|
||||
export function QuestionEnCours({
|
||||
previousAnswers,
|
||||
customSituationVisualisation,
|
||||
setCompanySelectionStep,
|
||||
}: Props) {
|
||||
const dispatch = useDispatch()
|
||||
const { t } = useTranslation()
|
||||
|
@ -56,6 +58,10 @@ export function QuestionEnCours({
|
|||
}, 5)
|
||||
}, [])
|
||||
|
||||
const handleGoToCompanySelection = useCallback(() => {
|
||||
setCompanySelectionStep?.(true)
|
||||
}, [setCompanySelectionStep])
|
||||
|
||||
const handleGoToPrevious = useCallback(() => {
|
||||
goToPrevious()
|
||||
focusFirstElemInForm()
|
||||
|
@ -130,7 +136,7 @@ export function QuestionEnCours({
|
|||
/>
|
||||
</fieldset>
|
||||
<Grid container spacing={2}>
|
||||
{previousAnswers.length > 0 && !estSurLaPremièreQuestion && (
|
||||
{previousAnswers.length > 0 && !estSurLaPremièreQuestion ? (
|
||||
<Grid item xs={6} sm="auto">
|
||||
<Button
|
||||
color="primary"
|
||||
|
@ -141,6 +147,17 @@ export function QuestionEnCours({
|
|||
<span aria-hidden>←</span> <Trans>Précédent</Trans>
|
||||
</Button>
|
||||
</Grid>
|
||||
) : (
|
||||
<Grid item xs={6} sm="auto">
|
||||
<Button
|
||||
color="primary"
|
||||
light
|
||||
onPress={handleGoToCompanySelection}
|
||||
size="XS"
|
||||
>
|
||||
<span aria-hidden>←</span> <Trans>Précédent</Trans>
|
||||
</Button>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid item xs={6} sm="auto">
|
||||
<Button
|
||||
|
|
|
@ -221,6 +221,7 @@ Page d'accueil: Home page
|
|||
Passer: Pass
|
||||
Passer le contenu principal et aller directement au pied de page: Skip the main content and go directly to the footer
|
||||
Passer à la version française du site: Switch to the French version of the site
|
||||
Passer, passer aux questions sans sélectionner d'entreprise: Skip, skip to questions without selecting a company
|
||||
Passer, passer la question sans répondre: Pass, pass the question without answering
|
||||
Personnalisez l'intégration: Customize integration
|
||||
Plan du site: Site map
|
||||
|
@ -304,9 +305,11 @@ Statistiques: Statistics
|
|||
Statut du conjoint: Spouse's status
|
||||
Suivant: Next
|
||||
Suivant, enregistrer et passer à l'étape suivante: Next, save and go to the next step
|
||||
Suivant, passer aux questions avec l'entreprise sélectionnée: Next, questions with the selected company
|
||||
Suivant, passer à la question suivante: Next, move on to the next question
|
||||
Suivant, voir le résultat: Next, see the result
|
||||
Switch to the english version of the website: Switch to the english version of the website
|
||||
Sélectionnez votre entreprise afin de préciser votre résultat.: Select your company to clarify your result.
|
||||
Tableau indiquant la satisfaction des utilisateurs en {{percentOrVotes}} sur le site mon-entreprise par mois.:
|
||||
Table showing user satisfaction with {{percentOrVotes}} on the mon-entreprise
|
||||
site, by month.
|
||||
|
@ -365,6 +368,7 @@ Votre avis nous intéresse: We value your opinion
|
|||
Votre chiffre d'affaires estimé: Your estimated sales
|
||||
Votre couverture invalidité et décès: Your disability and death coverage
|
||||
Votre domaine d'activité: Your field of activity
|
||||
Votre entreprise: Your company
|
||||
Votre message (requis): Your message (required)
|
||||
Votre rémunération totale estimée: Your estimated total remuneration
|
||||
Vous allez dépasser le plafond de la micro-entreprise: You will exceed the micro-business limit
|
||||
|
@ -1709,6 +1713,7 @@ simulateurs:
|
|||
(health insurance, family allowances, long-term care<1> and <3>
|
||||
basic</3> pensions</1>).
|
||||
précision:
|
||||
company: "Improve your simulation by selecting your company:"
|
||||
défaut: "Improve your simulation by answering the questions below:"
|
||||
warning:
|
||||
artiste-auteur: This simulator allows you to estimate the amount of your
|
||||
|
|
|
@ -234,6 +234,7 @@ Page d'accueil: Page d'accueil
|
|||
Passer: Passer
|
||||
Passer le contenu principal et aller directement au pied de page: Passer le contenu principal et aller directement au pied de page
|
||||
Passer à la version française du site: Passer à la version française du site
|
||||
Passer, passer aux questions sans sélectionner d'entreprise: Passer, passer aux questions sans sélectionner d'entreprise
|
||||
Passer, passer la question sans répondre: Passer, passer la question sans répondre
|
||||
Personnalisez l'intégration: Personnalisez l'intégration
|
||||
Plan du site: Plan du site
|
||||
|
@ -321,9 +322,11 @@ Statistiques: Statistiques
|
|||
Statut du conjoint: Statut du conjoint
|
||||
Suivant: Suivant
|
||||
Suivant, enregistrer et passer à l'étape suivante: Suivant, enregistrer et passer à l'étape suivante
|
||||
Suivant, passer aux questions avec l'entreprise sélectionnée: Suivant, passer aux questions avec l'entreprise sélectionnée
|
||||
Suivant, passer à la question suivante: Suivant, passer à la question suivante
|
||||
Suivant, voir le résultat: Suivant, voir le résultat
|
||||
Switch to the english version of the website: Switch to the english version of the website
|
||||
Sélectionnez votre entreprise afin de préciser votre résultat.: Sélectionnez votre entreprise afin de préciser votre résultat.
|
||||
Tableau indiquant la satisfaction des utilisateurs en {{percentOrVotes}} sur le site mon-entreprise par mois.:
|
||||
Tableau indiquant la satisfaction des utilisateurs en {{percentOrVotes}} sur
|
||||
le site mon-entreprise par mois.
|
||||
|
@ -385,6 +388,7 @@ Votre avis nous intéresse: Votre avis nous intéresse
|
|||
Votre chiffre d'affaires estimé: Votre chiffre d'affaires estimé
|
||||
Votre couverture invalidité et décès: Votre couverture invalidité et décès
|
||||
Votre domaine d'activité: Votre domaine d'activité
|
||||
Votre entreprise: Votre entreprise
|
||||
Votre message (requis): Votre message (requis)
|
||||
Votre rémunération totale estimée: Votre rémunération totale estimée
|
||||
Vous allez dépasser le plafond de la micro-entreprise: Vous allez dépasser le plafond de la micro-entreprise
|
||||
|
@ -1819,6 +1823,7 @@ simulateurs:
|
|||
sociale (assurance maladie, allocations familiales, dépendance<1> et
|
||||
retraite <3> de base</3></1>).
|
||||
précision:
|
||||
company: "Améliorez votre simulation en sélectionnant votre entreprise :"
|
||||
défaut: "Améliorez votre simulation en répondant aux questions :"
|
||||
warning:
|
||||
artiste-auteur: Ce simulateur permet d'estimer le montant de vos cotisations à
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import { createSelector } from 'reselect'
|
||||
|
||||
import { companySituationSelector } from './simulationSelectors'
|
||||
|
||||
export const entrepriseEstSélectionnéeSelector = createSelector(
|
||||
[companySituationSelector],
|
||||
(companySituation) => {
|
||||
return !!Object.keys(companySituation).length
|
||||
}
|
||||
)
|
Loading…
Reference in New Issue