refactor(site): Crée un composant indépendant pour les résultats de recherche d'entreprise
parent
aca54b5e96
commit
2597420cb4
|
@ -0,0 +1,78 @@
|
|||
import { useEffect } from 'react'
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
import { EntrepriseSearchField } from '@/components/entreprise/EntrepriseSearchField'
|
||||
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 '../entreprise/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
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ import { Body } from '@/design-system/typography/paragraphs'
|
|||
import SeeAnswersButton from '../conversation/SeeAnswersButton'
|
||||
import Value from '../EngineValue/Value'
|
||||
|
||||
export function CompanyDetails({
|
||||
export function EntrepriseDetails({
|
||||
showSituation = false,
|
||||
headingTag = 'h3',
|
||||
}: {
|
|
@ -0,0 +1,84 @@
|
|||
import { useSearchFieldState } from '@react-stately/searchfield'
|
||||
import { ReactNode, useEffect, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { SearchableSelectField } from '@/design-system/field/SearchableSelectField/SearchableSelectField'
|
||||
import { Grid } from '@/design-system/layout'
|
||||
import { Entreprise } from '@/domaine/Entreprise'
|
||||
import useSearchCompany from '@/hooks/useSearchCompany'
|
||||
|
||||
import { Appear } from '../ui/animate'
|
||||
import EntrepriseSearchResults from './EntrepriseSearchResults'
|
||||
|
||||
export function EntrepriseSearchField(props: {
|
||||
label?: ReactNode
|
||||
selectedValue?: ReactNode | null
|
||||
onValue?: () => void
|
||||
onClear?: () => void
|
||||
onSubmit?: (search: Entreprise | null) => void
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const refResults = useRef<Entreprise[] | null>(null)
|
||||
|
||||
const searchFieldProps = {
|
||||
...props,
|
||||
label:
|
||||
!props.selectedValue &&
|
||||
t('EntrepriseSearchField.label', "Nom de l'entreprise, SIREN ou SIRET"),
|
||||
description:
|
||||
!props.selectedValue &&
|
||||
t(
|
||||
'EntrepriseSearchField.description',
|
||||
'Le numéro Siret est un numéro de 14 chiffres unique pour chaque entreprise. Exemple : 40123778000127'
|
||||
),
|
||||
onSubmit() {
|
||||
const results = refResults.current
|
||||
props.onSubmit?.(results?.[0] ?? null)
|
||||
},
|
||||
onClear() {
|
||||
props.onClear?.()
|
||||
},
|
||||
placeholder: t(
|
||||
'EntrepriseSearchField.placeholder',
|
||||
'Exemple : Café de la gare ou 40123778000127'
|
||||
),
|
||||
}
|
||||
|
||||
const state = useSearchFieldState(searchFieldProps)
|
||||
|
||||
const { onSubmit } = props
|
||||
|
||||
const [searchPending, results] = useSearchCompany(state.value)
|
||||
|
||||
useEffect(() => {
|
||||
refResults.current = results ?? null
|
||||
}, [results])
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<SearchableSelectField
|
||||
data-test-id="company-search-input"
|
||||
state={state}
|
||||
isSearchStalled={searchPending}
|
||||
aria-label={
|
||||
searchFieldProps.label +
|
||||
', ' +
|
||||
t(
|
||||
"recherche lancée automatiquement après l'entrée de caractères, les résultats s'afficheront à la suite de cet élément."
|
||||
)
|
||||
}
|
||||
{...searchFieldProps}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Appear unless={searchPending || !state.value}>
|
||||
{state.value && !searchPending && !props.selectedValue && (
|
||||
<EntrepriseSearchResults results={results} onSubmit={onSubmit} />
|
||||
)}
|
||||
</Appear>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
|
@ -1,24 +1,19 @@
|
|||
import { useSearchFieldState } from '@react-stately/searchfield'
|
||||
import { ReactNode, useEffect, useRef } from 'react'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { styled } from 'styled-components'
|
||||
|
||||
import { ForceThemeProvider } from '@/components/utils/DarkModeContext'
|
||||
import { Message } from '@/design-system'
|
||||
import { Card } from '@/design-system/card'
|
||||
import { SearchableSelectField } from '@/design-system/field/SearchableSelectField/SearchableSelectField'
|
||||
import { FocusStyle } from '@/design-system/global-style'
|
||||
import { ChevronIcon } from '@/design-system/icons'
|
||||
import { Grid } from '@/design-system/layout'
|
||||
import { Strong } from '@/design-system/typography'
|
||||
import { StyledLink } from '@/design-system/typography/link'
|
||||
import { Li, Ul } from '@/design-system/typography/list'
|
||||
import { Body } from '@/design-system/typography/paragraphs'
|
||||
import { Entreprise } from '@/domaine/Entreprise'
|
||||
import useSearchCompany from '@/hooks/useSearchCompany'
|
||||
|
||||
import { Appear, FromTop } from '../ui/animate'
|
||||
import EntrepriseSearchDetails from './SearchDetails'
|
||||
import { FromTop } from '../ui/animate'
|
||||
import EntrepriseSearchDetails from './EntrepriseSearchDetails'
|
||||
|
||||
const StyledCard = styled(Card)`
|
||||
flex-direction: row; // for Safari <= 13
|
||||
|
@ -28,80 +23,7 @@ const StyledCard = styled(Card)`
|
|||
}
|
||||
`
|
||||
|
||||
export function EntrepriseSearchField(props: {
|
||||
label?: ReactNode
|
||||
selectedValue?: ReactNode | null
|
||||
onValue?: () => void
|
||||
onClear?: () => void
|
||||
onSubmit?: (search: Entreprise | null) => void
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const refResults = useRef<Entreprise[] | null>(null)
|
||||
|
||||
const searchFieldProps = {
|
||||
...props,
|
||||
label:
|
||||
!props.selectedValue &&
|
||||
t('CompanySearchField.label', "Nom de l'entreprise, SIREN ou SIRET"),
|
||||
description:
|
||||
!props.selectedValue &&
|
||||
t(
|
||||
'CompanySearchField.description',
|
||||
'Le numéro Siret est un numéro de 14 chiffres unique pour chaque entreprise. Exemple : 40123778000127'
|
||||
),
|
||||
onSubmit() {
|
||||
const results = refResults.current
|
||||
props.onSubmit?.(results?.[0] ?? null)
|
||||
},
|
||||
onClear() {
|
||||
props.onClear?.()
|
||||
},
|
||||
placeholder: t(
|
||||
'CompanySearchField.placeholder',
|
||||
'Exemple : Café de la gare ou 40123778000127'
|
||||
),
|
||||
}
|
||||
|
||||
const state = useSearchFieldState(searchFieldProps)
|
||||
|
||||
const { onSubmit } = props
|
||||
|
||||
const [searchPending, results] = useSearchCompany(state.value)
|
||||
|
||||
useEffect(() => {
|
||||
refResults.current = results ?? null
|
||||
}, [results])
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={12}>
|
||||
<SearchableSelectField
|
||||
data-test-id="company-search-input"
|
||||
state={state}
|
||||
isSearchStalled={searchPending}
|
||||
aria-label={
|
||||
searchFieldProps.label +
|
||||
', ' +
|
||||
t(
|
||||
"recherche lancée automatiquement après l'entrée de caractères, les résultats s'afficheront à la suite de cet élément."
|
||||
)
|
||||
}
|
||||
{...searchFieldProps}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<Appear unless={searchPending || !state.value}>
|
||||
{state.value && !searchPending && !props.selectedValue && (
|
||||
<Results results={results} onSubmit={onSubmit} />
|
||||
)}
|
||||
</Appear>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
function Results({
|
||||
export default function EntrepriseSearchResults({
|
||||
results,
|
||||
onSubmit,
|
||||
}: {
|
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -73,11 +73,6 @@ Comment ça marche ? Voir la page explicative sur la page du dépôt github, nou
|
|||
How does it work? See the explanatory page on the github repository page, new
|
||||
window
|
||||
Commune ou code postal: Town or zip code
|
||||
CompanySearchField:
|
||||
description: "The Siret number is a 14-digit number unique to each company.
|
||||
Example: 40123778000127"
|
||||
label: Company name, SIREN or SIRET
|
||||
placeholder: "Example: Café de la gare or 40123778000127"
|
||||
Comparer...: Compare...
|
||||
Confirmer: Confirm
|
||||
Cotisations: Contributions
|
||||
|
@ -119,6 +114,11 @@ English version of the website enabled.: English version of the website enabled.
|
|||
Enregistrer et continuer: Save and continue
|
||||
Enregistrer et voir le résultat: Save and view results
|
||||
Entreprise créée le <2><0></0></2> et domiciliée à <6><0></0></6>: Company founded on <2><0></0></2> and domiciled at <6><0></0></6>
|
||||
EntrepriseSearchField:
|
||||
description: "The Siret number is a 14-digit number unique to each company.
|
||||
Example: 40123778000127"
|
||||
label: Company name, SIREN or SIRET
|
||||
placeholder: "Example: Café de la gare or 40123778000127"
|
||||
Envoyer: Send
|
||||
"Exemple : Des informations plus claires, un calcul détaillé...": "Example: clearer information, detailed calculation..."
|
||||
Exonérations: Exemptions
|
||||
|
@ -365,6 +365,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
|
||||
|
|
|
@ -78,11 +78,6 @@ Comment ça marche ? Voir la page explicative sur la page du dépôt github, nou
|
|||
Comment ça marche ? Voir la page explicative sur la page du dépôt github,
|
||||
nouvelle fenêtre
|
||||
Commune ou code postal: Commune ou code postal
|
||||
CompanySearchField:
|
||||
description: "Le numéro Siret est un numéro de 14 chiffres unique pour chaque
|
||||
entreprise. Exemple : 40123778000127"
|
||||
label: Nom de l'entreprise, SIREN ou SIRET
|
||||
placeholder: "Exemple : Café de la gare ou 40123778000127"
|
||||
Comparer...: Comparer...
|
||||
Confirmer: Confirmer
|
||||
Cotisations: Cotisations
|
||||
|
@ -126,6 +121,11 @@ English version of the website enabled.: English version of the website enabled.
|
|||
Enregistrer et continuer: Enregistrer et continuer
|
||||
Enregistrer et voir le résultat: Enregistrer et voir le résultat
|
||||
Entreprise créée le <2><0></0></2> et domiciliée à <6><0></0></6>: Entreprise créée le <2><0></0></2> et domiciliée à <6><0></0></6>
|
||||
EntrepriseSearchField:
|
||||
description: "Le numéro Siret est un numéro de 14 chiffres unique pour chaque
|
||||
entreprise. Exemple : 40123778000127"
|
||||
label: Nom de l'entreprise, SIREN ou SIRET
|
||||
placeholder: "Exemple : Café de la gare ou 40123778000127"
|
||||
Envoyer: Envoyer
|
||||
"Exemple : Des informations plus claires, un calcul détaillé...": "Exemple : Des informations plus claires, un calcul détaillé..."
|
||||
Exonérations: Exonérations
|
||||
|
@ -384,6 +384,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
|
||||
|
|
|
@ -3,8 +3,8 @@ import { Trans, useTranslation } from 'react-i18next'
|
|||
import { useDispatch } from 'react-redux'
|
||||
import { generatePath, useNavigate } from 'react-router-dom'
|
||||
|
||||
import { CompanyDetails } from '@/components/company/Details'
|
||||
import { EntrepriseSearchField } from '@/components/company/SearchField'
|
||||
import { EntrepriseDetails } from '@/components/entreprise/EntrepriseDetails'
|
||||
import { EntrepriseSearchField } from '@/components/entreprise/EntrepriseSearchField'
|
||||
import { useEngine } from '@/components/utils/EngineContext'
|
||||
import AnswerGroup from '@/design-system/answer-group'
|
||||
import { Button } from '@/design-system/buttons'
|
||||
|
@ -38,8 +38,8 @@ export default function SearchOrCreate() {
|
|||
<Grid item xl={8} lg={10} md={12}>
|
||||
{companySIREN ? (
|
||||
<>
|
||||
<H3 as="h2">Votre entreprise</H3>
|
||||
<CompanyDetails />
|
||||
<H3 as="h2">{t('Votre entreprise')}</H3>
|
||||
<EntrepriseDetails />
|
||||
<Spacing md />
|
||||
<AnswerGroup role="list">
|
||||
<Button
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Trans, useTranslation } from 'react-i18next'
|
|||
import { useDispatch } from 'react-redux'
|
||||
|
||||
import { TrackPage } from '@/components/ATInternetTracking'
|
||||
import { CompanyDetails } from '@/components/company/Details'
|
||||
import { EntrepriseDetails } from '@/components/entreprise/EntrepriseDetails'
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { useEngine } from '@/components/utils/EngineContext'
|
||||
import { Message } from '@/design-system'
|
||||
|
@ -79,7 +79,7 @@ export default function AccueilChoixStatut() {
|
|||
</Body>
|
||||
</Trans>
|
||||
</Message>
|
||||
<CompanyDetails />
|
||||
<EntrepriseDetails />
|
||||
<PopoverConfirm
|
||||
trigger={(buttonProps) => (
|
||||
<Button
|
||||
|
|
|
@ -15,11 +15,11 @@ import {
|
|||
import { styled } from 'styled-components'
|
||||
|
||||
import { TrackPage } from '@/components/ATInternetTracking'
|
||||
import { CompanyDetails } from '@/components/company/Details'
|
||||
import { ConseillersEntreprisesButton } from '@/components/ConseillersEntreprisesButton'
|
||||
import RuleInput from '@/components/conversation/RuleInput'
|
||||
import { CurrentSimulatorCard } from '@/components/CurrentSimulatorCard'
|
||||
import { Condition } from '@/components/EngineValue/Condition'
|
||||
import { EntrepriseDetails } from '@/components/entreprise/EntrepriseDetails'
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { SimulateurCard } from '@/components/SimulateurCard'
|
||||
import { FromTop } from '@/components/ui/animate'
|
||||
|
@ -242,7 +242,7 @@ function PourMonEntreprise() {
|
|||
)
|
||||
}
|
||||
|
||||
const configCompanyDetails: SimulationConfig = {
|
||||
const configEntrepriseDetails: SimulationConfig = {
|
||||
questions: {
|
||||
'liste noire': ['entreprise . imposition . régime'] as DottedName[],
|
||||
},
|
||||
|
@ -269,7 +269,7 @@ const AskCompanyMissingDetails = () => {
|
|||
const { absoluteSitePaths } = useSitePaths()
|
||||
useSimulationConfig({
|
||||
key: absoluteSitePaths.assistants.index,
|
||||
config: configCompanyDetails,
|
||||
config: configEntrepriseDetails,
|
||||
})
|
||||
|
||||
const [questions, onQuestionAnswered] = useQuestionList()
|
||||
|
@ -277,7 +277,7 @@ const AskCompanyMissingDetails = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<CompanyDetails showSituation headingTag="h2" />
|
||||
<EntrepriseDetails showSituation headingTag="h2" />
|
||||
{!!questions.length && (
|
||||
<>
|
||||
<Body
|
||||
|
|
Loading…
Reference in New Issue