diff --git a/front/src/app/components/layout/MetaContent.tsx b/front/src/app/components/layout/DefaultMetaContent.tsx similarity index 61% rename from front/src/app/components/layout/MetaContent.tsx rename to front/src/app/components/layout/DefaultMetaContent.tsx index 831b45a630..d05f1bf912 100644 --- a/front/src/app/components/layout/MetaContent.tsx +++ b/front/src/app/components/layout/DefaultMetaContent.tsx @@ -1,37 +1,35 @@ import React from "react"; -import { Helmet, HelmetProvider } from "react-helmet-async"; +import { Helmet } from "react-helmet-async"; import { MetaContentType, adminMetaContent, defaultMetaContents, + defaultPageMetaContents, groupMetaContent, - metaContents, standardMetaContent, } from "src/app/contents/meta/metaContents"; import { StandardPageSlugs } from "src/app/routes/routeParams/standardPage"; import { routes, useRoute } from "src/app/routes/routes"; import { Route } from "type-route"; -export const MetaContent = (): JSX.Element => { +export const DefaultMetaContent = (): JSX.Element => { const route = useRoute(); const contents = getMetaContents(route); return ( - - - - {contents - ? `${contents.title} - PMSMP: Immersion Facile` - : defaultMetaContents.title} - - - - + + + {contents + ? `${contents.title} - PMSMP: Immersion Facile` + : defaultMetaContents.title} + + + ); }; @@ -48,6 +46,6 @@ const getMetaContents = ( if (route.name === "admin") { return adminMetaContent[route.params.tab]; } - return metaContents[route.name]; + return defaultPageMetaContents[route.name]; } }; diff --git a/front/src/app/contents/meta/metaContents.ts b/front/src/app/contents/meta/metaContents.ts index 1120ed5e41..f308a8649c 100644 --- a/front/src/app/contents/meta/metaContents.ts +++ b/front/src/app/contents/meta/metaContents.ts @@ -12,7 +12,9 @@ export const defaultMetaContents: MetaContentType = { description: "Faciliter la réalisation des immersions professionnelles.", }; -export const metaContents: Partial> = { +export const defaultPageMetaContents: Partial< + Record +> = { addAgency: { title: "Formulaire d'ajout d'un prescripteur", description: "Devenir prescripteur de PMSMP et immersions professionnelles", @@ -112,6 +114,55 @@ export const metaContents: Partial> = { description: "Utilisez notre moteur de recherche pour trouver une entreprise accueillante d'Immersions Professionnelles ou PMSMP", }, + agencyDashboard: { + title: "Tableau de bord agence", + description: "Retrouvez vos conventions en cours et passées", + }, + beneficiaryDashboard: { + title: "Tableau de bord bénéficiaire", + description: "Bientôt disponible", + }, + establishmentDashboard: { + title: "Tableau de bord entreprise", + description: + "Retrouvez vos conventions en cours et passées, les candidatures faites à votre entreprise", + }, + initiateConvention: { + title: "Initier une convention", + description: + "Initier une convention pour une Immersion Professionnelle (PMSMP)", + }, + openApiDoc: { + title: "Documentation API", + description: "Documentation de l'API de l'application Immersion Facilitée", + }, + conventionConfirmation: { + title: "Confirmation de la convention", + description: + "Confirmation de la convention d'immersion professionnelle (PMSMP)", + }, + searchResult: { + title: "Offre d'immersion (PMSMP)", + description: "Fiche présentant une offre d'immersion (PMSMP)", + }, + searchResultExternal: { + title: "Offre d'immersion (PMSMP)", + description: "Fiche présentant une offre d'immersion (PMSMP)", + }, + searchDiagoriente: { + title: + "Rechercher une entreprise pour réaliser une immersion professionnelle", + description: + "Utilisez notre moteur de recherche pour trouver une entreprise accueillante d'Immersions Professionnelles ou PMSMP", + }, + conventionDocument: { + title: "Document de convention d'immersion (PMSMP) finalisé", + description: "Document de convention d'immersion (PMSMP) finalisé", + }, + group: { + title: "Page de regroupement d'immersions", + description: "Page de regroupement d'immersions", + }, }; export const standardMetaContent: Record = { diff --git a/front/src/app/main.tsx b/front/src/app/main.tsx index dfb27df88c..8f52f6bf87 100644 --- a/front/src/app/main.tsx +++ b/front/src/app/main.tsx @@ -3,12 +3,13 @@ import * as Sentry from "@sentry/browser"; import React from "react"; import { createRoot } from "react-dom/client"; import { ErrorBoundary } from "react-error-boundary"; +import { HelmetProvider } from "react-helmet-async"; import { Provider } from "react-redux"; import { App } from "src/app/App"; import { MinimalErrorPage } from "src/app/pages/error/MinimalErrorPage"; import { store } from "src/config/dependencies"; import { ENV } from "src/config/environmentVariables"; -import { MetaContent } from "./components/layout/MetaContent"; +import { DefaultMetaContent } from "./components/layout/DefaultMetaContent"; import { RouteProvider } from "./routes/routes"; Sentry.init({ @@ -31,10 +32,12 @@ createRoot(rootContainer).render( } > - - - - + + + + + + , diff --git a/front/src/app/pages/search/SearchResultPage.tsx b/front/src/app/pages/search/SearchResultPage.tsx index 2ebaa6c6db..c4fd5d29ab 100644 --- a/front/src/app/pages/search/SearchResultPage.tsx +++ b/front/src/app/pages/search/SearchResultPage.tsx @@ -4,10 +4,12 @@ import Button from "@codegouvfr/react-dsfr/Button"; import ButtonsGroup from "@codegouvfr/react-dsfr/ButtonsGroup"; import React, { ElementRef, useEffect, useRef, useState } from "react"; import { Loader, MainWrapper } from "react-design-system"; +import { Helmet } from "react-helmet-async"; import { useDispatch } from "react-redux"; import { AppellationDto, ContactMethod, + SearchResultDto, getMapsLink, makeAppellationInformationUrl, makeNafClassInformationUrl, @@ -18,6 +20,7 @@ import { ContactByPhone } from "src/app/components/immersion-offer/ContactByPhon import { ContactInPerson } from "src/app/components/immersion-offer/ContactInPerson"; import { HeaderFooterLayout } from "src/app/components/layout/HeaderFooterLayout"; import { SearchResultLabels } from "src/app/components/search/SearchResultLabels"; +import { defaultPageMetaContents } from "src/app/contents/meta/metaContents"; import { useAppSelector } from "src/app/hooks/reduxHooks"; import { routes, useRoute } from "src/app/routes/routes"; import { searchSelectors } from "src/core-logic/domain/search/search.selectors"; @@ -50,6 +53,34 @@ const SearchResultSection = ({ ); +const getMetaForSearchResult = ( + currentSearchResult: SearchResultDto | null, +): { + title: string; + description: string; +} => { + if (!currentSearchResult) return { title: "", description: "" }; + const hasAppellations = currentSearchResult.appellations?.length; + return { + title: `${currentSearchResult.name}${ + hasAppellations + ? ` - ${currentSearchResult.appellations + .map((appellation) => `${appellation.appellationLabel}`) + .join(", ")}` + : "" + }`, + description: `Fiche présentant l'immersion proposée par l'entreprise ${ + currentSearchResult?.name + }${ + hasAppellations + ? `en tant que ${currentSearchResult.appellations.map( + (appellation) => appellation.appellationLabel, + )}` + : "" + }`, + }; +}; + export const SearchResultPage = () => { const route = useRoute() as Route< typeof routes.searchResult | typeof routes.searchResultExternal @@ -57,6 +88,7 @@ export const SearchResultPage = () => { const currentSearchResult = useAppSelector( searchSelectors.currentSearchResult, ); + const defaultMetaContents = defaultPageMetaContents.searchResult; const feedback = useAppSelector(searchSelectors.feedback); const isLoading = useAppSelector(searchSelectors.isLoading); const formContactRef = useRef>(null); @@ -99,6 +131,16 @@ export const SearchResultPage = () => { return ( + + + {getMetaForSearchResult(currentSearchResult).title} :{" "} + {defaultMetaContents?.title} + + + <> {isLoading && }