diff --git a/site/source/actions/companyStatusActions.ts b/site/source/actions/companyStatusActions.ts index e6028f6d8..30d72b115 100644 --- a/site/source/actions/companyStatusActions.ts +++ b/site/source/actions/companyStatusActions.ts @@ -78,7 +78,7 @@ export const resetCompanyStatusChoice = ( export const useSetEntreprise = () => { const dispatch = useDispatch() - return (entreprise: FabriqueSocialEntreprise) => { + return (entreprise: FabriqueSocialEntreprise | null) => { if (entreprise === null) { return } diff --git a/site/source/api/sirene.ts b/site/source/api/sirene.ts index a7618f592..d974cf54d 100644 --- a/site/source/api/sirene.ts +++ b/site/source/api/sirene.ts @@ -1,7 +1,11 @@ +import { FabriqueSocialEntreprise } from './fabrique-social' + const isSIREN = (input: string) => /^[\s]*([\d][\s]*){9}$/.exec(input) const isSIRET = (input: string) => /^[\s]*([\d][\s]*){14}$/.exec(input) -export async function fetchCompanyDetails(siren: string) { +export async function fetchCompanyDetails( + siren: string +): Promise { // Le paramètre `statut_diffusion` filtre les SIREN non diffusibles, cf. // https://github.com/betagouv/mon-entreprise/issues/1399#issuecomment-770736525 const response = await fetch( @@ -15,7 +19,7 @@ export async function fetchCompanyDetails(siren: string) { } const json = await response.json() - return json.unite_legale + return json.unite_legale as FabriqueSocialEntreprise } export async function searchDenominationOrSiren(value: string) { diff --git a/site/source/design-system/field/SearchField.tsx b/site/source/design-system/field/SearchField.tsx index 17ee1a857..2dbb74947 100644 --- a/site/source/design-system/field/SearchField.tsx +++ b/site/source/design-system/field/SearchField.tsx @@ -1,3 +1,5 @@ +import { Loader } from '@/design-system/icons/Loader' +import { SearchIcon } from '@/design-system/icons/SearchIcon' import { useButton } from '@react-aria/button' import { useSearchField } from '@react-aria/searchfield' import { @@ -5,9 +7,7 @@ import { useSearchFieldState, } from '@react-stately/searchfield' import { AriaSearchFieldProps } from '@react-types/searchfield' -import { Loader } from '@/design-system/icons/Loader' -import { SearchIcon } from '@/design-system/icons/SearchIcon' -import { InputHTMLAttributes, useRef } from 'react' +import { useRef } from 'react' import styled, { css } from 'styled-components' import { StyledContainer, diff --git a/site/source/pages/Landing/SearchOrCreate.tsx b/site/source/pages/Landing/SearchOrCreate.tsx index 9f940ba5b..ba8dc067c 100644 --- a/site/source/pages/Landing/SearchOrCreate.tsx +++ b/site/source/pages/Landing/SearchOrCreate.tsx @@ -1,20 +1,22 @@ import { resetCompany } from '@/actions/companyActions' import { useSetEntreprise } from '@/actions/companyStatusActions' -import { FabriqueSocialEntreprise } from '@/api/fabrique-social' +import { + FabriqueSocialEntreprise, + searchDenominationOrSiren, +} from '@/api/fabrique-social' import { CompanyDetails } from '@/components/company/Details' import { CompanySearchField } from '@/components/company/SearchField' -import Value from '@/components/EngineValue' import Emoji from '@/components/utils/Emoji' import { useEngine } from '@/components/utils/EngineContext' import { SitePathsContext } from '@/components/utils/SitePathsContext' -import { Message } from '@/design-system' import AnswerGroup from '@/design-system/answer-group' import { Button } from '@/design-system/buttons' import { Spacing } from '@/design-system/layout' -import { H3, H4 } from '@/design-system/typography/heading' +import { H3 } from '@/design-system/typography/heading' import { RootState } from '@/reducers/rootReducer' +import { getCookieValue } from '@/storage/readCookie' import { Grid } from '@mui/material' -import { useCallback, useContext } from 'react' +import { useCallback, useContext, useEffect } from 'react' import { Trans } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' import { useHistory } from 'react-router-dom' @@ -25,6 +27,7 @@ export default function SearchOrCreate() { (state: RootState) => state.choixStatutJuridique.companyStatusChoice ) const companySIREN = useEngine().evaluate('entreprise . SIREN').nodeValue + useSetEntrepriseFromUrssafConnection() const handleCompanySubmit = useHandleCompanySubmit() const dispatch = useDispatch() @@ -87,3 +90,41 @@ function useHandleCompanySubmit() { return handleCompanySubmit } + +function useSetEntrepriseFromUrssafConnection() { + const setEntreprise = useSetEntreprise() + const siret = siretFromUrssafFrConnection() + const companySIREN = useEngine().evaluate('entreprise . SIREN').nodeValue + useEffect(() => { + if (siret && !companySIREN) { + searchDenominationOrSiren(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 + } +} diff --git a/site/source/storage/readCookie.ts b/site/source/storage/readCookie.ts new file mode 100644 index 000000000..82d27997e --- /dev/null +++ b/site/source/storage/readCookie.ts @@ -0,0 +1,8 @@ +// From https://stackoverflow.com/a/25490531 +export function getCookieValue(cookieName: string) { + return ( + document.cookie + .match('(^|;)\\s*' + cookieName + '\\s*=\\s*([^;]+)') + ?.pop() || '' + ) +}