فهرست منبع

lint pages and components

Olivier Massot 1 سال پیش
والد
کامیت
32889c945b
100فایلهای تغییر یافته به همراه1713 افزوده شده و 2073 حذف شده
  1. 50 42
      .eslintrc.cjs
  2. 8 12
      app.vue
  3. 33 32
      components/About/Chronologie.vue
  4. 40 36
      components/About/Equipe.vue
  5. 8 11
      components/About/FAQ.vue
  6. 28 31
      components/About/Logiciels.vue
  7. 35 39
      components/About/Presentation.vue
  8. 5 15
      components/About/Valeurs.vue
  9. 25 24
      components/Common/ActionMenu.vue
  10. 11 26
      components/Common/Agenda.vue
  11. 11 9
      components/Common/AgendaLink.vue
  12. 8 15
      components/Common/Avantages.vue
  13. 20 16
      components/Common/Banner.vue
  14. 6 10
      components/Common/Card/Benefit.vue
  15. 5 5
      components/Common/Card/Stat.vue
  16. 12 21
      components/Common/Carousel/Clients.vue
  17. 13 26
      components/Common/Carousel/Fonctionnalite.vue
  18. 19 32
      components/Common/Contact.vue
  19. 8 11
      components/Common/ContainerVideo.vue
  20. 14 17
      components/Common/MenuScroll.vue
  21. 31 29
      components/Common/Meta.vue
  22. 20 33
      components/Common/Presentation.vue
  23. 55 67
      components/Common/ReviewSection.vue
  24. 46 46
      components/Common/Share.vue
  25. 38 48
      components/Common/Table/Comparatif.vue
  26. 36 46
      components/Contact/AddressSection.vue
  27. 86 80
      components/Contact/Form.vue
  28. 31 40
      components/Contact/Map.vue
  29. 8 24
      components/Formation/Catalogue.vue
  30. 1 3
      components/Formation/Certification.vue
  31. 1 3
      components/Formation/OPCA.vue
  32. 1 3
      components/Formation/Participation.vue
  33. 5 5
      components/Formation/Presentation.vue
  34. 6 13
      components/Home/Besoin.vue
  35. 24 26
      components/Home/Caroussel.vue
  36. 13 14
      components/Home/EventAgenda.vue
  37. 7 21
      components/Home/Help.vue
  38. 27 32
      components/Home/Promotion.vue
  39. 40 49
      components/Home/Reviews.vue
  40. 11 22
      components/Home/Solution.vue
  41. 66 67
      components/JoinUs/Form.vue
  42. 16 30
      components/JoinUs/MissionDetail.vue
  43. 35 54
      components/JoinUs/Missions.vue
  44. 33 37
      components/Layout/AnchoredSection.vue
  45. 14 13
      components/Layout/Captcha.vue
  46. 8 17
      components/Layout/FAQ.vue
  47. 42 67
      components/Layout/Footer/Footer.vue
  48. 10 4
      components/Layout/Footer/Prefooter.vue
  49. 23 25
      components/Layout/Footer/Solutions.vue
  50. 8 11
      components/Layout/Navigation.vue
  51. 13 18
      components/Layout/Navigation/Lg.vue
  52. 34 38
      components/Layout/Navigation/Md.vue
  53. 13 16
      components/Layout/Navigation/Topbar.vue
  54. 8 9
      components/Layout/Pagination.vue
  55. 2 6
      components/Layout/UI/SectionTitle.vue
  56. 2 8
      components/Layout/UI/SubTitle.vue
  57. 13 14
      components/Layout/UI/Title.vue
  58. 6 5
      components/Layout/UI/TitlePage.vue
  59. 9 12
      components/Logiciels/Artist/Abonnement.vue
  60. 8 12
      components/Logiciels/Artist/Abonnement/ToSubscribe.vue
  61. 1 0
      components/Logiciels/Artist/Avantages.vue
  62. 4 9
      components/Logiciels/Artist/Comparatif.vue
  63. 3 8
      components/Logiciels/Artist/Fonctionnalites.vue
  64. 3 5
      components/Logiciels/Artist/Formations.vue
  65. 4 4
      components/Logiciels/Artist/Presentation.vue
  66. 40 30
      components/Logiciels/Artist/SomeNumbers.vue
  67. 16 13
      components/Logiciels/Manager/Avantages.vue
  68. 4 6
      components/Logiciels/Manager/Fonctionnalites.vue
  69. 3 6
      components/Logiciels/Manager/Formation.vue
  70. 3 4
      components/Logiciels/Manager/Network.vue
  71. 1 1
      components/Logiciels/Manager/Presentation.vue
  72. 0 2
      components/Logiciels/Manager/Reviews.vue
  73. 6 22
      components/Logiciels/Manager/SomeNumbers.vue
  74. 19 13
      components/Logiciels/School/Avantages.vue
  75. 4 7
      components/Logiciels/School/Comparatif.vue
  76. 5 10
      components/Logiciels/School/Fonctionnalites.vue
  77. 9 7
      components/Logiciels/School/Formations.vue
  78. 2 2
      components/Logiciels/School/Presentation.vue
  79. 43 49
      components/Logiciels/School/SomeNumbers.vue
  80. 2 3
      components/Logiciels/Title.vue
  81. 15 26
      components/News/Details.vue
  82. 19 21
      components/News/List.vue
  83. 23 57
      components/Webinaire/Catalogue.vue
  84. 33 40
      components/Webinaire/FAQ.vue
  85. 44 27
      composables/data/useEntityFetch.ts
  86. 8 8
      composables/data/useEntityManager.ts
  87. 10 13
      composables/data/useEnumFetch.ts
  88. 9 9
      composables/data/useEnumManager.ts
  89. 50 47
      composables/data/useMaestroRequestService.ts
  90. 4 5
      composables/useClientDevice.ts
  91. 2 3
      models/ApiModel.ts
  92. 11 10
      models/ApiResource.ts
  93. 16 16
      models/Maestro/ContactRequest.ts
  94. 10 10
      models/Maestro/JobApplication.ts
  95. 20 20
      models/Maestro/JobPosting.ts
  96. 23 23
      models/Maestro/News.ts
  97. 4 4
      models/Maestro/Tag.ts
  98. 6 8
      models/decorators.ts
  99. 5 5
      models/models.ts
  100. 20 23
      nuxt.config.ts

+ 50 - 42
.eslintrc.cjs

@@ -1,43 +1,51 @@
-root: true,
-env: {
-  browser: true,
-  node: true,
-},
-parser: 'vue-eslint-parser',
-parserOptions: {
-  ecmaVersion: 2020,
-  parser: '@typescript-eslint/parser',
-  sourceType: 'module',
-  tsconfigRootDir: __dirname,
-},
-extends: [
-  '@nuxtjs/eslint-config-typescript',
-  'plugin:nuxt/recommended',
-  'eslint:recommended',
-  'plugin:@typescript-eslint/recommended',
-  'plugin:vue/vue3-recommended',
-  'plugin:prettier/recommended',
-],
-ignorePatterns: ['.nuxt', 'coverage/*', 'vendor/*', 'dist/*'],
-plugins: ['vue', '@typescript-eslint'],
-  // add your custom rules here
-rules: {
-  'no-console': 0, // on autorise les appels à la console (puisque ceux-ci seront de toute façon nettoyés à la compilation)
-  'vue/valid-v-slot': [
-    'error',
-    {
-      allowModifiers: true,
-    },
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    node: true,
+  },
+  parser: 'vue-eslint-parser',
+  parserOptions: {
+    ecmaVersion: 2020,
+    parser: '@typescript-eslint/parser',
+    sourceType: 'module',
+    tsconfigRootDir: __dirname,
+  },
+  extends: [
+    '@nuxtjs/eslint-config-typescript',
+    'plugin:nuxt/recommended',
+    'eslint:recommended',
+    'plugin:@typescript-eslint/recommended',
+    'plugin:vue/vue3-recommended',
+    'plugin:prettier/recommended',
   ],
-},
-globals: {
-  useRuntimeConfig: 'readonly',
-  navigateTo: 'readonly',
-  computed: 'readonly',
-  ref: 'readonly',
-  definePageMeta: 'readonly',
-  useRouter: 'readonly',
-  useRoute: 'readonly',
-  useI18n: 'readonly',
-  onMounted: 'readonly',
-},
+  ignorePatterns: ['.nuxt', 'coverage/*', 'vendor/*', 'dist/*'],
+  plugins: ['vue', '@typescript-eslint'],
+  // add your custom rules here
+  rules: {
+    'no-console': 0, // on autorise les appels à la console (puisque ceux-ci seront de toute façon nettoyés à la compilation)
+    'vue/valid-v-slot': [
+      'error',
+      {
+        allowModifiers: true,
+      },
+    ],
+    'vue/multi-word-component-names': 0,
+    'vue/no-v-html': 0,
+    '@typescript-eslint/ban-ts-comment': 0,
+  },
+  globals: {
+    useRuntimeConfig: 'readonly',
+    navigateTo: 'readonly',
+    computed: 'readonly',
+    ref: 'readonly',
+    definePageMeta: 'readonly',
+    useRouter: 'readonly',
+    useRoute: 'readonly',
+    useI18n: 'readonly',
+    onMounted: 'readonly',
+    useLayoutStore: 'readonly',
+    useClientDevice: 'readonly',
+    useSeoMeta: 'readonly',
+  },
+}

+ 8 - 12
app.vue

@@ -1,21 +1,17 @@
 <template>
-  <div id="top" />
+  <div>
+    <div id="top" />
 
-  <LayoutNavigation />
+    <LayoutNavigation />
 
-  <nuxt-page />
+    <nuxt-page />
 
-  <LayoutFooter />
+    <LayoutFooter />
+  </div>
 </template>
 
 <script setup lang="ts">
+const layoutStore = useLayoutStore();
 
-import { useDisplay } from "vuetify";
-
-const { mdAndDown } = useDisplay()
-
-const layoutStore = useLayoutStore()
-
-layoutStore.resetAnchoredSections()
-
+layoutStore.resetAnchoredSections();
 </script>

+ 33 - 32
components/About/Chronologie.vue

@@ -1,7 +1,7 @@
 <template>
   <AnchoredSection id="history">
     <LayoutContainer class="alt-theme">
-      <v-container >
+      <v-container>
         <v-row class="mb-6 mt-6 center-90">
           <v-col cols="6">
             <LayoutUISubTitle>
@@ -11,14 +11,8 @@
 
           <v-col cols="6">
             <div class="carousel-controls">
-              <v-btn
-                icon="fas fa-chevron-left"
-                @click="goPrevious"
-              />
-              <v-btn
-                icon="fas fa-chevron-right"
-                @click="goNext"
-              />
+              <v-btn icon="fas fa-chevron-left" @click="goPrevious" />
+              <v-btn icon="fas fa-chevron-right" @click="goNext" />
             </div>
           </v-col>
         </v-row>
@@ -27,15 +21,15 @@
       <v-row class="mb-12 center-90">
         <v-col cols="12">
           <Carousel
-            v-model="activeSlide"
             ref="carousel"
+            v-model="activeSlide"
             :items-to-show="lgAndUp ? 2 : 1"
             :items-to-scroll="1"
           >
             <Slide
               v-for="(slide, index) in slides"
               :key="slide.title"
-              :class="{'active': index === activeSlide}"
+              :class="{ active: index === activeSlide }"
             >
               <div class="card">
                 <div class="image-container">
@@ -49,18 +43,12 @@
 
                   <h4 v-html="slide.title" />
 
-                  <p
-                    v-html="slide.description"
-                    class="mb-6"
-                  />
+                  <p class="mb-6" v-html="slide.description" />
                 </div>
               </div>
 
               <div class="timeline-container">
-                <div
-                  v-if="slide.year"
-                  class="timeline"
-                >
+                <div v-if="slide.year" class="timeline">
                   <div
                     class="timeline-point"
                     :style="{
@@ -85,12 +73,13 @@
 import { useDisplay } from "vuetify";
 import { Carousel, Slide } from "vue3-carousel";
 import "vue3-carousel/dist/carousel.css";
+import type { Ref } from "vue";
 import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import type { ChronologyItem } from "~/types/interface";
 
 const activeSlide: Ref<number> = ref(0);
 
-const { smAndDown, lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay();
 
 const carousel: Ref<typeof Carousel | null> = ref(null);
 
@@ -98,7 +87,7 @@ const goPrevious = () => carousel.value!.prev();
 const goNext = () => carousel.value!.next();
 
 const computePositionOnTimeline = (year: string) => {
-  const intYear = parseInt(year)
+  const intYear = parseInt(year);
 
   if (!intYear || isNaN(intYear)) {
     return 0;
@@ -114,70 +103,80 @@ const slides: Array<ChronologyItem> = [
     title: "L'origine d'Opentalent",
     description:
       "Sous une pleine lune inspirante, Guillaume alors imagine un outil collaboratif en ligne révolutionnaire pour le secteur culturel. Cette idée germe alors qu'il est président d'orchestre et membre du CA d'une école de musique, marquant le début du concept Opentalent.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/1-Origine_Opentalent-outil_collaboratif_pour_la_culture.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/1-Origine_Opentalent-outil_collaboratif_pour_la_culture.jpg",
   },
   {
     year: "2006",
     title: "Développement et partenariat stratégique",
     description:
       "Michel, passionné par l'innovation technologique, rejoint Guillaume. Ensemble, ils développent Opentalent avec le soutien de la Fédération de Haute-Savoie. Leur travail acharné bénévole durant 2 ans donne naissance à un logiciel SAS avant-gardiste, une première dans l'univers des structures culturelles.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/2-Developpement_et_partenariat_strategique_Opentalent.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/2-Developpement_et_partenariat_strategique_Opentalent.jpg",
   },
   {
     year: "2008",
     title: "Naissance de l'entreprise 2iOpenservice",
     description:
       "La Fédération de Haute-Savoie, séduite par le projet, invite à collaborer avec la CMF, élargissant l'impact d'Opentalent. 2IOpenservice est alors officiellement créée, marquant une nouvelle ère dans la gestion culturelle digitale.  ",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/3-Naissance_de_l_entreprise_2IOpenservice-Opentalent.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/3-Naissance_de_l_entreprise_2IOpenservice-Opentalent.jpg",
   },
   {
     year: "2009",
     title: "MusAssos - la réponse aux besoins pour les petites structures",
     description:
       "Pour répondre aux besoins spécifiques des écoles affiliées à la CMF, 2iopenservice lance MusAssos, une solution adapté aux petites et moyennes structures, facilitant la gestion et la promotion culturelle.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/4-Logiciel_MusAssos-pour_les_petites_et_moyennes_structures.png",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/4-Logiciel_MusAssos-pour_les_petites_et_moyennes_structures.png",
   },
   {
     year: "2010",
     title: "CMF Réseau <br> l'innovation communautaire",
     description:
       "La CMF adopte AdminFédé pour connecter ses adhérents, et AdminAsso devient accessible à tous, démocratisant l'accès aux outils de gestion artistique.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/5-Confédération_Musicale_de_France-CMF_Réseau-AdminFédé_AdminAsso.png",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/5-Confédération_Musicale_de_France-CMF_Réseau-AdminFédé_AdminAsso.png",
   },
   {
     year: "2014",
     title: "Vers une Culture Multidisciplinaire avec FFEC",
     description:
       "Le logiciel d'Opentalent s'étend au-delà de l'enseignement artistique, embrassant l'art, la musique, le théâtre, la danse et le cirque. En partenariat avec la FFEC, Reso Cirque voit le jour, intégrant notre solution au cœur de la pratique circassienne.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/6-FFEC_Reso_Cirque-Ouverture_vers_une_culture_multidisciplinaire.png",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/6-FFEC_Reso_Cirque-Ouverture_vers_une_culture_multidisciplinaire.png",
   },
   {
     year: "2015",
     title: "Refonte Technologique",
     description:
       "Nous modernisons notre gamme de logiciels pour la rendre plus sécurisée et compatible avec divers supports, marquant une étape clé dans notre évolution technologique.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/7-Refonte_technologique_des_logiciels_Opentalent_securitee_modernitee_intuitivitee.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/7-Refonte_technologique_des_logiciels_Opentalent_securitee_modernitee_intuitivitee.jpg",
   },
   {
     year: "2019",
     title: "Nouvelle Génération Opentalent",
     description:
       "Avec des fonctionnalités améliorées et une interface utilisateur intuitive, la nouvelle génération d'Opentalent se démarque, prouvant notre engagement envers l'excellence et l'accessibilité.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/8-Nouvelle_generation_Opentalent_moderne_securisee_experience_optimisee.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/8-Nouvelle_generation_Opentalent_moderne_securisee_experience_optimisee.jpg",
   },
   {
     year: "2024",
     title: "Relooking du site Opentalent",
     description:
       "Le site Opentalent se réinvente, reflétant notre évolution et notre capacité à nous adapter aux tendances actuelles, tout en conservant notre essence originelle.",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/9-Relooking_du_site_internet_Opentalent_agenda_et_logiciels_culturels.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/9-Relooking_du_site_internet_Opentalent_agenda_et_logiciels_culturels.jpg",
   },
   {
     year: "",
     title: "LE FUTUR AVEC VOUS... ",
     description:
       "Opentalent, plus qu'une gamme de logiciels ou un agenda culturel, c'est une aventure collective. Ensemble, poursuivons cette quête d'innovation et de partage culturel. <br> Rejoignez-nous dans cette aventure passionnante et façonnons l'avenir de la culture. <br> <strong> Opentalent, c'est vous ! </strong>",
-    imageUrl: "/images/pages/qui-sommes-nous/chronologie/10-Opentalent_ensemble_construisons_notre_futur.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/chronologie/10-Opentalent_ensemble_construisons_notre_futur.jpg",
   },
 ];
 </script>
@@ -224,7 +223,9 @@ const slides: Array<ChronologyItem> = [
   .carousel__slide.active {
     opacity: 1;
     transform: scale(1.1);
-    transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
+    transition:
+      transform 0.3s ease-in-out,
+      opacity 0.3s ease-in-out;
   }
 
   .card {

+ 40 - 36
components/About/Equipe.vue

@@ -2,33 +2,29 @@
   <AnchoredSection id="team">
     <LayoutContainer class="mb-12">
       <v-row class="mt-12 center-90">
-        <LayoutUISubTitle>
-          Notre équipe
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Notre équipe </LayoutUISubTitle>
       </v-row>
 
       <v-row class="center-90">
-        <LayoutUITitle>
-          Une équipe spécialisée et passionnée
-        </LayoutUITitle>
+        <LayoutUITitle> Une équipe spécialisée et passionnée </LayoutUITitle>
 
         <span class="details ml-4 mt-6 mb-12">
-          Chez Opentalent, on recherche des compétences mais surtout des hommes et
-          des femmes qui souhaitent s'engager dans un projet porteur de sens.
+          Chez Opentalent, on recherche des compétences mais surtout des hommes
+          et des femmes qui souhaitent s'engager dans un projet porteur de sens.
         </span>
       </v-row>
 
       <v-row class="center-90">
         <v-col
-          cols="12" sm="6" md="4" lg="3"
           v-for="associate in associates"
           :key="associate.name"
+          cols="12"
+          sm="6"
+          md="4"
+          lg="3"
         >
           <v-card>
-            <v-img
-              :src="associate.photo"
-              :height="370"
-            />
+            <v-img :src="associate.photo" :height="370" />
 
             <v-card-title class="name">
               {{ associate.name }}
@@ -43,15 +39,15 @@
 
       <v-row class="center-90">
         <v-col
-          cols="12" sm="6" md="4" lg="3"
           v-for="employee in employees"
           :key="employee.name"
+          cols="12"
+          sm="6"
+          md="4"
+          lg="3"
         >
           <v-card>
-            <v-img
-              :src="employee.photo"
-              :height="370"
-            />
+            <v-img :src="employee.photo" :height="370" />
 
             <v-card-title class="name">
               {{ employee.name }}
@@ -75,14 +71,16 @@ const associates: Array<SocietyMember> = [
   {
     name: "Guillaume",
     position: "Co-fondateur / Gérant",
-    photo: "/images/pages/qui-sommes-nous/equipe/Guillaume_CORCOBA-co-fondateur_et_Gerant.png",
-    alt: "Avatar d’un homme avec les cheveux poivre et sel court portant un polo bordeaux et un jean"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Guillaume_CORCOBA-co-fondateur_et_Gerant.png",
+    alt: "Avatar d’un homme avec les cheveux poivre et sel court portant un polo bordeaux et un jean",
   },
   {
     name: "Michel",
     position: "Co-fondateur / Product Owner",
-    photo: "/images/pages/qui-sommes-nous/equipe/Michel_PERNET-SOLLIET-Co-fondateur_et_Product_Owner.png",
-    alt: "Avatar d’un homme avec les cheveux bruns mi-long portant un pull jaune et un pantalon noir"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Michel_PERNET-SOLLIET-Co-fondateur_et_Product_Owner.png",
+    alt: "Avatar d’un homme avec les cheveux bruns mi-long portant un pull jaune et un pantalon noir",
   },
 ];
 
@@ -90,50 +88,56 @@ const employees: Array<SocietyMember> = [
   {
     name: "Johan",
     position: "Formation et Assistance",
-    photo: "/images/pages/qui-sommes-nous/equipe/Johan_HAUDIQUET-Formateur_et_Assistance.png",
-    alt: "Avatar d’un homme avec les cheveux bruns court portant un sweat noir et un pantalon beige"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Johan_HAUDIQUET-Formateur_et_Assistance.png",
+    alt: "Avatar d’un homme avec les cheveux bruns court portant un sweat noir et un pantalon beige",
   },
   {
     name: "Nathalie",
     position: "Développement Commercial",
-    photo: "/images/pages/qui-sommes-nous/equipe/Nathalie_CHEVALON-Chargee_de_developpement_commercial.png",
-    alt: "Avatar d’une femme avec les cheveux bruns mi-long et ondulée portant une chemise noire/blanche et un jean bleu foncé"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Nathalie_CHEVALON-Chargee_de_developpement_commercial.png",
+    alt: "Avatar d’une femme avec les cheveux bruns mi-long et ondulée portant une chemise noire/blanche et un jean bleu foncé",
   },
   {
     name: "Laetitia",
     position: "Marketing & Communication",
-    photo: "/images/pages/qui-sommes-nous/equipe/Laetitia_SIFFOINTE-Chargee_de_Marketing_et_Communication.png",
-    alt: "Avatar d’une femme avec les cheveux blonds long et ondulée portant un pull gris et un jean noir"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Laetitia_SIFFOINTE-Chargee_de_Marketing_et_Communication.png",
+    alt: "Avatar d’une femme avec les cheveux blonds long et ondulée portant un pull gris et un jean noir",
   },
   {
     name: "Florence",
     position: "Assistante administrative et commerciale",
     photo: "/images/pages/qui-sommes-nous/equipe/Florence_JOANNIDIS-ADV.png",
-    alt: "Avatar d’une femme avec des lunettes, les cheveux bruns long et attaché portant un pull bleu et un jean bleu foncé"
+    alt: "Avatar d’une femme avec des lunettes, les cheveux bruns long et attaché portant un pull bleu et un jean bleu foncé",
   },
   {
     name: "Vincent",
     position: "Lead developer",
     photo: "/images/pages/qui-sommes-nous/equipe/Vincent_GUFFON-Lead_dev.png",
-    alt: "Avatar d’un homme avec les cheveux bruns court avec une barbe rousse portant un tee-shirt noir et un jean bleu"
+    alt: "Avatar d’un homme avec les cheveux bruns court avec une barbe rousse portant un tee-shirt noir et un jean bleu",
   },
   {
     name: "Olivier",
     position: "Développeur",
-    photo: "/images/pages/qui-sommes-nous/equipe/Olivier_MASSOT-Developpeur.png",
-    alt: "Avatar d’un homme avec les cheveux blonds mi-long et un bouc blond portant un gilet gris et un jean noir"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Olivier_MASSOT-Developpeur.png",
+    alt: "Avatar d’un homme avec les cheveux blonds mi-long et un bouc blond portant un gilet gris et un jean noir",
   },
   {
     name: "Sébastien",
     position: "Développeur",
-    photo: "/images/pages/qui-sommes-nous/equipe/Sebastien_FAVRE-BONTE_Developpeur.png",
-    alt: "Avatar d’un homme avec des lunettes, les cheveux bruns court portant un pull bleu et un jean bleu foncé"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Sebastien_FAVRE-BONTE_Developpeur.png",
+    alt: "Avatar d’un homme avec des lunettes, les cheveux bruns court portant un pull bleu et un jean bleu foncé",
   },
   {
     name: "Maha",
     position: "Développeuse",
-    photo: "/images/pages/qui-sommes-nous/equipe/Maha_BOUCHIBA-Developpeuse.png",
-    alt: "Avatar d’une femme portant un turban sur les cheveux, haut beige et blanc et un jean bleu foncé"
+    photo:
+      "/images/pages/qui-sommes-nous/equipe/Maha_BOUCHIBA-Developpeuse.png",
+    alt: "Avatar d’une femme portant un turban sur les cheveux, haut beige et blanc et un jean bleu foncé",
   },
 ];
 </script>

+ 8 - 11
components/About/FAQ.vue

@@ -3,24 +3,21 @@
     <LayoutContainer>
       <v-row no-gutters class="alt-theme">
         <v-col cols="12" md="6">
-           <v-img
-             src="/images/pages/qui-sommes-nous/contact/Opentalent_a_votre_service.png"
-             alt="Un homme et une femme tous les deux le sourire aux lèvres se serre la main"
-             cover
-           />
+          <v-img
+            src="/images/pages/qui-sommes-nous/contact/Opentalent_a_votre_service.png"
+            alt="Un homme et une femme tous les deux le sourire aux lèvres se serre la main"
+            cover
+          />
         </v-col>
 
         <v-col cols="12" md="6">
           <div class="d-flex flex-column">
             <h4>
-              Chez Opentalent, nous avons à coeur de répondre à vos interrogations
-              et de vous apporter la solution faite pour vous.
+              Chez Opentalent, nous avons à coeur de répondre à vos
+              interrogations et de vous apporter la solution faite pour vous.
             </h4>
 
-            <v-btn
-              to="/nous-contacter"
-              class="inv-theme mt-12"
-            >
+            <v-btn to="/nous-contacter" class="inv-theme mt-12">
               Nous contacter
             </v-btn>
           </div>

+ 28 - 31
components/About/Logiciels.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="softwares">
     <LayoutContainer>
       <v-row class="mb-6 center-90">
-        <LayoutUISubTitle>
-          Nos logiciels
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Nos logiciels </LayoutUISubTitle>
 
         <LayoutUITitle>
           Nos logiciels dédiés à chaque acteur culturel
@@ -20,10 +18,7 @@
           </p>
 
           <ul class="ml-4">
-            <li
-              v-for="(feature, index) in features"
-              :key="index"
-            >
+            <li v-for="(feature, index) in features" :key="index">
               {{ feature }}
             </li>
           </ul>
@@ -34,29 +29,18 @@
         </v-col>
 
         <v-col
-          cols="12"
-          md="3"
           v-for="(item, index) in items"
           :key="index"
+          cols="12"
+          md="3"
           :class="item.class"
         >
           <nuxt-link :to="item.link" class="software-link">
-            <v-img
-              :src="item.imageUrl"
-              cover
-              class="container-image"
-            >
+            <v-img :src="item.imageUrl" cover class="container-image">
               <footer>
-                <v-img
-                  :src="item.logoUrl"
-                  :alt="item.logoAlt"
-                  class="logo"
-                />
-
-                <v-btn
+                <v-img :src="item.logoUrl" :alt="item.logoAlt" class="logo" />
 
-                  class="plus-button"
-                >
+                <v-btn class="plus-button">
                   <v-icon>fas fa-plus</v-icon>
                 </v-btn>
               </footer>
@@ -81,28 +65,41 @@ const features: Array<string> = [
   "Et bien plus encore...",
 ];
 
-const items: Array<{imageUrl: string, alt: string, logoUrl: string, logoAlt: string, class: string, link: string}> = [
+const items: Array<{
+  imageUrl: string;
+  alt: string;
+  logoUrl: string;
+  logoAlt: string;
+  class: string;
+  link: string;
+}> = [
   {
-    imageUrl: "/images/pages/qui-sommes-nous/logiciels/Opentalent_Artist_pour_les_structures_culturelles.jpg",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/logiciels/Opentalent_Artist_pour_les_structures_culturelles.jpg",
     alt: "Partition tenue par une femme dans une chorale",
     logoUrl: "/images/logos/opentalent/Logo_Opentalent_Artist-blanc.png",
-    logoAlt: "Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes",
+    logoAlt:
+      "Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes",
     class: "artist",
     link: "/opentalent_artist",
   },
   {
-    imageUrl: "/images/pages/qui-sommes-nous/logiciels/Opentalent_School_pour_les_etablissements_d_enseignement_artistique.JPG",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/logiciels/Opentalent_School_pour_les_etablissements_d_enseignement_artistique.JPG",
     alt: "Deux jeunes filles jouant du violon",
     logoUrl: "/images/logos/opentalent/Logo_Opentalent_School-blanc.png",
-    logoAlt: "Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique",
+    logoAlt:
+      "Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique",
     class: "school",
     link: "/opentalent_school",
   },
   {
-    imageUrl: "/images/pages/qui-sommes-nous/logiciels/Opentalent_Manager_pour_les_reseaux_culturels.png",
+    imageUrl:
+      "/images/pages/qui-sommes-nous/logiciels/Opentalent_Manager_pour_les_reseaux_culturels.png",
     alt: "Carte de réseau des structures de la confédération musicale de France",
     logoUrl: "/images/logos/opentalent/Logo_Opentalent_Manager-blanc.png",
-    logoAlt: "Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités",
+    logoAlt:
+      "Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités",
     class: "manager",
     link: "/opentalent_manager",
   },
@@ -140,7 +137,7 @@ li:before {
 }
 
 .software-link {
-  >.container-image:hover {
+  > .container-image:hover {
     transform: scale(1.05);
   }
 }

+ 35 - 39
components/About/Presentation.vue

@@ -3,18 +3,16 @@
     <LayoutContainer>
       <v-row class="my-12 center-90">
         <v-col cols="12">
-          <LayoutUISubTitle>
-            Qui sommes-nous ?
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> Qui sommes-nous ? </LayoutUISubTitle>
         </v-col>
       </v-row>
 
       <v-row class="my-12 center-90">
         <v-col cols="12">
           <div class="italic-title">
-            “Imaginé par des musiciens pour des musiciens, Opentalent se veut être
-            la référence pour la gestion et la promotion du spectacle vivant sur
-            les territoires.”
+            “Imaginé par des musiciens pour des musiciens, Opentalent se veut
+            être la référence pour la gestion et la promotion du spectacle
+            vivant sur les territoires.”
           </div>
         </v-col>
       </v-row>
@@ -29,42 +27,39 @@
         </v-col>
 
         <v-col cols="12" md="6">
-          <h3>
-            Une histoire de passionnés
-          </h3>
+          <h3>Une histoire de passionnés</h3>
 
           <p class="mb-8">
-            En 2005, Guillaume CORCOBA, musicien depuis toujours et à ce moment
-            président d'un orchestre d'harmonie, mais également membre du conseil
-            d'administration de sa fédération, réfléchit à un outil pour
-            centraliser les informations de sa structure, mais également au niveau
-            fédéral. Il souhaite simplifier la gestion des structures culturelles
-            et en faire la promotion, car pour lui, le milieu culturel est
-            indispensable. Il est rapidement rejoint par Michel   PERNET-SOLLIET,
-            lui aussi musicien, et ils montent ensemble Openassos, qui deviendra
-            quelques années plus tard, Opentalent. Opentalent c'est un ensemble de
-            3 logiciels spécialement dédiés à la culture et un agenda culturel
-            pour en faire la promotion.
+            En 2005, Guillaume CORCOBA, musicien depuis toujours et à ce moment
+            président d'un orchestre d'harmonie, mais également membre du
+            conseil d'administration de sa fédération, réfléchit à un outil pour
+            centraliser les informations de sa structure, mais également au
+            niveau fédéral. Il souhaite simplifier la gestion des structures
+            culturelles et en faire la promotion, car pour lui, le milieu
+            culturel est indispensable. Il est rapidement rejoint par Michel
+            PERNET-SOLLIET, lui aussi musicien, et ils montent ensemble
+            Openassos, qui deviendra quelques années plus tard, Opentalent.
+            Opentalent c'est un ensemble de 3 logiciels spécialement dédiés à la
+            culture et un agenda culturel pour en faire la promotion.
           </p>
 
-          <h3>
-            La Culture au service du développement territorial
-          </h3>
+          <h3>La Culture au service du développement territorial</h3>
 
           <p>
-            Qui n'a jamais entendu que la culture coûtait trop cher ? On l'entend
-            , ha ça oui on l'a même trop entendu ! Mais la culture c'est avant
-            tout un facteur de lien social incroyable. On se retrouve, on échange,
-            on partage... on vit ensemble. On crée des vrais moments et on
-            développe des groupes de passionnés. On participe à rendre nos
-            collectivités attractives et surtout on les fait vivre, toute l'année,
-            à toutes les saisons. Depuis plusieurs décennies, un grand nombre de
-            territoires s'appuie sur le développement de la culture comme un outil
-            de développement territorial pour faire face à la
-            désindustrialisation, à une croissance démographique ralentie ou
-            encore une image défavorable. Ce modèle de développement par la
-            culture pour pallier un déficit d’attractivité touristique inspire de
-            plus en plus de politiques de développement territorial.
+            Qui n'a jamais entendu que la culture coûtait trop cher ? On
+            l'entend , ha ça oui on l'a même trop entendu ! Mais la culture
+            c'est avant tout un facteur de lien social incroyable. On se
+            retrouve, on échange, on partage... on vit ensemble. On crée des
+            vrais moments et on développe des groupes de passionnés. On
+            participe à rendre nos collectivités attractives et surtout on les
+            fait vivre, toute l'année, à toutes les saisons. Depuis plusieurs
+            décennies, un grand nombre de territoires s'appuie sur le
+            développement de la culture comme un outil de développement
+            territorial pour faire face à la désindustrialisation, à une
+            croissance démographique ralentie ou encore une image défavorable.
+            Ce modèle de développement par la culture pour pallier un déficit
+            d’attractivité touristique inspire de plus en plus de politiques de
+            développement territorial.
           </p>
         </v-col>
       </v-row>
@@ -149,13 +144,14 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
   }
 
   @media (max-width: 1240px) {
-    h3, h4, p, .v-img {
+    h3,
+    h4,
+    p,
+    .v-img {
       width: 100%;
       margin-left: auto;
       margin-right: auto;
     }
   }
 }
-
-
 </style>

+ 5 - 15
components/About/Valeurs.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="values">
     <LayoutContainer class="mt-12">
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Les valeurs qui nous portent
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Les valeurs qui nous portent </LayoutUISubTitle>
       </v-row>
 
       <v-row class="mt-6 center-90 align-center mb-12">
@@ -19,23 +17,15 @@
 
         <v-col cols="12" lg="6">
           <div class="values">
-            <v-row
-              v-for="(row, rowIndex) in values"
-              :key="rowIndex"
-            >
+            <v-row v-for="(row, rowIndex) in values" :key="rowIndex">
               <v-col
-                cols="12"
-                md="6"
                 v-for="(value, valueIndex) in row"
                 :key="valueIndex"
+                cols="12"
+                md="6"
               >
                 <div class="d-flex flex-row align-center">
-                  <v-img
-                    :src="value.img"
-                    :alt="value.alt"
-                    cover
-                    class="mr-3"
-                  />
+                  <v-img :src="value.img" :alt="value.alt" cover class="mr-3" />
 
                   <h6>
                     {{ value.title }}

+ 25 - 24
components/Common/ActionMenu.vue

@@ -4,7 +4,7 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
 -->
 <template>
   <!-- Écrans larges : menu lateral, accroché au bord droit de l'écran -->
-  <div class="sticky-menu lateral" v-if="lgAndUp && isVisible">
+  <div v-if="lgAndUp && isVisible" class="sticky-menu lateral">
     <v-row
       v-for="(action, index) in actionsOrDefault"
       :key="index"
@@ -13,9 +13,7 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
     >
       <NuxtLink :to="action.url" class="link">
         <div>
-          <v-icon
-            :class="action.icon"
-          />
+          <v-icon :class="action.icon" />
 
           <p class="text-square mt-2">
             {{ action.text }}
@@ -26,7 +24,7 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
   </div>
 
   <!-- Petits écrans : menu sous forme de bandeau en pied de page (sauf si le footer du site est visible) -->
-  <div class="sticky-menu band" v-else-if="isVisible">
+  <div v-else-if="isVisible" class="sticky-menu band">
     <v-btn
       v-for="(action, index) in actionsOrDefault"
       :key="index"
@@ -41,20 +39,24 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
 <script setup lang="ts">
 import { useRouter } from "vue-router";
 import { useDisplay } from "vuetify";
+import type { ComputedRef } from "vue";
 import { useLayoutStore } from "~/stores/layoutStore";
 import { ActionMenuItemType } from "~/types/enum/layout";
 import type { ActionMenuItem } from "~/types/interface";
 
 const { lgAndUp } = useDisplay();
 const router = useRouter();
-const layoutStore = useLayoutStore()
-const { isMobileDevice } = useClientDevice()
+const layoutStore = useLayoutStore();
+const { isMobileDevice } = useClientDevice();
 
 const telephoneNumber = "09 72 12 60 17";
 
-const isVisible: ComputedRef<boolean> = computed(() =>
-  !layoutStore.isHeaderVisible && !layoutStore.isBannerVisible && !layoutStore.isFooterVisible
-)
+const isVisible: ComputedRef<boolean> = computed(
+  () =>
+    !layoutStore.isHeaderVisible &&
+    !layoutStore.isBannerVisible &&
+    !layoutStore.isFooterVisible,
+);
 
 // Actions par défaut du menu, peut-être surchargé via la propriété `actions`
 const defaultActions: Array<ActionMenuItem> = [
@@ -63,7 +65,7 @@ const defaultActions: Array<ActionMenuItem> = [
     color: "secondary",
     icon: "far fa-comments",
     text: "Nous contacter",
-    url: { path: 'nous-contacter', hash: '#form' },
+    url: { path: "nous-contacter", hash: "#form" },
   },
   {
     type: ActionMenuItemType.CALL_US,
@@ -80,21 +82,21 @@ const props = defineProps({
   actions: {
     type: Array<ActionMenuItem>,
     required: false,
-    default: []
-  }
-})
+    default: [],
+  },
+});
 
 const actionsOrDefault: ComputedRef<Array<ActionMenuItem>> = computed(() => {
-  return props.actions.length > 0 ? props.actions : defaultActions
-})
+  return props.actions.length > 0 ? props.actions : defaultActions;
+});
 
 const callUs = () => {
   if (isMobileDevice()) {
     window.location.href = `tel:${telephoneNumber}`;
   } else {
-    navigateTo({ path: 'nous-contacter', hash: '#details' })
+    navigateTo({ path: "nous-contacter", hash: "#details" });
   }
-}
+};
 
 /**
  * On a cliqué sur une des actions du menu
@@ -107,24 +109,23 @@ const onActionClick = (action: ActionMenuItem) => {
       break;
 
     case ActionMenuItemType.CALL_US:
-      callUs()
+      callUs();
       break;
 
     case ActionMenuItemType.FOLLOW_LINK:
       if (!action.url) {
-        throw Error('Missing prop : url')
+        throw new Error("Missing prop : url");
       }
-      navigateTo(action.url)
-      break
+      navigateTo(action.url);
+      break;
 
     default:
-      throw Error('Unrecognized action')
+      throw new Error("Unrecognized action");
   }
 };
 </script>
 
 <style scoped lang="scss">
-
 .sticky-menu {
   z-index: 100;
 }

+ 11 - 26
components/Common/Agenda.vue

@@ -3,32 +3,22 @@ Section "Agenda des évènements"
 -->
 <template>
   <AnchoredSection id="agenda">
-    <LayoutContainer class="mb-12" >
+    <LayoutContainer class="mb-12">
       <v-row class="center-90 align-center my-6">
         <v-col cols="4" class="align-center">
-          <LayoutUITitle>
-            L'agenda Opentalent
-          </LayoutUITitle>
+          <LayoutUITitle> L'agenda Opentalent </LayoutUITitle>
         </v-col>
 
         <v-col cols="4">
           <!-- Factoriser les contrôles du carousel dans un component -->
           <div class="carousel-controls">
-            <v-btn
-              icon="fas fa-chevron-left"
-              @click="goPrevious"
-            />
-            <v-btn
-              icon="fas fa-chevron-right"
-              @click="goNext"
-            />
+            <v-btn icon="fas fa-chevron-left" @click="goPrevious" />
+            <v-btn icon="fas fa-chevron-right" @click="goNext" />
           </div>
         </v-col>
 
         <v-col cols="4" class="d-flex flex-row flex-1 justify-end align-center">
-          <v-btn class="btn-news" text>
-            Voir tous les évènements
-          </v-btn>
+          <v-btn class="btn-news" text> Voir tous les évènements </v-btn>
         </v-col>
       </v-row>
 
@@ -40,11 +30,7 @@ Section "Agenda des évènements"
 
       <v-row class="center-90">
         <v-col cols="12">
-          <Carousel
-            ref="carousel"
-            :items-to-show="3"
-            :items-to-scroll="2"
-          >
+          <Carousel ref="carousel" :items-to-show="3" :items-to-scroll="2">
             <Slide
               v-for="(event, eventIndex) in events"
               :key="eventIndex"
@@ -69,9 +55,7 @@ Section "Agenda des évènements"
                       :color="tagColor(tag)"
                       label
                     >
-                      <span
-                        :class="tagTextColor(tag)"
-                      >
+                      <span :class="tagTextColor(tag)">
                         {{ tag }}
                       </span>
                     </v-chip>
@@ -89,6 +73,7 @@ Section "Agenda des évènements"
 <script setup lang="ts">
 import { Carousel, Slide } from "vue3-carousel";
 import "vue3-carousel/dist/carousel.css";
+import type { Ref } from "vue";
 import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import type { Event } from "~/types/interface";
 
@@ -164,11 +149,11 @@ const goNext = () => carousel.value!.next();
 </script>
 
 <style scoped>
-.v-container{
+.v-container {
   padding: 0 !important;
 }
 
-.container{
+.container {
   background: var(--neutral-color);
 }
 
@@ -226,7 +211,7 @@ const goNext = () => carousel.value!.next();
     }
   }
 
-  footer{
+  footer {
     display: flex;
     text-align: left !important;
 

+ 11 - 9
components/Common/AgendaLink.vue

@@ -7,19 +7,21 @@
 <script setup lang="ts">
 import UrlUtils from "~/services/utils/urlUtils";
 
-const runtimeConfig = useRuntimeConfig()
+const runtimeConfig = useRuntimeConfig();
 
 const props = defineProps({
   href: {
-    type: String
-  }
-})
+    type: String,
+    required: true,
+  },
+});
 
 const target = computed(() => {
-  return UrlUtils.join(runtimeConfig.public.agendaBaseUrl as string, props.href as string)
-})
+  return UrlUtils.join(
+    runtimeConfig.public.agendaBaseUrl as string,
+    props.href as string,
+  );
+});
 </script>
 
-<style scoped lang="scss">
-
-</style>
+<style scoped lang="scss"></style>

+ 8 - 15
components/Common/Avantages.vue

@@ -11,35 +11,28 @@
     </v-row>
 
     <v-row class="center-90 benefits">
-      <v-col
-        cols="12"
-        md="4"
-        v-for="(benefit, index) in benefits"
-        :key="index"
-      >
-        <CommonCardBenefit
-          :benefit="benefit"
-        />
+      <v-col v-for="(benefit, index) in benefits" :key="index" cols="12" md="4">
+        <CommonCardBenefit :benefit="benefit" />
       </v-col>
     </v-row>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
+import type { PropType } from "vue";
 import type { Benefit } from "~/types/interface";
-import { useDisplay } from "vuetify";
 
-const props = defineProps({
+defineProps({
   benefits: {
     type: Array as PropType<Array<Benefit>>,
-    required: true
+    required: true,
   },
   title: {
     type: String,
     required: false,
-    default: "Des avantages concrets"
-  }
-})
+    default: "Des avantages concrets",
+  },
+});
 </script>
 
 <style scoped lang="scss">

+ 20 - 16
components/Common/Banner.vue

@@ -24,8 +24,11 @@
             </v-row>
           </div>
 
-          <div v-if="logoSrc" :class="'logo-square' + (logoAltTheme ? ' alt-theme' : '')">
-            <img :src="logoSrc" :alt="logoAlt"/>
+          <div
+            v-if="logoSrc"
+            :class="'logo-square' + (logoAltTheme ? ' alt-theme' : '')"
+          >
+            <img :src="logoSrc" :alt="logoAlt" />
           </div>
 
           <div class="image-text mt-12">
@@ -38,46 +41,47 @@
 </template>
 
 <script setup lang="ts">
-
+import type { PropType } from "vue";
 import { useLayoutStore } from "~/stores/layoutStore";
 
-const props = defineProps({
+defineProps({
   imageSrc: {
     type: String,
-    required: true
+    required: true,
   },
   imageAlt: {
     type: String,
-    default: ""
+    default: "",
   },
   squareText: {
     type: String,
-    default: "École de musique, d'art, de danse, de cirque, conservatoires et MJC"
+    default:
+      "École de musique, d'art, de danse, de cirque, conservatoires et MJC",
   },
   logoSrc: {
     type: String as PropType<string | null>,
     required: false,
-    default: null
+    default: null,
   },
   logoAlt: {
     type: String,
     required: false,
-    default: ""
+    default: "",
   },
   logoAltTheme: {
     type: Boolean,
-    default: false
+    default: false,
   },
   reverseImage: {
     type: Boolean,
-    default: false
-  }
+    default: false,
+  },
 });
 
-const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore();
 const onIntersect = (isIntersecting: boolean) => {
-  layoutStore.setIsBannerVisible(isIntersecting)
-}
+  layoutStore.setIsBannerVisible(isIntersecting);
+};
 </script>
 
 <style scoped lang="scss">
@@ -120,7 +124,7 @@ const onIntersect = (isIntersecting: boolean) => {
 .custom-icon {
   width: 3rem;
   height: 3rem;
-  margin-top: .5rem;
+  margin-top: 0.5rem;
 }
 
 .details-square {

+ 6 - 10
components/Common/Card/Benefit.vue

@@ -14,7 +14,7 @@ Carte "Avantage" de la section Avantages d'une page Logiciel
         </span>
       </div>
 
-      <v-divider thickness="1"/>
+      <v-divider thickness="1" />
 
       <div class="description">
         <p class="mr-4">
@@ -22,25 +22,21 @@ Carte "Avantage" de la section Avantages d'une page Logiciel
         </p>
       </div>
 
-      <v-img
-        :src="benefit.image"
-        :alt="benefit.alt"
-        cover
-      />
+      <v-img :src="benefit.image" :alt="benefit.alt" cover />
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
+import type { PropType } from "vue";
 import type { Benefit } from "~/types/interface";
 
-const props = defineProps({
+defineProps({
   benefit: {
     type: Object as PropType<Benefit>,
-    required: true
-  }
+    required: true,
+  },
 });
-
 </script>
 
 <style scoped lang="scss">

+ 5 - 5
components/Common/Card/Stat.vue

@@ -12,10 +12,12 @@
 <script setup lang="ts">
 const props = defineProps({
   number: {
-    type: String
+    type: String,
+    required: true,
   },
   text: {
-    type: String
+    type: String,
+    required: true,
   },
 });
 </script>
@@ -33,7 +35,7 @@ const props = defineProps({
   align-items: center;
   text-align: center;
 
-  p:first-child{
+  p:first-child {
     font-weight: 600;
     font-size: 60px;
     line-height: 68px;
@@ -49,6 +51,4 @@ const props = defineProps({
     height: 12rem;
   }
 }
-
-
 </style>

+ 12 - 21
components/Common/Carousel/Clients.vue

@@ -6,7 +6,8 @@
     <v-row justify="center">
       <h3 class="text-center">
         <slot name="title">
-          Plus de <span class="alt-color">5000 structures</span> nous font confiance
+          Plus de <span class="alt-color">5000 structures</span> nous font
+          confiance
         </slot>
       </h3>
     </v-row>
@@ -28,7 +29,7 @@
           :items-to-scroll="smAndUp ? 2 : 1"
           :wrap-around="true"
         >
-          <Slide v-for="(item, index) in items" :key="item.src">
+          <Slide v-for="item in items" :key="item.src">
             <div>
               <v-img :src="item.src" :alt="item.alt" />
             </div>
@@ -36,22 +37,12 @@
         </Carousel>
 
         <!-- Fléche de droite -->
-        <v-btn
-          v-if="lgAndUp"
-          icon="fas fa-chevron-right"
-          @click="goToNext"
-        />
+        <v-btn v-if="lgAndUp" icon="fas fa-chevron-right" @click="goToNext" />
       </v-row>
 
       <v-row v-if="mdAndDown">
-        <v-btn
-          icon="fas fa-chevron-left"
-          @click="goToPrevious"
-        />
-        <v-btn
-          icon="fas fa-chevron-right"
-          @click="goToNext"
-        />
+        <v-btn icon="fas fa-chevron-left" @click="goToPrevious" />
+        <v-btn icon="fas fa-chevron-right" @click="goToNext" />
       </v-row>
     </v-container>
   </LayoutContainer>
@@ -59,18 +50,18 @@
 
 <script setup lang="ts">
 import { Carousel, Slide } from "vue3-carousel";
-import type { PropType } from "@vue/runtime-core";
+import type { PropType, Ref } from "vue";
 import { useDisplay } from "vuetify";
 
-const { smAndUp, mdAndUp, lgAndUp, mdAndDown } = useDisplay()
+const { smAndUp, lgAndUp, mdAndDown } = useDisplay();
 
 const carousel: Ref<typeof Carousel | null> = ref(null);
 
-const props = defineProps({
+defineProps({
   items: {
-    type: Array as PropType<Array<{ src: string, alt: string }>>,
-    required: true
-  }
+    type: Array as PropType<Array<{ src: string; alt: string }>>,
+    required: true,
+  },
 });
 
 const goToPrevious = () => {

+ 13 - 26
components/Common/Carousel/Fonctionnalite.vue

@@ -25,14 +25,10 @@
           :items-to-scroll="1"
           :wrap-around="true"
         >
-          <Slide v-for="(card, index) in cards" :key="index" >
+          <Slide v-for="(card, index) in cards" :key="index">
             <div class="card-container">
               <v-card class="inv-theme">
-                <v-img
-                  :src="card.logo"
-                  :alt="card.title"
-                  class="mx-auto"
-                />
+                <v-img :src="card.logo" :alt="card.title" class="mx-auto" />
 
                 <v-card-title>
                   <h5>
@@ -43,22 +39,15 @@
                 <v-card-item>
                   <v-card-text>
                     <ul>
-                      <li
-                        v-for="item in card.list"
-                        :key="item"
-                      >
+                      <li v-for="item in card.list" :key="item">
                         <p>{{ item }}</p>
                       </li>
                     </ul>
                   </v-card-text>
-
                 </v-card-item>
 
                 <div class="footer">
-                  <p
-                    v-for="option in card.options"
-                    :key="option"
-                  >
+                  <p v-for="option in card.options" :key="option">
                     {{ option }}
                   </p>
                 </div>
@@ -75,22 +64,23 @@
 import { useDisplay } from "vuetify";
 import { Carousel, Slide } from "vue3-carousel";
 import "vue3-carousel/dist/carousel.css";
-import type { PropType } from "@vue/runtime-core";
+import type { PropType, Ref } from "vue";
 import type { Functionality } from "~/types/interface";
 
 const { lgAndUp, mdAndUp, smAndUp } = useDisplay();
 
-const props = defineProps({
+defineProps({
   cards: {
     type: Array as PropType<Array<Functionality>>,
-    required: true
-  }
-})
+    required: true,
+  },
+});
 
 const carousel: Ref<typeof Carousel | null> = ref(null);
 
-const itemsToShow = computed(() => lgAndUp.value ? 5 : (mdAndUp.value ? 3 : (smAndUp.value ? 2 : 1)))
-
+const itemsToShow = computed(() =>
+  lgAndUp.value ? 5 : mdAndUp.value ? 3 : smAndUp.value ? 2 : 1,
+);
 
 const nextAction = () => {
   carousel.value!.next();
@@ -171,7 +161,7 @@ const previousAction = () => {
     position: absolute;
     left: 0;
     margin-left: 1.3rem;
-    font-size: .9rem;
+    font-size: 0.9rem;
 
     p {
       text-align: left;
@@ -205,7 +195,4 @@ const previousAction = () => {
 //    max-width: 300px !important;
 //  }
 //}
-
-
-
 </style>

+ 19 - 32
components/Common/Contact.vue

@@ -3,9 +3,7 @@
     <LayoutContainer>
       <!-- Section "Appelez nous" -->
       <v-row class="center-90">
-        <LayoutUISubTitle v-if="smAndDown">
-          Contactez-nous
-        </LayoutUISubTitle>
+        <LayoutUISubTitle v-if="smAndDown"> Contactez-nous </LayoutUISubTitle>
 
         <v-col cols="12" md="6">
           <v-img
@@ -17,18 +15,12 @@
         </v-col>
 
         <v-col cols="12" lg="5" class="contact-section">
-          <LayoutUISubTitle v-if="mdAndUp">
-            Contactez-nous
-          </LayoutUISubTitle>
+          <LayoutUISubTitle v-if="mdAndUp"> Contactez-nous </LayoutUISubTitle>
 
-          <LayoutUITitle>
-            Vous avez un projet ?
-          </LayoutUITitle>
+          <LayoutUITitle> Vous avez un projet ? </LayoutUITitle>
 
           <div class="px-6">
-            <h6 class="subtitle">
-              N'attendez plus, appelez-nous !
-            </h6>
+            <h6 class="subtitle">N'attendez plus, appelez-nous !</h6>
             <p class="contact-details">
               Vous avez une identité, des besoins, des projets... On est là pour
               vous écouter et vous offrir une offre personnalisée ! Que vous
@@ -38,26 +30,22 @@
               l'intégralité des fonctionnalités.
             </p>
 
-            <v-btn to="nous-contacter" class="btn-contact"> Nous contacter </v-btn>
+            <v-btn to="nous-contacter" class="btn-contact">
+              Nous contacter
+            </v-btn>
           </div>
         </v-col>
       </v-row>
 
       <!-- Section "Adhérent CMF" -->
-      <v-row class="center-90 cmf-section" >
-        <v-col cols="12" lg="6" >
-          <LayoutUISubTitle>
-            Adhérents CMF
-          </LayoutUISubTitle>
+      <v-row class="center-90 cmf-section">
+        <v-col cols="12" lg="6">
+          <LayoutUISubTitle> Adhérents CMF </LayoutUISubTitle>
 
-          <LayoutUITitle>
-            Bénéficiez de conditions privilégiées
-          </LayoutUITitle>
+          <LayoutUITitle> Bénéficiez de conditions privilégiées </LayoutUITitle>
 
           <div class="pl-4">
-            <h6 class="subtitle">
-              N'attendez plus, appelez-nous
-            </h6>
+            <h6 class="subtitle">N'attendez plus, appelez-nous</h6>
 
             <p class="contact-details">
               Si votre établissement d’enseignement artistique est adhérent à la
@@ -83,22 +71,21 @@
         </v-col>
 
         <v-col cols="12" md="6">
-           <v-img
-             src="/images/logos/cmf/Logo_Confederation_Musicale_de_France-CMF_vivre_la_musique_ensemble.jpg"
-             alt="Logo Confédération Musicale de France - CMF avec son slogan : vivre la musique ensemble"
-             class="logo-cmf mt-12"
-           />
+          <v-img
+            src="/images/logos/cmf/Logo_Confederation_Musicale_de_France-CMF_vivre_la_musique_ensemble.jpg"
+            alt="Logo Confédération Musicale de France - CMF avec son slogan : vivre la musique ensemble"
+            class="logo-cmf mt-12"
+          />
         </v-col>
       </v-row>
     </LayoutContainer>
   </AnchoredSection>
 </template>
 <script setup>
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import { useDisplay } from "vuetify";
+import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 
-const { smAndDown, mdAndDown, mdAndUp } = useDisplay()
-
+const { smAndDown, mdAndDown, mdAndUp } = useDisplay();
 </script>
 
 <style scoped>

+ 8 - 11
components/Common/ContainerVideo.vue

@@ -24,32 +24,29 @@
       </v-row>
     </div>
 
-    <div v-else>
-
-    </div>
+    <div v-else></div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-
 import { useDisplay } from "vuetify";
 
-const { mdAndUp, lgAndUp } = useDisplay()
+const { lgAndUp } = useDisplay();
 
-const props = defineProps({
+defineProps({
   title: {
     type: String,
-    required: true
+    required: true,
   },
   quote: {
     type: String,
-    required: true
+    required: true,
   },
   videoUrl: {
     type: String,
-    default: ""
-  }
-})
+    default: "",
+  },
+});
 </script>
 
 <style scoped lang="scss">

+ 14 - 17
components/Common/MenuScroll.vue

@@ -4,9 +4,7 @@ Menu de navigation entre les sections d'une page, accrochée au haut de l'écran
 <template>
   <LayoutContainer v-scroll="handleScroll">
     <v-row>
-      <v-col
-        cols="12"
-      >
+      <v-col cols="12">
         <v-list
           class="menu-container"
           density="compact"
@@ -23,7 +21,7 @@ Menu de navigation entre les sections d'une page, accrochée au haut de l'écran
           <div v-for="menu in menus" :key="menu.anchor">
             <nuxt-link :to="{ path: '', hash: '#' + menu.anchor }">
               <v-list-item
-                :class="{ active : isSticky && menu.anchor === activeMenuItem }"
+                :class="{ active: isSticky && menu.anchor === activeMenuItem }"
               >
                 {{ menu.label }}
               </v-list-item>
@@ -36,32 +34,32 @@ Menu de navigation entre les sections d'une page, accrochée au haut de l'écran
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
+import type { ComputedRef, PropType, Ref } from "vue";
 import type { MenuScroll } from "~/types/interface";
 import { useLayoutStore } from "~/stores/layoutStore";
 
 defineProps({
   menus: {
-    type: Array as PropType<Array < MenuScroll >>,
-    required: true
-  }
+    type: Array as PropType<Array<MenuScroll>>,
+    required: true,
+  },
 });
 
-const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore();
 
 const isSticky: Ref<boolean> = ref(false);
 
 const activeMenuItem: ComputedRef<string | null> = computed(() => {
-  return Object.entries(
-    layoutStore.isAnchoredSectionOnScreen
-  ).find(
-    ([key, value]) => value === true
-  )?.[0] ?? null
-})
+  return (
+    Object.entries(layoutStore.isAnchoredSectionOnScreen).find(
+      ([_, value]) => value,
+    )?.[0] ?? null
+  );
+});
 
 const handleScroll = () => {
   isSticky.value = window.scrollY > 800;
-}
+};
 </script>
 
 <style scoped lang="scss">
@@ -106,4 +104,3 @@ const handleScroll = () => {
   padding: 5px;
 }
 </style>
-

+ 31 - 29
components/Common/Meta.vue

@@ -1,36 +1,38 @@
 <!--
 Définit les balises meta de la page
 -->
-<template></template>
+<template>
+  <div />
+</template>
 
 <script setup lang="ts">
-  const props = defineProps({
-    title: {
-      type: String,
-      required: true
-    },
-    description: {
-      type: String,
-      required: true
-    },
-    image: {
-      type: String,
-      required: false,
-      default: 'images/Opentalent'
-    }
-  })
+const props = defineProps({
+  title: {
+    type: String,
+    required: true,
+  },
+  description: {
+    type: String,
+    required: true,
+  },
+  image: {
+    type: String,
+    required: false,
+    default: "images/Opentalent",
+  },
+});
 
-  useSeoMeta({
-    title : props.title,
-    ogTitle : props.title,
-    twitterTitle : props.title,
-    description : props.description,
-    ogDescription : props.description,
-    twitterDescription : props.description,
-    ogImage : props.image,
-    twitterImage: props.image,
-    twitterCard : 'summary_large_image',
-    ogType: 'website',
-    ogLocale: 'fr_FR'
-  })
+useSeoMeta({
+  title: props.title,
+  ogTitle: props.title,
+  twitterTitle: props.title,
+  description: props.description,
+  ogDescription: props.description,
+  twitterDescription: props.description,
+  ogImage: props.image,
+  twitterImage: props.image,
+  twitterCard: "summary_large_image",
+  ogType: "website",
+  ogLocale: "fr_FR",
+});
 </script>

+ 20 - 33
components/Common/Presentation.vue

@@ -4,10 +4,9 @@ Section "Présentation" d'une page Logiciel
 <template>
   <LayoutContainer>
     <v-row class="center-90">
-
       <!-- Colonne 1 (sous-titre, illustration logiciels, prix) -->
       <v-col cols="12" lg="5">
-        <LayoutUISubTitle class="ml-8" >
+        <LayoutUISubTitle class="ml-8">
           {{ title }}
         </LayoutUISubTitle>
 
@@ -20,11 +19,7 @@ Section "Présentation" d'une page Logiciel
         <div class="pricing-rectangle rectangle-4 ml-6">
           <div class="logo-circle">
             <div class="content-flex ml-6">
-              <v-img
-                :src="logoSrc"
-                :alt="logoAlt"
-                class="software-logo"
-              />
+              <v-img :src="logoSrc" :alt="logoAlt" class="software-logo" />
             </div>
           </div>
 
@@ -55,10 +50,7 @@ Section "Présentation" d'une page Logiciel
         </h3>
 
         <ul class="ml-12 mt-6">
-          <li
-            v-for="item in features"
-            :key="item"
-          >
+          <li v-for="item in features" :key="item">
             {{ item }}
           </li>
         </ul>
@@ -68,11 +60,7 @@ Section "Présentation" d'une page Logiciel
         </h3>
 
         <div class="picto-container">
-          <div
-            v-for="picto in pictos"
-            :key="picto.text"
-            class="picto"
-          >
+          <div v-for="picto in pictos" :key="picto.text" class="picto">
             <v-img :src="picto.src" class="img" />
 
             <p class="text">
@@ -86,33 +74,31 @@ Section "Présentation" d'une page Logiciel
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
+import type { PropType } from "vue";
 import type { FeaturePicto } from "~/types/interface";
 
-const route = useRoute();
-
-const props = defineProps({
+defineProps({
   title: {
     type: String,
-    required: true
+    required: true,
   },
   section1title: {
     type: String,
     required: false,
-    default: "Un outil complet en ligne"
+    default: "Un outil complet en ligne",
   },
   section2title: {
     type: String,
     required: false,
-    default: "Des caractéristiques uniques & dédiée"
+    default: "Des caractéristiques uniques & dédiée",
   },
   features: {
     type: Object as PropType<Array<string>>,
-    required: true
+    required: true,
   },
   pictos: {
     type: Array as PropType<Array<FeaturePicto>>,
-    required: true
+    required: true,
   },
   logoSrc: {
     type: String,
@@ -125,26 +111,27 @@ const props = defineProps({
   pricingFromText: {
     type: String,
     required: false,
-    default: "à partir de"
+    default: "à partir de",
   },
   pricingAmount: {
     type: String,
-    default: ""
+    default: "",
   },
   pricingPeriodText: {
     type: String,
     required: false,
-    default: "/ mois"
+    default: "/ mois",
   },
   pricingAnnouncementText: {
     type: String,
     required: false,
-    default: "payable annuellement"
+    default: "payable annuellement",
   },
   pricingAltText: {
+    type: String,
     required: false,
-    default: ""
-  }
+    default: "",
+  },
 });
 </script>
 
@@ -169,8 +156,8 @@ const props = defineProps({
     display: flex;
     align-items: center;
     justify-content: center;
-    top:1rem;
-    right: .5rem;
+    top: 1rem;
+    right: 0.5rem;
   }
 
   .details {

+ 55 - 67
components/Common/ReviewSection.vue

@@ -1,83 +1,71 @@
 <template>
-    <LayoutContainer>
-      <v-row class="center-90">
-        <v-col cols="12" lg="3">
-          <div class="controls-section">
-            <h3>
-              Ce sont eux qui en parlent le mieux
-            </h3>
-
-            <div class="carousel-controls">
-              <v-btn
-                icon="fas fa-chevron-left"
-                @click="goPrevious"
-              />
-              <v-btn
-                icon="fas fa-chevron-right"
-                @click="goNext"
-              />
-            </div>
+  <LayoutContainer>
+    <v-row class="center-90">
+      <v-col cols="12" lg="3">
+        <div class="controls-section">
+          <h3>Ce sont eux qui en parlent le mieux</h3>
+
+          <div class="carousel-controls">
+            <v-btn icon="fas fa-chevron-left" @click="goPrevious" />
+            <v-btn icon="fas fa-chevron-right" @click="goNext" />
           </div>
-        </v-col>
-
-        <v-col cols="12" lg="9">
-          <Carousel
-            ref="carousel"
-            :items-to-show="lgAndUp ? 3 : 1"
-            :wrapAround="true"
-            :show-arrows="false"
-            snapAlign="center"
-            class="carousel"
-          >
-            <Slide
-              v-for="(card, index) in cards"
-              :key="index"
-              class="card"
-            >
-              <v-container>
-                <v-card class="inv-theme">
-                  <v-card-item>
-                    <v-card-text>
-                      <i>"{{ card.review }}"</i>
-                    </v-card-text>
-                  </v-card-item>
-
-                  <v-card-actions>
-                    <p class="reviewer-name">
-                      {{ card.name }}
-                    </p>
-
-                    <p class="reviewer-status">
-                      {{ card.status }}
-                    </p>
-                    <p class="reviewer-structure">
-                      {{ card.structure }}
-                    </p>
-                  </v-card-actions>
-                </v-card>
-              </v-container>
-            </Slide>
-          </Carousel>
-        </v-col>
-      </v-row>
+        </div>
+      </v-col>
+
+      <v-col cols="12" lg="9">
+        <Carousel
+          ref="carousel"
+          :items-to-show="lgAndUp ? 3 : 1"
+          :wrap-around="true"
+          :show-arrows="false"
+          snap-align="center"
+          class="carousel"
+        >
+          <Slide v-for="(card, index) in cards" :key="index" class="card">
+            <v-container>
+              <v-card class="inv-theme">
+                <v-card-item>
+                  <v-card-text>
+                    <i>"{{ card.review }}"</i>
+                  </v-card-text>
+                </v-card-item>
+
+                <v-card-actions>
+                  <p class="reviewer-name">
+                    {{ card.name }}
+                  </p>
+
+                  <p class="reviewer-status">
+                    {{ card.status }}
+                  </p>
+                  <p class="reviewer-structure">
+                    {{ card.structure }}
+                  </p>
+                </v-card-actions>
+              </v-card>
+            </v-container>
+          </Slide>
+        </Carousel>
+      </v-col>
+    </v-row>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
 import { Carousel, Slide } from "vue3-carousel";
 import "vue3-carousel/dist/carousel.css";
-import type { PropType } from "@vue/runtime-core";
-import type { Review } from "~/types/interface";
+import type { PropType, Ref } from "vue";
 import { useDisplay } from "vuetify";
+import type { Review } from "~/types/interface";
 
-const props = defineProps({
+defineProps({
   cards: {
     type: Array as PropType<Array<Review>>,
     required: true,
   },
 });
 
-const { lgAndUp } = useDisplay()
+const { lgAndUp } = useDisplay();
 
 const carousel: Ref<typeof Carousel | null> = ref(null);
 
@@ -92,7 +80,7 @@ const goNext = () => {
 
 <style scoped lang="scss">
 .v-container {
-  padding: 0 0 48px 0!important;
+  padding: 0 0 48px 0 !important;
 }
 
 .controls-section {
@@ -163,7 +151,7 @@ const goNext = () => {
   }
 
   .v-card-item {
-    flex: 1
+    flex: 1;
   }
 
   .v-card-text {
@@ -230,7 +218,7 @@ const goNext = () => {
   padding-top: 16px;
 }
 
-@media (max-width:600px) {
+@media (max-width: 600px) {
   :deep(.v-carousel__controls) {
     color: var(--on-neutral-color);
     background-color: var(--neutral-color);

+ 46 - 46
components/Common/Share.vue

@@ -7,60 +7,60 @@
       target="_blank"
       :style="{ color: network.colorOnHover }"
     >
-      <v-icon :icon="network.icon"/>
+      <v-icon :icon="network.icon" />
     </nuxt-link>
   </div>
 </template>
 
 <script setup lang="ts">
-  import type { SocialNetworkShareBtn } from "~/types/interface";
+import type { Ref } from "vue";
+import type { SocialNetworkShareBtn } from "~/types/interface";
 
-  const url: Ref<string | null> = ref(null)
-  const networks: Ref<Array<SocialNetworkShareBtn>> = ref([])
+const url: Ref<string | null> = ref(null);
+const networks: Ref<Array<SocialNetworkShareBtn>> = ref([]);
 
-  if (process.client) {
-    url.value = window.location.href
-
-    networks.value = [
-      {
-        name: "Facebook",
-        icon: "fa-brands fa-facebook",
-        colorOnHover: "#135fc2",
-        url: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url.value)}`
-      },
-      {
-        name: "Twitter",
-        icon: "fa-brands fa-twitter",
-        colorOnHover: "#1781c2",
-        url: `https://twitter.com/intent/tweet?url=${encodeURIComponent(url.value)}`
-      },
-      {
-        name: "Messenger",
-        icon: "fa-brands fa-facebook-messenger",
-        colorOnHover: "#0085ff",
-        url: `https://messenger.com`
-      },
-      {
-        name: "Instagram",
-        icon: "fa-brands fa-instagram",
-        colorOnHover: "#d0006a",
-        url: "https://instagram.com"
-      },
-      {
-        name: "Linkedin",
-        icon: "fa-brands fa-linkedin",
-        colorOnHover: "#006291",
-        url: `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(url.value)}`
-      },
-      {
-        name: "Email",
-        icon: "fas fa-envelope",
-        colorOnHover: "#292929",
-        url: `mailto:?body=${url.value}`
-      },
-    ]
-  }
+if (process.client) {
+  url.value = window.location.href;
 
+  networks.value = [
+    {
+      name: "Facebook",
+      icon: "fa-brands fa-facebook",
+      colorOnHover: "#135fc2",
+      url: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url.value)}`,
+    },
+    {
+      name: "Twitter",
+      icon: "fa-brands fa-twitter",
+      colorOnHover: "#1781c2",
+      url: `https://twitter.com/intent/tweet?url=${encodeURIComponent(url.value)}`,
+    },
+    {
+      name: "Messenger",
+      icon: "fa-brands fa-facebook-messenger",
+      colorOnHover: "#0085ff",
+      url: `https://messenger.com`,
+    },
+    {
+      name: "Instagram",
+      icon: "fa-brands fa-instagram",
+      colorOnHover: "#d0006a",
+      url: "https://instagram.com",
+    },
+    {
+      name: "Linkedin",
+      icon: "fa-brands fa-linkedin",
+      colorOnHover: "#006291",
+      url: `https://www.linkedin.com/shareArticle?mini=true&url=${encodeURIComponent(url.value)}`,
+    },
+    {
+      name: "Email",
+      icon: "fas fa-envelope",
+      colorOnHover: "#292929",
+      url: `mailto:?body=${url.value}`,
+    },
+  ];
+}
 </script>
 
 <style scoped lang="scss">

+ 38 - 48
components/Common/Table/Comparatif.vue

@@ -4,7 +4,7 @@
       <table v-if="mdAndUp">
         <thead>
           <tr>
-            <th/>
+            <th />
 
             <th>
               <p class="standard">Standard</p>
@@ -27,10 +27,7 @@
         </thead>
 
         <tbody>
-          <tr
-            v-for="(item, index) in items"
-            :key="item.label"
-          >
+          <tr v-for="item in items" :key="item.label">
             <td class="label-column">
               {{ item.label }}
             </td>
@@ -109,10 +106,7 @@
 
             <table>
               <tbody>
-                <tr
-                  v-for="(item, index) in items"
-                  :key="item.label"
-                >
+                <tr v-for="item in items" :key="item.label">
                   <td class="label-column">
                     {{ item.label }}
                   </td>
@@ -153,33 +147,30 @@
 
             <table>
               <tbody>
-              <tr
-                v-for="(item, index) in items"
-                :key="item.label"
-              >
-                <td class="label-column">
-                  {{ item.label }}
-                </td>
-
-                <td>
-                  <v-icon
-                    v-if="item.includedInPremium === true"
-                    icon="far fa-check-circle"
-                    size="18"
-                  />
-
-                  <v-icon
-                    v-else-if="item.includedInPremium === false"
-                    icon="far fa-times-circle"
-                    size="18"
-                    color="red"
-                  />
-
-                  <span v-else>
-                  {{ item.includedInPremium }}
-                </span>
-                </td>
-              </tr>
+                <tr v-for="item in items" :key="item.label">
+                  <td class="label-column">
+                    {{ item.label }}
+                  </td>
+
+                  <td>
+                    <v-icon
+                      v-if="item.includedInPremium === true"
+                      icon="far fa-check-circle"
+                      size="18"
+                    />
+
+                    <v-icon
+                      v-else-if="item.includedInPremium === false"
+                      icon="far fa-times-circle"
+                      size="18"
+                      color="red"
+                    />
+
+                    <span v-else>
+                      {{ item.includedInPremium }}
+                    </span>
+                  </td>
+                </tr>
               </tbody>
             </table>
           </v-carousel-item>
@@ -190,36 +181,37 @@
 </template>
 
 <script setup lang="ts">
-import type { ComparisonItem } from "~/types/interface";
 import { useDisplay } from "vuetify";
+import type { PropType } from "vue";
+import type { ComparisonItem } from "~/types/interface";
 
-const { mdAndUp } = useDisplay()
+const { mdAndUp } = useDisplay();
 
 const props = defineProps({
   standardPrice: {
     type: String,
-    required: true
+    required: true,
   },
   premiumPrice: {
     type: String,
-    required: true
+    required: true,
   },
   items: {
     type: Array as PropType<Array<ComparisonItem>>,
-    required: true
-  }
+    required: true,
+  },
 });
 
-const height = computed(() => 150 + props.items.length * 48)
+const height = computed(() => 150 + props.items.length * 48);
 
-const carouselPos = ref(0)
+const carouselPos = ref(0);
 
 const goToPrevious = () => {
-  carouselPos.value = 0
+  carouselPos.value = 0;
 };
 
 const goToNext = () => {
-  carouselPos.value = 1
+  carouselPos.value = 1;
 };
 </script>
 
@@ -349,6 +341,4 @@ td:first-child {
     padding-right: 10px;
   }
 }
-
-
 </style>

+ 36 - 46
components/Contact/AddressSection.vue

@@ -5,27 +5,18 @@
         <ContactMap class="contact-map" />
       </v-col>
       <v-col cols="6" class="address-col px-8">
-
-        <h4>
-          <v-icon icon="fas fa-envelope"/> Pour nous écrire
-        </h4>
+        <h4><v-icon icon="fas fa-envelope" /> Pour nous écrire</h4>
 
         <v-card>
-          <div>
-            2iOpenService
-          </div>
-          <div>
-            217, rue Raoul Follereau
-          </div>
-          <div>
-            74300 - Cluses
-          </div>
+          <div>2iOpenService</div>
+          <div>217, rue Raoul Follereau</div>
+          <div>74300 - Cluses</div>
         </v-card>
 
         <div class="mb-6" />
 
         <h4>
-          <v-icon icon="fas fa-phone"/>
+          <v-icon icon="fas fa-phone" />
           Ou par téléphone
         </h4>
 
@@ -39,9 +30,7 @@
           <span v-else>
             <v-card>
               Contactez nous au
-              <a href="tel:+33972126017">
-                09 72 12 60 17
-              </a>
+              <a href="tel:+33972126017"> 09 72 12 60 17 </a>
             </v-card>
           </span>
         </div>
@@ -51,42 +40,43 @@
 </template>
 
 <script setup lang="ts">
-  const revealPhoneNumber = ref(false)
+const revealPhoneNumber = ref(false);
 </script>
 
 <style scoped lang="scss">
-  .container {
-    width: 70%;
-  }
+.container {
+  width: 70%;
+}
 
-  h4 {
-    display: flex;
-    flex-direction: row;
-    color: var(--primary-color);
-    font-size: 20px;
-    font-weight: 500;
-    margin: 24px 0;
-  }
+h4 {
+  display: flex;
+  flex-direction: row;
+  color: var(--primary-color);
+  font-size: 20px;
+  font-weight: 500;
+  margin: 24px 0;
+}
 
-  .v-icon {
-    margin-right: 16px;
-  }
+.v-icon {
+  margin-right: 16px;
+}
 
-  .address-col > div, .address-col > .v-card > div {
-    padding: 8px 16px;
-  }
+.address-col > div,
+.address-col > .v-card > div {
+  padding: 8px 16px;
+}
 
-  .v-card {
-    margin: 16px 64px;
-    padding: 12px;
-  }
+.v-card {
+  margin: 16px 64px;
+  padding: 12px;
+}
 
-  .v-btn {
-    margin: 16px 64px;
-  }
+.v-btn {
+  margin: 16px 64px;
+}
 
-  a {
-    color: var(--on-neutral-color);
-    text-decoration: underline;
-  }
+a {
+  color: var(--on-neutral-color);
+  text-decoration: underline;
+}
 </style>

+ 86 - 80
components/Contact/Form.vue

@@ -2,9 +2,7 @@
   <LayoutContainer>
     <div id="anchor" />
 
-    <h4>
-      <span class="line" /> Veuillez remplir le formulaire ci-dessous
-    </h4>
+    <h4><span class="line" /> Veuillez remplir le formulaire ci-dessous</h4>
 
     <v-form
       v-if="!contactRequestSent"
@@ -13,21 +11,17 @@
       @submit.prevent="submit"
     >
       <v-container>
-        <i>Les champs dont le nom est suivi d'un astérisque (*) sont obligatoires</i>
+        <i
+          >Les champs dont le nom est suivi d'un astérisque (*) sont
+          obligatoires</i
+        >
 
-        <h6>
-          Vos coordonnées
-        </h6>
+        <h6>Vos coordonnées</h6>
 
         <!-- Gender selection -->
         <v-row>
           <v-col cols="12">
-            <v-radio-group
-              v-model="contactRequest.gender"
-              row
-              mandatory
-              inline
-            >
+            <v-radio-group v-model="contactRequest.gender" row mandatory inline>
               <v-radio label="Madame" value="Madame" />
               <v-radio label="Monsieur" value="Monsieur" />
             </v-radio-group>
@@ -108,9 +102,7 @@
           </v-col>
         </v-row>
 
-        <h6>
-          Votre demande concerne *
-        </h6>
+        <h6>Votre demande concerne *</h6>
 
         <!-- Request type and product concerned  -->
         <v-row>
@@ -136,9 +128,7 @@
           </v-col>
         </v-row>
 
-        <h6>
-          Votre message
-        </h6>
+        <h6>Votre message</h6>
 
         <!-- Message  -->
         <v-row class="mb-8">
@@ -150,14 +140,19 @@
               required
               maxlength="400"
             />
-            <span class="remaining-cars-notice">{{ leftCars }} caractères restants</span>
+            <span class="remaining-cars-notice"
+              >{{ leftCars }} caractères restants</span
+            >
           </v-col>
         </v-row>
 
         <!-- Policy and  checkboxes -->
         <v-checkbox
           v-model="contactRequest.privacyPolicyAccepted"
-          :rules="[(v: boolean) => v || 'Vous devez accepter la politique de confidentialité']"
+          :rules="[
+            (v: boolean) =>
+              v || 'Vous devez accepter la politique de confidentialité',
+          ]"
           label="J'ai pris connaissance de la politique de confidentialité et j'accepte le traitement de mes données personnelles par Opentalent. *"
         />
 
@@ -168,7 +163,7 @@
 
         <div class="d-flex flex-row justify-center">
           <!-- @see https://github.com/hCaptcha/vue-hcaptcha -->
-          <LayoutCaptcha/>
+          <LayoutCaptcha />
         </div>
 
         <!-- Submit Button -->
@@ -190,84 +185,98 @@
       </v-container>
 
       <div class="legal">
-        Les données recueillies par Opentalent sont utilisées pour le traitement de votre demande et pour vous informer sur nos offres.
-        Elles sont destinées aux services Opentalent et à ses sous-traitants pour l’exécution des contrats. Conformément à la loi
-        "Informatique et Libertés du 6 Janvier 1978", vous disposez d’un droit d’accès, de modifications, de rectification et de suppression
-        des données vous concernant. Pour toute demande, adressez-vous à : Opentalent, 217 rue Raoul Follereau, 74300 CLUSES,
-        opentalent.fr s’engage à la confidentialité et à la protection de vos données.
+        Les données recueillies par Opentalent sont utilisées pour le traitement
+        de votre demande et pour vous informer sur nos offres. Elles sont
+        destinées aux services Opentalent et à ses sous-traitants pour
+        l’exécution des contrats. Conformément à la loi "Informatique et
+        Libertés du 6 Janvier 1978", vous disposez d’un droit d’accès, de
+        modifications, de rectification et de suppression des données vous
+        concernant. Pour toute demande, adressez-vous à : Opentalent, 217 rue
+        Raoul Follereau, 74300 CLUSES, opentalent.fr s’engage à la
+        confidentialité et à la protection de vos données.
       </div>
     </v-form>
 
     <div v-else class="confirmation-message d-flex flex-row justify-center">
       <v-card>
-        <v-icon icon="fas fa-check mr-1"/>
-        Votre demande de contact a bien été enregistrée, nous reviendrons vers vous dès que possible.
+        <v-icon icon="fas fa-check mr-1" />
+        Votre demande de contact a bien été enregistrée, nous reviendrons vers
+        vous dès que possible.
       </v-card>
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
+import { useRouter } from "vue-router";
+import { type ComputedRef, reactive, Ref } from "vue";
 import ContactRequest from "~/models/Maestro/ContactRequest";
 import { useEntityManager } from "~/composables/data/useEntityManager";
-import { useRouter } from "vue-router";
 
 const route = useRoute();
-const router = useRouter()
-const { em } = useEntityManager()
-
-const form: Ref<any | null> = ref(null)
-
-const requestTypes: Array<{id: string, label: string}> = [
-  { id: "CONTACT_REQUEST_INFORMATION", label: "Demande d'information"},
-  { id: "CONTACT_REQUEST_ESTIMATE", label: "Demande de devis"},
-  { id: "CONTACT_REQUEST_DEMO", label: "Demande de démonstration"},
-  { id: "CONTACT_REQUEST_OPTION", label: "Demande d'option supplémentaire"},
-  { id: "CONTACT_REQUEST_OTHER", label: "Autre"}
-]
-
-const products: Array<{id: string, label: string}> = [
-  { id: "PRODUCT_AGENDA", label: "Agenda culturel"},
-  { id: "PRODUCT_ARTIST", label: "Opentalent Artist"},
-  { id: "PRODUCT_SCHOOL", label: "Opentalent School"},
-  { id: "PRODUCT_MANAGER", label: "Opentalent Manager"},
-  { id: "PRODUCT_ADVERTISING", label: "Publicité"},
-  { id: "PRODUCT_OTHER", label: "Autre"}
-]
-
-const defaultRequestType = route.query.request ?? 'CONTACT_REQUEST_INFORMATION'
-
-//@ts-ignore
-const contactRequest: ContactRequest = reactive(em.newInstance(ContactRequest, { requestType: defaultRequestType }))
+const router = useRouter();
+const { em } = useEntityManager();
+
+const form: Ref<HTMLElement | null> = ref(null);
+
+const requestTypes: Array<{ id: string; label: string }> = [
+  { id: "CONTACT_REQUEST_INFORMATION", label: "Demande d'information" },
+  { id: "CONTACT_REQUEST_ESTIMATE", label: "Demande de devis" },
+  { id: "CONTACT_REQUEST_DEMO", label: "Demande de démonstration" },
+  { id: "CONTACT_REQUEST_OPTION", label: "Demande d'option supplémentaire" },
+  { id: "CONTACT_REQUEST_OTHER", label: "Autre" },
+];
+
+const products: Array<{ id: string; label: string }> = [
+  { id: "PRODUCT_AGENDA", label: "Agenda culturel" },
+  { id: "PRODUCT_ARTIST", label: "Opentalent Artist" },
+  { id: "PRODUCT_SCHOOL", label: "Opentalent School" },
+  { id: "PRODUCT_MANAGER", label: "Opentalent Manager" },
+  { id: "PRODUCT_ADVERTISING", label: "Publicité" },
+  { id: "PRODUCT_OTHER", label: "Autre" },
+];
+
+const defaultRequestType = route.query.request ?? "CONTACT_REQUEST_INFORMATION";
+
+// @ts-ignore
+const contactRequest: ContactRequest = reactive(
+  em.newInstance(ContactRequest, { requestType: defaultRequestType }),
+);
 
 // --- Validation ---
-const maxMessageLength = 2000
+const maxMessageLength = 2000;
 
-const leftCars: ComputedRef<number> = computed(() =>
-  maxMessageLength - (contactRequest.message ? contactRequest.message.length : 0)
-)
+const leftCars: ComputedRef<number> = computed(
+  () =>
+    maxMessageLength -
+    (contactRequest.message ? contactRequest.message.length : 0),
+);
 
-const validateName = (name: string | null) => !!name || "Le nom est obligatoire";
+const validateName = (name: string | null) =>
+  !!name || "Le nom est obligatoire";
 
-const validateSurname = (surname: string | null) => !!surname || "Le prénom est obligatoire";
+const validateSurname = (surname: string | null) =>
+  !!surname || "Le prénom est obligatoire";
 
 const validatePostalCode = (postalCode: string | null) =>
-  (!!postalCode && /^\d{5}$/.test(postalCode)) || "Le code postal doit être valide";
+  (!!postalCode && /^\d{5}$/.test(postalCode)) ||
+  "Le code postal doit être valide";
 
-const validateCity = (city: string | null) => !!city || "La ville est obligatoire";
+const validateCity = (city: string | null) =>
+  !!city || "La ville est obligatoire";
 
 const validateEmail = (email: string | null) =>
   (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide";
 
 const validatePhone = (email: string | null) =>
-  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) || "Le numéro de téléphone doit être valide";
+  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) ||
+  "Le numéro de téléphone doit être valide";
 
 const validateStructureName = (structureName: string | null) =>
   !!structureName || "Le nom de la structure est requis";
 
 const validateNonEmptyMessage = (message: string | null) =>
-  (!!message && message.length > 0) ||
-  "Le message ne peut pas être vide";
+  (!!message && message.length > 0) || "Le message ne peut pas être vide";
 
 const validateMessageLength = (message: string | null) =>
   (!!message && message.length <= maxMessageLength) ||
@@ -275,7 +284,7 @@ const validateMessageLength = (message: string | null) =>
 
 const contactRequestSent: Ref<boolean> = ref(false);
 
-const errorMsg: Ref<string | null> = ref(null)
+const errorMsg: Ref<string | null> = ref(null);
 
 /**
  * Submits the contact form.
@@ -287,33 +296,30 @@ const errorMsg: Ref<string | null> = ref(null)
  * @returns {void}
  */
 const submit = async (): Promise<void> => {
-  const { valid } = await form.value.validate()
+  const { valid } = await form.value.validate();
 
   if (!valid) {
-    contactRequestSent.value = false
-    return
+    contactRequestSent.value = false;
+    return;
   }
 
   try {
-    await em.persist(ContactRequest, contactRequest)
+    await em.persist(ContactRequest, contactRequest);
   } catch (e) {
-    errorMsg.value = "Une erreur s'est produite, nous sommes navrés pour le désagrément. Veuillez réessayer plus tard."
-    return
+    errorMsg.value =
+      "Une erreur s'est produite, nous sommes navrés pour le désagrément. Veuillez réessayer plus tard.";
+    return;
   }
 
   contactRequestSent.value = true;
-  errorMsg.value = null
+  errorMsg.value = null;
 
   // Défile vers le début de page pour afficher le message de confirmation
-  setTimeout(
-    () => router.push({ path: '', hash: '#anchor' }),
-    30
-  )
+  setTimeout(() => router.push({ path: "", hash: "#anchor" }), 30);
 };
 </script>
 
 <style scoped lang="scss">
-
 h4 {
   display: flex;
   flex-direction: row;

+ 31 - 40
components/Contact/Map.vue

@@ -1,8 +1,6 @@
 <template>
-<LayoutContainer>
-    <h4>
-      <span class="line" /> Contactez-nous
-    </h4>
+  <LayoutContainer>
+    <h4><span class="line" /> Contactez-nous</h4>
 
     <v-row>
       <v-col cols="12" md="6">
@@ -11,7 +9,7 @@
             ref="map"
             :zoom="15"
             :center="location"
-            :options="{scrollWheelZoom: false}"
+            :options="{ scrollWheelZoom: false }"
           >
             <l-tile-layer
               url="https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png"
@@ -20,41 +18,36 @@
               attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
             />
 
-            <l-marker
-              :icon="icon"
-              :lat-lng="location"
-            />
-<!--              <l-popup>-->
-<!--                <v-row>-->
-<!--                  <v-col cols="4" class="d-flex align-center">-->
-<!--                    <v-img src="/images/Opentalent_Griffe.png"/>-->
-<!--                  </v-col>-->
-<!--                  <v-col cols="8">-->
-<!--                    <div>-->
-<!--                      OPENTALENT-->
-<!--                    </div>-->
-<!--                    <div>-->
-<!--                      217, rue Raoul Follereau-->
-<!--                    </div>-->
-<!--                    <div>-->
-<!--                      74300 - Cluses-->
-<!--                    </div>-->
-<!--                  </v-col>-->
-<!--                </v-row>-->
-<!--              </l-popup>-->
+            <l-marker :icon="icon" :lat-lng="location" />
+            <!--              <l-popup>-->
+            <!--                <v-row>-->
+            <!--                  <v-col cols="4" class="d-flex align-center">-->
+            <!--                    <v-img src="/images/Opentalent_Griffe.png"/>-->
+            <!--                  </v-col>-->
+            <!--                  <v-col cols="8">-->
+            <!--                    <div>-->
+            <!--                      OPENTALENT-->
+            <!--                    </div>-->
+            <!--                    <div>-->
+            <!--                      217, rue Raoul Follereau-->
+            <!--                    </div>-->
+            <!--                    <div>-->
+            <!--                      74300 - Cluses-->
+            <!--                    </div>-->
+            <!--                  </v-col>-->
+            <!--                </v-row>-->
+            <!--              </l-popup>-->
           </l-map>
         </div>
       </v-col>
 
       <v-col cols="12" md="6" class="infos">
-        <div class="name mb-8">
-          Opentalent
-        </div>
+        <div class="name mb-8">Opentalent</div>
 
         <div class="d-flex flex-row align-center mb-8">
           <v-icon icon="fa fa-map-marker-alt" />
           <span>
-            217 rue Raoul Follereau<br/>
+            217 rue Raoul Follereau<br />
             74300 CLUSES
           </span>
         </div>
@@ -74,23 +67,22 @@
 </template>
 
 <script setup lang="ts">
-import 'leaflet/dist/leaflet.css'
-import { LMap, LTileLayer, LMarker, LIcon } from '@vue-leaflet/vue-leaflet'
-import L from 'leaflet';
+import "leaflet/dist/leaflet.css";
+import { LMap, LTileLayer, LMarker } from "@vue-leaflet/vue-leaflet";
+import L from "leaflet";
 
-const location = [46.075245, 6.570162]
+const location = [46.075245, 6.570162];
 
+// eslint-disable-next-line import/no-named-as-default-member
 const icon = L.icon({
-  iconUrl: '/images/pages/contact/map/Pointeur_Opentalent.png',
+  iconUrl: "/images/pages/contact/map/Pointeur_Opentalent.png",
   iconSize: [80, 80],
   iconAnchor: [22, 94],
   popupAnchor: [5, -100],
-})
-
+});
 </script>
 
 <style scoped lang="scss">
-
 h4 {
   display: flex;
   flex-direction: row;
@@ -116,7 +108,6 @@ h4 {
   }
 }
 
-
 .map-container {
   height: 500px;
   width: 100%;

+ 8 - 24
components/Formation/Catalogue.vue

@@ -6,18 +6,11 @@
           Découvrez notre catalogue de formation
         </LayoutUISubTitle>
 
-        <LayoutUITitle class="ml-8">
-          Catalogue
-        </LayoutUITitle>
+        <LayoutUITitle class="ml-8"> Catalogue </LayoutUITitle>
       </v-row>
 
       <v-row class="center-90 catalog">
-        <v-col
-          v-for="(course, index) in courses"
-          :key="index"
-          cols="12"
-          lg="4"
-        >
+        <v-col v-for="(course, index) in courses" :key="index" cols="12" lg="4">
           <v-card class="mb-4">
             <v-card-text>
               <div class="title-card-container">
@@ -35,9 +28,7 @@
               </p>
 
               <div class="objectives">
-                <h6 class="title-obj">
-                  Objectifs pédagogiques
-                </h6>
+                <h6 class="title-obj">Objectifs pédagogiques</h6>
 
                 <ul>
                   <li
@@ -49,14 +40,10 @@
                 </ul>
               </div>
 
-              <div class="badge-time">
-                Durée : {{ course.duration }}
-              </div>
+              <div class="badge-time">Durée : {{ course.duration }}</div>
 
               <div class="program">
-                <h6 class="title-obj">
-                  Programme
-                </h6>
+                <h6 class="title-obj">Programme</h6>
 
                 <v-row>
                   <v-col
@@ -95,12 +82,9 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
 import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import type { Training } from "~/types/interface";
 
-const { mdAndDown } = useDisplay();
-
 const downloadPdf = (pdfUrl: string) => {
   window.open(pdfUrl, "_blank");
 };
@@ -199,7 +183,6 @@ const courses: Array<Training> = [
 </script>
 
 <style scoped lang="scss">
-
 .catalog {
   padding: 2rem;
 
@@ -234,11 +217,12 @@ const courses: Array<Training> = [
     line-height: 1rem;
     color: var(--primary-color);
     margin-top: 1rem;
-    margin-bottom: .5rem;
+    margin-bottom: 0.5rem;
     height: 5rem;
   }
 
-  .objectives, .program {
+  .objectives,
+  .program {
     justify-content: space-between;
     align-items: center;
     background: var(--secondary-color-light);

+ 1 - 3
components/Formation/Certification.vue

@@ -3,9 +3,7 @@
     <LayoutContainer>
       <v-row class="center-90">
         <v-col cols="12" md="5">
-          <LayoutUISubTitle>
-            DES FORMATIONS CERTIFIÉES
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> DES FORMATIONS CERTIFIÉES </LayoutUISubTitle>
 
           <LayoutUITitle>
             Certification Qualiopi : Marque de certification

+ 1 - 3
components/Formation/OPCA.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="financing">
     <LayoutContainer class="alt-theme py-6 my-6">
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Financement des formations
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Financement des formations </LayoutUISubTitle>
       </v-row>
 
       <v-container>

+ 1 - 3
components/Formation/Participation.vue

@@ -3,9 +3,7 @@
     <LayoutContainer class="alt-theme">
       <v-row class="center-90">
         <v-col cols="12">
-          <LayoutUISubTitle>
-            Accessibilité
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> Accessibilité </LayoutUISubTitle>
         </v-col>
       </v-row>
 

+ 5 - 5
components/Formation/Presentation.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="presentation">
     <LayoutContainer>
       <v-row class="mt-6 center-90">
-        <LayoutUISubTitle>
-          Présentation de nos formations
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Présentation de nos formations </LayoutUISubTitle>
       </v-row>
 
       <v-row class="mb-12 center-90">
@@ -12,7 +10,8 @@
           <v-img
             src="/images/pages/formations/presentation/Un_programme_de_formation_complet_sur_nos_logiciels_Opentalent.jpg"
             alt="Mains tapant sur un clavier d’ordinateur portable"
-            class="programme-img1"/>
+            class="programme-img1"
+          />
         </v-col>
 
         <v-col md="6">
@@ -81,7 +80,8 @@ import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
   }
 }
 
-h3, p {
+h3,
+p {
   width: 35rem;
   max-width: 100%;
 

+ 6 - 13
components/Home/Besoin.vue

@@ -1,19 +1,16 @@
 <template>
   <LayoutContainer>
-    <v-row
-      class="mt-6"
-      justify="center"
-    >
+    <v-row class="mt-6" justify="center">
       <v-col cols="12" lg="6">
         <div class="screen-img ml-4" />
       </v-col>
 
-      <v-col cols="12" lg="6" class="detail-col" >
+      <v-col cols="12" lg="6" class="detail-col">
         <h3 class="mt-12">
           Une solution évolutive pour vous donner entière satisfaction
         </h3>
 
-        <p class="details ">
+        <p class="details">
           La satisfaction de nos clients est notre première motivation et nous
           nous tenons à votre écoute pour faire évoluer notre logiciel. <br />
           <b>Un besoin ?</b> <br />
@@ -26,15 +23,11 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-  import { useDisplay } from "vuetify";
-  const { mdAndDown } = useDisplay();
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-.v-row
-{
-  margin-left:auto !important;
+.v-row {
+  margin-left: auto !important;
   margin-right: auto !important;
   max-width: 1400px !important;
 }

+ 24 - 26
components/Home/Caroussel.vue

@@ -14,22 +14,18 @@ Carrousel de la page d'accueil
       :interval="10000"
       :cycle="true"
     >
-      <v-carousel-item
-        v-for="(item, index) in carouselItems"
-        :key="index"
-      >
+      <v-carousel-item v-for="(item, index) in carouselItems" :key="index">
         <v-row>
           <!-- Partie description (logo, description, bouton 'en savoir plus') -->
           <v-col cols="12" lg="6" class="col presentation">
             <nuxt-link :to="item.link">
-              <v-img
-                :src="item.logo"
-                :alt="item.logoAlt"
-                class="logo"
-              />
+              <v-img :src="item.logo" :alt="item.logoAlt" class="logo" />
             </nuxt-link>
 
-            <p class="description" v-html="mdAndUp ? item.description : item.descriptionSm" />
+            <p
+              class="description"
+              v-html="mdAndUp ? item.description : item.descriptionSm"
+            />
 
             <v-btn
               :to="item.link"
@@ -71,11 +67,7 @@ Carrousel de la page d'accueil
                 </v-card-text>
               </v-card>
 
-              <v-img
-                :src="item.image"
-                :alt="item.imageAlt"
-                class="image"
-              />
+              <v-img :src="item.image" :alt="item.imageAlt" class="image" />
             </v-row>
           </v-col>
         </v-row>
@@ -96,13 +88,14 @@ Carrousel de la page d'accueil
 
 <script setup lang="ts">
 import { useDisplay } from "vuetify";
+import type { Ref } from "vue";
 import type { CarouselItem } from "~/types/interface";
 import { useLayoutStore } from "~/stores/layoutStore";
 
 const { mdAndUp, lgAndUp } = useDisplay();
 
 // Index de la slide active
-let activeIndex: Ref<number> = ref(0);
+const activeIndex: Ref<number> = ref(0);
 
 const setActiveIndex = (index: number) => {
   activeIndex.value = index;
@@ -111,7 +104,8 @@ const setActiveIndex = (index: number) => {
 const carouselItems: Ref<Array<CarouselItem>> = ref([
   {
     logo: "/images/logos/opentalent/Logo_Opentalent_School-gris.png",
-    logoAlt: "Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique",
+    logoAlt:
+      "Logo Opentalent School - logiciel de gestion et de communication pour les établissements d’enseignement artistique",
     description:
       "Pour les petits comme pour les GRANDS établissements d’enseignement artistique tels que les écoles de musique, de danse, de théâtre, d'art, de cirque et conservatoire.<br> Il permet la gestion au quotidien et en temps réel de votre établissement, de gérer vos élèves et vos professeurs, vos emplois du temps, le suivi pédagogique, vos salles, la facturation et les encaissements…",
     descriptionSm:
@@ -130,7 +124,8 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
   },
   {
     logo: "/images/logos/opentalent/Logo_Opentalent_Artist-gris.png",
-    logoAlt: "Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes",
+    logoAlt:
+      "Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes",
     description:
       "Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque. <br> Gérez votre activité avec un logiciel de gestion et de communication au service de votre passion.",
     descriptionSm:
@@ -144,12 +139,14 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
     name: "Thierry Dupont ",
     school: "Orchestre d’harmonie",
     status: "Admin",
-    avatar: "/images/pages/home/carousel/Photo_de_profil_d_un_homme_jouant_du_banjo.png",
+    avatar:
+      "/images/pages/home/carousel/Photo_de_profil_d_un_homme_jouant_du_banjo.png",
     avatarAlt: "Photo de profil d’un homme jouant du banjo",
   },
   {
     logo: "/images/logos/opentalent/Logo_Opentalent_Manager-gris.png",
-    logoAlt: "Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités",
+    logoAlt:
+      "Logo Opentalent Manager - logiciel de gestion et de communication pour les fédérations, les confédérations et les collectivités",
     description:
       "La solution de mise en réseau des organisations culturelles.<br> Fédérations, confédérations et collectivités, utilisez une solution collaborative innovante et unique spécialement développée pour les réseaux culturels.",
     descriptionSm:
@@ -163,19 +160,19 @@ const carouselItems: Ref<Array<CarouselItem>> = ref([
     name: "Marie Voisin",
     school: "Réseau d'organisations culturelles ",
     status: "ADMIN",
-    avatar: "/images/pages/home/carousel/Photo_de_profil_d_une_femme_en_tailleur.png",
+    avatar:
+      "/images/pages/home/carousel/Photo_de_profil_d_une_femme_en_tailleur.png",
     avatarAlt: "Photo de profil d’une femme en tailleur",
   },
 ]);
 
-const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore();
 const onIntersect = (isIntersecting: boolean) => {
-  layoutStore.setIsBannerVisible(isIntersecting)
-}
+  layoutStore.setIsBannerVisible(isIntersecting);
+};
 </script>
 
 <style scoped lang="scss">
-
 /* ============= CAROUSEL ===============  */
 :deep(.v-carousel__controls) {
   display: none;
@@ -296,7 +293,8 @@ const onIntersect = (isIntersecting: boolean) => {
     padding: 0 !important;
   }
 
-  .school, .status {
+  .school,
+  .status {
     text-align: center;
     white-space: normal;
   }

+ 13 - 14
components/Home/EventAgenda.vue

@@ -10,17 +10,15 @@ Section "Agenda" de la page d'accueil
 
       <div class="d-flex align-center justify-center">
         <h3>
-          Retrouvez tous les événements et toutes les structures culturelles autour de chez vous
+          Retrouvez tous les événements et toutes les structures culturelles
+          autour de chez vous
         </h3>
       </div>
 
       <v-row justify="center" class="btn-container">
         <v-col cols="12" lg="6">
           <AgendaLink href="/">
-            <v-btn
-              append-icon="fas fa-arrow-right"
-              class="btn-event"
-            >
+            <v-btn append-icon="fas fa-arrow-right" class="btn-event">
               Découvrir l'agenda
             </v-btn>
           </AgendaLink>
@@ -49,17 +47,18 @@ const { lgAndUp } = useDisplay();
 </script>
 
 <style scoped>
-
 .container {
   height: 30rem;
-  background: linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
-  linear-gradient(
-    180deg,
-    rgba(14, 45, 50, 0.04) 0%,
-    rgba(14, 45, 50, 0.2) 100%
-  ),
-  linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
-  url("/images/components/agenda/Opentalent_Agenda_événement_culturel.jpg") no-repeat center 60%;
+  background:
+    linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
+    linear-gradient(
+      180deg,
+      rgba(14, 45, 50, 0.04) 0%,
+      rgba(14, 45, 50, 0.2) 100%
+    ),
+    linear-gradient(0deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)),
+    url("/images/components/agenda/Opentalent_Agenda_événement_culturel.jpg")
+      no-repeat center 60%;
   background-size: cover;
 }
 

+ 7 - 21
components/Home/Help.vue

@@ -13,28 +13,19 @@ Section "Besoin d'aide" de la page d'accueil
       </v-col>
 
       <v-col cols="12" lg="6" class="col">
-        <h3>
-          Notre équipe est à vos côtés
-          pour vous guider
-        </h3>
+        <h3>Notre équipe est à vos côtés pour vous guider</h3>
 
         <p>
           Besoin d’aide ? <br />
-          Vous souhaitez en savoir plus sur nos solutions ou vous avez
-          besoin d'assistance sur l'utilisation de l'un de nos logiciels ?
+          Vous souhaitez en savoir plus sur nos solutions ou vous avez besoin
+          d'assistance sur l'utilisation de l'un de nos logiciels ?
         </p>
 
         <v-row>
           <ul>
-            <li>
-              Ouvert du lundi au vendredi de 8h30 à 17h30
-            </li>
-            <li>
-              Support joignable par mail
-            </li>
-            <li>
-              De nombreux articles tutoriels accessibles 24h/24
-            </li>
+            <li>Ouvert du lundi au vendredi de 8h30 à 17h30</li>
+            <li>Support joignable par mail</li>
+            <li>De nombreux articles tutoriels accessibles 24h/24</li>
           </ul>
         </v-row>
 
@@ -52,14 +43,9 @@ Section "Besoin d'aide" de la page d'accueil
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-  import { useDisplay } from "vuetify";
-
-  const { mdAndDown} = useDisplay();
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-
 .v-container {
   margin: 64px auto 24px auto;
   padding: 16px;

+ 27 - 32
components/Home/Promotion.vue

@@ -48,7 +48,6 @@
         >
           <v-icon v-show="false" icon="fas fa-play" class="play-icon" />
         </v-img>
-
       </v-col>
     </v-row>
 
@@ -56,9 +55,7 @@
       <v-col>
         <v-row>
           <v-col>
-            <h3>
-              Un outil complet et intuitif pour chaque structure
-            </h3>
+            <h3>Un outil complet et intuitif pour chaque structure</h3>
           </v-col>
         </v-row>
 
@@ -66,23 +63,25 @@
           <v-col cols="12" lg="6">
             <v-row>
               <v-col cols="3">
-                <img src="/images/pages/home/promotion/Logiciel_en_ligne_SaaS.svg" alt="Icône nuage cloud" />
+                <img
+                  src="/images/pages/home/promotion/Logiciel_en_ligne_SaaS.svg"
+                  alt="Icône nuage cloud"
+                />
               </v-col>
               <v-col cols="9">
-                <p>
-                  Logiciel de gestion et communication en ligne
-                </p>
+                <p>Logiciel de gestion et communication en ligne</p>
               </v-col>
             </v-row>
 
             <v-row>
               <v-col cols="3">
-                <img src="/images/pages/home/promotion/Site_internet_intégré.svg" alt="Icône site internet" />
+                <img
+                  src="/images/pages/home/promotion/Site_internet_intégré.svg"
+                  alt="Icône site internet"
+                />
               </v-col>
               <v-col cols="9">
-                <p>
-                  Site web intégré et simple d’usage
-                </p>
+                <p>Site web intégré et simple d’usage</p>
               </v-col>
             </v-row>
           </v-col>
@@ -90,23 +89,25 @@
           <v-col cols="12" lg="6">
             <v-row>
               <v-col cols="3">
-                <img src="/images/pages/home/promotion/Visibilite_augmente_avec_l_agenda_culturel_Opentalent.svg" alt="Icône avion en papier" />
+                <img
+                  src="/images/pages/home/promotion/Visibilite_augmente_avec_l_agenda_culturel_Opentalent.svg"
+                  alt="Icône avion en papier"
+                />
               </v-col>
               <v-col cols="9">
-                <p>
-                  Augmentez votre visibilité avec l'agenda culturel
-                </p>
+                <p>Augmentez votre visibilité avec l'agenda culturel</p>
               </v-col>
             </v-row>
 
             <v-row>
               <v-col cols="3">
-                <img src="/images/pages/home/promotion/Icone_communication_en_reseau.svg" alt="Icône de deux enveloppes" />
+                <img
+                  src="/images/pages/home/promotion/Icone_communication_en_reseau.svg"
+                  alt="Icône de deux enveloppes"
+                />
               </v-col>
               <v-col cols="9">
-                <p>
-                  Communiquez en réseau
-                </p>
+                <p>Communiquez en réseau</p>
               </v-col>
             </v-row>
           </v-col>
@@ -116,21 +117,15 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-
-import { useDisplay } from "vuetify";
-
-const { mdAndUp } = useDisplay()
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-
 .highlight {
   color: var(--secondary-color);
 }
 
 .v-row.gestion {
-  >.v-col {
+  > .v-col {
     margin-bottom: 4rem;
     background: var(--primary-color);
 
@@ -168,7 +163,7 @@ const { mdAndUp } = useDisplay()
   }
 
   @media (max-width: 960px) {
-    >.v-col {
+    > .v-col {
       margin-bottom: 0;
     }
 
@@ -264,9 +259,9 @@ const { mdAndUp } = useDisplay()
       }
     }
 
-    >.v-col-12 {
-      padding-top : 0;
-      padding-bottom : 0;
+    > .v-col-12 {
+      padding-top: 0;
+      padding-bottom: 0;
     }
 
     .v-col-3 {

+ 40 - 49
components/Home/Reviews.vue

@@ -1,26 +1,19 @@
 <template>
   <LayoutContainer>
     <div class="container-1">
-      <LayoutUISectionTitle>
-        Avis Clients
-      </LayoutUISectionTitle>
+      <LayoutUISectionTitle> Avis Clients </LayoutUISectionTitle>
 
-      <h4>
-        C'est vous qui le dites
-      </h4>
+      <h4>C'est vous qui le dites</h4>
     </div>
 
     <!-- Ecrans larges -->
     <div v-if="lgAndUp" class="container-2">
-
       <!-- Partie 1 : Avis clients -->
       <v-row justify="center">
         <div class="col-review">
           <v-col cols="6">
             <v-card class="left mx-auto">
-              <v-card-title>
-                Patrice CATHELIN
-              </v-card-title>
+              <v-card-title> Patrice CATHELIN </v-card-title>
 
               <v-card-text>
                 <p>
@@ -44,9 +37,7 @@
 
           <v-col cols="6">
             <v-card class="right mx-auto">
-              <v-card-title>
-                Karine GIRAUD
-              </v-card-title>
+              <v-card-title> Karine GIRAUD </v-card-title>
 
               <v-card-text>
                 <p>
@@ -60,9 +51,7 @@
               </v-card-text>
 
               <div class="card-footer">
-                <small class="status">
-                  Secrétaire administrative
-                </small>
+                <small class="status"> Secrétaire administrative </small>
 
                 <small class="structure">
                   Association Musicale Sainte Cécile de Lagord (17)
@@ -77,9 +66,7 @@
         <div class="col-review">
           <v-col cols="6">
             <v-card class="left mx-auto">
-              <v-card-title>
-                Laurent BEL
-              </v-card-title>
+              <v-card-title> Laurent BEL </v-card-title>
 
               <v-card-text>
                 <p>
@@ -106,9 +93,7 @@
 
           <v-col cols="6">
             <v-card class="right mx-auto">
-              <v-card-title>
-                Philippe BORY
-              </v-card-title>
+              <v-card-title> Philippe BORY </v-card-title>
 
               <v-card-text>
                 <p>
@@ -121,9 +106,7 @@
               </v-card-text>
 
               <div class="card-footer">
-                <small class="status">
-                  Personnel administratif
-                </small>
+                <small class="status"> Personnel administratif </small>
 
                 <small class="structure">
                   École d'Arts de Saint-Michel-sur-Orge (91)
@@ -144,11 +127,7 @@
     <div v-else class="container-sm">
       <v-row>
         <v-col cols="12">
-          <Carousel
-            :itemsToShow="1"
-            :wrap-around="true"
-            ref="reviewCarousel"
-          >
+          <Carousel ref="reviewCarousel" :items-to-show="1" :wrap-around="true">
             <Slide v-for="(card, index) in cards" :key="index">
               <v-card>
                 <v-card-title>
@@ -174,10 +153,7 @@
 
       <v-row class="justify-center align-center mb-8">
         <v-col class="d-flex justify-space-around align-center">
-          <v-btn
-            icon="fas fa-arrow-left-long"
-            @click="goToPrevious"
-          />
+          <v-btn icon="fas fa-arrow-left-long" @click="goToPrevious" />
 
           <div class="carousel-controls">
             <div
@@ -188,14 +164,11 @@
             />
           </div>
 
-          <v-btn
-            icon="fas fa-arrow-right-long"
-            @click="goToNext"
-          />
+          <v-btn icon="fas fa-arrow-right-long" @click="goToNext" />
         </v-col>
       </v-row>
 
-      <CommonCarouselClients :items="items" class="alt-theme pt-12"/>
+      <CommonCarouselClients :items="items" class="alt-theme pt-12" />
     </div>
   </LayoutContainer>
 </template>
@@ -204,6 +177,7 @@
 import { Carousel, Slide } from "vue3-carousel";
 import "vue3-carousel/dist/carousel.css";
 import { useDisplay } from "vuetify";
+import type { Ref } from "vue";
 import type { Review } from "~/types/interface";
 
 const { lgAndUp } = useDisplay();
@@ -217,7 +191,7 @@ const state = ref({
 const goToNext = () => {
   reviewCarousel.value!.next();
   state.value.activeIndex = (state.value.activeIndex + 1) % cards.length;
-}
+};
 
 const goToPrevious = () => {
   reviewCarousel.value!.prev();
@@ -225,7 +199,7 @@ const goToPrevious = () => {
     state.value.activeIndex - 1 < 0
       ? cards.length - 1
       : state.value.activeIndex - 1;
-}
+};
 
 const cards: Array<Review> = [
   {
@@ -258,18 +232,35 @@ const cards: Array<Review> = [
   },
 ];
 
-const items: Ref<Array<{ src: string, alt: string }>> = ref([
-  { src: "/images/pages/home/reviews/Logo_Conservatoire_Les_Ateliers_des_Arts_Agglomeration_du_Puy-en-Velay.svg", alt: "Logo du Conservatoire « Les ateliers des arts" },
-  { src: "/images/pages/home/reviews/Logo_Conservatoire-Senlis.png", alt: "Logo du Conservatoire de Senlis" },
-  { src: "/images/pages/home/reviews/Logo_Ecole_de_Musique-Sausheim.png", alt: "Logo de l’École de musique Sausheim" },
-  { src: "/images/pages/home/reviews/Logo_Conservatoire_Marly_le_Roi-Roger_Bourdin.jpeg", alt: "Logo du Conservatoire Marly le Roi Roger Bourdin" },
-  { src: "/images/pages/home/reviews/Logo_Conservatoire_de_Musiques_et_de_Danses_du_Thouarsais.jpeg", alt: "Logo du Conservatoire de Musique et de Danse du Thouarsais" },
-  { src: "/images/pages/home/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg", alt: "Logo du Conservatoire d’Annemasse" },
+const items: Ref<Array<{ src: string; alt: string }>> = ref([
+  {
+    src: "/images/pages/home/reviews/Logo_Conservatoire_Les_Ateliers_des_Arts_Agglomeration_du_Puy-en-Velay.svg",
+    alt: "Logo du Conservatoire « Les ateliers des arts",
+  },
+  {
+    src: "/images/pages/home/reviews/Logo_Conservatoire-Senlis.png",
+    alt: "Logo du Conservatoire de Senlis",
+  },
+  {
+    src: "/images/pages/home/reviews/Logo_Ecole_de_Musique-Sausheim.png",
+    alt: "Logo de l’École de musique Sausheim",
+  },
+  {
+    src: "/images/pages/home/reviews/Logo_Conservatoire_Marly_le_Roi-Roger_Bourdin.jpeg",
+    alt: "Logo du Conservatoire Marly le Roi Roger Bourdin",
+  },
+  {
+    src: "/images/pages/home/reviews/Logo_Conservatoire_de_Musiques_et_de_Danses_du_Thouarsais.jpeg",
+    alt: "Logo du Conservatoire de Musique et de Danse du Thouarsais",
+  },
+  {
+    src: "/images/pages/home/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg",
+    alt: "Logo du Conservatoire d’Annemasse",
+  },
 ]);
 </script>
 
 <style scoped>
-
 .container-1 {
   background-color: var(--neutral-color);
 

+ 11 - 22
components/Home/Solution.vue

@@ -4,13 +4,9 @@ Section "Solutions" de la page d'accueil
 
 <template>
   <LayoutContainer>
-    <LayoutUISectionTitle class="alt-theme">
-      3 solutions
-    </LayoutUISectionTitle>
+    <LayoutUISectionTitle class="alt-theme"> 3 solutions </LayoutUISectionTitle>
 
-    <h4 class="text-center" >
-      Trouvez la solution faite pour vous
-    </h4>
+    <h4 class="text-center">Trouvez la solution faite pour vous</h4>
 
     <v-row class="solutions center-90">
       <v-col
@@ -21,15 +17,13 @@ Section "Solutions" de la page d'accueil
       >
         <v-container>
           <div class="d-flex justify-center align-left flex-column">
-            <small>
-              Opentalent
-            </small>
+            <small> Opentalent </small>
 
             <h2>
               {{ solution.name }}
             </h2>
 
-            <v-divider thickness="2"/>
+            <v-divider thickness="2" />
 
             <p>
               {{ solution.description }}
@@ -37,7 +31,7 @@ Section "Solutions" de la page d'accueil
 
             <nuxt-link :to="solution.link">
               <v-row>
-                <div :class="['image-container', solution.class]" >
+                <div :class="['image-container', solution.class]">
                   <v-img :src="solution.image" />
                   <v-btn v-if="xlAndUp">Découvrir</v-btn>
                 </div>
@@ -58,10 +52,7 @@ Section "Solutions" de la page d'accueil
 
               <v-col cols="12" sm="6">
                 <ul>
-                  <li
-                    v-for="(sol, i) in solution.solutions.slice(4)"
-                    :key="i"
-                  >
+                  <li v-for="(sol, i) in solution.solutions.slice(4)" :key="i">
                     {{ sol }}
                   </li>
                 </ul>
@@ -77,7 +68,7 @@ Section "Solutions" de la page d'accueil
     </v-row>
 
     <v-container class="footer">
-      <v-row >
+      <v-row>
         <v-col cols="12">
           <p>* en option</p>
         </v-col>
@@ -87,11 +78,10 @@ Section "Solutions" de la page d'accueil
 </template>
 
 <script setup lang="ts">
-
-import type { SolutionItem } from "~/types/interface";
 import { useDisplay } from "vuetify";
+import type { SolutionItem } from "~/types/interface";
 
-const { xlAndUp, lgAndDown } = useDisplay()
+const { xlAndUp, lgAndDown } = useDisplay();
 
 const solutions: Array<SolutionItem> = [
   {
@@ -128,7 +118,7 @@ const solutions: Array<SolutionItem> = [
       "Communication",
       "Site internet intégré",
       "Statistiques",
-    ]
+    ],
   },
   {
     name: "Manager",
@@ -183,7 +173,7 @@ h4 {
 
 @media (min-width: 600px) {
   h3 {
-    margin-bottom: 3rem
+    margin-bottom: 3rem;
   }
 }
 
@@ -352,7 +342,6 @@ h4 {
         padding-bottom: 0;
       }
     }
-
   }
 }
 

+ 66 - 67
components/JoinUs/Form.vue

@@ -1,20 +1,12 @@
 <template>
   <div>
-    <v-card
-      v-if="!jobApplicationSent"
-    >
-      <v-card-title
-        class="text-center"
-      >
+    <v-card v-if="!jobApplicationSent">
+      <v-card-title class="text-center">
         Formulaire de Candidature
       </v-card-title>
 
       <v-card-text>
-        <v-form
-          ref="form"
-          validate-on="submit lazy"
-          @submit.prevent="submit"
-        >
+        <v-form ref="form" validate-on="submit lazy" @submit.prevent="submit">
           <v-text-field
             id="jobApplicationName"
             v-model="jobApplication.name"
@@ -45,7 +37,6 @@
             :rules="[validateEmail]"
             label="Email*"
             required
-
           />
 
           <v-file-input
@@ -74,87 +65,88 @@
             label="Message*"
             required
           />
-          <span class="remaining-cars-notice">{{ leftCars }} caractères restants</span>
+          <span class="remaining-cars-notice"
+            >{{ leftCars }} caractères restants</span
+          >
 
           <div class="d-flex flex-column align-center mt-4">
             <!-- @see https://github.com/hCaptcha/vue-hcaptcha -->
-            <LayoutCaptcha/>
+            <LayoutCaptcha />
           </div>
         </v-form>
       </v-card-text>
 
-      <p class="text-right mr-6">
-        * Champs obligatoires
-      </p>
+      <p class="text-right mr-6">* Champs obligatoires</p>
 
       <v-card-actions class="justify-center">
-        <v-btn
-          class="btn-more mb-4 submit"
-          @click="submit"
-        >
-          Envoyer
-        </v-btn>
+        <v-btn class="btn-more mb-4 submit" @click="submit"> Envoyer </v-btn>
       </v-card-actions>
     </v-card>
   </div>
 </template>
 
 <script setup lang="ts">
+import { type ComputedRef, reactive, Ref } from "vue";
 import ContactRequest from "~/models/Maestro/ContactRequest";
 import { useEntityManager } from "~/composables/data/useEntityManager";
 import JobApplication from "~/models/Maestro/JobApplication";
 import FileUtils from "~/services/utils/FileUtils";
 
-const { em } = useEntityManager()
+const { em } = useEntityManager();
 
-const form: Ref<any | null> = ref(null)
+const form: Ref<HTMLElement | null> = ref(null);
 
-const jobApplicationSent: Ref<boolean> = ref(false)
+const jobApplicationSent: Ref<boolean> = ref(false);
 
-const emit = defineEmits(['submit'])
+const emit = defineEmits(["submit"]);
 
-//@ts-ignore
-const jobApplication: ContactRequest = reactive(em.newInstance(JobApplication))
+// @ts-ignore
+const jobApplication: ContactRequest = reactive(em.newInstance(JobApplication));
 
-const resumeUpload = ref(null)
+const resumeUpload = ref(null);
 
-const motivationLetterUpload = ref(null)
+const motivationLetterUpload = ref(null);
 
 // --- Validation ---
-const maxMessageLength = 2000
+const maxMessageLength = 2000;
 
-const leftCars: ComputedRef<number> = computed(() =>
-  maxMessageLength - (jobApplication.message ? jobApplication.message.length : 0)
-)
+const leftCars: ComputedRef<number> = computed(
+  () =>
+    maxMessageLength -
+    (jobApplication.message ? jobApplication.message.length : 0),
+);
 
 // Taille maximum en Mo
-const maxFileSize = 5
+const maxFileSize = 5;
 
-const validateName = (name: string | null) => !!name || "Le nom est obligatoire";
+const validateName = (name: string | null) =>
+  !!name || "Le nom est obligatoire";
 
-const validateSurname = (surname: string | null) => !!surname || "Le prénom est obligatoire";
+const validateSurname = (surname: string | null) =>
+  !!surname || "Le prénom est obligatoire";
 
 const validateEmail = (email: string | null) =>
   (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide";
 
 const validatePhone = (email: string | null) =>
-  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) || "Le numéro de téléphone doit être valide";
+  (!!email && /^((\+|00)33\s?|0)[1-7]([\s.]?\d{2}){4}$/.test(email)) ||
+  "Le numéro de téléphone doit être valide";
 
 const validateResume = () =>
-  resumeUpload.value !== null && resumeUpload.value[0] !== null || "Vous devez joindre un CV à l'un des formats indiqués";
+  (resumeUpload.value !== null && resumeUpload.value[0] !== null) ||
+  "Vous devez joindre un CV à l'un des formats indiqués";
 
 const validateFileSize = () =>
-  resumeUpload.value !== null
-  && resumeUpload.value[0] !== null
-  //@ts-ignore
-  && resumeUpload.value[0].size < (maxFileSize * 1024 * 1024)
-  || "La taille du fichier ne doit pas dépasser " + maxFileSize + " Mo";
+  (resumeUpload.value !== null &&
+    resumeUpload.value[0] !== null &&
+    // @ts-ignore
+    resumeUpload.value[0].size < maxFileSize * 1024 * 1024) ||
+  "La taille du fichier ne doit pas dépasser " + maxFileSize + " Mo";
 
 const validateNonEmptyMessage = (message: string | null) =>
-  (!!message && message.length > 0) ||
-  "Le message ne peut pas être vide";
+  (!!message && message.length > 0) || "Le message ne peut pas être vide";
 
-const validateMessageLength = async (message: string | null) =>
+const validateMessageLength = (message: string | null) =>
   (!!message && message.length <= maxMessageLength) ||
   "Le message ne doit pas dépasser " + maxMessageLength + " caractères";
 
@@ -162,32 +154,39 @@ const validateMessageLength = async (message: string | null) =>
  * Soumet le formulaire de candidature (boite de dialogue)
  */
 const submit = async () => {
-  const { valid } = await form.value.validate()
+  const { valid } = await form.value.validate();
 
   if (!valid) {
-    jobApplicationSent.value = false
-    return
+    jobApplicationSent.value = false;
+    return;
   }
 
-  jobApplication.resume = (resumeUpload.value !== null && resumeUpload.value[0] !== null) ?
-    {
-      //@ts-ignore
-      'name': resumeUpload.value[0].name,
-      'content': await FileUtils.blobToBase64(resumeUpload.value[0])
-    } : null
-
-  jobApplication.motivationLetter = (motivationLetterUpload.value !== null && motivationLetterUpload.value[0] !== null) ?
-    {
-      //@ts-ignore
-      'name': motivationLetterUpload.value[0].name,
-      'content': await FileUtils.blobToBase64(motivationLetterUpload.value[0])
-    } : null
-
-  await em.persist(JobApplication, jobApplication)
+  jobApplication.resume =
+    resumeUpload.value !== null && resumeUpload.value[0] !== null
+      ? {
+          // @ts-ignore
+          name: resumeUpload.value[0].name,
+          content: await FileUtils.blobToBase64(resumeUpload.value[0]),
+        }
+      : null;
+
+  jobApplication.motivationLetter =
+    motivationLetterUpload.value !== null &&
+    motivationLetterUpload.value[0] !== null
+      ? {
+          // @ts-ignore
+          name: motivationLetterUpload.value[0].name,
+          content: await FileUtils.blobToBase64(
+            motivationLetterUpload.value[0],
+          ),
+        }
+      : null;
+
+  await em.persist(JobApplication, jobApplication);
 
   jobApplicationSent.value = true;
 
-  emit('submit')
+  emit("submit");
 };
 </script>
 

+ 16 - 30
components/JoinUs/MissionDetail.vue

@@ -17,18 +17,12 @@
       <div>
         <div v-if="pending">
           <v-row class="justify-center progress">
-            <v-progress-circular
-              indeterminate
-              color="grey"
-            />
+            <v-progress-circular indeterminate color="grey" />
           </v-row>
         </div>
 
         <div v-else-if="job !== null">
-          <CommonMeta
-            :title="job.title"
-            description="Offre d'emploi"
-          />
+          <CommonMeta :title="job.title" description="Offre d'emploi" />
 
           <h3>
             {{ job.title }}
@@ -54,7 +48,7 @@
             <v-col cols="12" md="6">
               <v-row>
                 <div>
-                  Secteur d'activité : <b>{{ job.sector.join(', ') }}</b>
+                  Secteur d'activité : <b>{{ job.sector.join(", ") }}</b>
                 </div>
               </v-row>
 
@@ -68,22 +62,15 @@
           </v-row>
 
           <v-row class="center-90">
-            <p
-              v-html="job.content"
-              class="center-90 description mb-12"
-            />
+            <p class="center-90 description mb-12" v-html="job.content" />
           </v-row>
 
           <v-row class="d-flex justify-center align-center">
-            <v-btn class="btn-apply mb-12">
-              Je postule
-            </v-btn>
+            <v-btn class="btn-apply mb-12"> Je postule </v-btn>
           </v-row>
 
           <v-row class="d-flex justify-space-between center-90">
-            <p>
-              MOTS CLÉS
-            </p>
+            <p>MOTS CLÉS</p>
             <div v-if="mdAndUp">
               <p>PARTAGER</p>
             </div>
@@ -91,7 +78,7 @@
 
           <v-row class="d-flex justify-space-between mb-8 center-90">
             <p class="key-word mt-3">
-              <span v-for="tag in job.tags" class="mr-2">
+              <span v-for="tag in job.tags" :key="tag.id" class="mr-2">
                 {{ tag.name }}
               </span>
             </p>
@@ -105,35 +92,34 @@
         </div>
       </div>
     </div>
-
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
 import "vue3-carousel/dist/carousel.css";
+import { useDisplay } from "vuetify";
 import { useEntityFetch } from "~/composables/data/useEntityFetch";
 import JobPosting from "~/models/Maestro/JobPosting";
 import DateUtils from "~/services/utils/dateUtils";
-import { useDisplay } from "vuetify";
 
-const { mdAndUp, smAndDown } = useDisplay()
+const { mdAndUp, smAndDown } = useDisplay();
 
 const route = useRoute();
-const { fetch } = useEntityFetch()
+const { fetch } = useEntityFetch();
 
-const jobId: number = parseInt(route.params.id as string)
+const jobId: number = parseInt(route.params.id as string);
 if (!jobId || isNaN(jobId)) {
-  throw new Error('Missing or invalid id')
+  throw new Error("Missing or invalid id");
 }
 
-const { data: job, pending } = fetch(JobPosting, jobId)
+const { data: job, pending } = fetch(JobPosting, jobId);
 
 const formatDate = (date: string) => {
-  console.log(date)
+  console.log(date);
   if (!date) {
-    return "-"
+    return "-";
   }
-  return DateUtils.format(new Date(date), "dd/MM/yyyy")
+  return DateUtils.format(new Date(date), "dd/MM/yyyy");
 };
 </script>
 

+ 35 - 54
components/JoinUs/Missions.vue

@@ -2,36 +2,24 @@
   <LayoutContainer>
     <div v-if="pending">
       <v-row class="justify-center progress">
-        <v-progress-circular
-          indeterminate
-          color="grey"
-        />
+        <v-progress-circular indeterminate color="grey" />
       </v-row>
     </div>
 
     <div
-      v-else
       v-for="(job, index) in jobs"
+      v-else
       :key="index"
       class="mission-container"
     >
       <div class="title-container">
-        <NuxtLink
-          :to="`/nous-rejoindre/${job.id}`"
-          class="title"
-        >
+        <NuxtLink :to="`/nous-rejoindre/${job.id}`" class="title">
           {{ job.title }} - {{ job.contractType }}
 
-          <v-icon
-            v-if="job.featured"
-            class="star fas fa-star"
-          />
+          <v-icon v-if="job.featured" class="star fas fa-star" />
         </NuxtLink>
 
-        <v-btn
-          :to="`/nous-rejoindre/${job.id}`"
-          class="btn-more"
-        >
+        <v-btn :to="`/nous-rejoindre/${job.id}`" class="btn-more">
           En savoir plus
         </v-btn>
       </div>
@@ -50,8 +38,8 @@
           v-if="jobCollection && jobCollection.pagination"
           :model-value="page"
           :pagination="jobCollection.pagination"
-          @update:model-value="onPageUpdated"
           class="mt-4"
+          @update:model-value="onPageUpdated"
         />
       </v-col>
     </v-row>
@@ -59,7 +47,7 @@
     <v-row class="mb-6">
       <v-col cols="12">
         <p class="apply-now">
-          Nous sommes toujours à la recherche de nouveaux talents.<br/>
+          Nous sommes toujours à la recherche de nouveaux talents.<br />
           N'hésitez pas à déposer votre candidature ci-dessous :
         </p>
       </v-col>
@@ -67,10 +55,7 @@
 
     <v-row>
       <v-col cols="12">
-        <v-btn
-          class="btn-send"
-          @click="dialog = true"
-        >
+        <v-btn class="btn-send" @click="dialog = true">
           Envoyer ma candidature
         </v-btn>
       </v-col>
@@ -85,75 +70,71 @@
       :retain-focus="false"
     >
       <div v-if="!jobApplicationSent">
-        <JoinUsForm @submit="onFormSubmit"/>
+        <JoinUsForm @submit="onFormSubmit" />
 
-        <v-btn @click="dialog = false">
-          Annuler
-        </v-btn>
+        <v-btn @click="dialog = false"> Annuler </v-btn>
       </div>
       <div v-else>
         <v-card class="pa-6 text-center">
-          Votre candidature a bien été envoyée, merci de votre intérêt.<br/>
+          Votre candidature a bien été envoyée, merci de votre intérêt.<br />
           Nous vous recontacterons dès que possible.
         </v-card>
 
-        <v-btn @click="dialog = false">
-          Fermer
-        </v-btn>
+        <v-btn @click="dialog = false"> Fermer </v-btn>
       </div>
     </v-dialog>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
+import type { ComputedRef, Ref } from "vue";
 import { useEntityFetch } from "~/composables/data/useEntityFetch";
 import JobPosting from "~/models/Maestro/JobPosting";
 import type { AnyJson } from "~/types/data";
 
-const { fetchCollection } = useEntityFetch()
+const { fetchCollection } = useEntityFetch();
 
 const page: Ref<number> = ref(1);
 
 const query: ComputedRef<AnyJson> = computed(() => {
-    return { type: "ENTREPRISE", page: page.value }
-  }
-)
+  return { type: "ENTREPRISE", page: page.value };
+});
 
-const { data: jobCollection, pending, refresh } = fetchCollection(
-  JobPosting,
-  null,
-  query
-)
+const {
+  data: jobCollection,
+  pending,
+  refresh,
+} = fetchCollection(JobPosting, null, query);
 
 // TODO: voir pourquoi on se retrouve obligé de passer par ce computed pour avoir le type TS correct?
 const jobs: ComputedRef<JobPosting[]> = computed(() => {
-  return jobCollection.value !== null ?
-         jobCollection.value.items as JobPosting[] :
-         []
-})
+  return jobCollection.value !== null
+    ? (jobCollection.value.items as JobPosting[])
+    : [];
+});
 
 const onPageUpdated = async (newVal: number): Promise<void> => {
-  page.value = newVal
+  page.value = newVal;
 
-  pending.value = true
-  await refresh()
+  pending.value = true;
+  await refresh();
 
   // TODO: remplacer par un watcher sur pending?
   setTimeout(
-    async () => await navigateTo({ path: '', hash: '#join-us-anchor' }),
-    200
-  )
-}
+    async () => await navigateTo({ path: "", hash: "#join-us-anchor" }),
+    200,
+  );
+};
 
 /**
  * Faut-il afficher la boite de dialogue de candidature
  */
 const dialog = ref(false);
-const jobApplicationSent: Ref<boolean> = ref(false)
+const jobApplicationSent: Ref<boolean> = ref(false);
 
 const onFormSubmit = () => {
-  jobApplicationSent.value = true
-}
+  jobApplicationSent.value = true;
+};
 </script>
 
 <style scoped lang="scss">

+ 33 - 37
components/Layout/AnchoredSection.vue

@@ -1,55 +1,51 @@
 <template>
-  <div
-    :id="id"
-    ref="section"
-    v-scroll="onScroll"
-  >
-    <slot/>
+  <div :id="id" ref="section" v-scroll="onScroll">
+    <slot />
   </div>
 </template>
 
 <script setup lang="ts">
-  import { useLayoutStore } from "~/stores/layoutStore";
+import type { Ref } from "vue";
+import { useLayoutStore } from "~/stores/layoutStore";
 
-  const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore();
 
-  const props = defineProps({
-    id: {
-      type: String,
-      required: true
-    }
-  })
+const props = defineProps({
+  id: {
+    type: String,
+    required: true,
+  },
+});
 
-  if (!props.id) {
-    throw new Error("Anchor's id is missing")
-  }
+if (!props.id) {
+  throw new Error("Anchor's id is missing");
+}
 
-  const section: Ref<HTMLElement | null> = ref(null)
+const section: Ref<HTMLElement | null> = ref(null);
 
-  layoutStore.setIsAnchoredSectionOnScreen(props.id, false)
+layoutStore.setIsAnchoredSectionOnScreen(props.id, false);
 
-  const top: Ref<number | null> = ref(null)
-  const bottom: Ref<number | null> = ref(null)
+const top: Ref<number | null> = ref(null);
+const bottom: Ref<number | null> = ref(null);
 
-  const onScroll = (scroll: any) => {
-    top.value = section.value!.offsetTop
-    bottom.value = section.value!.offsetTop + section.value!.offsetHeight
+// @ts-ignore
+const onScroll = (scroll) => {
+  top.value = section.value!.offsetTop;
+  bottom.value = section.value!.offsetTop + section.value!.offsetHeight;
 
-    if (top.value === null || bottom.value === null) {
-      return
-    }
+  if (top.value === null || bottom.value === null) {
+    return;
+  }
 
-    const screenVerticalCenter = scroll.target.documentElement.scrollTop + window.innerHeight / 2
+  const screenVerticalCenter =
+    scroll.target.documentElement.scrollTop + window.innerHeight / 2;
 
-    const active = screenVerticalCenter > top.value && screenVerticalCenter < bottom.value
-    if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
-        layoutStore.setIsAnchoredSectionOnScreen(
-          props.id,
-          active
-        )
-    }
+  const active =
+    screenVerticalCenter > top.value && screenVerticalCenter < bottom.value;
+  if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
+    layoutStore.setIsAnchoredSectionOnScreen(props.id, active);
   }
+};
 </script>
 
-<style scoped>
-</style>
+<style scoped></style>

+ 14 - 13
components/Layout/Captcha.vue

@@ -17,9 +17,10 @@
 
 <script setup lang="ts">
 import VueHcaptcha from "@hcaptcha/vue3-hcaptcha";
+import type { Ref } from "vue";
 
-const runtimeConfig = useRuntimeConfig()
-const siteKey = runtimeConfig.public.hCaptchaSiteKey
+const runtimeConfig = useRuntimeConfig();
+const siteKey = runtimeConfig.public.hCaptchaSiteKey;
 
 const verified: Ref<boolean> = ref(false);
 const expired: Ref<boolean> = ref(false);
@@ -29,43 +30,43 @@ const error: Ref<string> = ref("");
 
 // La case étant masquée, si elle est cochée, alors on peut en déduire
 // qu'on a affaire un robot (voir mécanisme du honey pot)
-const honeyPotChecked: Ref<boolean> = ref(false)
+const honeyPotChecked: Ref<boolean> = ref(false);
 
-const emit = defineEmits(['update'])
+const emit = defineEmits(["update"]);
 
 const validateCaptchaState = () =>
-  verified.value && !honeyPotChecked.value ||
+  (verified.value && !honeyPotChecked.value) ||
   "Veuillez procéder à la vérification";
 
 function onVerify(tokenStr: string, ekey: string) {
   verified.value = true;
   token.value = tokenStr;
   eKey.value = ekey;
-  emit('update', true)
+  emit("update", true);
 }
 
 function onExpire() {
   verified.value = false;
-  token.value = '';
-  eKey.value = '';
+  token.value = "";
+  eKey.value = "";
   expired.value = true;
 }
 
 function onChallengeExpire() {
   verified.value = false;
-  token.value = '';
-  eKey.value = '';
+  token.value = "";
+  eKey.value = "";
   expired.value = true;
 }
 
 function onError(err: string) {
-  token.value = '';
-  eKey.value = '';
+  token.value = "";
+  eKey.value = "";
   error.value = err;
   console.log(`Error: ${err}`);
 
   if (process.dev) {
-    console.log('Dev mode: force captcha validation')
+    console.log("Dev mode: force captcha validation");
     verified.value = true;
   }
 }

+ 8 - 17
components/Layout/FAQ.vue

@@ -7,8 +7,8 @@
         </LayoutUISubTitle>
 
         <h3 class="mt-6">
-          Quelle que soit votre demande, notre équipe est à vos côtés pour
-          vous guider
+          Quelle que soit votre demande, notre équipe est à vos côtés pour vous
+          guider
         </h3>
 
         <v-btn
@@ -31,16 +31,11 @@
               alt="Icône livre avec logo Youtube"
             />
 
-            <p>
-              De nombreux articles tutoriels accessibles 24h/24
-            </p>
+            <p>De nombreux articles tutoriels accessibles 24h/24</p>
           </div>
         </v-btn>
 
-        <v-btn
-          href="https://ressources.opentalent.fr/"
-          target="_blank"
-        >
+        <v-btn href="https://ressources.opentalent.fr/" target="_blank">
           <div>
             <v-img
               src="/images/components/faq/Icone_FAQ.svg"
@@ -48,8 +43,7 @@
             />
 
             <p class="text-btn">
-              Support accessible du lundi au vendredi via l’outil en
-              ligne
+              Support accessible du lundi au vendredi via l’outil en ligne
             </p>
           </div>
         </v-btn>
@@ -58,6 +52,7 @@
   </div>
 </template>
 
+<script setup lang="ts"></script>
 <style scoped lang="scss">
 .v-row {
   position: relative;
@@ -156,7 +151,7 @@ h3 {
     text-transform: none !important;
     background: rgba(0, 0, 0, 0.6);
 
-    .v-btn__content>div {
+    .v-btn__content > div {
       display: flex;
       flex-direction: row;
       align-items: center;
@@ -184,7 +179,7 @@ h3 {
       margin: 12px 5%;
       height: 8rem;
 
-      .v-btn__content>div {
+      .v-btn__content > div {
         display: flex;
         flex-direction: column;
         align-items: center;
@@ -203,9 +198,5 @@ h3 {
       max-width: 90%;
     }
   }
-
-
 }
 </style>
-<script setup lang="ts">
-</script>

+ 42 - 67
components/Layout/Footer/Footer.vue

@@ -15,37 +15,27 @@
           </v-col>
 
           <!-- Deuxième section : liens agenda culturel (écrans larges seulement) -->
-          <v-col v-if="lgAndUp" cols="7" >
+          <v-col v-if="lgAndUp" cols="7">
             <v-row>
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    Agenda culturel
-                  </h5>
+                  <h5>Agenda culturel</h5>
                 </v-row>
                 <v-row>
-                  <AgendaLink href="/annuaire">
-                    Annuaire
-                  </AgendaLink>
+                  <AgendaLink href="/annuaire"> Annuaire </AgendaLink>
                 </v-row>
                 <v-row>
-                  <AgendaLink href="/actualites">
-                    Actualités
-                  </AgendaLink>
+                  <AgendaLink href="/actualites"> Actualités </AgendaLink>
                 </v-row>
                 <v-row>
-                  <AgendaLink href="/annonces">
-                    Annonces
-                  </AgendaLink>
+                  <AgendaLink href="/annonces"> Annonces </AgendaLink>
                 </v-row>
               </v-col>
 
               <!-- Troisième section : liens logiciels culturels (écrans larges seulement) -->
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    Logiciels culturels
-                  </h5>
+                  <h5>Logiciels culturels</h5>
                 </v-row>
                 <v-row>
                   <nuxt-link to="/opentalent_artist">
@@ -55,8 +45,7 @@
                 <v-row>
                   <nuxt-link to="/opentalent_school">
                     Opentalent School
-                  </nuxt-link
-                  >
+                  </nuxt-link>
                 </v-row>
                 <v-row>
                   <nuxt-link to="/opentalent_manager">
@@ -68,42 +57,37 @@
               <!-- Quatrième section : A propos (écrans larges seulement) -->
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    A PROPOS
-                  </h5>
+                  <h5>A PROPOS</h5>
                 </v-row>
                 <v-row>
-                  <nuxt-link to="/qui-sommes-nous">
-                    Qui sommes-nous
-                  </nuxt-link>
+                  <nuxt-link to="/qui-sommes-nous"> Qui sommes-nous </nuxt-link>
                 </v-row>
                 <v-row>
-                  <nuxt-link to="/nous-rejoindre">
-                    Nous rejoindre
-                  </nuxt-link
-                  >
+                  <nuxt-link to="/nous-rejoindre"> Nous rejoindre </nuxt-link>
                 </v-row>
                 <v-row>
-                  <nuxt-link to="/nous-contacter">
-                    Nous contacter
-                  </nuxt-link>
+                  <nuxt-link to="/nous-contacter"> Nous contacter </nuxt-link>
                 </v-row>
               </v-col>
 
               <!-- Cinquième section : liens espace client (écrans larges seulement) -->
               <v-col cols="3">
                 <v-row>
-                  <h5>
-                    Espace client
-                  </h5>
+                  <h5>Espace client</h5>
                 </v-row>
                 <v-row>
-                  <nuxt-link href="https://ressources.opentalent.fr/display/FAQ/Accueil" target="_blank">
+                  <nuxt-link
+                    href="https://ressources.opentalent.fr/display/FAQ/Accueil"
+                    target="_blank"
+                  >
                     Foire Aux Questions
                   </nuxt-link>
                 </v-row>
                 <v-row>
-                  <nuxt-link href="https://ressources.opentalent.fr/" target="_blank">
+                  <nuxt-link
+                    href="https://ressources.opentalent.fr/"
+                    target="_blank"
+                  >
                     Support en ligne
                   </nuxt-link>
                 </v-row>
@@ -114,9 +98,7 @@
           <!-- Sixième section : liens réseaux sociaux (écrans larges seulement) -->
           <v-col v-if="lgAndUp" cols="2">
             <v-row class="justify-center">
-              <h5>
-                Suivez-nous
-              </h5>
+              <h5>Suivez-nous</h5>
             </v-row>
 
             <v-row class="justify-center social-networks">
@@ -154,10 +136,7 @@
         </v-row>
 
         <!-- Deuxième section alt : version petits écrans -->
-        <v-row
-          v-if="mdAndDown"
-          class="justify-center social-networks"
-        >
+        <v-row v-if="mdAndDown" class="justify-center social-networks">
           <!-- TODO: voir si faisable de fusionner avec la section précédente -->
           <v-col cols="12" class="text-center">
             <nuxt-link
@@ -186,7 +165,7 @@
 
       <!-- Troisième section alt : version petits écrans -->
       <v-row v-if="mdAndDown">
-        <v-col cols="12" >
+        <v-col cols="12">
           <div v-for="(item, index) in footerLinks" :key="index">
             <v-container>
               <div class="section" @click="toggleSection(index)">
@@ -194,13 +173,17 @@
                   {{ item.label }}
 
                   <v-icon
-                    :icon="isActive(index) ? 'fas fa-chevron-up' : 'fas fa-chevron-down'"
+                    :icon="
+                      isActive(index)
+                        ? 'fas fa-chevron-up'
+                        : 'fas fa-chevron-down'
+                    "
                   />
                 </div>
 
                 <div
-                  v-show="isActive(index)"
                   v-for="(sublink, sublinkIndex) in item.sublink"
+                  v-show="isActive(index)"
                   :key="sublinkIndex"
                   class="mt-3"
                 >
@@ -210,7 +193,6 @@
                 </div>
               </div>
             </v-container>
-
           </div>
         </v-col>
       </v-row>
@@ -218,24 +200,20 @@
       <div class="footnotes">
         <v-row justify="center">
           <p class="mt-6">
-            <nuxt-link to="/mentions-legales">
-              Mentions légales
-            </nuxt-link>
+            <nuxt-link to="/mentions-legales"> Mentions légales </nuxt-link>
             -
-            <nuxt-link to="/politique-de-confidentialite-et-protection-des-donnees-personnelles">
+            <nuxt-link
+              to="/politique-de-confidentialite-et-protection-des-donnees-personnelles"
+            >
               Politiques de confidentialité
             </nuxt-link>
             -
-            <nuxt-link to="/CGV">
-              Conditions Générales de Ventes
-            </nuxt-link>
+            <nuxt-link to="/CGV"> Conditions Générales de Ventes </nuxt-link>
           </p>
         </v-row>
 
         <v-row class="mb-3" justify="center">
-          <p>
-            2024 &copy; Tous droits réservés par Opentalent
-          </p>
+          <p>2024 &copy; Tous droits réservés par Opentalent</p>
         </v-row>
       </div>
     </LayoutContainer>
@@ -247,8 +225,7 @@ import { useDisplay } from "vuetify";
 import { useLayoutStore } from "~/stores/layoutStore";
 import AgendaLink from "~/components/Common/AgendaLink.vue";
 
-
-const { mdAndDown, mdAndUp, lgAndUp, lgAndDown } = useDisplay();
+const { mdAndDown, lgAndUp } = useDisplay();
 
 const footerLinks = ref([
   {
@@ -330,15 +307,13 @@ function isActive(index) {
   return activeIndex.value === index;
 }
 
-const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore();
 const onIntersect = (isIntersecting) => {
-  layoutStore.setIsFooterVisible(isIntersecting)
-}
-
+  layoutStore.setIsFooterVisible(isIntersecting);
+};
 </script>
 
 <style scoped lang="scss">
-
 .container {
   background: var(--primary-color);
   color: var(--on-primary-color);
@@ -402,7 +377,8 @@ a {
   border-top: 0.4px solid var(--neutral-color-alt-strong);
   box-shadow: 0 3px 24px rgba(0, 0, 0, 0.07);
 
-  a, p {
+  a,
+  p {
     text-decoration: none;
     color: var(--on-primary-color);
     font-size: 0.8rem;
@@ -410,7 +386,6 @@ a {
     @media (max-width: 600px) {
       max-width: 90%;
       text-align: center;
-
     }
   }
 }
@@ -443,7 +418,7 @@ a {
     font-size: 1.5rem;
     cursor: pointer;
 
-    >div:first-child {
+    > div:first-child {
       border-bottom: 1px solid var(--on-primary-color);
       padding-bottom: 6px;
       text-transform: uppercase;

+ 10 - 4
components/Layout/Footer/Prefooter.vue

@@ -57,7 +57,9 @@ Première section du footer (galerie des logiciels)
       <v-row class="justify-center">
         <v-col cols="3" class="border-right">
           <nuxt-link to="/opentalent_artist">
-            <v-img src="/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png"/>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png"
+            />
           </nuxt-link>
         </v-col>
 
@@ -67,7 +69,9 @@ Première section du footer (galerie des logiciels)
 
         <v-col cols="3">
           <nuxt-link to="/opentalent_school">
-            <v-img src="/images/logos/opentalent/Logo_Opentalent_School_Griffe.png"/>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_School_Griffe.png"
+            />
           </nuxt-link>
         </v-col>
 
@@ -77,7 +81,9 @@ Première section du footer (galerie des logiciels)
 
         <v-col cols="3">
           <nuxt-link to="/opentalent_manager">
-            <v-img src="/images/logos/opentalent/Logo_Opentalent_Manager_Griffe.png"/>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_Manager_Griffe.png"
+            />
           </nuxt-link>
         </v-col>
       </v-row>
@@ -88,7 +94,7 @@ Première section du footer (galerie des logiciels)
 <script setup lang="ts">
 import { useDisplay } from "vuetify";
 
-const { lgAndUp } = useDisplay()
+const { lgAndUp } = useDisplay();
 </script>
 
 <style scoped lang="scss">

+ 23 - 25
components/Layout/Footer/Solutions.vue

@@ -3,9 +3,7 @@
     <LayoutContainer>
       <v-row class="center-90">
         <v-col cols="12">
-          <LayoutUISubTitle>
-            NOS LOGICIELS OPENTALENT
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> NOS LOGICIELS OPENTALENT </LayoutUISubTitle>
 
           <LayoutUITitle>
             Ces solutions peuvent aussi vous intéresser
@@ -13,13 +11,13 @@
         </v-col>
       </v-row>
 
-      <v-row
-        v-if="showArtist"
-        class="row-artist center-90"
-      >
+      <v-row v-if="showArtist" class="row-artist center-90">
         <v-col cols="6" md="2">
           <NuxtLink to="/opentalent_artist">
-            <v-img src="/images/logos/opentalent/Logo_Opentalent_Artist-gris.png" class="logo" />
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_Artist-gris.png"
+              class="logo"
+            />
           </NuxtLink>
         </v-col>
 
@@ -45,14 +43,14 @@
         </v-col>
       </v-row>
 
-      <v-row
-        v-if="showManager"
-        class="row-manager center-90"
-      >
+      <v-row v-if="showManager" class="row-manager center-90">
         <v-col cols="6" md="2">
           <NuxtLink to="/opentalent_manager">
-          <v-img src="/images/logos/opentalent/Logo_Opentalent_Manager-gris.png" class="logo" />
-        </NuxtLink>
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_Manager-gris.png"
+              class="logo"
+            />
+          </NuxtLink>
         </v-col>
 
         <v-col cols="6" md="10">
@@ -74,13 +72,13 @@
         </v-col>
       </v-row>
 
-      <v-row
-        v-if="showSchool"
-        class="row-school center-90"
-      >
+      <v-row v-if="showSchool" class="row-school center-90">
         <v-col cols="6" md="2">
           <NuxtLink to="/opentalent_school">
-            <v-img src="/images/logos/opentalent/Logo_Opentalent_School-gris.png" class="logo" />
+            <v-img
+              src="/images/logos/opentalent/Logo_Opentalent_School-gris.png"
+              class="logo"
+            />
           </NuxtLink>
         </v-col>
 
@@ -116,23 +114,23 @@
 </template>
 
 <script setup lang="ts">
-const props = defineProps({
+defineProps({
   showArtist: {
     type: Boolean,
     required: false,
-    default: true
+    default: true,
   },
   showSchool: {
     type: Boolean,
     required: false,
-    default: true
+    default: true,
   },
   showManager: {
     type: Boolean,
     required: false,
-    default: true
+    default: true,
   },
-})
+});
 </script>
 
 <style scoped lang="scss">
@@ -193,7 +191,7 @@ const props = defineProps({
 .logo {
   width: 15rem;
   height: 10rem;
-  margin-left: .5rem;
+  margin-left: 0.5rem;
   margin-right: 2rem;
 }
 </style>

+ 8 - 11
components/Layout/Navigation.vue

@@ -29,33 +29,30 @@ const menu: Array<MainMenuItem> = [
       { label: "Opentalent Artist", to: "/opentalent_artist" },
       { label: "Opentalent School", to: "/opentalent_school" },
       { label: "Opentalent Manager", to: "/opentalent_manager" },
-    ]
+    ],
   },
   {
     label: "Nos services",
     children: [
       { label: "Formations", to: "/formations" },
       { label: "Webinaires", to: "/webinaires" },
-    ]
+    ],
   },
   {
     label: "À propos",
     children: [
       { label: "Qui sommes-nous", to: "/qui-sommes-nous" },
       { label: "Nous rejoindre", to: "/nous-rejoindre" },
-    ]
+    ],
   },
   { label: "Actualités", to: "/actualites" },
   { label: "Contact", to: "/nous-contacter" },
-]
+];
 
-const layoutStore = useLayoutStore()
+const layoutStore = useLayoutStore();
 const onIntersect = (isIntersecting: boolean) => {
-  layoutStore.setIsHeaderVisible(isIntersecting)
-}
-
+  layoutStore.setIsHeaderVisible(isIntersecting);
+};
 </script>
 
-<style scoped>
-
-</style>
+<style scoped></style>

+ 13 - 18
components/Layout/Navigation/Lg.vue

@@ -3,7 +3,7 @@
   <div>
     <LayoutNavigationTopbar />
 
-    <v-row class="navigation-lg" style="margin-top: 0 !important;">
+    <v-row class="navigation-lg" style="margin-top: 0 !important">
       <!-- Logo Opentalent -->
       <v-col cols="2">
         <nuxt-link to="/">
@@ -17,12 +17,8 @@
 
       <!-- Menu principal -->
       <v-col cols="10" class="pl-6">
-        <v-menu
-          v-for="item in menu"
-          :key="item.label"
-          :open-on-hover="true"
-        >
-          <template v-slot:activator="{ props }">
+        <v-menu v-for="item in menu" :key="item.label" :open-on-hover="true">
+          <template #activator="{ props }">
             <nuxt-link
               v-bind="props"
               class="menuItem first-level"
@@ -32,10 +28,7 @@
             </nuxt-link>
           </template>
 
-          <v-list
-            v-if="item.children?.length! > 0"
-            class="menu-list"
-          >
+          <v-list v-if="item.children?.length! > 0" class="menu-list">
             <v-list-item
               v-for="child in item.children"
               :key="child.label"
@@ -52,14 +45,15 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
+import type { PropType } from "vue";
 import type { MainMenuItem } from "~/types/interface";
 
-const props = defineProps({
+defineProps({
   menu: {
-    type: Array as PropType<Array<MainMenuItem>>
-  }
-})
+    type: Array as PropType<Array<MainMenuItem>>,
+    required: true,
+  },
+});
 </script>
 
 <style scoped lang="scss">
@@ -72,7 +66,8 @@ const props = defineProps({
   color: var(--on-neutral-color);
 }
 
-.menuItem, .menuItem .v-list-item-title {
+.menuItem,
+.menuItem .v-list-item-title {
   font-weight: 500;
   font-size: 0.9rem;
   letter-spacing: 0.1em;
@@ -87,7 +82,7 @@ const props = defineProps({
   align-items: center;
   background-color: var(--neutral-color);
 
-  .menuItem  {
+  .menuItem {
     padding: 18px;
   }
 

+ 34 - 38
components/Layout/Navigation/Md.vue

@@ -4,16 +4,18 @@
       <!-- Top bar -->
       <v-app-bar>
         <template #prepend>
-          <v-app-bar-nav-icon
-            @click="toggleMenu"
-          />
+          <v-app-bar-nav-icon @click="toggleMenu" />
         </template>
 
         <v-app-bar-title>
           <nuxt-link to="/">
             <v-img
               class="logo-md"
-              :src="smAndUp ? '/images/logos/opentalent/Logo_Opentalent-gris.png' : '/images/logos/opentalent/Logo_Opentalent_Griffe.png'"
+              :src="
+                smAndUp
+                  ? '/images/logos/opentalent/Logo_Opentalent-gris.png'
+                  : '/images/logos/opentalent/Logo_Opentalent_Griffe.png'
+              "
             />
           </nuxt-link>
         </v-app-bar-title>
@@ -25,27 +27,16 @@
             class="icon"
           />
 
-          <v-btn
-            to="/nous-contacter"
-            icon="fas fa-phone"
-            class="icon"
-          />
+          <v-btn to="/nous-contacter" icon="fas fa-phone" class="icon" />
 
           <AgendaLink href="/agenda-culturel">
-            <v-btn
-              icon="fas fa-calendar"
-              class="icon"
-            />
+            <v-btn icon="fas fa-calendar" class="icon" />
           </AgendaLink>
         </template>
       </v-app-bar>
 
       <!-- Tiroir de navigation principal -->
-      <v-navigation-drawer
-        v-model="isMenuOpen"
-        app
-        temporary
-      >
+      <v-navigation-drawer v-model="isMenuOpen" app temporary>
         <v-list nav dense>
           <v-list-item
             v-if="isSubMenu"
@@ -53,7 +44,7 @@
             @click="onBackItemClick"
           >
             <v-list-item-title>
-              <v-icon icon="fas fa-caret-left" class="mr-1"/> Retour
+              <v-icon icon="fas fa-caret-left" class="mr-1" /> Retour
             </v-list-item-title>
           </v-list-item>
 
@@ -80,29 +71,32 @@
 </template>
 
 <script setup lang="ts">
+import type { PropType, Ref } from "vue";
+import { useDisplay } from "vuetify";
 import AgendaLink from "~/components/Common/AgendaLink.vue";
-import type { PropType } from "@vue/runtime-core";
 import type { MainMenuItem } from "~/types/interface";
-import { useDisplay } from "vuetify";
 
-const { smAndUp } = useDisplay()
+const { smAndUp } = useDisplay();
 
 const props = defineProps({
   menu: {
-    type: Array as PropType<Array<MainMenuItem>>
-  }
-})
+    type: Array as PropType<Array<MainMenuItem>>,
+    required: true,
+  },
+});
 
 const isMenuOpen: Ref<boolean> = ref(false);
 const toggleMenu = () => {
   isMenuOpen.value = !isMenuOpen.value;
 };
 
-const activeMenuIndex: Ref<number | null> = ref(null)
+const activeMenuIndex: Ref<number | null> = ref(null);
 
 const activeMenu = computed(() =>
-  activeMenuIndex.value !== null ? props.menu![activeMenuIndex.value].children : props.menu
-)
+  activeMenuIndex.value !== null
+    ? props.menu![activeMenuIndex.value].children
+    : props.menu,
+);
 
 /**
  * Determines if the is active menu is a sub-menu .
@@ -110,7 +104,7 @@ const activeMenu = computed(() =>
  * @function isSubMenu
  * @returns {boolean} - True if a sub-menu is active, otherwise false.
  */
-const isSubMenu = computed(() => activeMenuIndex.value !== null)
+const isSubMenu = computed(() => activeMenuIndex.value !== null);
 
 /**
  * Handles the click event on a menu item.
@@ -121,27 +115,29 @@ const isSubMenu = computed(() => activeMenuIndex.value !== null)
  */
 const onMenuItemClick = (index: number, item: MainMenuItem): void => {
   if (!item.children) {
-    return
+    return;
   }
-  withAnimation(() => activeMenuIndex.value = index)
-}
+  withAnimation(() => (activeMenuIndex.value = index));
+};
 
 /**
  * Function to handle back button click event.
  */
 const onBackItemClick = (): void => {
-  withAnimation(() => activeMenuIndex.value = null)
-}
+  withAnimation(() => (activeMenuIndex.value = null));
+};
 
 /**
  * Déclenche une animation de changement de menu en fermant et rouvrant le drawer
  * @param callback
  */
 const withAnimation = (callback: () => void) => {
-  isMenuOpen.value = false
-  callback()
-  setTimeout(() => {isMenuOpen.value = true}, 85)
-}
+  isMenuOpen.value = false;
+  callback();
+  setTimeout(() => {
+    isMenuOpen.value = true;
+  }, 85);
+};
 </script>
 
 <style scoped lang="scss">

+ 13 - 16
components/Layout/Navigation/Topbar.vue

@@ -1,21 +1,18 @@
 <template>
-  <div class="top-bar" >
-      <v-btn
-        href="https://admin.opentalent.fr/#/login/"
-        prepend-icon="fas fa-user"
-        class="btn-login"
-      >
-        Se connecter
-      </v-btn>
+  <div class="top-bar">
+    <v-btn
+      href="https://admin.opentalent.fr/#/login/"
+      prepend-icon="fas fa-user"
+      class="btn-login"
+    >
+      Se connecter
+    </v-btn>
 
-      <AgendaLink href="/">
-        <v-btn
-          prepend-icon="fas fa-calendar"
-          class="btn-agenda"
-        >
-            Agenda Culturel
-        </v-btn>
-      </AgendaLink>
+    <AgendaLink href="/">
+      <v-btn prepend-icon="fas fa-calendar" class="btn-agenda">
+        Agenda Culturel
+      </v-btn>
+    </AgendaLink>
   </div>
 </template>
 

+ 8 - 9
components/Layout/Pagination.vue

@@ -9,26 +9,25 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "@vue/runtime-core";
+import type { PropType } from "vue";
 import type { Pagination } from "~/types/data";
 
-const props = defineProps({
+defineProps({
   modelValue: {
     type: Number,
-    required: true
+    required: true,
   },
   pagination: {
     type: Object as PropType<Pagination>,
-    required: true
-  }
+    required: true,
+  },
 });
 
-const emit = defineEmits(['update:modelValue']);
+const emit = defineEmits(["update:modelValue"]);
 
 const onPageUpdated = (newPage: number) => {
-  emit('update:modelValue', newPage);
+  emit("update:modelValue", newPage);
 };
 </script>
 
-<style scoped lang="scss">
-</style>
+<style scoped lang="scss"></style>

+ 2 - 6
components/Layout/UI/SectionTitle.vue

@@ -1,18 +1,14 @@
 <!-- Titre H2 -->
 <template>
   <div class="d-flex justify-center align-center flex-column">
-    <v-icon
-      size="6"
-      icon="fas fa-circle"
-    />
+    <v-icon size="6" icon="fas fa-circle" />
     <h3>
       <slot />
     </h3>
   </div>
 </template>
 
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
 h3 {

+ 2 - 8
components/Layout/UI/SubTitle.vue

@@ -4,10 +4,7 @@ Titre H4 précédé d'une puce
 <template>
   <LayoutContainer>
     <div class="container">
-      <v-icon
-        :icon="icon"
-        :size="iconSize"
-      />
+      <v-icon :icon="icon" :size="iconSize" />
       <h2>
         <slot />
       </h2>
@@ -16,9 +13,7 @@ Titre H4 précédé d'une puce
 </template>
 
 <script setup lang="ts">
-const router = useRouter();
-
-const props = defineProps({
+defineProps({
   icon: {
     type: String,
     default: "fas fa-circle",
@@ -57,5 +52,4 @@ h2 {
   letter-spacing: 1px;
   text-transform: uppercase;
 }
-
 </style>

+ 13 - 14
components/Layout/UI/Title.vue

@@ -7,22 +7,21 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-  h3 {
-    color: var(--on-neutral-color);
-    font-weight: 600;
-    font-size: 3rem;
-    line-height: 3rem;
-    margin-left: 1rem;
+h3 {
+  color: var(--on-neutral-color);
+  font-weight: 600;
+  font-size: 3rem;
+  line-height: 3rem;
+  margin-left: 1rem;
 
-    @media (max-width: 600px) {
-      font-size: 2rem;
-      line-height: 2rem;
-      margin-left: 1.5%;
-      width: 97%;
-    }
+  @media (max-width: 600px) {
+    font-size: 2rem;
+    line-height: 2rem;
+    margin-left: 1.5%;
+    width: 97%;
   }
+}
 </style>

+ 6 - 5
components/Layout/UI/TitlePage.vue

@@ -12,11 +12,12 @@
 <script setup lang="ts">
 import { useDisplay } from "vuetify";
 
-const { mdAndDown } = useDisplay()
+const { mdAndDown } = useDisplay();
 </script>
 
 <style scoped lang="scss">
-h1, h2 {
+h1,
+h2 {
   text-align: center;
   text-transform: uppercase;
 }
@@ -50,9 +51,10 @@ h2 {
 }
 
 @media (max-width: 600px) {
-  h1, h2 {
+  h1,
+  h2 {
     width: 80%;
-    margin: auto
+    margin: auto;
   }
 
   h1 {
@@ -66,5 +68,4 @@ h2 {
     font-size: 1.2rem;
   }
 }
-
 </style>

+ 9 - 12
components/Logiciels/Artist/Abonnement.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="subscription">
     <LayoutContainer>
       <v-row class="mt-12 center-90">
-        <LayoutUISubTitle>
-          S'abonner dès maintenant
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> S'abonner dès maintenant </LayoutUISubTitle>
 
         <v-col v-if="lgAndUp" cols="4" class="col-1">
           <LogicielsArtistAbonnementToSubscribe />
@@ -12,7 +10,8 @@
 
         <v-col cols="12" lg="8" class="col-2">
           <h3>
-            Opentalent Artist, <br> la solution que vous attendiez...
+            Opentalent Artist, <br />
+            la solution que vous attendiez...
           </h3>
 
           <p class="solution">
@@ -26,7 +25,8 @@
           <LogicielsArtistAbonnementToSubscribe v-if="mdAndDown" />
 
           <p class="cmf">
-            Adhérents CMF ? <br> Et si on vous disait que vous l’aviez déjà&nbsp;...
+            Adhérents CMF ? <br />
+            Et si on vous disait que vous l’aviez déjà&nbsp;...
           </p>
 
           <div class="border-row">
@@ -43,8 +43,6 @@
                 alt="Logo Confédération Musicale de France - CMF"
                 class="logo-cmf"
               />
-
-
             </nuxt-link>
 
             <div class="cmf-container">
@@ -65,20 +63,19 @@
 </template>
 
 <script setup>
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import { useDisplay } from "vuetify";
+import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 
-const { mdAndDown, lgAndUp } = useDisplay()
+const { mdAndDown, lgAndUp } = useDisplay();
 </script>
 
 <style scoped lang="scss">
-
 @media (max-width: 1240px) {
   .col-1 {
-    order: 2
+    order: 2;
   }
   .col-2 {
-    order: 1
+    order: 1;
   }
 }
 

+ 8 - 12
components/Logiciels/Artist/Abonnement/ToSubscribe.vue

@@ -8,8 +8,8 @@
 
   <div class="subscription-info">
     <p class="mt-3 mb-6">
-      Pour vous abonner au logiciel, téléchargez et remplissez le
-      formulaire avant de nous le transmettre
+      Pour vous abonner au logiciel, téléchargez et remplissez le formulaire
+      avant de nous le transmettre
     </p>
     <a
       href="/files/Bon_De_Commande_Artist_Public-2024.pdf"
@@ -22,28 +22,24 @@
 
   <div class="subscription-steps">
     <ol>
-      <li class="mt-6">
-        Téléchargez et complétez le formulaire
-      </li>
+      <li class="mt-6">Téléchargez et complétez le formulaire</li>
       <li>
-        Joignez le règlement par chèque ou par virement avec le formulaire à l'ordre de "2iOpenService"<br />
+        Joignez le règlement par chèque ou par virement avec le formulaire à
+        l'ordre de "2iOpenService"<br />
       </li>
       <li>
         Après réception de votre formulaire d'adhésion et de votre règlement,
         nous vous ouvrons le service choisi. Vous recevrez alors un mail avec
-        votre identifiant de connexion, votre mot de passe,
-        ainsi que l'URL de votre site internet.
+        votre identifiant de connexion, votre mot de passe, ainsi que l'URL de
+        votre site internet.
       </li>
     </ol>
   </div>
 </template>
 
-<script setup lang="ts">
-
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
-
 .profile-circle {
   top: 3rem;
   width: 100px;

+ 1 - 0
components/Logiciels/Artist/Avantages.vue

@@ -8,6 +8,7 @@ Section "Avantages" de la page du logiciel Artist
 </template>
 
 <script setup lang="ts">
+import type { Ref } from "vue";
 import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import type { Benefit } from "~/types/interface";
 

+ 4 - 9
components/Logiciels/Artist/Comparatif.vue

@@ -1,17 +1,13 @@
 <template>
   <AnchoredSection id="comparative">
     <LayoutContainer>
-      <LayoutUISubTitle>
-        Comparatif de nos solutions
-      </LayoutUISubTitle>
+      <LayoutUISubTitle> Comparatif de nos solutions </LayoutUISubTitle>
 
-      <LayoutUITitle>
-        Choisissez la version qui vous convient !
-      </LayoutUITitle>
+      <LayoutUITitle> Choisissez la version qui vous convient ! </LayoutUITitle>
 
       <CommonTableComparatif
-        standardPrice="11€"
-        premiumPrice="18€"
+        standard-price="11€"
+        premium-price="18€"
         :items="comparisonItems"
       />
     </LayoutContainer>
@@ -92,7 +88,6 @@ const comparisonItems: Array<ComparisonItem> = [
 </script>
 
 <style scoped>
-
 .v-container {
   width: 95%;
   margin-right: auto;

+ 3 - 8
components/Logiciels/Artist/Fonctionnalites.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="functionalities">
     <div>
       <LayoutContainer>
-        <CommonCarouselFonctionnalite
-          :cards="cards"
-        />
+        <CommonCarouselFonctionnalite :cards="cards" />
       </LayoutContainer>
     </div>
   </AnchoredSection>
@@ -20,10 +18,7 @@ const cards: Array<Functionality> = [
     logo: "/images/components/fonctionnalites/Icone_espaces_dedies.svg",
     logoAlt: "Icône smartphone avec cadenas verrouillé",
     title: "ESPACES DÉDIÉS *",
-    list: [
-      "Administrations",
-      "Membres/Adhérents",
-    ],
+    list: ["Administrations", "Membres/Adhérents"],
     options: ["*Disponible sur tous supports"],
   },
   {
@@ -96,7 +91,7 @@ const cards: Array<Functionality> = [
       "Renouvellement de votre adhésion fédérale",
       "Gestion de l'assurance CMF",
     ],
-    options: ['* uniquement dédié aux adhérents CMF']
+    options: ["* uniquement dédié aux adhérents CMF"],
   },
   {
     logo: "/images/components/fonctionnalites/Icone_promotion.svg",

+ 3 - 5
components/Logiciels/Artist/Formations.vue

@@ -4,7 +4,7 @@
       <div class="alt-theme">
         <v-container>
           <v-row class="center-90">
-            <LayoutUISubTitle class="mt-12" >
+            <LayoutUISubTitle class="mt-12">
               Pour aller plus loin
             </LayoutUISubTitle>
           </v-row>
@@ -22,7 +22,7 @@
                 Webinaire - Partez à la découverte du logiciel Opentalent Artist
               </h3>
 
-              <p class="details" >
+              <p class="details">
                 Rejoignez notre webinaire, spécialement conçu pour les
                 professionnels du secteur culturel, orchestres, chorales,
                 compagnies de danse, ainsi que les troupes de théâtre et de
@@ -35,9 +35,7 @@
               </p>
 
               <nuxt-link to="/webinaires">
-                <v-btn>
-                  S'inscrire à nos webinaires
-                </v-btn>
+                <v-btn> S'inscrire à nos webinaires </v-btn>
               </nuxt-link>
             </v-col>
           </v-row>

+ 4 - 4
components/Logiciels/Artist/Presentation.vue

@@ -6,7 +6,7 @@
       :pictos="pictos"
       logo-src="/images/logos/opentalent/Logo_Opentalent_Artist-blanc-col.png"
       logo-alt="Logo Opentalent Artist - logiciel de gestion et de communication pour les orchestres, les chorales, les compagnies artistiques et troupes"
-      pricingAmount="11€"
+      pricing-amount="11€"
     />
 
     <CommonContainerVideo
@@ -24,8 +24,8 @@ const features = [
   "Logiciel de gestion et communication en ligne",
   "Destiné aux structures culturelles (tout statut juridique)",
   "Gestion complète (membres, événements, planning, matériel,...)",
-  "Une solution simple d'utilisation, intuitive et collaborative"
-]
+  "Une solution simple d'utilisation, intuitive et collaborative",
+];
 
 const pictos: Array<FeaturePicto> = [
   {
@@ -42,7 +42,7 @@ const pictos: Array<FeaturePicto> = [
   },
   {
     src: "/images/pages/opentalent_artist/presentation/Communication_en_reseau.png",
-    text: "Communiquez en réseau"
+    text: "Communiquez en réseau",
   },
 ];
 </script>

+ 40 - 30
components/Logiciels/Artist/SomeNumbers.vue

@@ -1,56 +1,66 @@
 <template>
   <LayoutContainer>
     <v-row class="custom-row">
-      <LayoutUISubTitle class="mb-12">
-        Quelques chiffres
-      </LayoutUISubTitle>
+      <LayoutUISubTitle class="mb-12"> Quelques chiffres </LayoutUISubTitle>
     </v-row>
 
     <v-container>
       <v-row class="card-container mb-12">
-        <v-col
-          lg="3"
-          class="d-flex justify-center align-center small-padding"
-        >
-          <CommonCardStat
-            number="184 634"
-            text="Utilisateurs"
-          />
+        <v-col lg="3" class="d-flex justify-center align-center small-padding">
+          <CommonCardStat number="184 634" text="Utilisateurs" />
         </v-col>
 
         <v-col lg="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="3 423"
-            text="Structures"
-          />
+          <CommonCardStat number="3 423" text="Structures" />
         </v-col>
 
         <v-col lg="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="15"
-            text="Années d'expérience"
-          />
+          <CommonCardStat number="15" text="Années d'expérience" />
         </v-col>
       </v-row>
     </v-container>
 
-    <CommonCarouselClients :items="items" >
-      <template v-slot:title>
-        Plus de <span class="alt-color">3400 structures</span> nous ont déjà adoptées
+    <CommonCarouselClients :items="items">
+      <template #title>
+        Plus de <span class="alt-color">3400 structures</span> nous ont déjà
+        adoptées
       </template>
     </CommonCarouselClients>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-const items: Ref<Array<{ src: string, alt: string }>> = ref([
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Sarriannaise.jpeg", alt: "Logo de l’Union Musicale Sarriannaise" },
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Societe_Musicale_Sully_sur_Loire.jpg", alt: "Logo de la Société Musicale de Sully sur Loire" },
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Orchestre_d_Harmonie_de_Cluses.jpeg", alt: "Logo de l’Orchestre d’Harmonie de Cluses" },
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Musique_Municipale_Geispolsheim.jpeg", alt: "Logo Musique Municipale de Geispolsheim" },
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Harmonie_Municipale_de_Montherme.png", alt: "Logo de l’Harmonie Municipale de Montherme" },
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Echo_Musical_de_Faye_d_Anjou.jpeg", alt: "Logo de l’Echo Musical de Faye d’Anjou" },
-  { src: "/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Wattrelosienne.jpg", alt: "Logo de l’Union Musicale Wattrelosienne" },
+import type { Ref } from "vue";
+
+const items: Ref<Array<{ src: string; alt: string }>> = ref([
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Sarriannaise.jpeg",
+    alt: "Logo de l’Union Musicale Sarriannaise",
+  },
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Societe_Musicale_Sully_sur_Loire.jpg",
+    alt: "Logo de la Société Musicale de Sully sur Loire",
+  },
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Orchestre_d_Harmonie_de_Cluses.jpeg",
+    alt: "Logo de l’Orchestre d’Harmonie de Cluses",
+  },
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Musique_Municipale_Geispolsheim.jpeg",
+    alt: "Logo Musique Municipale de Geispolsheim",
+  },
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Harmonie_Municipale_de_Montherme.png",
+    alt: "Logo de l’Harmonie Municipale de Montherme",
+  },
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Echo_Musical_de_Faye_d_Anjou.jpeg",
+    alt: "Logo de l’Echo Musical de Faye d’Anjou",
+  },
+  {
+    src: "/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Wattrelosienne.jpg",
+    alt: "Logo de l’Union Musicale Wattrelosienne",
+  },
 ]);
 </script>
 

+ 16 - 13
components/Logiciels/Manager/Avantages.vue

@@ -1,5 +1,3 @@
-
-
 <template>
   <AnchoredSection id="benefits">
     <CommonAvantages
@@ -19,16 +17,18 @@ const benefits: Array<Benefit> = [
     number: "01",
     description:
       "S'adapte à tous les réseaux de type pyramidal, quelque soit le nombre de niveaux : fédérations, institutions publiques...",
-    image: "/images/pages/opentalent_manager/avantages/Un_logiciel_sur-mesure.jpg",
-    alt: "Mètre ruban de couture"
+    image:
+      "/images/pages/opentalent_manager/avantages/Un_logiciel_sur-mesure.jpg",
+    alt: "Mètre ruban de couture",
   },
   {
     title: "Adapté",
     number: "02",
     description:
       "Chaque structure du réseau dispose de sa propre solution indépendante et connectée au réseau : Opentalent manager, Opentalent school, Opentalent artist",
-    image: "/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg",
-    alt: "Réseaux structurés différemment ayant un lien part un atome commun"
+    image:
+      "/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg",
+    alt: "Réseaux structurés différemment ayant un lien part un atome commun",
   },
   {
     title: "Économique",
@@ -36,31 +36,34 @@ const benefits: Array<Benefit> = [
     description:
       "Une solution éprouvée au niveau national, sans avoir à supporter de coûts de développement importants pour ce type de logiciel.",
     image: "/images/pages/opentalent_manager/avantages/Un_outil_economique.jpg",
-    alt: "Main mettant une pièce dans un cochon tirelire"
+    alt: "Main mettant une pièce dans un cochon tirelire",
   },
   {
     title: "De pilotage",
     number: "04",
     description:
       "Pilotez votre réseau de manière quotidienne et en temps réel. Gagnez du temps avec notre solution qui génère automatiquement un rapport d'activité complet.",
-    image: "/images/pages/opentalent_manager/avantages/Un_pilotage_des_structures_simple.jpg",
-    alt: "Commandant de bord posant en uniforme"
+    image:
+      "/images/pages/opentalent_manager/avantages/Un_pilotage_des_structures_simple.jpg",
+    alt: "Commandant de bord posant en uniforme",
   },
   {
     title: "En réseau",
     number: "05",
     description:
       "Mise à jour automatique des coordonnées publiques entre les membres du réseau.",
-    image: "/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg",
-    alt: "Multi-réseau"
+    image:
+      "/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg",
+    alt: "Multi-réseau",
   },
   {
     title: "Confidentiel",
     number: "06",
     description:
       "Chaque structure garde son indépendance et reste entièrement maître des informations et des données qu'elle saisit.",
-    image: "/images/pages/opentalent_manager/avantages/Confidentialite_des_donnees_et_independance.jpg",
-    alt: "Jeune femme ayant le doigt devant la bouche pour instaurer le silence"
+    image:
+      "/images/pages/opentalent_manager/avantages/Confidentialite_des_donnees_et_independance.jpg",
+    alt: "Jeune femme ayant le doigt devant la bouche pour instaurer le silence",
   },
 ];
 </script>

+ 4 - 6
components/Logiciels/Manager/Fonctionnalites.vue

@@ -4,9 +4,7 @@
       <LayoutContainer>
         <v-row>
           <v-col cols="12">
-            <CommonCarouselFonctionnalite
-              :cards="cards"
-            />
+            <CommonCarouselFonctionnalite :cards="cards" />
           </v-col>
         </v-row>
       </LayoutContainer>
@@ -21,10 +19,10 @@ import type { Functionality } from "~/types/interface";
 
 const cards: Array<Functionality> = [
   {
-    logo:"/images/components/fonctionnalites/Icone_espaces_dedies.svg",
+    logo: "/images/components/fonctionnalites/Icone_espaces_dedies.svg",
     logoAlt: "Icône smartphone avec cadenas verrouillé",
     title: "ESPACES DÉDIÉS *",
-    list: ["Administration","Membres / Adhérents"],
+    list: ["Administration", "Membres / Adhérents"],
     options: ["*Disponible sur tous supports "],
   },
   {
@@ -67,7 +65,7 @@ const cards: Array<Functionality> = [
       "Création de modèles de courriers, mails ou SMS",
       "Outil de publipostage intégré pour un envoi personnalisé",
     ],
-    options: ["* en option"]
+    options: ["* en option"],
   },
   {
     logo: "/images/components/fonctionnalites/Icone_site_internet.svg",

+ 3 - 6
components/Logiciels/Manager/Formation.vue

@@ -9,11 +9,7 @@
         </v-row>
 
         <v-row class="formation pb-6 align-center center-90">
-          <v-col
-            md="6"
-            v-for="(formation, index) in formations"
-            :key="index"
-          >
+          <v-col v-for="(formation, index) in formations" :key="index" md="6">
             <div class="mb-6">
               <v-img
                 :src="formation.image"
@@ -52,7 +48,8 @@ import type { Formation } from "~/types/interface.js";
 
 const formations: Array<Formation> = [
   {
-    image: "/images/components/formations/Formations_en_ligne_et_presentiel.jpg",
+    image:
+      "/images/components/formations/Formations_en_ligne_et_presentiel.jpg",
     alt: "Formateur dans une salle avec 5 personnes levant la main",
     overlayClass: "image-overlay1",
     sessions: "Formation sur-mesure",

+ 3 - 4
components/Logiciels/Manager/Network.vue

@@ -2,9 +2,7 @@
   <AnchoredSection id="network">
     <LayoutContainer>
       <v-row class="mt-12 center-90">
-        <LayoutUISubTitle>
-          Un réseau pyramidal
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Un réseau pyramidal </LayoutUISubTitle>
       </v-row>
 
       <v-row class="center-90">
@@ -14,7 +12,8 @@
           </LayoutUITitle>
 
           <p class="pyramide-details ml-3 mt-6">
-            Notre système s'adapte à toutes les structures de réseau pyramidal, quel que soit le nombre de niveau.
+            Notre système s'adapte à toutes les structures de réseau pyramidal,
+            quel que soit le nombre de niveau.
           </p>
         </v-col>
 

+ 1 - 1
components/Logiciels/Manager/Presentation.vue

@@ -32,7 +32,7 @@ const features: Array<string> = [
   "Répond aux besoins globaux des réseaux culturels ",
   "Gestion collaborative ",
   "Mise en valeur des activités des membres du réseau ",
-]
+];
 
 const pictos: Array<FeaturePicto> = [
   {

+ 0 - 2
components/Logiciels/Manager/Reviews.vue

@@ -11,7 +11,6 @@
 </template>
 
 <script setup lang="ts">
-
 import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import type { Review } from "~/types/interface";
 
@@ -54,7 +53,6 @@ const cards: Array<Review> = [
 ];
 </script>
 
-
 <style scoped>
 .v-container {
   padding: 0 !important;

+ 6 - 22
components/Logiciels/Manager/SomeNumbers.vue

@@ -1,33 +1,19 @@
 <template>
   <LayoutContainer>
     <v-row class="align-center">
-      <LayoutUISubTitle>
-        Quelques chiffres
-      </LayoutUISubTitle>
+      <LayoutUISubTitle> Quelques chiffres </LayoutUISubTitle>
     </v-row>
 
     <v-container>
       <v-row class="card-container justify-center mb-12">
-        <v-col
-          md="3"
-          class="d-flex justify-center align-center small-padding"
-        >
-          <CommonCardStat
-            number="140"
-            text="Structures en réseau"
-          />
+        <v-col md="3" class="d-flex justify-center align-center small-padding">
+          <CommonCardStat number="140" text="Structures en réseau" />
         </v-col>
         <v-col md="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="216498"
-            text="Utilisateurs"
-          />
+          <CommonCardStat number="216498" text="Utilisateurs" />
         </v-col>
         <v-col md="3" class="d-flex justify-center align-center">
-          <CommonCardStat
-            number="17"
-            text="Années de collaboration"
-          />
+          <CommonCardStat number="17" text="Années de collaboration" />
         </v-col>
       </v-row>
     </v-container>
@@ -49,9 +35,7 @@
   </LayoutContainer>
 </template>
 
-<script setup lang="ts">
-
-</script>
+<script setup lang="ts"></script>
 
 <style scoped lang="scss">
 .custom-row {

+ 19 - 13
components/Logiciels/School/Avantages.vue

@@ -8,32 +8,38 @@ Section "Avantages" de la page du logiciel School
 </template>
 
 <script setup lang="ts">
+import type { Ref } from "vue";
 import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
 import type { Benefit } from "~/types/interface";
 
 // Exemple de données pour les cartes
 const benefits: Ref<Array<Benefit>> = ref([
   {
-    title: 'Un gain de temps',
-    number: '01',
-    description: 'Centralisez toutes vos informations sur un seul et même outil et ne perdez plus de temps avec des fichiers sur diverses applications.',
-    image: '/images/components/avantages/un_gain_de_temps.jpg',
+    title: "Un gain de temps",
+    number: "01",
+    description:
+      "Centralisez toutes vos informations sur un seul et même outil et ne perdez plus de temps avec des fichiers sur diverses applications.",
+    image: "/images/components/avantages/un_gain_de_temps.jpg",
+    alt: "",
     isMemberCMF: true,
   },
   {
-    title: 'Une activité structurée',
-    number: '02',
-    description: 'Des espaces dédiés et des outils spécifiques à vos besoins pour une gestion optimisée et une lecture simplifiée.',
-    image: '/images/components/avantages/une_activite_structuree.png',
+    title: "Une activité structurée",
+    number: "02",
+    description:
+      "Des espaces dédiés et des outils spécifiques à vos besoins pour une gestion optimisée et une lecture simplifiée.",
+    image: "/images/components/avantages/une_activite_structuree.png",
+    alt: "",
     isMemberCMF: false,
   },
   {
-    title: 'Une gestion collaborative',
-    number: '03',
-    description: 'Grâce à des comptes dédiés, personnalisés et autonomes, permettez à vos membres de mettre à jour leurs informations et d\'interagir dans leur agenda.',
-    image: '/images/components/avantages/une_gestion_collaborative.jpg',
+    title: "Une gestion collaborative",
+    number: "03",
+    description:
+      "Grâce à des comptes dédiés, personnalisés et autonomes, permettez à vos membres de mettre à jour leurs informations et d'interagir dans leur agenda.",
+    image: "/images/components/avantages/une_gestion_collaborative.jpg",
+    alt: "",
     isMemberCMF: true,
   },
 ]);
-
 </script>

+ 4 - 7
components/Logiciels/School/Comparatif.vue

@@ -2,17 +2,15 @@
   <AnchoredSection id="comparative">
     <LayoutContainer>
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Comparatif de nos solutions
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Comparatif de nos solutions </LayoutUISubTitle>
 
         <LayoutUITitle>
           Choisissez la version qui vous convient !
         </LayoutUITitle>
 
         <CommonTableComparatif
-          standardPrice="34,90€"
-          premiumPrice="49€"
+          standard-price="34,90€"
+          premium-price="49€"
           :items="comparisonItems"
         />
       </v-row>
@@ -112,5 +110,4 @@ const comparisonItems: Array<ComparisonItem> = [
   },
 ];
 </script>
-<style scoped>
-</style>
+<style scoped></style>

+ 5 - 10
components/Logiciels/School/Fonctionnalites.vue

@@ -1,9 +1,7 @@
 <template>
   <AnchoredSection id="functionalities">
     <LayoutContainer>
-      <CommonCarouselFonctionnalite
-        :cards="cards"
-      />
+      <CommonCarouselFonctionnalite :cards="cards" />
     </LayoutContainer>
   </AnchoredSection>
 </template>
@@ -18,11 +16,7 @@ const cards: Array<Functionality> = [
     logo: "/images/components/fonctionnalites/Icone_espaces_dedies.svg",
     logoAlt: "Icône smartphone avec cadenas verrouillé",
     title: "ESPACES DÉDIÉS *",
-    list: [
-      "Administration",
-      "Professeurs",
-      "Élèves / Familles",
-    ],
+    list: ["Administration", "Professeurs", "Élèves / Familles"],
     options: ["* Disponible sur tous supports"],
   },
   {
@@ -44,7 +38,7 @@ const cards: Array<Functionality> = [
       "Gestion des réinscriptions et des nouvelles inscriptions",
       "Gestion des quotas et du suivi des préinscriptions en ligne",
     ],
-    options: ["* en option"]
+    options: ["* en option"],
   },
   {
     logo: "/images/components/fonctionnalites/Icone_agenda.svg",
@@ -78,7 +72,8 @@ const cards: Array<Functionality> = [
   },
   {
     logo: "/images/components/fonctionnalites/Icone_facturation_et_reglement.svg",
-    logoAlt: "Fichier arborant un symbole monétaire devant un écran d'ordinateur",
+    logoAlt:
+      "Fichier arborant un symbole monétaire devant un écran d'ordinateur",
     title: "FACTURATION",
     list: [
       "Facturation automatisée selon différents critères",

+ 9 - 7
components/Logiciels/School/Formations.vue

@@ -3,17 +3,15 @@
     <LayoutContainer>
       <div class="alt-theme pt-6 mt-12">
         <v-row class="center-90">
-          <LayoutUISubTitle>
-            Nos accompagnements sur-mesure
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> Nos accompagnements sur-mesure </LayoutUISubTitle>
         </v-row>
 
         <v-row class="formation pb-6 align-center center-90">
           <v-col
-            cols="12"
-            md="6"
             v-for="(formation, index) in formations"
             :key="index"
+            cols="12"
+            md="6"
           >
             <div class="mb-6">
               <v-img
@@ -53,7 +51,8 @@ import type { Formation } from "~/types/interface";
 
 const formations: Array<Formation> = [
   {
-    image: "/images/components/formations/Formations_en_ligne_et_presentiel.jpg",
+    image:
+      "/images/components/formations/Formations_en_ligne_et_presentiel.jpg",
     alt: "Formateur dans une salle avec 5 personnes levant la main",
     overlayClass: "image-overlay1",
     sessions: "3 formations disponibles",
@@ -133,7 +132,10 @@ const formations: Array<Formation> = [
   }
 
   @media (max-width: 1240px) {
-    .background-img, h3, h4, .details {
+    .background-img,
+    h3,
+    h4,
+    .details {
       margin-left: auto;
       margin-right: auto;
       text-align: center;

+ 2 - 2
components/Logiciels/School/Presentation.vue

@@ -24,7 +24,7 @@ const features = [
   "Destiné aux établissements d'enseignement artistique",
   "Gestion quotidienne et en temps réel",
   "Pilotage complet de votre structure",
-]
+];
 
 const pictos: Array<FeaturePicto> = [
   {
@@ -41,7 +41,7 @@ const pictos: Array<FeaturePicto> = [
   },
   {
     src: "/images/pages/opentalent_school/presentation/picto4.png",
-    text: "Communiquez en réseau"
+    text: "Communiquez en réseau",
   },
 ];
 </script>

+ 43 - 49
components/Logiciels/School/SomeNumbers.vue

@@ -3,12 +3,11 @@
     <v-row class="align-center custom-row">
       <v-col cols="12">
         <v-row no-gutters>
-          <LayoutUISubTitle>
-            Quelques chiffres
-          </LayoutUISubTitle>
+          <LayoutUISubTitle> Quelques chiffres </LayoutUISubTitle>
 
           <LayoutUITitle>
-            Pour les petits comme pour les GRANDS<br/>établissements d'enseignement artistique
+            Pour les petits comme pour les GRANDS<br />établissements
+            d'enseignement artistique
           </LayoutUITitle>
         </v-row>
       </v-col>
@@ -21,63 +20,58 @@
         cols="12"
         class="d-flex justify-center align-center small-padding"
       >
-        <CommonCardStat
-          number="30 > 1 500"
-          text="Élèves"
-        />
+        <CommonCardStat number="30 > 1 500" text="Élèves" />
       </v-col>
-      <v-col
-        lg="3"
-        md="6"
-        cols="12"
-        class="d-flex justify-center align-center"
-      >
-        <CommonCardStat
-          number="139"
-          text="Clients"
-        />
+      <v-col lg="3" md="6" cols="12" class="d-flex justify-center align-center">
+        <CommonCardStat number="139" text="Clients" />
       </v-col>
-      <v-col
-        lg="3"
-        md="6"
-        cols="12"
-        class="d-flex justify-center align-center"
-      >
-        <CommonCardStat
-          number="153 602"
-          text="Utilisateurs"
-        />
+      <v-col lg="3" md="6" cols="12" class="d-flex justify-center align-center">
+        <CommonCardStat number="153 602" text="Utilisateurs" />
       </v-col>
-      <v-col
-        lg="3"
-        md="6"
-        cols="12"
-        class="d-flex justify-center align-center"
-      >
-        <CommonCardStat
-          number="15"
-          text="Années d'expérience"
-        />
+      <v-col lg="3" md="6" cols="12" class="d-flex justify-center align-center">
+        <CommonCardStat number="15" text="Années d'expérience" />
       </v-col>
     </v-row>
 
-    <CommonCarouselClients :items="items" >
-      <template v-slot:title>
-        Plus de <span class="alt-color">5000 structures</span> nous font confiance
+    <CommonCarouselClients :items="items">
+      <template #title>
+        Plus de <span class="alt-color">5000 structures</span> nous font
+        confiance
       </template>
     </CommonCarouselClients>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
-const items: Array<{ src: string, alt: string }> = [
-  { src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_Les_Ateliers_des_Arts_Agglomeration_du_Puy-en-Velay.svg", alt: "Logo du Conservatoire « Les ateliers des arts" },
-  { src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire-Senlis.png", alt: "Logo du Conservatoire de Senlis" },
-  { src: "/images/pages/opentalent_school/reviews/Logo_Ecole_de_Musique-Sausheim.png", alt: "Logo de l’École de musique Sausheim" },
-  { src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_Marly_le_Roi-Roger_Bourdin.jpeg", alt: "Logo du Conservatoire Marly le Roi Roger Bourdin" },
-  { src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_de_Musiques_et_de_Danses_du_Thouarsais.jpeg", alt: "Logo du Conservatoire de Musique et de Danse du Thouarsais" },
-  { src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg", alt: "Logo du Conservatoire d’Annemasse" },
-  { src: "/images/pages/opentalent_school/reviews/Logo_EBAG-Ecole_des_Beaux-Arts_du_Genevois.png", alt: "Ecole des Beaux-Arts du Genevois" },
+const items: Array<{ src: string; alt: string }> = [
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_Les_Ateliers_des_Arts_Agglomeration_du_Puy-en-Velay.svg",
+    alt: "Logo du Conservatoire « Les ateliers des arts",
+  },
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire-Senlis.png",
+    alt: "Logo du Conservatoire de Senlis",
+  },
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_Ecole_de_Musique-Sausheim.png",
+    alt: "Logo de l’École de musique Sausheim",
+  },
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_Marly_le_Roi-Roger_Bourdin.jpeg",
+    alt: "Logo du Conservatoire Marly le Roi Roger Bourdin",
+  },
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_de_Musiques_et_de_Danses_du_Thouarsais.jpeg",
+    alt: "Logo du Conservatoire de Musique et de Danse du Thouarsais",
+  },
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg",
+    alt: "Logo du Conservatoire d’Annemasse",
+  },
+  {
+    src: "/images/pages/opentalent_school/reviews/Logo_EBAG-Ecole_des_Beaux-Arts_du_Genevois.png",
+    alt: "Ecole des Beaux-Arts du Genevois",
+  },
 ];
 </script>
 

+ 2 - 3
components/Logiciels/Title.vue

@@ -1,10 +1,9 @@
-
 <template>
   <LayoutContainer>
     <div class="container-title">
       <v-col v-if="mdAndUp" cols="3" class="lateral-text">
         <span>
-          <slot name="left-text"/>
+          <slot name="left-text" />
         </span>
       </v-col>
       <v-col cols="12" md="6">
@@ -24,7 +23,7 @@
 <script setup lang="ts">
 import { useDisplay } from "vuetify";
 
-const { mdAndUp } = useDisplay()
+const { mdAndUp } = useDisplay();
 </script>
 
 <style scoped lang="scss">

+ 15 - 26
components/News/Details.vue

@@ -17,10 +17,7 @@
       <div>
         <div v-if="pending">
           <v-row class="justify-center progress">
-            <v-progress-circular
-              indeterminate
-              color="grey"
-            />
+            <v-progress-circular indeterminate color="grey" />
           </v-row>
         </div>
 
@@ -32,10 +29,7 @@
 
           <v-row class="center-90 mb-12">
             <v-col cols="12" md="6">
-              <v-img
-                :src="getImageUrl(newsItem.attachment)"
-                cover
-              />
+              <v-img :src="getImageUrl(newsItem.attachment)" cover />
             </v-col>
 
             <v-col cols="12" md="6" class="d-flex flex-column justify-center">
@@ -50,10 +44,7 @@
           </v-row>
 
           <v-row class="center-90">
-            <p
-              v-html="newsItem.bodyText"
-              class="description"
-            />
+            <p class="description" v-html="newsItem.bodyText" />
           </v-row>
 
           <v-row class="d-flex justify-center align-center">
@@ -70,9 +61,7 @@
 
           <v-row class="d-flex justify-space-between center-90">
             <div>
-              <p v-if="newsItem.tags.length > 0">
-                MOTS CLÉS
-              </p>
+              <p v-if="newsItem.tags.length > 0">MOTS CLÉS</p>
             </div>
             <div v-if="mdAndUp">
               <p>PARTAGER</p>
@@ -81,7 +70,7 @@
 
           <v-row class="d-flex justify-space-between mb-8 center-90">
             <p class="key-word mt-3">
-              <span v-for="tag in newsItem.tags" class="mr-2">
+              <span v-for="tag in newsItem.tags" :key="tag.id" class="mr-2">
                 {{ tag.name }}
               </span>
             </p>
@@ -100,29 +89,29 @@
 </template>
 
 <script setup lang="ts">
+import { useDisplay } from "vuetify";
 import { useEntityFetch } from "~/composables/data/useEntityFetch";
 import News from "~/models/Maestro/News";
-import { useDisplay } from "vuetify";
 
-const { mdAndUp, smAndDown } = useDisplay()
+const { mdAndUp, smAndDown } = useDisplay();
 
 const route = useRoute();
-const { fetch } = useEntityFetch()
-const config = useRuntimeConfig()
+const { fetch } = useEntityFetch();
+const config = useRuntimeConfig();
 
-const newsId: number = parseInt(route.params.id as string)
+const newsId: number = parseInt(route.params.id as string);
 if (!newsId || isNaN(newsId)) {
-  throw new Error('Missing or invalid id')
+  throw new Error("Missing or invalid id");
 }
 
-const { data: newsItem, pending } = fetch(News, newsId)
+const { data: newsItem, pending } = fetch(News, newsId);
 
 const getImageUrl = (attachment: string): string | null => {
   if (!attachment) {
-    return null
+    return null;
   }
-  return `${config.public.apiBaseUrl}/uploads/news/${attachment}`
-}
+  return `${config.public.apiBaseUrl}/uploads/news/${attachment}`;
+};
 </script>
 
 <style scoped>

+ 19 - 21
components/News/List.vue

@@ -1,17 +1,12 @@
 <template>
   <div v-if="pending">
     <v-row class="justify-center progress">
-      <v-progress-circular
-        indeterminate
-        color="grey"
-      />
+      <v-progress-circular indeterminate color="grey" />
     </v-row>
   </div>
 
-  <div v-else-if="!newsCollection || !(newsCollection!.items)">
-    <v-row class="justify-center">
-      Aucun résultat trouvé
-    </v-row>
+  <div v-else-if="!newsCollection || !newsCollection!.items">
+    <v-row class="justify-center"> Aucun résultat trouvé </v-row>
   </div>
 
   <div v-else>
@@ -88,8 +83,8 @@
           v-if="newsCollection && newsCollection.pagination"
           :model-value="page"
           :pagination="newsCollection.pagination"
-          @update:model-value="onPageUpdated"
           class="mt-4"
+          @update:model-value="onPageUpdated"
         />
       </v-col>
     </v-row>
@@ -97,12 +92,12 @@
 </template>
 
 <script setup lang="ts">
+import type { ComputedRef, Ref } from "vue";
 import { useEntityFetch } from "~/composables/data/useEntityFetch";
 import News from "~/models/Maestro/News";
 
-const i18n = useI18n();
 const config = useRuntimeConfig();
-const { fetchCollection } = useEntityFetch()
+const { fetchCollection } = useEntityFetch();
 
 const getImageUrl = (attachment: string) =>
   `${config.public.apiBaseUrl}/uploads/news/${attachment}`;
@@ -114,23 +109,27 @@ const query: ComputedRef<Record<string, string | number>> = computed(() => {
     page: page.value,
     type: "BUSINESS",
     "startPublication[before]": "now",
-    "endPublication[after]": "now"
+    "endPublication[after]": "now",
   };
 });
 
-const { data: newsCollection, pending, refresh } = fetchCollection(News, null, query)
+const {
+  data: newsCollection,
+  pending,
+  refresh,
+} = fetchCollection(News, null, query);
 
 const onPageUpdated = async (newVal: number): Promise<void> => {
-  page.value = newVal
+  page.value = newVal;
 
-  pending.value = true
-  await refresh()
+  pending.value = true;
+  await refresh();
 
   setTimeout(
-    async () => await navigateTo({ path: '', hash: '#news-anchor' }),
-    200
-  )
-}
+    async () => await navigateTo({ path: "", hash: "#news-anchor" }),
+    200,
+  );
+};
 </script>
 
 <style scoped lang="scss">
@@ -182,7 +181,6 @@ h1 {
       width: 97%;
       margin: 1.5%;
     }
-
   }
 
   .details {

+ 23 - 57
components/Webinaire/Catalogue.vue

@@ -2,38 +2,28 @@
   <LayoutContainer>
     <div class="grey-container">
       <v-row class="center-90">
-        <LayoutUISubTitle>
-          Des webinaires pour tous
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Des webinaires pour tous </LayoutUISubTitle>
       </v-row>
 
       <v-row class="center-90">
         <v-col cols="12" class="section-title">
-          <h3>
-            Simplifiez la gestion et la communication de votre structure
-          </h3>
+          <h3>Simplifiez la gestion et la communication de votre structure</h3>
 
           <div class="strong-label">
-            Votre structure culturelle, établissement d’enseignement artistique ou fédération mérite les outils les plus performants du marché pour briller en toute simplicité.
-            Découvrez comment nos outils peuvent transformer votre quotidien :
+            Votre structure culturelle, établissement d’enseignement artistique
+            ou fédération mérite les outils les plus performants du marché pour
+            briller en toute simplicité. Découvrez comment nos outils peuvent
+            transformer votre quotidien :
           </div>
         </v-col>
       </v-row>
 
       <v-row class="center-90 catalog">
-        <v-col
-          v-for="(course, index) in courses"
-          :key="index"
-          cols="12"
-          md="4"
-        >
+        <v-col v-for="(course, index) in courses" :key="index" cols="12" md="4">
           <v-card class="mb-4">
             <v-card-text>
               <div class="title-card-container">
-                <v-img
-                  :src="course.imageUrl"
-                  :alt="course.imageAlt"
-                />
+                <v-img :src="course.imageUrl" :alt="course.imageAlt" />
 
                 <h4>
                   {{ course.title }}
@@ -45,9 +35,7 @@
               </p>
 
               <div class="objectives mt-6">
-                <h6>
-                  Objectifs
-                </h6>
+                <h6>Objectifs</h6>
 
                 <ul>
                   <li
@@ -59,14 +47,10 @@
                 </ul>
               </div>
 
-              <div class="badge-time">
-                Durée : {{ course.duration }}
-              </div>
+              <div class="badge-time">Durée : {{ course.duration }}</div>
 
               <div class="program">
-                <h6>
-                  Programme
-                </h6>
+                <h6>Programme</h6>
 
                 <v-row>
                   <v-col
@@ -90,10 +74,7 @@
                 {{ course.price }}
               </div>
 
-              <v-chip
-                class="chip-register"
-                @click="showModal(course.title)"
-              >
+              <v-chip class="chip-register" @click="showModal(course.title)">
                 Inscrivez-vous
               </v-chip>
             </v-card-text>
@@ -103,15 +84,9 @@
     </div>
 
     <!-- Modale d'inscription -->
-    <v-dialog
-      v-model="modalShowing"
-      max-width="800"
-      class="calendar-modal"
-    >
+    <v-dialog v-model="modalShowing" max-width="800" class="calendar-modal">
       <div class="alt-theme d-flex flex-column align-center">
-        <LayoutUISubTitle>
-          Inscrivez vous
-        </LayoutUISubTitle>
+        <LayoutUISubTitle> Inscrivez vous </LayoutUISubTitle>
 
         <h4 class="title-inscription text-center mt-4">
           Vous y êtes presque !
@@ -125,12 +100,7 @@
 
         <v-row>
           <v-col cols="12">
-            <v-btn
-              class="close-button"
-              @click="closeModal()"
-            >
-              Fermer
-            </v-btn>
+            <v-btn class="close-button" @click="closeModal()"> Fermer </v-btn>
           </v-col>
         </v-row>
       </div>
@@ -139,12 +109,9 @@
 </template>
 
 <script setup lang="ts">
+import type { Ref } from "vue";
 import type { Training } from "~/types/interface";
 
-const downloadPdf = (pdfUrl: string) => {
-  window.open(pdfUrl, "_blank");
-};
-
 const courses: Array<Training> = [
   {
     imageUrl: "/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png",
@@ -271,7 +238,7 @@ const showModal = (webinaireTitle: string) => {
   selectedWebinar.value = webinaireTitle.trim();
 };
 
-const modalShowing = computed(() => selectedWebinar.value)
+const modalShowing = computed(() => selectedWebinar.value);
 
 const closeModal = () => {
   selectedWebinar.value = null;
@@ -291,17 +258,16 @@ const closeModal = () => {
 
   h3 {
     font-size: 42px;
-    letter-spacing: .1rem;
+    letter-spacing: 0.1rem;
     line-height: 3.5rem;
-    margin-bottom: .5rem;
+    margin-bottom: 0.5rem;
     margin-top: 2rem;
-
   }
 
   .strong-label {
     font-size: 1.5rem;
     font-weight: 400 !important;
-    letter-spacing: .1rem;
+    letter-spacing: 0.1rem;
     line-height: 2rem;
     margin-bottom: 1rem;
   }
@@ -347,7 +313,8 @@ const closeModal = () => {
     }
   }
 
-  .objectives, .program {
+  .objectives,
+  .program {
     justify-content: space-between;
     align-items: center;
     background: var(--secondary-color-light);
@@ -396,7 +363,6 @@ const closeModal = () => {
 }
 
 .calendar-modal {
-
   h4 {
     font-weight: 600;
     font-size: 2rem;
@@ -405,7 +371,7 @@ const closeModal = () => {
   }
 
   .close-button {
-    background-color: #e34461;  /* TODO: pqoi cette couleur ici? */
+    background-color: #e34461; /* TODO: pqoi cette couleur ici? */
     color: var(--on-primary-color);
     font-weight: 500;
     font-size: 14px;

+ 33 - 40
components/Webinaire/FAQ.vue

@@ -4,29 +4,19 @@ Foire aux questions
 <template>
   <LayoutContainer>
     <v-row class="center-90">
-      <LayoutUISubTitle>
-        Des questions ?
-      </LayoutUISubTitle>
+      <LayoutUISubTitle> Des questions ? </LayoutUISubTitle>
     </v-row>
 
     <v-row class="center-90">
       <v-col cols="12" class="section-title">
-        <h3>
-          Tout savoir sur nos webinaire en ligne
-        </h3>
+        <h3>Tout savoir sur nos webinaire en ligne</h3>
 
-        <div class="strong-label">
-          Les questions les plus fréquentes
-        </div>
+        <div class="strong-label">Les questions les plus fréquentes</div>
       </v-col>
     </v-row>
 
     <div class="faq center-90">
-      <div
-        v-for="(item, index) in faqItems"
-        :key="index"
-        class="faq-item"
-      >
+      <div v-for="(item, index) in faqItems" :key="index" class="faq-item">
         <div
           :class="'question' + (isOpen(index) ? ' open' : '')"
           @click="toggle(index)"
@@ -36,48 +26,52 @@ Foire aux questions
           {{ item.question }}
         </div>
 
-        <div
-          v-if="isOpen(index)"
-          class="answer"
-          v-html="item.answer"
-        />
+        <div v-if="isOpen(index)" class="answer" v-html="item.answer" />
       </div>
     </div>
   </LayoutContainer>
 </template>
 
 <script setup lang="ts">
+import type { Ref } from "vue";
 import type { FaqEntry } from "~/types/interface";
 
 const faqItems: Array<FaqEntry> = [
   {
-    question: 'Comment s’inscrire à un webinaire?',
-    answer: 'Pour vous inscrire à un webinaire, suivez le lien "Inscrivez-vous" correspondant au cours qui vous intéresse.',
+    question: "Comment s’inscrire à un webinaire?",
+    answer:
+      'Pour vous inscrire à un webinaire, suivez le lien "Inscrivez-vous" correspondant au cours qui vous intéresse.',
   },
   {
-    question: 'Combien de temps dure nos webinaires ?',
-    answer: 'Nos webinaires durent en moyenne 1H30. Les sessions de questions/réponses peuvent parfois prolonger la durée prévue de nos webinaires.',
+    question: "Combien de temps dure nos webinaires ?",
+    answer:
+      "Nos webinaires durent en moyenne 1H30. Les sessions de questions/réponses peuvent parfois prolonger la durée prévue de nos webinaires.",
   },
   {
-    question: 'Comment se passe un webinaire ?',
-    answer: 'Inscrivez-vous à l\'un de nos webinaires en choisissant une date sur l\'agenda et renseignez vos informations. ' +
-            'Vous recevrez à la suite de votre inscription sur notre site, un email de confirmation avec un rappel de la date et de l\'horaire de participation ainsi que l\'URL de connexion pour le webinaire. ' +
-            'Un mail de relance à J-1 vous sera envoyer vous rappelant votre participation au webinaire. ' +
-            'Le jour J, cliquez sur l\'URL de connexion. Nous vous encourageons à arriver quelques minutes en avance pour vous assurer de pouvoir accéder au webinaire sans aucun problème technique. ' +
-            'Lors du début du webinaire, toutes les instructions nécessaires vous seront fournies.'
+    question: "Comment se passe un webinaire ?",
+    answer:
+      "Inscrivez-vous à l'un de nos webinaires en choisissant une date sur l'agenda et renseignez vos informations. " +
+      "Vous recevrez à la suite de votre inscription sur notre site, un email de confirmation avec un rappel de la date et de l'horaire de participation ainsi que l'URL de connexion pour le webinaire. " +
+      "Un mail de relance à J-1 vous sera envoyer vous rappelant votre participation au webinaire. " +
+      "Le jour J, cliquez sur l'URL de connexion. Nous vous encourageons à arriver quelques minutes en avance pour vous assurer de pouvoir accéder au webinaire sans aucun problème technique. " +
+      "Lors du début du webinaire, toutes les instructions nécessaires vous seront fournies.",
   },
   {
-    question: 'De quel matériel aurais-je besoin pour suivre le webinaire ?',
-    answer: 'Pour plus de confort, il est recommandé d\'être équipé d\'un outil (de préférence un ordinateur) disposant d\'un micro et de haut-parleur.',
+    question: "De quel matériel aurais-je besoin pour suivre le webinaire ?",
+    answer:
+      "Pour plus de confort, il est recommandé d'être équipé d'un outil (de préférence un ordinateur) disposant d'un micro et de haut-parleur.",
   },
   {
-    question: 'Y-a-t\'il une limite de participants ?',
-    answer: 'Il n\'y a pas de limite de participants lors de nos webinaires. Cependant, nous nous réservons le droit d\'annuler une session si le nombre de participants est inférieur à 3 personnes.',
+    question: "Y-a-t'il une limite de participants ?",
+    answer:
+      "Il n'y a pas de limite de participants lors de nos webinaires. Cependant, nous nous réservons le droit d'annuler une session si le nombre de participants est inférieur à 3 personnes.",
   },
   {
-    question: 'J\'ai besoin d\'aide...',
-    answer: 'Notre équipe est là pour vous. <br/><button style="background-color: #0E2D32; color: #fff; border: none;border-radius: 4px;padding: 0.5rem 1rem;cursor: pointer;margin-top: 6px;"   class="contact-btn" onclick="window.location.href=\'/nous-contacter\'">Contactez-nous</button>'
-}];
+    question: "J'ai besoin d'aide...",
+    answer:
+      'Notre équipe est là pour vous. <br/><button style="background-color: #0E2D32; color: #fff; border: none;border-radius: 4px;padding: 0.5rem 1rem;cursor: pointer;margin-top: 6px;"   class="contact-btn" onclick="window.location.href=\'/nous-contacter\'">Contactez-nous</button>',
+  },
+];
 
 const activeIndex: Ref<number | null> = ref(null);
 
@@ -90,7 +84,6 @@ function isOpen(index: number) {
 }
 </script>
 
-
 <style scoped lang="scss">
 .section-title {
   display: flex;
@@ -99,9 +92,9 @@ function isOpen(index: number) {
 
   h3 {
     font-size: 2rem;
-    letter-spacing: .1rem;
+    letter-spacing: 0.1rem;
     line-height: 3.5rem;
-    margin-bottom: .5rem;
+    margin-bottom: 0.5rem;
     margin-top: 2rem;
     text-transform: uppercase;
   }
@@ -109,7 +102,7 @@ function isOpen(index: number) {
   .strong-label {
     font-size: 1.5rem;
     font-weight: 400 !important;
-    letter-spacing: .1rem;
+    letter-spacing: 0.1rem;
     line-height: 2rem;
     margin-bottom: 1rem;
     text-align: center;

+ 44 - 27
composables/data/useEntityFetch.ts

@@ -1,42 +1,59 @@
-import {useEntityManager} from "~/composables/data/useEntityManager";
+import type { AsyncData } from "#app";
+import type { ComputedRef, Ref } from "vue";
+import { v4 as uuid4 } from "uuid";
+import { useEntityManager } from "~/composables/data/useEntityManager";
 import ApiResource from "~/models/ApiResource";
-import type {AssociativeArray, Collection} from "~/types/data";
-import type {AsyncData} from "#app";
-import type {ComputedRef, Ref} from "vue";
-import {v4 as uuid4} from "uuid";
+import type { AssociativeArray, Collection } from "~/types/data";
 
 interface useEntityFetchReturnType {
-  fetch: (model: typeof ApiResource, id: number) => AsyncData<ApiResource, ApiResource | true>,
-  fetchCollection: (model: typeof ApiResource, parent?: ApiResource | null, query?: Ref<AssociativeArray>) => AsyncData<Collection, any>
+  fetch: (
+    model: typeof ApiResource,
+    id: number,
+  ) => AsyncData<ApiResource, ApiResource | true>;
+  fetchCollection: (
+    model: typeof ApiResource,
+    parent?: ApiResource | null,
+    query?: Ref<AssociativeArray>,
+  ) => AsyncData<Collection, any>;
   // @ts-ignore
-  getRef: <T extends ApiResource>(model: typeof T, id: Ref<number | null>) => ComputedRef<null | T>
+  getRef: <T extends ApiResource>(
+    model: typeof T,
+    id: Ref<number | null>,
+  ) => ComputedRef<null | T>;
 }
 
 // TODO: améliorer le typage des fonctions sur le modèle de getRef
-export const useEntityFetch = (lazy: boolean = false): useEntityFetchReturnType => {
-  const { em } = useEntityManager()
+export const useEntityFetch = (
+  lazy: boolean = false,
+): useEntityFetchReturnType => {
+  const { em } = useEntityManager();
 
-  const fetch = (model: typeof ApiResource, id: number) => useAsyncData(
-    model.entity + '_' + id + '_' + uuid4(),
-    () => em.fetch(model, id, true),
-    { lazy }
-  )
+  const fetch = (model: typeof ApiResource, id: number) =>
+    useAsyncData(
+      model.entity + "_" + id + "_" + uuid4(),
+      () => em.fetch(model, id, true),
+      { lazy },
+    );
 
   const fetchCollection = (
     model: typeof ApiResource,
     parent: ApiResource | null = null,
-    query: Ref<AssociativeArray | null> = ref(null)
-  ) => useAsyncData(
-    model.entity + '_many_' + uuid4(),
-    () => em.fetchCollection(model, parent, query.value ?? undefined),
-    { lazy }
-  )
+    query: Ref<AssociativeArray | null> = ref(null),
+  ) =>
+    useAsyncData(
+      model.entity + "_many_" + uuid4(),
+      () => em.fetchCollection(model, parent, query.value ?? undefined),
+      { lazy },
+    );
 
   // @ts-ignore
-  const getRef = <T extends ApiResource>(model: typeof T, id: Ref<number | null>): ComputedRef<T | null> => {
-    return computed(() => (id.value ? em.find(model, id.value) as T : null))
-  }
+  const getRef = <T extends ApiResource>(
+    model: typeof T,
+    id: Ref<number | null>,
+  ): ComputedRef<T | null> => {
+    return computed(() => (id.value ? (em.find(model, id.value) as T) : null));
+  };
 
-  //@ts-ignore
-  return { fetch, fetchCollection, getRef }
-}
+  // @ts-ignore
+  return { fetch, fetchCollection, getRef };
+};

+ 8 - 8
composables/data/useEntityManager.ts

@@ -1,15 +1,15 @@
+import { useRepo } from "pinia-orm";
 import EntityManager from "~/services/data/entityManager";
-import {useMaestroRequestService} from "~/composables/data/useMaestroRequestService";
-import {useRepo} from "pinia-orm";
+import { useMaestroRequestService } from "~/composables/data/useMaestroRequestService";
 
-let entityManager: EntityManager | null = null
+let entityManager: EntityManager | null = null;
 
 export const useEntityManager = () => {
   if (entityManager === null) {
-    const { apiRequestService } = useMaestroRequestService()
-    const getRepo = useRepo
+    const { apiRequestService } = useMaestroRequestService();
+    const getRepo = useRepo;
 
-    entityManager = new EntityManager(apiRequestService, getRepo)
+    entityManager = new EntityManager(apiRequestService, getRepo);
   }
-  return { em: entityManager }
-}
+  return { em: entityManager };
+};

+ 10 - 13
composables/data/useEnumFetch.ts

@@ -1,20 +1,17 @@
-import {useEnumManager} from "~/composables/data/useEnumManager";
-import type {Enum} from "~/types/data";
-import type {AsyncData} from "#app";
+import type { AsyncData } from "#app";
+import { useEnumManager } from "~/composables/data/useEnumManager";
+import type { Enum } from "~/types/data";
 
 interface useEnumFetchReturnType {
-  fetch: (enumName: string) => AsyncData<Enum, null | true | Error>,
+  fetch: (enumName: string) => AsyncData<Enum, null | true | Error>;
 }
 
 export const useEnumFetch = (lazy: boolean = false): useEnumFetchReturnType => {
-  const { enumManager } = useEnumManager()
+  const { enumManager } = useEnumManager();
 
-  const fetch = (enumName: string) => useAsyncData(
-    enumName,
-    () => enumManager.fetch(enumName),
-    { lazy }
-  )
+  const fetch = (enumName: string) =>
+    useAsyncData(enumName, () => enumManager.fetch(enumName), { lazy });
 
-  //@ts-ignore
-  return { fetch }
-}
+  // @ts-ignore
+  return { fetch };
+};

+ 9 - 9
composables/data/useEnumManager.ts

@@ -1,15 +1,15 @@
-import {useMaestroRequestService} from "~/composables/data/useMaestroRequestService";
+import { useI18n } from "vue-i18n";
+import { useMaestroRequestService } from "~/composables/data/useMaestroRequestService";
 import EnumManager from "~/services/data/enumManager";
-import {useI18n} from "vue-i18n";
 
-let enumManager:EnumManager | null = null
+let enumManager: EnumManager | null = null;
 
 export const useEnumManager = () => {
-  //Avoid memory leak
+  // Avoid memory leak
   if (enumManager === null) {
-    const { apiRequestService } = useMaestroRequestService()
-    const i18n = useI18n() as any
-    enumManager = new EnumManager(apiRequestService, i18n)
+    const { apiRequestService } = useMaestroRequestService();
+    const i18n = useI18n() as any;
+    enumManager = new EnumManager(apiRequestService, i18n);
   }
-  return { enumManager: enumManager }
-}
+  return { enumManager };
+};

+ 50 - 47
composables/data/useMaestroRequestService.ts

@@ -1,63 +1,66 @@
-import ApiRequestService from "~/services/data/apiRequestService";
-import type {Ref} from "@vue/reactivity";
+import type { Ref } from "vue";
 import type { FetchContext, FetchOptions } from "ofetch";
+import ApiRequestService from "~/services/data/apiRequestService";
 
 /**
  * Retourne une instance de ApiRequestService configurée pour interroger l'api Maestro
  *
  * @see https://github.com/unjs/ohmyfetch/blob/main/README.md#%EF%B8%8F-create-fetch-with-default-options
  */
-let apiRequestServiceClass: null | ApiRequestService = null
+let apiRequestServiceClass: null | ApiRequestService = null;
 
 export const useMaestroRequestService = () => {
-    const runtimeConfig = useRuntimeConfig()
-
-    const baseURL = runtimeConfig.apiBaseUrl ?? runtimeConfig.public.apiBaseUrl
-
-    const pending: Ref<boolean> = ref(false)
-
-    /**
-     * Peuple les headers avant l'envoi de la requête
-     *
-     * @param request
-     * @param options
-     */
-    const onRequest = async function ({ request, options }: FetchContext) {
-        // @ts-ignore
-        if(options && options.noXaccessId) {
-            return
-        }
-
-        pending.value = true
-        console.log('Request : ' + request + ' (SSR: ' + process.server + ')')
-    }
+  const runtimeConfig = useRuntimeConfig();
+
+  const baseURL = runtimeConfig.apiBaseUrl ?? runtimeConfig.public.apiBaseUrl;
 
-    const onResponse = async function({ request, options, response }: FetchContext) {
-        pending.value = false
+  const pending: Ref<boolean> = ref(false);
+
+  /**
+   * Peuple les headers avant l'envoi de la requête
+   *
+   * @param request
+   * @param options
+   */
+  const onRequest = async function ({ request, options }: FetchContext) {
+    // @ts-ignore
+    if (options && options.noXaccessId) {
+      return;
     }
 
-    /**
-     * Gère les erreurs retournées par l'api
-     *
-     * @param request
-     * @param response
-     * @param error
-     */
+    pending.value = true;
+    console.log("Request : " + request + " (SSR: " + process.server + ")");
+  };
 
+  const onResponse = async function ({
+    request,
+    options,
+    response,
+  }: FetchContext) {
+    pending.value = false;
+  };
 
-    const config : FetchOptions = {
-        baseURL,
-        onRequest,
-        onResponse,
-    }
+  /**
+   * Gère les erreurs retournées par l'api
+   *
+   * @param request
+   * @param response
+   * @param error
+   */
 
-    //Avoid memory leak
-    if (apiRequestServiceClass === null) {
-        // Utilise la fonction `create` d'ohmyfetch pour générer un fetcher dédié à l'interrogation de Ap2i
-        const fetcher = $fetch.create(config)
-        // @ts-ignore
-        apiRequestServiceClass = new ApiRequestService(fetcher)
-    }
+  const config: FetchOptions = {
+    baseURL,
+    onRequest,
+    onResponse,
+  };
+
+  // Avoid memory leak
+  if (apiRequestServiceClass === null) {
+    // Utilise la fonction `create` d'ohmyfetch pour générer un fetcher dédié à l'interrogation de Ap2i
+    const fetcher = $fetch.create(config);
+    // @ts-ignore
+    apiRequestServiceClass = new ApiRequestService(fetcher);
+  }
 
-    return { apiRequestService: apiRequestServiceClass, pending: pending }
-}
+  return { apiRequestService: apiRequestServiceClass, pending };
+};

+ 4 - 5
composables/useClientDevice.ts

@@ -1,12 +1,11 @@
-
 export function useClientDevice() {
   const isMobileDevice = () => {
     return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
-      navigator.userAgent
+      navigator.userAgent,
     );
-  }
+  };
 
   return {
-    isMobileDevice
-  }
+    isMobileDevice,
+  };
 }

+ 2 - 3
models/ApiModel.ts

@@ -5,7 +5,6 @@ import ApiResource from "~/models/ApiResource";
  *
  * These models support CRUD operations
  */
-class ApiModel extends ApiResource {
-}
+class ApiModel extends ApiResource {}
 
-export default ApiModel
+export default ApiModel;

+ 11 - 10
models/ApiResource.ts

@@ -1,21 +1,20 @@
-import {Model} from "pinia-orm";
+import { Model } from "pinia-orm";
 
 /**
  * Base class for resources that can be fetched from the API
  */
 export class ApiResource extends Model {
-
-  protected static _iriEncodedFields: Record<string, ApiResource>
+  protected static _iriEncodedFields: Record<string, ApiResource>;
 
   public static addIriEncodedField(name: string, target: ApiResource) {
     if (!this._iriEncodedFields) {
-      this._iriEncodedFields = {}
+      this._iriEncodedFields = {};
     }
-    this._iriEncodedFields[name] = target
+    this._iriEncodedFields[name] = target;
   }
 
   public static getIriEncodedFields() {
-    return this._iriEncodedFields
+    return this._iriEncodedFields;
   }
 
   /**
@@ -23,8 +22,8 @@ export class ApiResource extends Model {
    *
    * @see https://github.com/vuex-orm/vuex-orm/issues/255#issuecomment-876378684
    */
-  toJSON () {
-    return { ...this }
+  toJSON() {
+    return { ...this };
   }
 
   /**
@@ -33,8 +32,10 @@ export class ApiResource extends Model {
    * If it is, it means this entity does not exist in the data source and that it has a temporary id
    */
   public isNew(): boolean {
-    return !this.id || (typeof this.id === 'string' && this.id.slice(0, 3) === 'tmp')
+    return (
+      !this.id || (typeof this.id === "string" && this.id.slice(0, 3) === "tmp")
+    );
   }
 }
 
-export default ApiResource
+export default ApiResource;

+ 16 - 16
models/Maestro/ContactRequest.ts

@@ -1,5 +1,5 @@
+import { Uid, Str, Bool, Attr } from "pinia-orm/dist/decorators";
 import ApiModel from "~/models/ApiModel";
-import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
 
 /**
  * Maestro Model : ContactRequest
@@ -7,47 +7,47 @@ import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
  * @see https://gitlab.2iopenservice.com/opentalent/maestro/-/blob/master/src/ApiResource/ContactRequest.php?ref_type=heads
  */
 export default class ContactRequest extends ApiModel {
-  static entity = 'contact_request'
+  static entity = "contact_request";
 
   @Uid()
-  declare id: number
+  declare id: number;
 
   @Str(null)
-  declare name: string | null
+  declare name: string | null;
 
   @Str(null)
-  declare surname: string | null
+  declare surname: string | null;
 
   @Str(null)
-  declare email: string | null
+  declare email: string | null;
 
   @Str(null)
-  declare structureName: string | null
+  declare structureName: string | null;
 
   @Str(null)
-  declare message: string | null
+  declare message: string | null;
 
   @Bool(false)
-  declare privacyPolicyAccepted: boolean
+  declare privacyPolicyAccepted: boolean;
 
   @Str(null)
-  declare gender: string | null
+  declare gender: string | null;
 
   @Str(null)
-  declare postalCode: string | null
+  declare postalCode: string | null;
 
   @Str(null)
-  declare city: string | null
+  declare city: string | null;
 
   @Str(null)
-  declare phone: string | null
+  declare phone: string | null;
 
   @Str(null)
-  declare requestType: string | null
+  declare requestType: string | null;
 
   @Str(null)
-  declare concernedProduct: string | null
+  declare concernedProduct: string | null;
 
   @Bool(false)
-  declare newsletterSubscription: boolean
+  declare newsletterSubscription: boolean;
 }

+ 10 - 10
models/Maestro/JobApplication.ts

@@ -1,5 +1,5 @@
+import { Uid, Str, Bool, Attr } from "pinia-orm/dist/decorators";
 import ApiModel from "~/models/ApiModel";
-import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
 
 /**
  * Maestro Model : JobApplication
@@ -7,29 +7,29 @@ import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
  * @see https://gitlab.2iopenservice.com/opentalent/maestro/-/blob/master/src/ApiResources/JobApplication.php?ref_type=heads
  */
 export default class JobApplication extends ApiModel {
-  static entity = 'job_application'
+  static entity = "job_application";
 
   @Uid()
-  declare id: number
+  declare id: number;
 
   @Str(null)
-  declare name: string | null
+  declare name: string | null;
 
   @Str(null)
-  declare surname: string | null
+  declare surname: string | null;
 
   @Str(null)
-  declare phone: string | null
+  declare phone: string | null;
 
   @Str(null)
-  declare email: string | null
+  declare email: string | null;
 
   @Attr(null)
-  declare resume: object | null
+  declare resume: object | null;
 
   @Attr(null)
-  declare motivationLetter: object | null
+  declare motivationLetter: object | null;
 
   @Str(null)
-  declare message: string | null
+  declare message: string | null;
 }

+ 20 - 20
models/Maestro/JobPosting.ts

@@ -1,5 +1,5 @@
+import { Uid, Str, Bool, Attr } from "pinia-orm/dist/decorators";
 import ApiModel from "~/models/ApiModel";
-import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
 
 /**
  * Maestro Model : JobPosting
@@ -7,59 +7,59 @@ import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
  * @see https://gitlab.2iopenservice.com/opentalent/maestro/-/blob/master/src/Entity/JobPosting/JobPosting.php?ref_type=heads
  */
 export default class JobPosting extends ApiModel {
-  static entity = 'job_postings'
+  static entity = "job_postings";
 
   @Uid()
-  declare id: number
+  declare id: number;
 
   @Str(null)
-  declare type: string | null
+  declare type: string | null;
 
   @Str(null)
-  declare contractType: string | null
+  declare contractType: string | null;
 
   @Str(null)
-  declare title: string | null
+  declare title: string | null;
 
   @Str(null)
-  declare startPublication: string | null
+  declare startPublication: string | null;
 
   @Str(null)
-  declare updatedAt: string | null
+  declare updatedAt: string | null;
 
   @Str(null)
-  declare endPublication: string | null
+  declare endPublication: string | null;
 
   @Str(null)
-  declare city: string | null
+  declare city: string | null;
 
   @Str(null)
-  declare postalCode: string | null
+  declare postalCode: string | null;
 
   @Str(null)
-  declare content: string | null
+  declare content: string | null;
 
   @Bool(false)
-  declare featured: boolean
+  declare featured: boolean;
 
   @Attr([])
-  declare sector: string | null[]
+  declare sector: string | null[];
 
   @Attr([])
-  declare tags: any[]
+  declare tags: any[];
 
   @Str(null)
-  declare structureName: string | null
+  declare structureName: string | null;
 
   @Str(null)
-  declare structureNameText: any
+  declare structureNameText: any;
 
   @Str(null)
-  declare structureInfo: string | null
+  declare structureInfo: string | null;
 
   @Bool(false)
-  declare clientOpentalent: boolean
+  declare clientOpentalent: boolean;
 
   @Bool(false)
-  declare visible: boolean
+  declare visible: boolean;
 }

+ 23 - 23
models/Maestro/News.ts

@@ -1,5 +1,5 @@
+import { Uid, Str, Bool, Attr } from "pinia-orm/dist/decorators";
 import ApiModel from "~/models/ApiModel";
-import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
 
 /**
  * Maestro Model : News
@@ -7,68 +7,68 @@ import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
  * @see https://gitlab.2iopenservice.com/opentalent/maestro/-/blob/master/src/Entity/News/News.php?ref_type=heads
  */
 export default class News extends ApiModel {
-  static entity = 'news'
+  static entity = "news";
 
   @Uid()
-  declare id: number | string
+  declare id: number | string;
 
   @Str(null)
-  declare type: string | null
+  declare type: string | null;
 
   @Str(null)
-  declare title: string | null
+  declare title: string | null;
 
   @Str(null)
-  declare leadText: string | null
+  declare leadText: string | null;
 
   @Str(null)
-  declare bodyText: string | null
+  declare bodyText: string | null;
 
   @Bool(false)
-  declare featured: boolean
+  declare featured: boolean;
 
   @Bool(false)
-  declare favorite: boolean
+  declare favorite: boolean;
 
   @Attr({})
-  declare attachmentFile: any
+  declare attachmentFile: any;
 
   @Str(null)
-  declare attachment: string | null
+  declare attachment: string | null;
 
   @Str(null)
-  declare startPublication: string | null
+  declare startPublication: string | null;
 
   @Str(null)
-  declare updatedAt: string | null
+  declare updatedAt: string | null;
 
   @Str(null)
-  declare endPublication: string | null
+  declare endPublication: string | null;
 
   @Str(null)
-  declare domainType: string | null
+  declare domainType: string | null;
 
   @Str(null)
-  declare eventType: string | null
+  declare eventType: string | null;
 
   @Str(null)
-  declare categoryType: string | null
+  declare categoryType: string | null;
 
   @Str(null)
-  declare productType: string | null
+  declare productType: string | null;
 
   @Str(null)
-  declare optionsType: string | null
+  declare optionsType: string | null;
 
   @Str(null)
-  declare subOptionsType: string | null
+  declare subOptionsType: string | null;
 
   @Attr([])
-  declare tags: string[]
+  declare tags: string[];
 
   @Bool(false)
-  declare visible: boolean
+  declare visible: boolean;
 
   @Str(null)
-  declare linkButton: string
+  declare linkButton: string;
 }

+ 4 - 4
models/Maestro/Tag.ts

@@ -1,5 +1,5 @@
+import { Uid, Str, Bool, Attr } from "pinia-orm/dist/decorators";
 import ApiModel from "~/models/ApiModel";
-import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
 
 /**
  * Maestro Model : News
@@ -7,11 +7,11 @@ import {Uid, Str, Bool, Attr} from "pinia-orm/dist/decorators";
  * @see https://gitlab.2iopenservice.com/opentalent/maestro/-/blob/master/src/Entity/News/News.php?ref_type=heads
  */
 export default class Tag extends ApiModel {
-  static entity = 'tags'
+  static entity = "tags";
 
   @Uid()
-  declare id: number | string
+  declare id: number | string;
 
   @Str(null)
-  declare name: string | null
+  declare name: string | null;
 }

+ 6 - 8
models/decorators.ts

@@ -7,14 +7,12 @@ import ApiResource from "~/models/ApiResource";
  * If the property is decorated, the HydraNormalizer will parse the IRI when de-normalizing
  * to get the id(s), then re-encode it as IRI(s) when re-normalizing.
  */
-export function IriEncoded (
-  apiResource: typeof ApiResource
-): PropertyDecorator {
+export function IriEncoded(apiResource: typeof ApiResource): PropertyDecorator {
   return (target: Object, propertyKey: string | symbol) => {
-    //@ts-ignore
-    const self = target.$self()
+    // @ts-ignore
+    const self = target.$self();
 
-    //@ts-ignore
-    self.addIriEncodedField(propertyKey, apiResource)
-  }
+    // @ts-ignore
+    self.addIriEncodedField(propertyKey, apiResource);
+  };
 }

+ 5 - 5
models/models.ts

@@ -1,12 +1,12 @@
-const modules = import.meta.glob('~/models/*/*.ts')
 import ApiResource from "~/models/ApiResource";
+const modules = import.meta.glob("~/models/*/*.ts");
 
-const models: Record<string, typeof ApiResource> = {}
+const models: Record<string, typeof ApiResource> = {};
 
 for (const path in modules) {
   modules[path]().then((mod: any) => {
-    models[mod.default.entity] = mod.default
-  })
+    models[mod.default.entity] = mod.default;
+  });
 }
 
-export default models
+export default models;

+ 20 - 23
nuxt.config.ts

@@ -2,21 +2,21 @@ import fs from "fs";
 import vuetify from "vite-plugin-vuetify";
 import type { NuxtI18nOptions } from "@nuxtjs/i18n";
 
-let https = {}
+let https = {};
 
-let transpile = ['vuetify', 'pinia', 'pinia-orm', 'date-fns']
+const transpile = ["vuetify", "pinia", "pinia-orm", "date-fns"];
 
 if (!process.env.NUXT_ENV) {
-  throw Error('Missing environment file - Run yarn install')
+  throw new Error("Missing environment file - Run yarn install");
 }
 
-if (process.env.NUXT_ENV === 'dev') {
+if (process.env.NUXT_ENV === "dev") {
   https = {
-    key: fs.readFileSync('env/local.portail_v2.opentalent.fr.key'),
-    cert: fs.readFileSync('env/local.portail_v2.opentalent.fr.crt'),
-  }
+    key: fs.readFileSync("env/local.portail_v2.opentalent.fr.key"),
+    cert: fs.readFileSync("env/local.portail_v2.opentalent.fr.crt"),
+  };
 } else {
-  transpile.push('lodash')
+  transpile.push("lodash");
 }
 
 /**
@@ -41,10 +41,7 @@ export default defineNuxtConfig({
       hCaptchaSiteKey: "35360874-ebb1-4748-86e3-9b156d5bfc53",
     },
   },
-  css: [
-    "~/assets/style/main.scss",
-    "~/assets/style/theme.scss",
-  ],
+  css: ["~/assets/style/main.scss", "~/assets/style/theme.scss"],
   hooks: {
     "builder:watch": console.log,
   },
@@ -74,13 +71,13 @@ export default defineNuxtConfig({
         "vite:extendConfig",
         (config) =>
           (config.plugins ?? []).push(
-            vuetify()
-            //Remplacer par cela quand l'issue https://github.com/vuetifyjs/vuetify-loader/issues/273 sera règlée..
+            vuetify(),
+            // Remplacer par cela quand l'issue https://github.com/vuetifyjs/vuetify-loader/issues/273 sera règlée..
             // voir aussi : https://github.com/nuxt/nuxt/issues/15412 et https://github.com/vuetifyjs/vuetify-loader/issues/290
             // vuetify({
             //     styles: { configFile: './assets/css/settings.scss' }
             // })
-          ) as any
+          ) as any,
       );
     },
     [
@@ -98,12 +95,12 @@ export default defineNuxtConfig({
     "nuxt-lodash",
     "@nuxtjs/i18n",
     "@nuxt/devtools",
-    'nuxt3-leaflet'
+    "nuxt3-leaflet",
   ],
   router: {
     options: {
-      scrollBehaviorType: 'smooth'
-    }
+      scrollBehaviorType: "smooth",
+    },
   },
   webfontloader: {
     google: {
@@ -120,19 +117,19 @@ export default defineNuxtConfig({
       tsconfigRaw: {
         compilerOptions: {
           experimentalDecorators: true,
-        }
-      }
+        },
+      },
     },
     ssr: {
       noExternal: ["vuetify"],
     },
     server: {
       https,
-      //@ts-ignore
+      // @ts-ignore
       port: 443,
       hmr: {
         protocol: "wss",
-        port: 24680
+        port: 24680,
       },
     },
   },
@@ -154,6 +151,6 @@ export default defineNuxtConfig({
     detectBrowserLanguage: false,
   } as NuxtI18nOptions,
   build: {
-    transpile: transpile,
+    transpile,
   },
 });

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است