From 2275d2dcfaae0537c8c9fb3a7ed45237ca0c5d1e Mon Sep 17 00:00:00 2001 From: sokl-octo <165301800+sokl-octo@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:21:25 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20:=20Emp=C3=AAcher=20la=20mise=20en=20lign?= =?UTF-8?q?e=20de=20cartes=20sans=20link=20(#3234)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(mesure-jeune): refuse les mesures jeunes sans link * fix(mesure-empl): refuse les mesures employeurs sans link * refactor(mesures): crée un service pour transformer les mesures (filter/map) * feat(mesures): échoue gracieusement, la mesure sans link est affichée --- .../ui/Card/Flipping/FlippingCard.module.scss | 1 + .../ui/Card/Flipping/FlippingCard.test.tsx | 8 ++ .../ui/Card/Flipping/FlippingCard.tsx | 8 +- .../strapiErrorManagement.service.ts | 5 +- .../domain/mesureEmployeur.ts | 2 +- .../strapiMesuresEmployeurs.mapper.test.ts | 81 ++++++++++++------- .../infra/strapiMesuresEmployeurs.mapper.ts | 11 ++- ...strapiMesuresEmployeurs.repository.test.ts | 9 ++- .../strapiMesuresEmployeurs.repository.ts | 1 - .../services-jeunes/domain/servicesJeunes.ts | 2 +- .../infra/strapiServicesJeunes.mapper.test.ts | 55 +++++++++---- .../infra/strapiServicesJeunes.mapper.ts | 19 +++-- .../strapiServicesJeunes.repository.test.ts | 3 +- .../infra/strapiServicesJeunes.repository.ts | 1 - 14 files changed, 137 insertions(+), 69 deletions(-) diff --git a/src/client/components/ui/Card/Flipping/FlippingCard.module.scss b/src/client/components/ui/Card/Flipping/FlippingCard.module.scss index 106edc0666..4f738f3a7a 100644 --- a/src/client/components/ui/Card/Flipping/FlippingCard.module.scss +++ b/src/client/components/ui/Card/Flipping/FlippingCard.module.scss @@ -13,6 +13,7 @@ $transition-visibility: visibility 0ms $transition-duration linear; } .cardWrapper { + height: 100%; --flipped: 0; transform-style: preserve-3d; transition: transform $transition-duration ease-in-out; diff --git a/src/client/components/ui/Card/Flipping/FlippingCard.test.tsx b/src/client/components/ui/Card/Flipping/FlippingCard.test.tsx index 58b58befb1..ffb165ed84 100644 --- a/src/client/components/ui/Card/Flipping/FlippingCard.test.tsx +++ b/src/client/components/ui/Card/Flipping/FlippingCard.test.tsx @@ -32,4 +32,12 @@ describe('', () => { const image = screen.getByRole('presentation'); expect(image).toHaveAttribute('src', expect.stringContaining('image-par-defaut-carte.webp')); }); + + it('cache le lien lorsqu’il n’est pas fourni', async () => { + // When + render(); + + // Then + expect(screen.queryByRole('link')).not.toBeInTheDocument(); + }); }); diff --git a/src/client/components/ui/Card/Flipping/FlippingCard.tsx b/src/client/components/ui/Card/Flipping/FlippingCard.tsx index d59bde65d2..450f5c421f 100644 --- a/src/client/components/ui/Card/Flipping/FlippingCard.tsx +++ b/src/client/components/ui/Card/Flipping/FlippingCard.tsx @@ -13,7 +13,7 @@ import { ServiceJeune } from '~/server/services-jeunes/domain/servicesJeunes'; interface FlippingCardProps { imageUrl?: string - link: string + link?: string title: string category?: string titleAs?: HtmlHeadingTag @@ -24,7 +24,7 @@ interface FlippingCardProps { export function FlippingCard(props: FlippingCardProps) { const { category, imageUrl, link, title, titleAs, flippingCardContent, className, ...rest } = props; const cardFlipRef = useRef(null); - const isInternalLink = useIsInternalLink(link); + const isInternalLink = useIsInternalLink(link ?? ''); const [isCardFlipped, setIsCardFlipped] = useState(false); const [isAnimationOn, setIsAnimationOn] = useState(false); const hasFlipCardContent = !!flippingCardContent.length; @@ -86,10 +86,10 @@ export function FlippingCard(props: FlippingCardProps) { ref={flipButton} onClick={() => flipCard()}/> } - + {link && {isInternalLink ? 'Lire l‘article' : 'En savoir plus'} - + } diff --git a/src/server/cms/infra/repositories/strapiErrorManagement.service.ts b/src/server/cms/infra/repositories/strapiErrorManagement.service.ts index 71e4e6cb93..6e1f8ae1b9 100644 --- a/src/server/cms/infra/repositories/strapiErrorManagement.service.ts +++ b/src/server/cms/infra/repositories/strapiErrorManagement.service.ts @@ -1,8 +1,6 @@ import { createFailure, Failure } from '~/server/errors/either'; import { ErreurMetier } from '~/server/errors/erreurMetier.types'; -import { - DefaultErrorManagementService, -} from '~/server/services/error/errorManagement.service'; +import { DefaultErrorManagementService } from '~/server/services/error/errorManagement.service'; import { HttpError } from '~/server/services/http/httpError'; import { LoggerService } from '~/server/services/logger.service'; @@ -10,6 +8,7 @@ export class StrapiErrorManagementService extends DefaultErrorManagementService constructor(loggerService: LoggerService) { super(loggerService); } + protected createFailureForHttpError(error: HttpError) { if (error.response?.status === 400 && error?.response?.data?.message === '[API Strapi] 400 Bad request pour la ressource') { return createFailure(ErreurMetier.DEMANDE_INCORRECTE); diff --git a/src/server/mesures-employeurs/domain/mesureEmployeur.ts b/src/server/mesures-employeurs/domain/mesureEmployeur.ts index 6ff5f8d211..e311c8d0f4 100644 --- a/src/server/mesures-employeurs/domain/mesureEmployeur.ts +++ b/src/server/mesures-employeurs/domain/mesureEmployeur.ts @@ -4,6 +4,6 @@ export interface MesureEmployeur { titre: string banniere?: Image pourQui: string - link: string + link?: string } diff --git a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.test.ts b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.test.ts index 5c5a85a2e7..cec736ad19 100644 --- a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.test.ts +++ b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.test.ts @@ -46,45 +46,68 @@ describe('mapMesuresEmployeurs', () => { expect(result).toEqual(expectedMesuresEmployeurs); }); - describe('article', () => { - it('lorsqu‘aucun article est relié, renvoie en link l‘url associée à la mesure employeur', () => { - // GIVEN - const strapiMesuresEmployeurs = aStrapiMesuresEmployeursList({ - dispositifs: [aStrapiMesureEmployeur({ - article: undefined, - url: 'https://some.example.com/4', - })], - }); + describe('link', () => { + describe('article non relié, url non relié', () => { + it('laisse link undefined', () => { + // Given + const strapiMesuresEmployeurs = aStrapiMesuresEmployeursList({ + dispositifs: [aStrapiMesureEmployeur({ + article: undefined, + url: undefined, + })], + }); - // WHEN - const result = mapMesuresEmployeurs(strapiMesuresEmployeurs); + // When + const result = mapMesuresEmployeurs(strapiMesuresEmployeurs); - // THEN - expect(result).toStrictEqual([aMesureEmployeur({ - link: 'https://some.example.com/4', - })]); + // Then + const mesureObtenue = result[0]; + expect(mesureObtenue.link).toBeUndefined(); + }); }); - it('lorsqu‘un article est relié, renvoie un lien à partir du slug de l‘article', () => { - // GIVEN - const strapiMesuresEmployeurs = aStrapiMesuresEmployeursList({ - dispositifs: [aStrapiMesureEmployeur({ - article: aStrapiSingleRelation(aStrapiArticle({ slug: 'this-is-a-slug' })), - })], + describe('article non relié, url relié', () => { + it('renvoie en link l‘url associée à la mesure employeur', () => { + // GIVEN + const urlRelieAttendu = 'https://some.example.com/4'; + const strapiMesuresEmployeurs = aStrapiMesuresEmployeursList({ + dispositifs: [aStrapiMesureEmployeur({ + article: undefined, + url: urlRelieAttendu, + })], + }); + + // WHEN + const result = mapMesuresEmployeurs(strapiMesuresEmployeurs); + + // THEN + const mesureObtenue = result[0]; + expect(mesureObtenue.link).toStrictEqual(urlRelieAttendu); }); + }); - // WHEN - const result = mapMesuresEmployeurs(strapiMesuresEmployeurs); + describe('article relié', () => { + it('renvoie un lien à partir du slug de l‘article', () => { + // GIVEN + const slugAttendu = 'this-is-a-slug'; + const strapiMesuresEmployeurs = aStrapiMesuresEmployeursList({ + dispositifs: [aStrapiMesureEmployeur({ + article: aStrapiSingleRelation(aStrapiArticle({ slug: slugAttendu })), + })], + }); - // THEN - expect(result).toStrictEqual([aMesureEmployeur({ - link: '/articles/this-is-a-slug', - })]); + // WHEN + const result = mapMesuresEmployeurs(strapiMesuresEmployeurs); + + // THEN + const mesureObtenue = result[0]; + expect(mesureObtenue.link).toStrictEqual('/articles/' + slugAttendu); + }); }); - }); + }); - it('lorsque je ne fourni pas d‘alternative texte à la bannière, renvoie une string vide', () => { + it('lorsque je ne fournis pas d‘alternative texte à la bannière, renvoie une string vide', () => { const strapiMesuresEmployeurs = aStrapiMesuresEmployeursList({ dispositifs: [aStrapiMesureEmployeur({ banniere: aStrapiSingleRelation(aStrapiImage({ diff --git a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.ts b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.ts index 3171f17156..36d48c6454 100644 --- a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.ts +++ b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.mapper.ts @@ -4,14 +4,19 @@ import { StrapiMesuresEmployeurs } from '~/server/mesures-employeurs/infra/strap export function mapMesuresEmployeurs(strapiLesMesuresEmployeurs: StrapiMesuresEmployeurs.MesuresEmployeurs): Array { return strapiLesMesuresEmployeurs.dispositifs.map((strapiLesMesuresEmployeursDispositif) => { - const article = strapiLesMesuresEmployeursDispositif.article && flatMapSingleRelation(strapiLesMesuresEmployeursDispositif.article); - return { banniere: flatMapSingleImage(strapiLesMesuresEmployeursDispositif.banniere), - link: article ? `/articles/${article.slug}` : strapiLesMesuresEmployeursDispositif.url, + link: mapMesureEmployeurLink(strapiLesMesuresEmployeursDispositif), pourQui: strapiLesMesuresEmployeursDispositif.pourQui || '', titre: strapiLesMesuresEmployeursDispositif.titre, }; }); } +function mapMesureEmployeurLink(dispositif: StrapiMesuresEmployeurs.Dispositif): string | undefined { + const article = dispositif.article && flatMapSingleRelation(dispositif.article); + if(!article && !dispositif.url) { + return undefined; + } + return article ? `/articles/${article.slug}` : dispositif.url; +} diff --git a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.test.ts b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.test.ts index 72474eda25..b6ed153488 100644 --- a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.test.ts +++ b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.test.ts @@ -2,13 +2,14 @@ import { aStrapiService } from '~/server/cms/infra/repositories/strapi.service.f import { createFailure, createSuccess } from '~/server/errors/either'; import { ErreurMetier } from '~/server/errors/erreurMetier.types'; import { aMesuresEmployeursList } from '~/server/mesures-employeurs/domain/mesureEmployeur.fixture'; -import { aStrapiMesuresEmployeursList } from '~/server/mesures-employeurs/infra/strapiMesuresEmployeurs.fixture'; +import { + aStrapiMesuresEmployeursList, +} from '~/server/mesures-employeurs/infra/strapiMesuresEmployeurs.fixture'; import { StrapiMesuresEmployeursRepository, } from '~/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository'; import { aLogInformation, anErrorManagementService } from '~/server/services/error/errorManagement.fixture'; - describe('StrapiMesuresEmployeursRepository', () => { describe('getMesuresEmployeurs', () => { it('appelle le service strapi avec les bons paramètres', async () => { @@ -25,7 +26,7 @@ describe('StrapiMesuresEmployeursRepository', () => { }); describe('quand la récupération est en succès', () => { - it('quand le mapping vers les mesures employeurs est en succès, renvoie la liste des mesures employeurs', async () => { + it('quand map vers les mesures employeurs est en succès, renvoie la liste des mesures employeurs', async () => { const strapiService = aStrapiService(); jest.spyOn(strapiService, 'getSingleType').mockResolvedValue(createSuccess(aStrapiMesuresEmployeursList())); const strapiMesuresEmployeurs = new StrapiMesuresEmployeursRepository(strapiService, anErrorManagementService()); @@ -36,7 +37,7 @@ describe('StrapiMesuresEmployeursRepository', () => { expect(result).toStrictEqual(resultExpected); }); - it('quand le mapping vers les mesures employeurs est en échec, appelle le service de management d‘erreur avec l‘erreur et le contexte', async () => { + it('quand map vers les mesures employeurs est échec, appelle le service de management d‘erreur avec l‘erreur et le contexte', async () => { const strapiService = aStrapiService(); jest.spyOn(strapiService, 'getSingleType').mockResolvedValue(createSuccess({ someNonExistentField: '' })); diff --git a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.ts b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.ts index 1fbbbc6f27..aca7dd5377 100644 --- a/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.ts +++ b/src/server/mesures-employeurs/infra/strapiMesuresEmployeurs.repository.ts @@ -28,4 +28,3 @@ export class StrapiMesuresEmployeursRepository implements MesuresEmployeursRepos } } } - diff --git a/src/server/services-jeunes/domain/servicesJeunes.ts b/src/server/services-jeunes/domain/servicesJeunes.ts index cbead0afae..0f264e4e6a 100644 --- a/src/server/services-jeunes/domain/servicesJeunes.ts +++ b/src/server/services-jeunes/domain/servicesJeunes.ts @@ -5,7 +5,7 @@ export interface ServiceJeune { categorie?: string banniere?: Image concerne: string - link: string + link?: string } export namespace ServiceJeune { diff --git a/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.test.ts b/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.test.ts index 2931822a7d..42e4fa7168 100644 --- a/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.test.ts +++ b/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.test.ts @@ -46,24 +46,49 @@ describe('mapToServicesJeunes', () => { expect(result).toStrictEqual(anUnorderedAndNotFilterServiceJeuneList()); }); - describe('article', () => { - it('lorsqu‘aucun article est relié, ne renvoie pas d‘article et renvoie en link l‘url associée à la mesure jeune', () => { - // GIVEN - const strapiMesuresJeunesParCategorie = aStrapiMesuresJeunesParCategorieSansResultat({ - accompagnement: [aStrapiMesureJeune({ - article: undefined, - })], + describe('link', () => { + describe('article non relié, url non relié', () => { + it('laisse link undefined', () => { + // Given + const strapiMesuresJeunesParCategorie = aStrapiMesuresJeunesParCategorieSansResultat({ + accompagnement: [aStrapiMesureJeune({ + article: undefined, + url: undefined, + })], + }); + + // When + const result = mapToServicesJeunes(strapiMesuresJeunesParCategorie); + + // Then + const mesureObtenue = result[0]; + expect(mesureObtenue.link).toBeUndefined(); }); + }); - // WHEN - const result = mapToServicesJeunes(strapiMesuresJeunesParCategorie); + describe('article non relié, url relié', () => { + it('ne renvoie pas d‘article et renvoie en link l’url associée à la mesure jeune', () => { + // Given + const urlRelieAttendu = 'mon-url-relié'; + const strapiMesuresJeunesParCategorie = aStrapiMesuresJeunesParCategorieSansResultat({ + accompagnement: [aStrapiMesureJeune({ + article: undefined, + url: urlRelieAttendu, + })], + }); - // THEN - expect(result).toStrictEqual([aServiceJeune({ - link: 'Une belle url de carte', - })]); + // When + const result = mapToServicesJeunes(strapiMesuresJeunesParCategorie); + + // Then + const mesureObtenue = result[0]; + expect(mesureObtenue.link).toStrictEqual(urlRelieAttendu); + }); }); - it('lorsqu‘un article est relié, renvoie les informations relatives à l‘article et un lien à partir du slug de l‘article', () => { + }); + + describe('article relié', () => { + it('renvoie les informations relatives à l’article et un lien à partir du slug de l’article', () => { // GIVEN const strapiMesuresJeunesParCategorie = aStrapiMesuresJeunesParCategorieSansResultat({ accompagnement: [aStrapiMesureJeune({ @@ -81,7 +106,7 @@ describe('mapToServicesJeunes', () => { }); }); - it('lorsque je ne fourni pas d‘alternative texte à la bannière, renvoie une string vide', () => { + it('lorsque je ne fournis pas d‘alternative texte à la bannière, renvoie une string vide', () => { const strapiMesuresJeunesParCategorie = aStrapiMesuresJeunesParCategorieSansResultat({ accompagnement: [aStrapiMesureJeune({ banniere: aStrapiSingleRelation(aStrapiImage({ diff --git a/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.ts b/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.ts index 12608ea737..006de3d1b5 100644 --- a/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.ts +++ b/src/server/services-jeunes/infra/strapiServicesJeunes.mapper.ts @@ -20,9 +20,8 @@ export function mapToServicesJeunes(strapiMesuresJeunes: StrapiMesuresJeunes.Mes }); } -function mapServiceJeune(response: StrapiMesuresJeunes.MesureJeune, categorie: StrapiMesuresJeunes.Categorie): ServiceJeune { - const article = response.article && flatMapSingleRelation(response.article); - const banniere = flatMapSingleRelation(response.banniere); +function mapServiceJeune(strapiMesureJeune: StrapiMesuresJeunes.MesureJeune, categorie: StrapiMesuresJeunes.Categorie): ServiceJeune { + const banniere = flatMapSingleRelation(strapiMesureJeune.banniere); return { banniere: banniere && { @@ -30,9 +29,9 @@ function mapServiceJeune(response: StrapiMesuresJeunes.MesureJeune, categorie: S src: banniere.url, }, categorie: mapServiceJeuneCategorie(categorie), - concerne: response.pourQui, - link: article ? `/articles/${article.slug}` : response.url, - titre: response.titre, + concerne: strapiMesureJeune.pourQui, + link: mapServiceJeuneLink(strapiMesureJeune), + titre: strapiMesureJeune.titre, }; } @@ -52,3 +51,11 @@ function mapServiceJeuneCategorie(mesureJeuneKey: keyof StrapiMesuresJeunes.Mesu return ServiceJeune.Categorie.LOGEMENT; } } + +function mapServiceJeuneLink(mesure: StrapiMesuresJeunes.MesureJeune) { + const article = mesure.article && flatMapSingleRelation(mesure.article); + if(!article && !mesure.url) { + return undefined; + } + return article ? `/articles/${article.slug}` : mesure.url; +} diff --git a/src/server/services-jeunes/infra/strapiServicesJeunes.repository.test.ts b/src/server/services-jeunes/infra/strapiServicesJeunes.repository.test.ts index c6a00a2f15..21d9410147 100644 --- a/src/server/services-jeunes/infra/strapiServicesJeunes.repository.test.ts +++ b/src/server/services-jeunes/infra/strapiServicesJeunes.repository.test.ts @@ -67,9 +67,10 @@ describe('strapiMesuresJeunesRepository', () => { ]; expect(result).toEqual(createSuccess(orderedServicesJeunes)); }); + }); - describe('si le mapping vers les services jeunes est en erreur', () => { + describe('si map vers les services jeunes est en erreur', () => { it('appelle le service de gestion d’erreur avec l’erreur et le contexte', async () => { const strapiService = aStrapiService(); jest.spyOn(strapiService, 'getSingleType').mockResolvedValue(createSuccess({ diff --git a/src/server/services-jeunes/infra/strapiServicesJeunes.repository.ts b/src/server/services-jeunes/infra/strapiServicesJeunes.repository.ts index 6e0c7e119e..6a8a91b660 100644 --- a/src/server/services-jeunes/infra/strapiServicesJeunes.repository.ts +++ b/src/server/services-jeunes/infra/strapiServicesJeunes.repository.ts @@ -32,4 +32,3 @@ export class StrapiServicesJeunesRepository implements ServicesJeunesRepository } } } -