Skip to content

Commit

Permalink
feat: homepage v2 (#948)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matteo-OCTO authored Feb 27, 2025
1 parent 2d23b78 commit 344e129
Show file tree
Hide file tree
Showing 21 changed files with 453 additions and 18 deletions.
4 changes: 4 additions & 0 deletions src/assets/theme/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,10 @@
background-color: var(--custom-bleu-light);
}

.background-bleu-975-25 {
background-color: var(--blue-france-975-75);
}

.background--green-light {
background-color: #dcef64;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/custom/Action/ActionQuizTerminee.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<h2 class="fr-mt-2w text--center">
<span class="text--bold">Bravo !</span><br />
<span class="text--bleu fr-text--lead text--normal">
Vous avez terminé le quiz "<span class="fr-text--bold" v-html="titre" />" !
Vous avez terminé le quiz <br />"<span class="fr-text--bold" v-html="titre" />" !
</span>
</h2>

Expand Down
2 changes: 1 addition & 1 deletion src/components/custom/KYC/KYCForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
class="fr-mt-1w"
/>

<button :title="wordingBouton" class="fr-btn fr-btn--lg fr-mt-3w" type="submit">
<button :title="wordingBouton" class="fr-btn fr-mt-3w" type="submit">
{{ wordingBouton }}
</button>
<button
Expand Down
41 changes: 41 additions & 0 deletions src/components/custom/Thematiques/CarteSyntheseThematique.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<section class="fr-col-12 fr-col-md-6 fr-col-lg-3">
<div class="shadow text--left fr-p-2w full-height flex flex-column flex-space-between background--white">
<div class="fr-mb-3v flex flex-column align-items--center flex-space-between full-height">
<div class="fr-mb-2w full-width">
<h3 class="fr-h4 fr-pb-2w fr-mb-2w fr-text--md" v-html="syntheseThematique.titreHTML" />
<ul>
<li
v-for="point in syntheseThematique.bulletPoints"
:key="point"
v-html="point"
class="fr-mb-1v fr-mx-1v"
/>
</ul>
</div>

<router-link
class="fr-btn"
:to="{ name: RouteThematiquesName.THEMATIQUE_V2, params: { id: syntheseThematique.id } }"
>
Découvrir
</router-link>
</div>
</div>
</section>
</template>

<script lang="ts" setup>
import { SyntheseThematiqueViewModel } from '@/domaines/thematiques/ports/syntheseThematique.presenter';
import { RouteThematiquesName } from '@/router/thematiques/routes';
defineProps<{
syntheseThematique: SyntheseThematiqueViewModel;
}>();
</script>

<style scoped>
h3 {
border-bottom: 1px solid #eaeaea;
}
</style>
48 changes: 48 additions & 0 deletions src/components/pages/PageParOuCommencer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<div class="fr-pt-4w fr-pb-8w fr-pb-1w background-bleu-975-25">
<div class="fr-container">
<div class="text--center">
<h2 class="fr-h2 fr-mb-2w">Par où souhaitez-vous commencer ?</h2>
<p v-if="syntheseThematiquesViewModel?.commune">
D’après nos calculs, à
<span class="text--bold text--bleu text--italic">{{ syntheseThematiquesViewModel.commune }}</span
>, voici ce que nous pouvons vous proposer :
</p>
</div>

<div v-if="syntheseThematiquesViewModel" class="fr-grid-row fr-grid-row--gutters">
<CarteSyntheseThematique
v-for="syntheseThematique in syntheseThematiquesViewModel.cartesThematiques"
:key="syntheseThematique.id"
:synthese-thematique="syntheseThematique"
/>
</div>
</div>
</div>
</template>

<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import CarteSyntheseThematique from '@/components/custom/Thematiques/CarteSyntheseThematique.vue';
import { SyntheseThematiquesPresenterImpl } from '@/domaines/thematiques/adapters/syntheseThematiques.presenter.impl';
import { ThematiquesRepositoryAxios } from '@/domaines/thematiques/adapters/thematiques.repository.axios';
import { SyntheseThematiquesViewModel } from '@/domaines/thematiques/ports/syntheseThematique.presenter';
import { RecupererSyntheseThematiques } from '@/domaines/thematiques/recupererSyntheseThematiques.usecase';
import { utilisateurStore } from '@/store/utilisateur';
const syntheseThematiquesViewModel = ref<SyntheseThematiquesViewModel>();
const usecase = new RecupererSyntheseThematiques(new ThematiquesRepositoryAxios());
onMounted(async () => {
await usecase.execute(
utilisateurStore().utilisateur.id,
new SyntheseThematiquesPresenterImpl(vm => (syntheseThematiquesViewModel.value = vm)),
);
});
</script>

<style scoped>
.background-bleu-975-25 {
background-color: var(--blue-france-975-75);
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class ScoreActionQuizPresenterImpl implements ScoreActionQuizPresenter {
couleurBackground,
couleurBordure,
},
encouragement: 'Bravo ! Nous espérons que ce quiz vous aura permis d’en apprendre d’avantage !',
encouragement: 'Nous espérons que ce quiz vous aura permis d’en apprendre d’avantage !',
});
}
}
7 changes: 6 additions & 1 deletion src/domaines/thematiques/MenuThematiques.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface Thematique {
url: string;
labelDansLeMenu: string;
imageUrl: string;
emoji?: string;
}

export enum ClefThematiqueAPI {
Expand Down Expand Up @@ -34,25 +35,29 @@ export class MenuThematiques {
labelDansLeMenu: 'Me nourrir',
imageUrl:
'https://res.cloudinary.com/dq023imd8/image/upload/t_media_lib_thumb/v1728466523/cuisine_da54797693.svg',
emoji: '🍛',
},
[ClefThematiqueAPI.transports]: {
clefTechniqueAPI: 'transport',
url: 'me-deplacer',
labelDansLeMenu: 'Me déplacer',
imageUrl:
'https://res.cloudinary.com/dq023imd8/image/upload/t_media_lib_thumb/v1728466903/Mobilite_df75aefd09.svg',
emoji: '🚲',
},
[ClefThematiqueAPI.consommation]: {
clefTechniqueAPI: 'consommation',
url: 'consommer',
labelDansLeMenu: 'Consommer',
labelDansLeMenu: 'Mes achats',
imageUrl: 'https://res.cloudinary.com/dq023imd8/image/upload/t_media_lib_thumb/v1728468852/conso_7522b1950d.svg',
emoji: '📺',
},
[ClefThematiqueAPI.logement]: {
clefTechniqueAPI: 'logement',
url: 'me-loger',
labelDansLeMenu: 'Me loger',
imageUrl: 'https://res.cloudinary.com/dq023imd8/image/upload/t_media_lib_thumb/v1728468978/maison_80242d91f3.svg',
emoji: '🧱',
},
[ClefThematiqueAPI.dechets]: {
clefTechniqueAPI: 'dechet',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { ClefThematiqueAPI, MenuThematiques } from '@/domaines/thematiques/MenuThematiques';
import {
SyntheseThematiquePresenter,
SyntheseThematiquesViewModel,
} from '@/domaines/thematiques/ports/syntheseThematique.presenter';
import { SyntheseThematiques } from '@/domaines/thematiques/ports/thematiques.repository';
import { gererPluriel } from '@/shell/pluriel';

type Bulletpoint = { nombre: number; phrase: { singulier: string; pluriel: string } };

export class SyntheseThematiquesPresenterImpl implements SyntheseThematiquePresenter {
constructor(private readonly _syntheseThematiquesViewModel: (viewModel: SyntheseThematiquesViewModel) => void) {}

async presente(synthese: SyntheseThematiques): Promise<void> {
this._syntheseThematiquesViewModel({
commune: synthese.commune,
cartesThematiques: synthese.listeThematiques.map(thematiqueData => {
const thematique = MenuThematiques.getThematiqueData(thematiqueData.thematique as ClefThematiqueAPI);

const points: Bulletpoint[] = [
this.creerPointSimulateurConditionnellement(
thematique.clefTechniqueAPI as ClefThematiqueAPI,
thematiqueData.nombreSimulateurs,
),
{
nombre: thematiqueData.nombreRecettes,
phrase: {
singulier: 'recette délicieuse, saine et de saison',
pluriel: 'recettes délicieuses, saines et de saison',
},
},
{
nombre: thematiqueData.nombreAides,
phrase: {
singulier: 'aide sur votre territoire',
pluriel: 'aides sur votre territoire',
},
},
{
nombre: thematiqueData.nombreActions,
phrase: {
singulier: "idée d'actions",
pluriel: "idées d'actions",
},
},
];

const bulletPoints: string[] = this.transformerEnHTML(points);
const titreHTML = `<span aria-hidden="true">${thematique.emoji}</span>&nbsp ${thematique.labelDansLeMenu}`;

return {
id: thematique.url,
titreHTML,
bulletPoints,
};
}),
});
}

private creerPointSimulateurConditionnellement(clefTechniqueAPI: ClefThematiqueAPI, nombreSimulateurs: number) {
if (clefTechniqueAPI === ClefThematiqueAPI.logement) {
return {
nombre: nombreSimulateurs,
phrase: { singulier: 'simulateur Mes Aides Rénov', pluriel: 'simulateurs Mes Aides Rénov' },
};
} else if (clefTechniqueAPI === ClefThematiqueAPI.transports) {
return {
nombre: nombreSimulateurs,
phrase: { singulier: 'simulateur vélo et voiture', pluriel: 'simulateurs vélo et voiture' },
};
} else {
return {
nombre: nombreSimulateurs,
phrase: { singulier: 'simulateur', pluriel: 'simulateurs' },
};
}
}

private transformerEnHTML(points: Bulletpoint[]): string[] {
return points
.filter(({ nombre }) => nombre !== 0 && nombre !== undefined)
.map(({ nombre, phrase }): string => {
return `<span class="text--bold">${nombre}</span> ${gererPluriel(nombre, phrase.singulier, phrase.pluriel)}`;
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { AxiosFactory, intercept401 } from '@/axios.factory';
import { ClefThematiqueAPI } from '@/domaines/thematiques/MenuThematiques';
import { ThematiquesRepository } from '@/domaines/thematiques/ports/thematiques.repository';
import { SyntheseThematiques, ThematiquesRepository } from '@/domaines/thematiques/ports/thematiques.repository';

interface SyntheseThematiquesApiModel {
nom_commune: string;
liste_thematiques: {
thematique: string;
nombre_recettes: number;
nombre_actions: number;
nombre_aides: number;
nombre_simulateurs: number;
}[];
}

export class ThematiquesRepositoryAxios implements ThematiquesRepository {
@intercept401()
Expand All @@ -14,4 +25,20 @@ export class ThematiquesRepositoryAxios implements ThematiquesRepository {
const axios = AxiosFactory.getAxios();
await axios.post(`/utilisateurs/${idUtilisateur}/thematiques/${clefThematiqueApi}/reset_personnalisation`);
}

async recupererSyntheseThematiques(utilisateurId: string): Promise<SyntheseThematiques> {
const axiosInstance = AxiosFactory.getAxios();
const response = await axiosInstance.get<SyntheseThematiquesApiModel>(`/utilisateurs/${utilisateurId}/thematiques`);

return {
commune: response.data.nom_commune,
listeThematiques: response.data.liste_thematiques.map(thematique => ({
thematique: thematique.thematique,
nombreRecettes: thematique.nombre_recettes,
nombreActions: thematique.nombre_actions,
nombreAides: thematique.nombre_aides,
nombreSimulateurs: thematique.nombre_simulateurs,
})),
};
}
}
16 changes: 16 additions & 0 deletions src/domaines/thematiques/ports/syntheseThematique.presenter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { SyntheseThematiques } from '@/domaines/thematiques/ports/thematiques.repository';

export interface SyntheseThematiqueViewModel {
id: string;
titreHTML: string;
bulletPoints: string[];
}

export interface SyntheseThematiquesViewModel {
commune: string;
cartesThematiques: SyntheseThematiqueViewModel[];
}

export interface SyntheseThematiquePresenter {
presente(synthese: SyntheseThematiques): Promise<void>;
}
11 changes: 11 additions & 0 deletions src/domaines/thematiques/ports/thematiques.repository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { ClefThematiqueAPI } from '@/domaines/thematiques/MenuThematiques';
export interface SyntheseThematiques {
commune: string;
listeThematiques: {
thematique: string;
nombreRecettes: number;
nombreActions: number;
nombreAides: number;
nombreSimulateurs: number;
}[];
}

export interface ThematiquesRepository {
terminerPersonnalisation(idUtilisateur: string, clefThematiqueApi: ClefThematiqueAPI): Promise<void>;
resetPersonnalisation(idUtilisateur: string, clefThematiqueApi: ClefThematiqueAPI): Promise<void>;
recupererSyntheseThematiques(utilisateurId: string): Promise<SyntheseThematiques>;
}
11 changes: 11 additions & 0 deletions src/domaines/thematiques/recupererSyntheseThematiques.usecase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SyntheseThematiquePresenter } from '@/domaines/thematiques/ports/syntheseThematique.presenter';
import { ThematiquesRepository } from '@/domaines/thematiques/ports/thematiques.repository';

export class RecupererSyntheseThematiques {
constructor(private readonly repository: ThematiquesRepository) {}

async execute(idUtilisateur: string, presenter: SyntheseThematiquePresenter) {
const synthese = await this.repository.recupererSyntheseThematiques(idUtilisateur);
await presenter.presente(synthese);
}
}
19 changes: 19 additions & 0 deletions src/router/accueil/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { RouteRecordRaw } from 'vue-router';
const PageParOuCommencer = () => import('@/components/pages/PageParOuCommencer.vue');

export enum RouteAccueilName {
COMMENCER = 'agir_v2',
}

const accueilRoutes: RouteRecordRaw[] = [
{
path: `/v2/agir`,
name: RouteAccueilName.COMMENCER,
component: PageParOuCommencer,
meta: {
title: 'Thématique',
},
},
];

export default accueilRoutes;
2 changes: 2 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import accueilRoutes from '@/router/accueil/routes';
import actionsRoutes from '@/router/actions/routes';
import aidesRoutes from '@/router/aides/routes';
import articlesRoutes from '@/router/articles/routes';
Expand Down Expand Up @@ -57,6 +58,7 @@ const routes: RouteRecordRaw[] = [
...examenRoutes,
...collectiviteRoutes,
...actionsRoutes,
...accueilRoutes,
{
path: '/',
name: RouteCommuneName.ACCUEIL,
Expand Down
Loading

0 comments on commit 344e129

Please sign in to comment.