From 0d86f9b6f7034d547aafd1ac6295be9c1a51ba73 Mon Sep 17 00:00:00 2001 From: xavier jouppe Date: Tue, 7 Jan 2025 15:41:41 +0100 Subject: [PATCH] feat: UX attempt at travaux public --- .../_components/travaux-publics-section.tsx | 129 ----------------- .../documents/[slug]/page.tsx | 2 +- .../index.ts | 35 ----- clients/api-entreprise/certificats/cibtp.ts | 30 ---- clients/api-entreprise/certificats/cnetp.ts | 30 ---- clients/api-entreprise/certificats/probtp.ts | 30 ---- .../api-entreprise/travaux-publics/index.ts | 67 +++++++++ .../travaux-publics-section.tsx | 131 ++++++++++++++++++ models/espace-agent/conformite.ts | 1 + models/espace-agent/travaux-publics.ts | 79 ++++------- 10 files changed, 227 insertions(+), 307 deletions(-) delete mode 100644 app/(header-default)/documents/[slug]/_components/travaux-publics-section.tsx delete mode 100644 clients/api-entreprise/carte-professionnelle-travaux-publics/index.ts delete mode 100644 clients/api-entreprise/certificats/cibtp.ts delete mode 100644 clients/api-entreprise/certificats/cnetp.ts delete mode 100644 clients/api-entreprise/certificats/probtp.ts create mode 100644 clients/api-entreprise/travaux-publics/index.ts create mode 100644 components/espace-agent-components/travaux-publics-section.tsx diff --git a/app/(header-default)/documents/[slug]/_components/travaux-publics-section.tsx b/app/(header-default)/documents/[slug]/_components/travaux-publics-section.tsx deleted file mode 100644 index 9174b414a..000000000 --- a/app/(header-default)/documents/[slug]/_components/travaux-publics-section.tsx +++ /dev/null @@ -1,129 +0,0 @@ -'use client'; - -import ButtonLink from '#components-ui/button'; -import { Icon } from '#components-ui/icon/wrapper'; -import { AsyncDataSectionClient } from '#components/section/data-section/client'; -import { FullTable } from '#components/table/full'; -import { EAdministration } from '#models/administrations/EAdministration'; -import { IUniteLegale } from '#models/core/types'; -import { ISession } from '#models/user/session'; -import { APIRoutesPaths } from 'app/api/data-fetching/routes-paths'; -import { useAPIRouteData } from 'hooks/fetch/use-API-route-data'; - -const generateCertificateRow = ({ - certificateName, - certificateUrl, - documentUrl, -}: { - certificateName: string; - certificateUrl: string; - documentUrl: string | undefined; -}) => { - return [ - certificateName, - <> - Cette entreprise {documentUrl ? 'possède un' : 'n‘a pas de'}{' '} - - certificat {certificateName} - {' '} - valide. - , - documentUrl && ( - - Télécharger le PDF - - ), - ]; -}; - -export default function TravauxPublicsSection({ - uniteLegale, - session, -}: { - uniteLegale: IUniteLegale; - session: ISession | null; -}) { - const travauxPublics = useAPIRouteData( - APIRoutesPaths.EspaceAgentTravauxPublics, - uniteLegale.siege.siret, - session - ); - - return ( - - {(data) => ( - <> -

- Cette entreprise{' '} - {data.fntp?.documentUrl ? 'possède une' : 'n‘a pas de'}{' '} - - carte professionnelle d’entrepreneur de travaux publics - - , délivrée par la FNTP. -

- - {data.fntp?.documentUrl && ( -
- - Télécharger le justificatif - -
- )} - - - )} -
- ); -} diff --git a/app/(header-default)/documents/[slug]/page.tsx b/app/(header-default)/documents/[slug]/page.tsx index 6289df4bd..32df63064 100644 --- a/app/(header-default)/documents/[slug]/page.tsx +++ b/app/(header-default)/documents/[slug]/page.tsx @@ -15,10 +15,10 @@ import extractParamsAppRouter, { } from '#utils/server-side-helper/app/extract-params'; import getSession from '#utils/server-side-helper/app/get-session'; import { Metadata } from 'next'; +import TravauxPublicsSection from '../../../../components/espace-agent-components/travaux-publics-section'; import ActesSection from './_components/actes'; import JustificatifsSection from './_components/justificatifs'; import { SummaryDocuments } from './_components/summary-documents'; -import TravauxPublicsSection from './_components/travaux-publics-section'; export const generateMetadata = async ( props: AppRouterProps diff --git a/clients/api-entreprise/carte-professionnelle-travaux-publics/index.ts b/clients/api-entreprise/carte-professionnelle-travaux-publics/index.ts deleted file mode 100644 index 87b17233c..000000000 --- a/clients/api-entreprise/carte-professionnelle-travaux-publics/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -import routes from '#clients/routes'; -import { ICarteProfessionnelleTravauxPublics } from '#models/espace-agent/travaux-publics'; -import { Siren } from '#utils/helpers'; -import clientAPIEntreprise, { IAPIEntrepriseResponse } from '../client'; - -export type IAPIEntrepriseCarteProfessionnelleTravauxPublics = - IAPIEntrepriseResponse<{ - document_url: string; - expires_in: number; - }>; - -/** - * GET documents from API Entreprise - */ -export const clientApiEntrepriseCarteProfessionnelleTravauxPublics = async ( - siren: Siren -) => { - return await clientAPIEntreprise< - IAPIEntrepriseCarteProfessionnelleTravauxPublics, - ICarteProfessionnelleTravauxPublics - >( - `${ - process.env.API_ENTREPRISE_URL - }${routes.apiEntreprise.carteProfessionnelleTravauxPublics(siren)}`, - mapToDomainObject - ); -}; - -const mapToDomainObject = ( - response: IAPIEntrepriseCarteProfessionnelleTravauxPublics -): ICarteProfessionnelleTravauxPublics => { - return { - documentUrl: response.data.document_url, - }; -}; diff --git a/clients/api-entreprise/certificats/cibtp.ts b/clients/api-entreprise/certificats/cibtp.ts deleted file mode 100644 index 4cbd74c42..000000000 --- a/clients/api-entreprise/certificats/cibtp.ts +++ /dev/null @@ -1,30 +0,0 @@ -import routes from '#clients/routes'; -import { ICertificatTravauxPublics } from '#models/espace-agent/travaux-publics'; -import { Siret } from '#utils/helpers'; -import clientAPIEntreprise, { IAPIEntrepriseResponse } from '../client'; - -export type IAPIEntrepriseCibtp = IAPIEntrepriseResponse<{ - document_url: string; // https://storage.entreprise.api.gouv.fr/siade/xxxxxx.pdf - expires_in: number; // 600 -}>; - -/** - * GET documents from API Entreprise - */ -export const clientApiEntrepriseCibtp = async (siret: Siret) => { - return await clientAPIEntreprise( - `${ - process.env.API_ENTREPRISE_URL - }${routes.apiEntreprise.certifications.cibtp(siret)}`, - mapToDomainObject - ); -}; - -const mapToDomainObject = ({ - data, -}: IAPIEntrepriseCibtp): ICertificatTravauxPublics => { - return { - documentUrl: data.document_url, - expiresIn: data.expires_in, - }; -}; diff --git a/clients/api-entreprise/certificats/cnetp.ts b/clients/api-entreprise/certificats/cnetp.ts deleted file mode 100644 index 87d3dc614..000000000 --- a/clients/api-entreprise/certificats/cnetp.ts +++ /dev/null @@ -1,30 +0,0 @@ -import routes from '#clients/routes'; -import { ICertificatTravauxPublics } from '#models/espace-agent/travaux-publics'; -import { Siren } from '#utils/helpers'; -import clientAPIEntreprise, { IAPIEntrepriseResponse } from '../client'; - -export type IAPIEntrepriseCnetp = IAPIEntrepriseResponse<{ - document_url: string; // https://storage.entreprise.api.gouv.fr/siade/xxxxxx.pdf - expires_in: number; // 600 -}>; - -/** - * GET documents from API Entreprise - */ -export const clientApiEntrepriseCnetp = async (siren: Siren) => { - return await clientAPIEntreprise( - `${ - process.env.API_ENTREPRISE_URL - }${routes.apiEntreprise.certifications.cnetp(siren)}`, - mapToDomainObject - ); -}; - -const mapToDomainObject = ({ - data, -}: IAPIEntrepriseCnetp): ICertificatTravauxPublics => { - return { - documentUrl: data.document_url, - expiresIn: data.expires_in, - }; -}; diff --git a/clients/api-entreprise/certificats/probtp.ts b/clients/api-entreprise/certificats/probtp.ts deleted file mode 100644 index a75d11e5a..000000000 --- a/clients/api-entreprise/certificats/probtp.ts +++ /dev/null @@ -1,30 +0,0 @@ -import routes from '#clients/routes'; -import { ICertificatTravauxPublics } from '#models/espace-agent/travaux-publics'; -import { Siret } from '#utils/helpers'; -import clientAPIEntreprise, { IAPIEntrepriseResponse } from '../client'; - -export type IAPIEntrepriseProbtp = IAPIEntrepriseResponse<{ - document_url: string; - expires_in: number; -}>; - -/** - * GET documents from API Entreprise - */ -export const clientApiEntrepriseProbtp = async (siret: Siret) => { - return await clientAPIEntreprise( - `${ - process.env.API_ENTREPRISE_URL - }${routes.apiEntreprise.certifications.probtp(siret)}`, - mapToDomainObject - ); -}; - -const mapToDomainObject = ({ - data, -}: IAPIEntrepriseProbtp): ICertificatTravauxPublics => { - return { - documentUrl: data.document_url, - expiresIn: data.expires_in, - }; -}; diff --git a/clients/api-entreprise/travaux-publics/index.ts b/clients/api-entreprise/travaux-publics/index.ts new file mode 100644 index 000000000..f15d856de --- /dev/null +++ b/clients/api-entreprise/travaux-publics/index.ts @@ -0,0 +1,67 @@ +import routes from '#clients/routes'; +import { IDocumentDownloader } from '#models/espace-agent/travaux-publics'; +import { Siren, Siret } from '#utils/helpers'; +import clientAPIEntreprise, { IAPIEntrepriseResponse } from '../client'; + +export type IAPIEntrepriseDocumentTravauxPublics = IAPIEntrepriseResponse<{ + document_url: string; + expires_in: number; +}>; + +/** + * GET document CIBTP + */ +export const clientApiEntrepriseCibtp = async (siret: Siret) => { + return await clientAPIEntreprise( + `${ + process.env.API_ENTREPRISE_URL + }${routes.apiEntreprise.certifications.cibtp(siret)}`, + mapToDomainObject + ); +}; + +/** + * GET document Pro BTP + */ +export const clientApiEntrepriseProbtp = async (siret: Siret) => { + return await clientAPIEntreprise( + `${ + process.env.API_ENTREPRISE_URL + }${routes.apiEntreprise.certifications.probtp(siret)}`, + mapToDomainObject + ); +}; + +/** + * GET document CNETP + */ +export const clientApiEntrepriseCnetp = async (siren: Siren) => { + return await clientAPIEntreprise( + `${ + process.env.API_ENTREPRISE_URL + }${routes.apiEntreprise.certifications.cnetp(siren)}`, + mapToDomainObject + ); +}; + +/** + * GET document FNTP + */ +export const clientApiEntrepriseCarteProfessionnelleTravauxPublics = async ( + siren: Siren +) => { + return await clientAPIEntreprise( + `${ + process.env.API_ENTREPRISE_URL + }${routes.apiEntreprise.carteProfessionnelleTravauxPublics(siren)}`, + mapToDomainObject + ); +}; + +const mapToDomainObject = ( + response: IAPIEntrepriseDocumentTravauxPublics +): IDocumentDownloader => { + return { + url: response.data.document_url, + }; +}; diff --git a/components/espace-agent-components/travaux-publics-section.tsx b/components/espace-agent-components/travaux-publics-section.tsx new file mode 100644 index 000000000..30bbf55a8 --- /dev/null +++ b/components/espace-agent-components/travaux-publics-section.tsx @@ -0,0 +1,131 @@ +'use client'; + +import FAQLink from '#components-ui/faq-link'; +import { Icon } from '#components-ui/icon/wrapper'; +import { AsyncDataSectionClient } from '#components/section/data-section/client'; +import { TwoColumnTable } from '#components/table/simple'; +import { EAdministration } from '#models/administrations/EAdministration'; +import { + IAPINotRespondingError, + isAPI404, + isAPINotResponding, +} from '#models/api-not-responding'; +import { IUniteLegale } from '#models/core/types'; +import { IDocumentDownloader } from '#models/espace-agent/travaux-publics'; +import { ISession } from '#models/user/session'; +import { APIRoutesPaths } from 'app/api/data-fetching/routes-paths'; +import { useAPIRouteData } from 'hooks/fetch/use-API-route-data'; + +const DocumentDownloader = ({ + data, + administration, +}: { + data: IDocumentDownloader | IAPINotRespondingError; + administration: string; +}) => { + if (isAPINotResponding(data)) { + if (isAPI404(data)) { + return ( + {administration} : document introuvable. + ); + } else { + return ( + + La récupération du document auprès des services {administration} a + échoué. +
+ Ré-essayez plus tard ou rapprochez-vous de l’entreprise pour lui + demander la pièce directement. +
+
+
+ ); + } + } + return ( +
+ + {administration ? `${administration} : ` : ''}document disponible + + {data.url && ( + + {'télécharger'} + + )} +
+ ); +}; + +export default function TravauxPublicsSection({ + uniteLegale, + session, +}: { + uniteLegale: IUniteLegale; + session: ISession | null; +}) { + const travauxPublics = useAPIRouteData( + APIRoutesPaths.EspaceAgentTravauxPublics, + uniteLegale.siege.siret, + session + ); + + return ( + + {(data) => ( + <> + + Carte professionnelle d’entrepreneur de travaux publics, + délivrée à une entreprise en règle de ses obligations + sociales, administratives et juridiques. + , + , + ], + [ + + Certificat indiquant qu’une entreprise de travaux publics + affiliée à la caisse CNETP ou CIBTP est en règle de ses + cotisations congés payés et chômage-intempéries. + , + <> + + + , + ], + [ + + Document indiquant la régularité des cotisations de retraite + complémentaire auprès de la Protection Sociale du Bâtiment et + des Travaux publics (ProBTP). + , + , + ], + ]} + /> + + )} + + ); +} diff --git a/models/espace-agent/conformite.ts b/models/espace-agent/conformite.ts index 5f9884011..a654da38b 100644 --- a/models/espace-agent/conformite.ts +++ b/models/espace-agent/conformite.ts @@ -22,6 +22,7 @@ export const getConformiteEntreprise = async ( ): Promise => { const siret = verifySiret(maybeSiret as string); const siren = extractSirenFromSiret(siret); + const [fiscale, vigilance, msa] = await Promise.all([ clientApiEntrepriseConformiteFiscale(siren).catch((error) => handleApiEntrepriseError(error, { diff --git a/models/espace-agent/travaux-publics.ts b/models/espace-agent/travaux-publics.ts index b95a0b1cf..45224859d 100644 --- a/models/espace-agent/travaux-publics.ts +++ b/models/espace-agent/travaux-publics.ts @@ -1,24 +1,22 @@ -import { clientApiEntrepriseCarteProfessionnelleTravauxPublics } from '#clients/api-entreprise/carte-professionnelle-travaux-publics'; -import { clientApiEntrepriseCibtp } from '#clients/api-entreprise/certificats/cibtp'; -import { clientApiEntrepriseCnetp } from '#clients/api-entreprise/certificats/cnetp'; -import { clientApiEntrepriseProbtp } from '#clients/api-entreprise/certificats/probtp'; -import { HttpNotFound } from '#clients/exceptions'; +import { + clientApiEntrepriseCarteProfessionnelleTravauxPublics, + clientApiEntrepriseCibtp, + clientApiEntrepriseCnetp, + clientApiEntrepriseProbtp, +} from '#clients/api-entreprise/travaux-publics'; import { IAPINotRespondingError } from '#models/api-not-responding'; import { extractSirenFromSiret, verifySiret } from '#utils/helpers'; import { handleApiEntrepriseError } from './utils'; -export type ICertificatTravauxPublics = { - documentUrl: string; - expiresIn: number; -}; -export type ICarteProfessionnelleTravauxPublics = { - documentUrl: string; +export type IDocumentDownloader = { + url: string; }; + export type ITravauxPublics = { - fntp: ICarteProfessionnelleTravauxPublics | null; - cibtp: ICertificatTravauxPublics | null; - cnetp: ICertificatTravauxPublics | null; - probtp: ICertificatTravauxPublics | null; + fntp: IDocumentDownloader | IAPINotRespondingError; + cibtp: IDocumentDownloader | IAPINotRespondingError; + cnetp: IDocumentDownloader | IAPINotRespondingError; + probtp: IDocumentDownloader | IAPINotRespondingError; }; export const getTravauxPublic = async ( @@ -26,44 +24,21 @@ export const getTravauxPublic = async ( ): Promise => { const siret = verifySiret(slug as string); const siren = extractSirenFromSiret(siret); - try { - const [fntp, cibtp, cnetp, probtp] = await Promise.all([ - clientApiEntrepriseCarteProfessionnelleTravauxPublics(siren).catch( - (e) => { - if (e instanceof HttpNotFound) { - return null; - } else { - throw e; - } - } - ), - clientApiEntrepriseCibtp(siret).catch((e) => { - if (e instanceof HttpNotFound) { - return null; - } else { - throw e; - } - }), - clientApiEntrepriseCnetp(siren).catch((e) => { - if (e instanceof HttpNotFound) { - return null; - } else { - throw e; - } - }), - clientApiEntrepriseProbtp(siret).catch((e) => { - if (e instanceof HttpNotFound) { - return null; - } else { - throw e; - } - }), - ]); - return { fntp, cibtp, cnetp, probtp }; - } catch (e) { - return handleApiEntrepriseError(e, { + + const errorHandler = (e: any) => + handleApiEntrepriseError(e, { siren, + siret, apiResource: 'TravauxPublics', }); - } + + const [fntp, cibtp, cnetp, probtp] = await Promise.all([ + clientApiEntrepriseCarteProfessionnelleTravauxPublics(siren).catch( + errorHandler + ), + clientApiEntrepriseCibtp(siret).catch(errorHandler), + clientApiEntrepriseCnetp(siren).catch(errorHandler), + clientApiEntrepriseProbtp(siret).catch(errorHandler), + ]); + return { fntp, cibtp, cnetp, probtp }; };