Skip to content

Commit

Permalink
Fix : Empêcher la mise en ligne de cartes sans link (#3234)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
sokl-octo authored Aug 8, 2024
1 parent b4a0227 commit 2275d2d
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions src/client/components/ui/Card/Flipping/FlippingCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,12 @@ describe('<FlippingCard>', () => {
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(<FlippingCard title="test" flippingCardContent="pour qui" />);

// Then
expect(screen.queryByRole('link')).not.toBeInTheDocument();
});
});
8 changes: 4 additions & 4 deletions src/client/components/ui/Card/Flipping/FlippingCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,7 +24,7 @@ interface FlippingCardProps {
export function FlippingCard(props: FlippingCardProps) {
const { category, imageUrl, link, title, titleAs, flippingCardContent, className, ...rest } = props;
const cardFlipRef = useRef<HTMLDivElement>(null);
const isInternalLink = useIsInternalLink(link);
const isInternalLink = useIsInternalLink(link ?? '');
const [isCardFlipped, setIsCardFlipped] = useState(false);
const [isAnimationOn, setIsAnimationOn] = useState(false);
const hasFlipCardContent = !!flippingCardContent.length;
Expand Down Expand Up @@ -86,10 +86,10 @@ export function FlippingCard(props: FlippingCardProps) {
ref={flipButton}
onClick={() => flipCard()}/>
}
<Link href={link} prefetch={false} appearance="asPrimaryButton">
{link && <Link href={link} prefetch={false} appearance="asPrimaryButton">
{isInternalLink ? 'Lire l‘article' : 'En savoir plus'}
<Link.Icon/>
</Link>
</Link>}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
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';

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);
Expand Down
2 changes: 1 addition & 1 deletion src/server/mesures-employeurs/domain/mesureEmployeur.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export interface MesureEmployeur {
titre: string
banniere?: Image
pourQui: string
link: string
link?: string
}

Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@ import { StrapiMesuresEmployeurs } from '~/server/mesures-employeurs/infra/strap

export function mapMesuresEmployeurs(strapiLesMesuresEmployeurs: StrapiMesuresEmployeurs.MesuresEmployeurs): Array<MesureEmployeur> {
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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand All @@ -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());
Expand All @@ -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: '' }));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ export class StrapiMesuresEmployeursRepository implements MesuresEmployeursRepos
}
}
}

2 changes: 1 addition & 1 deletion src/server/services-jeunes/domain/servicesJeunes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface ServiceJeune {
categorie?: string
banniere?: Image
concerne: string
link: string
link?: string
}

export namespace ServiceJeune {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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({
Expand Down
19 changes: 13 additions & 6 deletions src/server/services-jeunes/infra/strapiServicesJeunes.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,18 @@ export function mapToServicesJeunes(strapiMesuresJeunes: StrapiMesuresJeunes.Mes
});
}

function mapServiceJeune(response: StrapiMesuresJeunes.MesureJeune, categorie: StrapiMesuresJeunes.Categorie): ServiceJeune {
const article = response.article && flatMapSingleRelation<StrapiArticle>(response.article);
const banniere = flatMapSingleRelation<Strapi.Image>(response.banniere);
function mapServiceJeune(strapiMesureJeune: StrapiMesuresJeunes.MesureJeune, categorie: StrapiMesuresJeunes.Categorie): ServiceJeune {
const banniere = flatMapSingleRelation<Strapi.Image>(strapiMesureJeune.banniere);

return {
banniere: banniere && {
alt: banniere.alternativeText || '',
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,
};
}

Expand All @@ -52,3 +51,11 @@ function mapServiceJeuneCategorie(mesureJeuneKey: keyof StrapiMesuresJeunes.Mesu
return ServiceJeune.Categorie.LOGEMENT;
}
}

function mapServiceJeuneLink(mesure: StrapiMesuresJeunes.MesureJeune) {
const article = mesure.article && flatMapSingleRelation<StrapiArticle>(mesure.article);
if(!article && !mesure.url) {
return undefined;
}
return article ? `/articles/${article.slug}` : mesure.url;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,3 @@ export class StrapiServicesJeunesRepository implements ServicesJeunesRepository
}
}
}

0 comments on commit 2275d2d

Please sign in to comment.