浏览代码

fix eslint and prettier

Olivier Massot 1 年之前
父节点
当前提交
352b36115a
共有 100 个文件被更改,包括 1726 次插入1728 次删除
  1. 4 5
      .prettierrc
  2. 2 2
      app.vue
  3. 48 48
      components/About/Chronologie.vue
  4. 44 44
      components/About/Equipe.vue
  5. 1 1
      components/About/FAQ.vue
  6. 34 34
      components/About/Logiciels.vue
  7. 1 1
      components/About/Presentation.vue
  8. 18 18
      components/About/Valeurs.vue
  9. 36 36
      components/Common/ActionMenu.vue
  10. 51 51
      components/Common/Agenda.vue
  11. 6 6
      components/Common/AgendaLink.vue
  12. 4 4
      components/Common/Avantages.vue
  13. 8 8
      components/Common/Banner.vue
  14. 3 3
      components/Common/Card/Benefit.vue
  15. 1 1
      components/Common/Card/Stat.vue
  16. 10 10
      components/Common/Carousel/Clients.vue
  17. 14 14
      components/Common/Carousel/Fonctionnalite.vue
  18. 3 3
      components/Common/Contact.vue
  19. 5 5
      components/Common/ContainerVideo.vue
  20. 11 11
      components/Common/MenuScroll.vue
  21. 6 6
      components/Common/Meta.vue
  22. 12 12
      components/Common/Presentation.vue
  23. 12 12
      components/Common/ReviewSection.vue
  24. 25 25
      components/Common/Share.vue
  25. 11 11
      components/Common/Table/Comparatif.vue
  26. 1 1
      components/Contact/AddressSection.vue
  27. 48 49
      components/Contact/Form.vue
  28. 6 6
      components/Contact/Map.vue
  29. 44 44
      components/Formation/Catalogue.vue
  30. 1 1
      components/Formation/Certification.vue
  31. 1 1
      components/Formation/OPCA.vue
  32. 2 2
      components/Formation/Participation.vue
  33. 1 1
      components/Formation/Presentation.vue
  34. 16 16
      components/Formation/Reviews.vue
  35. 1 1
      components/Home/Besoin.vue
  36. 51 51
      components/Home/Caroussel.vue
  37. 4 4
      components/Home/EventAgenda.vue
  38. 39 39
      components/Home/Reviews.vue
  39. 46 46
      components/Home/Solution.vue
  40. 34 35
      components/JoinUs/Form.vue
  41. 16 16
      components/JoinUs/MissionDetail.vue
  42. 22 22
      components/JoinUs/Missions.vue
  43. 16 16
      components/Layout/AnchoredSection.vue
  44. 30 30
      components/Layout/Captcha.vue
  45. 2 2
      components/Layout/FAQ.vue
  46. 39 39
      components/Layout/Footer/Footer.vue
  47. 2 2
      components/Layout/Footer/Prefooter.vue
  48. 1 1
      components/Layout/Footer/Solutions.vue
  49. 20 20
      components/Layout/Navigation.vue
  50. 3 3
      components/Layout/Navigation/Lg.vue
  51. 23 23
      components/Layout/Navigation/Md.vue
  52. 1 1
      components/Layout/Navigation/Topbar.vue
  53. 6 6
      components/Layout/Pagination.vue
  54. 2 2
      components/Layout/UI/SubTitle.vue
  55. 2 2
      components/Layout/UI/TitlePage.vue
  56. 3 3
      components/Logiciels/Artist/Abonnement.vue
  57. 18 18
      components/Logiciels/Artist/Avantages.vue
  58. 26 26
      components/Logiciels/Artist/Comparatif.vue
  59. 54 54
      components/Logiciels/Artist/Fonctionnalites.vue
  60. 1 1
      components/Logiciels/Artist/Formations.vue
  61. 14 14
      components/Logiciels/Artist/Presentation.vue
  62. 8 8
      components/Logiciels/Artist/Reviews.vue
  63. 16 16
      components/Logiciels/Artist/SomeNumbers.vue
  64. 30 30
      components/Logiciels/Manager/Avantages.vue
  65. 56 56
      components/Logiciels/Manager/Fonctionnalites.vue
  66. 16 16
      components/Logiciels/Manager/Formation.vue
  67. 1 1
      components/Logiciels/Manager/Network.vue
  68. 17 17
      components/Logiciels/Manager/Presentation.vue
  69. 18 18
      components/Logiciels/Manager/Reviews.vue
  70. 18 18
      components/Logiciels/School/Avantages.vue
  71. 33 33
      components/Logiciels/School/Comparatif.vue
  72. 71 71
      components/Logiciels/School/Fonctionnalites.vue
  73. 17 17
      components/Logiciels/School/Formations.vue
  74. 14 14
      components/Logiciels/School/Presentation.vue
  75. 14 14
      components/Logiciels/School/Reviews.vue
  76. 15 15
      components/Logiciels/School/SomeNumbers.vue
  77. 2 2
      components/Logiciels/Title.vue
  78. 13 13
      components/News/Details.vue
  79. 20 20
      components/News/List.vue
  80. 62 62
      components/Webinaire/Catalogue.vue
  81. 13 13
      components/Webinaire/FAQ.vue
  82. 30 31
      composables/data/useEntityFetch.ts
  83. 9 9
      composables/data/useEntityManager.ts
  84. 8 8
      composables/data/useEnumFetch.ts
  85. 10 9
      composables/data/useEnumManager.ts
  86. 20 24
      composables/data/useMaestroRequestService.ts
  87. 4 4
      composables/useClientDevice.ts
  88. 2 2
      models/ApiModel.ts
  89. 11 10
      models/ApiResource.ts
  90. 17 17
      models/Maestro/ContactRequest.ts
  91. 11 11
      models/Maestro/JobApplication.ts
  92. 21 21
      models/Maestro/JobPosting.ts
  93. 24 24
      models/Maestro/News.ts
  94. 5 5
      models/Maestro/Tag.ts
  95. 7 6
      models/decorators.ts
  96. 9 7
      models/models.ts
  97. 64 63
      nuxt.config.ts
  98. 10 10
      pages/formations.vue
  99. 21 21
      pages/opentalent_artist.vue
  100. 23 23
      pages/opentalent_manager.vue

+ 4 - 5
.prettierrc

@@ -1,7 +1,6 @@
 {
-  "prettier": {
-    "tabWidth": 2,
-    "singleQuote": true,
-    "semi": false
-  }
+  "trailingComma": "es5",
+  "tabWidth": 2,
+  "semi": false,
+  "singleQuote": true
 }

+ 2 - 2
app.vue

@@ -11,7 +11,7 @@
 </template>
 
 <script setup lang="ts">
-const layoutStore = useLayoutStore();
+const layoutStore = useLayoutStore()
 
-layoutStore.resetAnchoredSections();
+layoutStore.resetAnchoredSections()
 </script>

+ 48 - 48
components/About/Chronologie.vue

@@ -70,115 +70,115 @@
 </template>
 
 <script setup lang="ts">
-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";
+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 activeSlide: Ref<number> = ref(0)
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
-const goPrevious = () => carousel.value!.prev();
-const goNext = () => carousel.value!.next();
+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;
+    return 0
   }
-  const startYear = 2005;
-  const endYear = 2024;
-  return ((intYear - startYear) / (endYear - startYear)) * 100;
-};
+  const startYear = 2005
+  const endYear = 2024
+  return ((intYear - startYear) / (endYear - startYear)) * 100
+}
 
 const slides: Array<ChronologyItem> = [
   {
-    year: "2005",
+    year: '2005',
     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",
+      '/images/pages/qui-sommes-nous/chronologie/1-Origine_Opentalent-outil_collaboratif_pour_la_culture.jpg',
   },
   {
-    year: "2006",
-    title: "Développement et partenariat stratégique",
+    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",
+      '/images/pages/qui-sommes-nous/chronologie/2-Developpement_et_partenariat_strategique_Opentalent.jpg',
   },
   {
-    year: "2008",
+    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",
+      '/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",
+    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.",
+      '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",
+      '/images/pages/qui-sommes-nous/chronologie/4-Logiciel_MusAssos-pour_les_petites_et_moyennes_structures.png',
   },
   {
-    year: "2010",
+    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",
+      '/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",
+    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",
+      '/images/pages/qui-sommes-nous/chronologie/6-FFEC_Reso_Cirque-Ouverture_vers_une_culture_multidisciplinaire.png',
   },
   {
-    year: "2015",
-    title: "Refonte Technologique",
+    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.",
+      '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",
+      '/images/pages/qui-sommes-nous/chronologie/7-Refonte_technologique_des_logiciels_Opentalent_securitee_modernitee_intuitivitee.jpg',
   },
   {
-    year: "2019",
-    title: "Nouvelle Génération Opentalent",
+    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",
+      '/images/pages/qui-sommes-nous/chronologie/8-Nouvelle_generation_Opentalent_moderne_securisee_experience_optimisee.jpg',
   },
   {
-    year: "2024",
-    title: "Relooking du site Opentalent",
+    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.",
+      '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",
+      '/images/pages/qui-sommes-nous/chronologie/9-Relooking_du_site_internet_Opentalent_agenda_et_logiciels_culturels.jpg',
   },
   {
-    year: "",
-    title: "LE FUTUR AVEC VOUS... ",
+    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",
+      '/images/pages/qui-sommes-nous/chronologie/10-Opentalent_ensemble_construisons_notre_futur.jpg',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 44 - 44
components/About/Equipe.vue

@@ -64,82 +64,82 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { SocietyMember } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { SocietyMember } from '~/types/interface'
 
 const associates: Array<SocietyMember> = [
   {
-    name: "Guillaume",
-    position: "Co-fondateur / Gérant",
+    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",
+      '/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",
+    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",
+      '/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',
   },
-];
+]
 
 const employees: Array<SocietyMember> = [
   {
-    name: "Johan",
-    position: "Formation et Assistance",
+    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",
+      '/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",
+    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é",
+      '/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",
+    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",
+      '/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é",
+    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é',
   },
   {
-    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",
+    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',
   },
   {
-    name: "Olivier",
-    position: "Développeur",
+    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",
+      '/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",
+    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é",
+      '/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",
+    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é",
+      '/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>
 
 <style scoped lang="scss">

+ 1 - 1
components/About/FAQ.vue

@@ -28,7 +28,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

+ 34 - 34
components/About/Logiciels.vue

@@ -53,57 +53,57 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 
 const features: Array<string> = [
-  "Une gestion de vos contacts",
-  "Un agenda collaboratif et interactif",
-  "Une gestion du matériel et du stock",
-  "Une communication simplifiée",
+  'Une gestion de vos contacts',
+  'Un agenda collaboratif et interactif',
+  'Une gestion du matériel et du stock',
+  'Une communication simplifiée',
   "Un rapport d'activité complet",
-  "Un site internet intégré",
-  "Et bien plus encore...",
-];
+  'Un site internet intégré',
+  'Et bien plus encore...',
+]
 
 const items: Array<{
-  imageUrl: string;
-  alt: string;
-  logoUrl: string;
-  logoAlt: string;
-  class: string;
-  link: string;
+  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",
-    alt: "Partition tenue par une femme dans une chorale",
-    logoUrl: "/images/logos/opentalent/Logo_Opentalent_Artist-blanc.png",
+      '/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",
-    class: "artist",
-    link: "/opentalent_artist",
+      '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",
-    alt: "Deux jeunes filles jouant du violon",
-    logoUrl: "/images/logos/opentalent/Logo_Opentalent_School-blanc.png",
+      '/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",
-    class: "school",
-    link: "/opentalent_school",
+      '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",
-    alt: "Carte de réseau des structures de la confédération musicale de France",
-    logoUrl: "/images/logos/opentalent/Logo_Opentalent_Manager-blanc.png",
+      '/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",
-    class: "manager",
-    link: "/opentalent_manager",
+      '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',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">
@@ -125,7 +125,7 @@ li {
 }
 
 li:before {
-  content: "";
+  content: '';
   position: absolute;
   left: -10px;
   top: 50%;

+ 1 - 1
components/About/Presentation.vue

@@ -68,7 +68,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

+ 18 - 18
components/About/Valeurs.vue

@@ -45,43 +45,43 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { SocietyValue } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { SocietyValue } from '~/types/interface'
 
 const values: Array<Array<SocietyValue>> = [
   [
     {
-      img: "/images/pages/qui-sommes-nous/valeurs/Management.svg",
-      alt: "Icône management social",
-      title: "Management social",
+      img: '/images/pages/qui-sommes-nous/valeurs/Management.svg',
+      alt: 'Icône management social',
+      title: 'Management social',
       description:
         "Guillaume et Michel sont sur la même longueur d’onde et donnent le « La » à un management social et solidaire où plus que de mettre en avant l'entreprise, ils privilégient la mise en avant des hommes et femmes qui la composent. Toux ceux qui participent jour après jour à l’écriture de la partition sont valorisés. Le partage, l’échange et le dialogue en lieu et place des liens de subordination.",
     },
     {
-      img: "/images/pages/qui-sommes-nous/valeurs/Satisfaction-client.svg",
-      alt: "Icône Satisfaction client",
-      title: "Satisfaction client",
+      img: '/images/pages/qui-sommes-nous/valeurs/Satisfaction-client.svg',
+      alt: 'Icône Satisfaction client',
+      title: 'Satisfaction client',
       description:
-        "Opentalent met un point d’honneur à satisfaire ses clients en leur proposant des solutions de qualité, un projet global dans lequel ils se retrouvent. L’intention de base est bel et bien de proposer un équilibre entre les solutions informatiques et la volonté personnelle en lien avec la production et les publics concernés.",
+        'Opentalent met un point d’honneur à satisfaire ses clients en leur proposant des solutions de qualité, un projet global dans lequel ils se retrouvent. L’intention de base est bel et bien de proposer un équilibre entre les solutions informatiques et la volonté personnelle en lien avec la production et les publics concernés.',
     },
   ],
   [
     {
-      img: "/images/pages/qui-sommes-nous/valeurs/Ecologie.svg",
-      alt: "Icône Écologie",
-      title: "Écologie",
+      img: '/images/pages/qui-sommes-nous/valeurs/Ecologie.svg',
+      alt: 'Icône Écologie',
+      title: 'Écologie',
       description:
-        "Proche des entreprises de l’Économie Sociale et Solidaire, Opentalent accorde une grande importance aux démarches liées à l’écologie et au développement durable. Le code des outils est par exemple optimisé pour limiter les ressources nécessaires des serveurs, réduisant ainsi leur empreinte carbone et améliorant le confort des utilisateurs au quotidien.",
+        'Proche des entreprises de l’Économie Sociale et Solidaire, Opentalent accorde une grande importance aux démarches liées à l’écologie et au développement durable. Le code des outils est par exemple optimisé pour limiter les ressources nécessaires des serveurs, réduisant ainsi leur empreinte carbone et améliorant le confort des utilisateurs au quotidien.',
     },
     {
-      img: "/images/pages/qui-sommes-nous/valeurs/Open-source.svg",
-      alt: "Icône Open source",
-      title: "Open source",
+      img: '/images/pages/qui-sommes-nous/valeurs/Open-source.svg',
+      alt: 'Icône Open source',
+      title: 'Open source',
       description:
-        "Opentalent est une entreprise qui croit profondément aux vertus des logiciels Open Source et qui par son action contribue à leur développement.",
+        'Opentalent est une entreprise qui croit profondément aux vertus des logiciels Open Source et qui par son action contribue à leur développement.',
     },
   ],
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 36 - 36
components/Common/ActionMenu.vue

@@ -37,43 +37,43 @@ de l'écran (ou au bas de l'écran sur les petits écrans)
 </template>
 
 <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";
+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 { lgAndUp } = useDisplay()
+const router = useRouter()
+const layoutStore = useLayoutStore()
+const { isMobileDevice } = useClientDevice()
 
-const telephoneNumber = "09 72 12 60 17";
+const telephoneNumber = '09 72 12 60 17'
 
 const isVisible: ComputedRef<boolean> = computed(
   () =>
     !layoutStore.isHeaderVisible &&
     !layoutStore.isBannerVisible &&
-    !layoutStore.isFooterVisible,
-);
+    !layoutStore.isFooterVisible
+)
 
 // Actions par défaut du menu, peut-être surchargé via la propriété `actions`
 const defaultActions: Array<ActionMenuItem> = [
   {
     type: ActionMenuItemType.FOLLOW_LINK,
-    color: "secondary",
-    icon: "far fa-comments",
-    text: "Nous contacter",
-    url: { path: "nous-contacter", hash: "#form" },
+    color: 'secondary',
+    icon: 'far fa-comments',
+    text: 'Nous contacter',
+    url: { path: 'nous-contacter', hash: '#form' },
   },
   {
     type: ActionMenuItemType.CALL_US,
-    color: "primary",
-    icon: "fas fa-phone",
-    text: "Nous Appeler",
+    color: 'primary',
+    icon: 'fas fa-phone',
+    text: 'Nous Appeler',
   },
-];
+]
 
 const props = defineProps({
   /**
@@ -84,19 +84,19 @@ const props = defineProps({
     required: false,
     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}`;
+    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
@@ -105,24 +105,24 @@ const callUs = () => {
 const onActionClick = (action: ActionMenuItem) => {
   switch (action.type) {
     case ActionMenuItemType.ASK_FOR_A_DEMO:
-      router.push({ path: action.url as string, query: { request: "demo" } });
-      break;
+      router.push({ path: action.url as string, query: { request: 'demo' } })
+      break
 
     case ActionMenuItemType.CALL_US:
-      callUs();
-      break;
+      callUs()
+      break
 
     case ActionMenuItemType.FOLLOW_LINK:
       if (!action.url) {
-        throw new Error("Missing prop : url");
+        throw new Error('Missing prop : url')
       }
-      navigateTo(action.url);
-      break;
+      navigateTo(action.url)
+      break
 
     default:
-      throw new Error("Unrecognized action");
+      throw new Error('Unrecognized action')
   }
-};
+}
 </script>
 
 <style scoped lang="scss">

+ 51 - 51
components/Common/Agenda.vue

@@ -71,81 +71,81 @@ Section "Agenda des évènements"
 </template>
 
 <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";
+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'
 
 const tagColor = (tag: string) => {
   switch (tag) {
-    case "Payant":
-      return "red";
-    case "Gratuit":
-      return "green";
+    case 'Payant':
+      return 'red'
+    case 'Gratuit':
+      return 'green'
     default:
-      return "primary";
+      return 'primary'
   }
-};
+}
 
 const tagTextColor = (tag: string) => {
   switch (tag) {
-    case "Payant":
-      return "red--text";
-    case "Gratuit":
-      return "green--text";
+    case 'Payant':
+      return 'red--text'
+    case 'Gratuit':
+      return 'green--text'
     default:
-      return "black--text";
+      return 'black--text'
   }
-};
+}
 
 const events: Array<Event> = [
   {
-    rdv: "20h00",
-    title: "LA NUIT DES RÊVES  ",
-    localisation: "FESTIVALDE musique - LONGCHAMP",
-    date: "21/06/2023",
-    img: "/images/agenda/agenda2.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'LA NUIT DES RÊVES  ',
+    localisation: 'FESTIVALDE musique - LONGCHAMP',
+    date: '21/06/2023',
+    img: '/images/agenda/agenda2.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
   {
-    rdv: "20h00",
-    title: "LE LAC DES CYGNES",
-    localisation: "SPECTACLE DE DANSE - PARIS 1",
-    date: "22/06/2023",
-    img: "/images/agenda/agenda3.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Gratuit"],
+    rdv: '20h00',
+    title: 'LE LAC DES CYGNES',
+    localisation: 'SPECTACLE DE DANSE - PARIS 1',
+    date: '22/06/2023',
+    img: '/images/agenda/agenda3.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Gratuit'],
   },
   {
-    rdv: "20h00",
-    title: "SOLIDAYS 2023  : 23 > 25 juin",
-    localisation: "ORCHESTRE DE PARIS - PARIS 12",
-    date: "23/06/2023",
-    img: "/images/agenda/agenda4.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'SOLIDAYS 2023  : 23 > 25 juin',
+    localisation: 'ORCHESTRE DE PARIS - PARIS 12',
+    date: '23/06/2023',
+    img: '/images/agenda/agenda4.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
   {
-    rdv: "20h00",
-    title: "LE LAC DES CYGNES",
-    localisation: "FESTIVALDE musique - LONGCHAMP",
-    date: "24/06/2023",
-    img: "/images/agenda/agenda5.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'LE LAC DES CYGNES',
+    localisation: 'FESTIVALDE musique - LONGCHAMP',
+    date: '24/06/2023',
+    img: '/images/agenda/agenda5.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
   {
-    rdv: "20h00",
-    title: "SOLIDAYS 2023  : 23 > 25 juin ",
-    localisation: "SPECTACLE DE DANSE - PARIS 1",
-    date: "20/06/2023",
-    img: "/images/agenda/agenda1.jpg",
-    tags: ["Festival", "Musique", "Tout public", "Payant"],
+    rdv: '20h00',
+    title: 'SOLIDAYS 2023  : 23 > 25 juin ',
+    localisation: 'SPECTACLE DE DANSE - PARIS 1',
+    date: '20/06/2023',
+    img: '/images/agenda/agenda1.jpg',
+    tags: ['Festival', 'Musique', 'Tout public', 'Payant'],
   },
-];
+]
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
-const goPrevious = () => carousel.value!.prev();
-const goNext = () => carousel.value!.next();
+const goPrevious = () => carousel.value!.prev()
+const goNext = () => carousel.value!.next()
 </script>
 
 <style scoped>

+ 6 - 6
components/Common/AgendaLink.vue

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

+ 4 - 4
components/Common/Avantages.vue

@@ -19,8 +19,8 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "vue";
-import type { Benefit } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { Benefit } from '~/types/interface'
 
 defineProps({
   benefits: {
@@ -30,9 +30,9 @@ defineProps({
   title: {
     type: String,
     required: false,
-    default: "Des avantages concrets",
+    default: 'Des avantages concrets',
   },
-});
+})
 </script>
 
 <style scoped lang="scss">

+ 8 - 8
components/Common/Banner.vue

@@ -41,8 +41,8 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "vue";
-import { useLayoutStore } from "~/stores/layoutStore";
+import type { PropType } from 'vue'
+import { useLayoutStore } from '~/stores/layoutStore'
 
 defineProps({
   imageSrc: {
@@ -51,7 +51,7 @@ defineProps({
   },
   imageAlt: {
     type: String,
-    default: "",
+    default: '',
   },
   squareText: {
     type: String,
@@ -66,7 +66,7 @@ defineProps({
   logoAlt: {
     type: String,
     required: false,
-    default: "",
+    default: '',
   },
   logoAltTheme: {
     type: Boolean,
@@ -76,12 +76,12 @@ defineProps({
     type: Boolean,
     default: false,
   },
-});
+})
 
-const layoutStore = useLayoutStore();
+const layoutStore = useLayoutStore()
 const onIntersect = (isIntersecting: boolean) => {
-  layoutStore.setIsBannerVisible(isIntersecting);
-};
+  layoutStore.setIsBannerVisible(isIntersecting)
+}
 </script>
 
 <style scoped lang="scss">

+ 3 - 3
components/Common/Card/Benefit.vue

@@ -28,15 +28,15 @@ Carte "Avantage" de la section Avantages d'une page Logiciel
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "vue";
-import type { Benefit } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { Benefit } from '~/types/interface'
 
 defineProps({
   benefit: {
     type: Object as PropType<Benefit>,
     required: true,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">

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

@@ -19,7 +19,7 @@ const props = defineProps({
     type: String,
     required: true,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">

+ 10 - 10
components/Common/Carousel/Clients.vue

@@ -49,28 +49,28 @@
 </template>
 
 <script setup lang="ts">
-import { Carousel, Slide } from "vue3-carousel";
-import type { PropType, Ref } from "vue";
-import { useDisplay } from "vuetify";
+import { Carousel, Slide } from 'vue3-carousel'
+import type { PropType, Ref } from 'vue'
+import { useDisplay } from 'vuetify'
 
-const { smAndUp, lgAndUp, mdAndDown } = useDisplay();
+const { smAndUp, lgAndUp, mdAndDown } = useDisplay()
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
 defineProps({
   items: {
     type: Array as PropType<Array<{ src: string; alt: string }>>,
     required: true,
   },
-});
+})
 
 const goToPrevious = () => {
-  carousel.value!.prev();
-};
+  carousel.value!.prev()
+}
 
 const goToNext = () => {
-  carousel.value!.next();
-};
+  carousel.value!.next()
+}
 </script>
 
 <style scoped lang="scss">

+ 14 - 14
components/Common/Carousel/Fonctionnalite.vue

@@ -61,34 +61,34 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import type { PropType, Ref } from "vue";
-import type { Functionality } from "~/types/interface";
+import { useDisplay } from 'vuetify'
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import type { PropType, Ref } from 'vue'
+import type { Functionality } from '~/types/interface'
 
-const { lgAndUp, mdAndUp, smAndUp } = useDisplay();
+const { lgAndUp, mdAndUp, smAndUp } = useDisplay()
 
 defineProps({
   cards: {
     type: Array as PropType<Array<Functionality>>,
     required: true,
   },
-});
+})
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
 const itemsToShow = computed(() =>
-  lgAndUp.value ? 5 : mdAndUp.value ? 3 : smAndUp.value ? 2 : 1,
-);
+  lgAndUp.value ? 5 : mdAndUp.value ? 3 : smAndUp.value ? 2 : 1
+)
 
 const nextAction = () => {
-  carousel.value!.next();
-};
+  carousel.value!.next()
+}
 
 const previousAction = () => {
-  carousel.value!.prev();
-};
+  carousel.value!.prev()
+}
 </script>
 
 <style scoped lang="scss">

+ 3 - 3
components/Common/Contact.vue

@@ -82,10 +82,10 @@
   </AnchoredSection>
 </template>
 <script setup>
-import { useDisplay } from "vuetify";
-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>

+ 5 - 5
components/Common/ContainerVideo.vue

@@ -29,9 +29,9 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
 defineProps({
   title: {
@@ -44,9 +44,9 @@ defineProps({
   },
   videoUrl: {
     type: String,
-    default: "",
+    default: '',
   },
-});
+})
 </script>
 
 <style scoped lang="scss">
@@ -71,7 +71,7 @@ defineProps({
 }
 
 .screen-img-3 {
-  background-image: url("/images/components/presentation/Ordinateur_avec_ecran_fiche_adherent_du_logiciel_Opentalent_Artist.png");
+  background-image: url('/images/components/presentation/Ordinateur_avec_ecran_fiche_adherent_du_logiciel_Opentalent_Artist.png');
   background-size: cover;
   background-position: center;
   width: 650px;

+ 11 - 11
components/Common/MenuScroll.vue

@@ -34,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 { ComputedRef, PropType, Ref } from "vue";
-import type { MenuScroll } from "~/types/interface";
-import { useLayoutStore } from "~/stores/layoutStore";
+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,
   },
-});
+})
 
-const layoutStore = useLayoutStore();
+const layoutStore = useLayoutStore()
 
-const isSticky: Ref<boolean> = ref(false);
+const isSticky: Ref<boolean> = ref(false)
 
 const activeMenuItem: ComputedRef<string | null> = computed(() => {
   return (
     Object.entries(layoutStore.isAnchoredSectionOnScreen).find(
-      ([_, value]) => value,
+      ([_, value]) => value
     )?.[0] ?? null
-  );
-});
+  )
+})
 
 const handleScroll = () => {
-  isSticky.value = window.scrollY > 800;
-};
+  isSticky.value = window.scrollY > 800
+}
 </script>
 
 <style scoped lang="scss">

+ 6 - 6
components/Common/Meta.vue

@@ -18,9 +18,9 @@ const props = defineProps({
   image: {
     type: String,
     required: false,
-    default: "images/Opentalent",
+    default: 'images/Opentalent',
   },
-});
+})
 
 useSeoMeta({
   title: props.title,
@@ -31,8 +31,8 @@ useSeoMeta({
   twitterDescription: props.description,
   ogImage: props.image,
   twitterImage: props.image,
-  twitterCard: "summary_large_image",
-  ogType: "website",
-  ogLocale: "fr_FR",
-});
+  twitterCard: 'summary_large_image',
+  ogType: 'website',
+  ogLocale: 'fr_FR',
+})
 </script>

+ 12 - 12
components/Common/Presentation.vue

@@ -74,8 +74,8 @@ Section "Présentation" d'une page Logiciel
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "vue";
-import type { FeaturePicto } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { FeaturePicto } from '~/types/interface'
 
 defineProps({
   title: {
@@ -85,12 +85,12 @@ defineProps({
   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>>,
@@ -102,37 +102,37 @@ defineProps({
   },
   logoSrc: {
     type: String,
-    default: "",
+    default: '',
   },
   logoAlt: {
     type: String,
-    default: "",
+    default: '',
   },
   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>
 
 <style scoped lang="scss">

+ 12 - 12
components/Common/ReviewSection.vue

@@ -52,30 +52,30 @@
 </template>
 
 <script setup lang="ts">
-import { Carousel, Slide } from "vue3-carousel";
-import "vue3-carousel/dist/carousel.css";
-import type { PropType, Ref } from "vue";
-import { useDisplay } from "vuetify";
-import type { Review } from "~/types/interface";
+import { Carousel, Slide } from 'vue3-carousel'
+import 'vue3-carousel/dist/carousel.css'
+import type { PropType, Ref } from 'vue'
+import { useDisplay } from 'vuetify'
+import type { Review } from '~/types/interface'
 
 defineProps({
   cards: {
     type: Array as PropType<Array<Review>>,
     required: true,
   },
-});
+})
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
-const carousel: Ref<typeof Carousel | null> = ref(null);
+const carousel: Ref<typeof Carousel | null> = ref(null)
 
 const goPrevious = () => {
-  carousel.value!.prev();
-};
+  carousel.value!.prev()
+}
 
 const goNext = () => {
-  carousel.value!.next();
-};
+  carousel.value!.next()
+}
 </script>
 
 <style scoped lang="scss">

+ 25 - 25
components/Common/Share.vue

@@ -13,53 +13,53 @@
 </template>
 
 <script setup lang="ts">
-import type { Ref } from "vue";
-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;
+  url.value = window.location.href
 
   networks.value = [
     {
-      name: "Facebook",
-      icon: "fa-brands fa-facebook",
-      colorOnHover: "#135fc2",
+      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",
+      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",
+      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: 'Instagram',
+      icon: 'fa-brands fa-instagram',
+      colorOnHover: '#d0006a',
+      url: 'https://instagram.com',
     },
     {
-      name: "Linkedin",
-      icon: "fa-brands fa-linkedin",
-      colorOnHover: "#006291",
+      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",
+      name: 'Email',
+      icon: 'fas fa-envelope',
+      colorOnHover: '#292929',
       url: `mailto:?body=${url.value}`,
     },
-  ];
+  ]
 }
 </script>
 

+ 11 - 11
components/Common/Table/Comparatif.vue

@@ -181,11 +181,11 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import type { PropType } from "vue";
-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: {
@@ -200,19 +200,19 @@ const props = defineProps({
     type: Array as PropType<Array<ComparisonItem>>,
     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>
 
 <style scoped lang="scss">

+ 1 - 1
components/Contact/AddressSection.vue

@@ -40,7 +40,7 @@
 </template>
 
 <script setup lang="ts">
-const revealPhoneNumber = ref(false);
+const revealPhoneNumber = ref(false)
 </script>
 
 <style scoped lang="scss">

+ 48 - 49
components/Contact/Form.vue

@@ -208,83 +208,82 @@
 </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'
+import { type ComputedRef, reactive, Ref } from 'vue'
+import ContactRequest from '~/models/Maestro/ContactRequest'
+import { useEntityManager } from '~/composables/data/useEntityManager'
 
-const route = useRoute();
-const router = useRouter();
-const { em } = useEntityManager();
+const route = useRoute()
+const router = useRouter()
+const { em } = useEntityManager()
 
-const form: Ref<HTMLElement | null> = ref(null);
+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" },
-];
+  { 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" },
-];
+  { 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";
+const defaultRequestType = route.query.request ?? 'CONTACT_REQUEST_INFORMATION'
 
 // @ts-ignore
 const contactRequest: ContactRequest = reactive(
-  em.newInstance(ContactRequest, { requestType: defaultRequestType }),
-);
+  em.newInstance(ContactRequest, { requestType: defaultRequestType })
+)
 
 // --- Validation ---
-const maxMessageLength = 2000;
+const maxMessageLength = 2000
 
 const leftCars: ComputedRef<number> = computed(
   () =>
     maxMessageLength -
-    (contactRequest.message ? contactRequest.message.length : 0),
-);
+    (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";
+  !!surname || 'Le prénom est obligatoire'
 
 const validatePostalCode = (postalCode: string | null) =>
   (!!postalCode && /^\d{5}$/.test(postalCode)) ||
-  "Le code postal doit être valide";
+  'Le code postal doit être valide'
 
 const validateCity = (city: string | null) =>
-  !!city || "La ville est obligatoire";
+  !!city || 'La ville est obligatoire'
 
 const validateEmail = (email: string | null) =>
-  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide";
+  (!!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";
+  'Le numéro de téléphone doit être valide'
 
 const validateStructureName = (structureName: string | null) =>
-  !!structureName || "Le nom de la structure est requis";
+  !!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) ||
-  "Le message ne doit pas dépasser " + maxMessageLength + " caractères";
+  'Le message ne doit pas dépasser ' + maxMessageLength + ' caractères'
 
-const contactRequestSent: Ref<boolean> = ref(false);
+const contactRequestSent: Ref<boolean> = ref(false)
 
-const errorMsg: Ref<string | null> = ref(null);
+const errorMsg: Ref<string | null> = ref(null)
 
 /**
  * Submits the contact form.
@@ -296,27 +295,27 @@ 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;
+      "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;
+  contactRequestSent.value = true
+  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">

+ 6 - 6
components/Contact/Map.vue

@@ -67,19 +67,19 @@
 </template>
 
 <script setup lang="ts">
-import "leaflet/dist/leaflet.css";
-import { LMap, LTileLayer, LMarker } 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">

+ 44 - 44
components/Formation/Catalogue.vue

@@ -82,104 +82,104 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Training } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Training } from '~/types/interface'
 
 const downloadPdf = (pdfUrl: string) => {
-  window.open(pdfUrl, "_blank");
-};
+  window.open(pdfUrl, '_blank')
+}
 
 const courses: Array<Training> = [
   {
-    number: "01",
-    title: "Formation initiale ",
+    number: '01',
+    title: 'Formation initiale ',
     description:
       "Cette formation est destinée aux nouveaux utilisateurs. Elle est obligatoire lors de l'acquisition du logiciel. Elle est également utile lors d'un changement de personnel dans la structure. ",
     objectives: [
-      "Ajuster la configuration du logiciel",
-      "Gérer les élèves et leurs familles",
-      "Générer des factures et faire le suivi des règlements",
-      "Gérer le planning des cours",
-      "Évaluer les élèves et générer des bulletins",
-      "Communiquer avec les personnes du répertoire",
+      'Ajuster la configuration du logiciel',
+      'Gérer les élèves et leurs familles',
+      'Générer des factures et faire le suivi des règlements',
+      'Gérer le planning des cours',
+      'Évaluer les élèves et générer des bulletins',
+      'Communiquer avec les personnes du répertoire',
     ],
-    duration: "14h",
+    duration: '14h',
     program: [
       {
         id: 1,
         objectives: [
-          "Accès et interface",
-          "Configuration",
-          "Répertoire",
-          "Agenda",
+          'Accès et interface',
+          'Configuration',
+          'Répertoire',
+          'Agenda',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Parc matériel",
-          "Suivi pédagogique",
-          "Facturation",
-          "Communication",
+          'Parc matériel',
+          'Suivi pédagogique',
+          'Facturation',
+          'Communication',
         ],
       },
     ],
-    price: "1 674 € TTC",
+    price: '1 674 € TTC',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf",
+      'https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf',
   },
   {
-    number: "02",
-    title: "Formation complémentaire",
+    number: '02',
+    title: 'Formation complémentaire',
     // imageUrl: "/images/opentalent_school_black.jpg",
     description:
-      "Cette formation suppose d’avoir les connaissances de base sur le logiciel. Elle permet d’avoir une remise à niveau sur sur des fonctionnalités qui ont été incorrectement comprises / configurées, ou qui ont été récemment développées.",
+      'Cette formation suppose d’avoir les connaissances de base sur le logiciel. Elle permet d’avoir une remise à niveau sur sur des fonctionnalités qui ont été incorrectement comprises / configurées, ou qui ont été récemment développées.',
     objectives: [
-      "Ajuster la configuration du logiciel",
-      "Gérer les élèves et leurs familles",
+      'Ajuster la configuration du logiciel',
+      'Gérer les élèves et leurs familles',
     ],
-    duration: "7h",
+    duration: '7h',
     program: [
       {
         id: 1,
-        objectives: ["Accès et interface", "Configuration"],
+        objectives: ['Accès et interface', 'Configuration'],
       },
       {
         id: 2,
-        objectives: ["Répertoire"],
+        objectives: ['Répertoire'],
       },
     ],
-    price: "837€ TTC",
+    price: '837€ TTC',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf",
+      'https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf',
   },
   {
-    number: "03",
-    title: "Formation Typo 3",
+    number: '03',
+    title: 'Formation Typo 3',
     // imageUrl: "/images/opentalent_school_black.jpg",
     description:
       "Cette formation est destinée aux nouveaux utilisateurs Typo3. Elle est optionnelle et permet d'aller plus loin dans la gestion du site internet intégré.",
     objectives: [
-      "Gérer les pages et leur accès",
-      "Gérer le contenu des pages et leur accès",
-      "Configurer les options du site internet côté logiciel",
+      'Gérer les pages et leur accès',
+      'Gérer le contenu des pages et leur accès',
+      'Configurer les options du site internet côté logiciel',
     ],
-    duration: "7h",
+    duration: '7h',
     program: [
       {
         id: 1,
-        objectives: ["Gestion des pages", "Gestion des blocs"],
+        objectives: ['Gestion des pages', 'Gestion des blocs'],
       },
       {
         id: 2,
-        objectives: ["Configuration côté logiciel"],
+        objectives: ['Configuration côté logiciel'],
       },
     ],
-    price: "837€ TTC",
+    price: '837€ TTC',
     downloadLink:
-      " https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf",
+      ' https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
components/Formation/Certification.vue

@@ -44,7 +44,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
components/Formation/OPCA.vue

@@ -51,7 +51,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

+ 2 - 2
components/Formation/Participation.vue

@@ -53,7 +53,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">
@@ -101,7 +101,7 @@ h3 {
 
 .participation-img {
   position: relative;
-  background-image: url("/images/formation/participation.jpg");
+  background-image: url('/images/formation/participation.jpg');
   width: 700px;
   height: 550px;
   background-position: center;

+ 1 - 1
components/Formation/Presentation.vue

@@ -65,7 +65,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

+ 16 - 16
components/Formation/Reviews.vue

@@ -7,37 +7,37 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
-      "Formation très personnalisée et très productive. Tout à fait adaptée à nos besoins actuels.",
-    name: "Jocelyne DELAPORTE ",
-    status: "Responsable administrative",
-    structure: "École de Musique Municipale De Pecquencourt (59)",
+      'Formation très personnalisée et très productive. Tout à fait adaptée à nos besoins actuels.',
+    name: 'Jocelyne DELAPORTE ',
+    status: 'Responsable administrative',
+    structure: 'École de Musique Municipale De Pecquencourt (59)',
   },
   {
     review:
       "Merci à Johan d'avoir pris le temps de nous former, de rentrer dans les détails des questions abordées. Et merci à l'équipe pour votre réactivité lorsque l'on demande à être aidés",
-    name: "Claire CAGNON ",
-    status: "Secrétaire administrative",
-    structure: "École de Musique, Théâtre et Cirque Alsace Rhin Brisach (68)",
+    name: 'Claire CAGNON ',
+    status: 'Secrétaire administrative',
+    structure: 'École de Musique, Théâtre et Cirque Alsace Rhin Brisach (68)',
   },
   {
     review:
-      " Une journée de formation précieuse pour un point complet de la prise en main du logiciel et des réponses utiles aux questions et problématiques rencontrées.",
-    name: "Sayuri OKA NICOLEAU",
-    status: "Directrice administrative & pédagogique",
-    structure: "École Municipale de Musique de Croissy-sur-Seine (78)",
+      ' Une journée de formation précieuse pour un point complet de la prise en main du logiciel et des réponses utiles aux questions et problématiques rencontrées.',
+    name: 'Sayuri OKA NICOLEAU',
+    status: 'Directrice administrative & pédagogique',
+    structure: 'École Municipale de Musique de Croissy-sur-Seine (78)',
   },
   {
     review:
       "Un formateur à l'écoute des besoins de notre structure et des besoins de nous deux débutants sur le logiciel. Besoin compris pour une journée de formation complémentaire pour lancer la campagne d'inscription courant le deuxième trimestre 2022. Merci pour la patience de Johan, pédagogue et fin connaisseur de son logiciel.",
-    name: "Alain BATS",
-    status: "Président adjoint",
+    name: 'Alain BATS',
+    status: 'Président adjoint',
     structure: "L'École Intercommunale de Musique LEIM (74)",
   },
-];
+]
 </script>

+ 1 - 1
components/Home/Besoin.vue

@@ -52,7 +52,7 @@ p {
 }
 
 .screen-img {
-  background-image: url("/images/pages/home/besoin/Repondre-aux-besoins-des-clients-Opentalent.png");
+  background-image: url('/images/pages/home/besoin/Repondre-aux-besoins-des-clients-Opentalent.png');
   background-position: center;
   background-size: cover;
   width: 700px;

+ 51 - 51
components/Home/Caroussel.vue

@@ -87,89 +87,89 @@ Carrousel de la page d'accueil
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import type { Ref } from "vue";
-import type { CarouselItem } from "~/types/interface";
-import { useLayoutStore } from "~/stores/layoutStore";
+import { useDisplay } from 'vuetify'
+import type { Ref } from 'vue'
+import type { CarouselItem } from '~/types/interface'
+import { useLayoutStore } from '~/stores/layoutStore'
 
-const { mdAndUp, lgAndUp } = useDisplay();
+const { mdAndUp, lgAndUp } = useDisplay()
 
 // Index de la slide active
-const activeIndex: Ref<number> = ref(0);
+const activeIndex: Ref<number> = ref(0)
 
 const setActiveIndex = (index: number) => {
-  activeIndex.value = index;
-};
+  activeIndex.value = index
+}
 
 const carouselItems: Ref<Array<CarouselItem>> = ref([
   {
-    logo: "/images/logos/opentalent/Logo_Opentalent_School-gris.png",
+    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",
+      '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:
       "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.",
-    buttonClass: "btn-school",
+    buttonClass: 'btn-school',
     image:
-      "/images/pages/home/carousel/Logiciel_Opentalent_School-eleve-Conservatoire_de_Musique.png",
-    imageAlt: "Jeune élève de batterie",
-    color: "rgba(32, 147, 190, 0.4)",
-    link: "/opentalent_school",
-    name: "Cindy Blanchard",
-    school: "Conservatoire de Musique",
-    status: "élève",
-    avatar: "/images/pages/home/carousel/Photo_de_profil_d_une_jeune_fille.png",
-    avatarAlt: "Photo de profil d’une jeune fille",
+      '/images/pages/home/carousel/Logiciel_Opentalent_School-eleve-Conservatoire_de_Musique.png',
+    imageAlt: 'Jeune élève de batterie',
+    color: 'rgba(32, 147, 190, 0.4)',
+    link: '/opentalent_school',
+    name: 'Cindy Blanchard',
+    school: 'Conservatoire de Musique',
+    status: 'élève',
+    avatar: '/images/pages/home/carousel/Photo_de_profil_d_une_jeune_fille.png',
+    avatarAlt: 'Photo de profil d’une jeune fille',
   },
   {
-    logo: "/images/logos/opentalent/Logo_Opentalent_Artist-gris.png",
+    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",
+      '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.",
+      '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:
-      "Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque.",
-    buttonClass: "btn-artist",
+      'Pour les structures culturelles pratiquantes telles que les orchestres, les chorales, les compagnies de danse, théâtre et cirque.',
+    buttonClass: 'btn-artist',
     image:
-      "/images/pages/home/carousel/Logiciel_Opentalent_Artist-administrateur-Orchestre_d_harmonie.png",
-    imageAlt: "Homme jouant du banjo",
-    color: "rgba(250, 194, 10, 0.4)",
-    link: "opentalent_artist",
-    name: "Thierry Dupont ",
-    school: "Orchestre d’harmonie",
-    status: "Admin",
+      '/images/pages/home/carousel/Logiciel_Opentalent_Artist-administrateur-Orchestre_d_harmonie.png',
+    imageAlt: 'Homme jouant du banjo',
+    color: 'rgba(250, 194, 10, 0.4)',
+    link: 'opentalent_artist',
+    name: 'Thierry Dupont ',
+    school: 'Orchestre d’harmonie',
+    status: 'Admin',
     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",
+      '/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",
+    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",
+      '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.",
+      '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:
-      "La solution de mise en réseau des organisations culturelles, telles que les fédérations, confédérations et collectivités.",
-    buttonClass: "btn-manager",
+      'La solution de mise en réseau des organisations culturelles, telles que les fédérations, confédérations et collectivités.',
+    buttonClass: 'btn-manager',
     image:
-      "/images/pages/home/carousel/Logiciel_Opentalent_Manager-Administrateur_Federation.png",
-    imageAlt: "Un homme en costard et une femme tailleur souriant",
-    color: "rgba(216, 5, 11, 0.4)",
-    link: "opentalent_manager",
-    name: "Marie Voisin",
+      '/images/pages/home/carousel/Logiciel_Opentalent_Manager-Administrateur_Federation.png',
+    imageAlt: 'Un homme en costard et une femme tailleur souriant',
+    color: 'rgba(216, 5, 11, 0.4)',
+    link: 'opentalent_manager',
+    name: 'Marie Voisin',
     school: "Réseau d'organisations culturelles ",
-    status: "ADMIN",
+    status: 'ADMIN',
     avatar:
-      "/images/pages/home/carousel/Photo_de_profil_d_une_femme_en_tailleur.png",
-    avatarAlt: "Photo de profil d’une femme en tailleur",
+      '/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">

+ 4 - 4
components/Home/EventAgenda.vue

@@ -41,9 +41,9 @@ Section "Agenda" de la page d'accueil
 </template>
 
 <script setup>
-import { useDisplay } from "vuetify";
-import AgendaLink from "~/components/Common/AgendaLink.vue";
-const { lgAndUp } = useDisplay();
+import { useDisplay } from 'vuetify'
+import AgendaLink from '~/components/Common/AgendaLink.vue'
+const { lgAndUp } = useDisplay()
 </script>
 
 <style scoped>
@@ -57,7 +57,7 @@ const { lgAndUp } = useDisplay();
       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")
+    url('/images/components/agenda/Opentalent_Agenda_événement_culturel.jpg')
       no-repeat center 60%;
   background-size: cover;
 }

+ 39 - 39
components/Home/Reviews.vue

@@ -174,90 +174,90 @@
 </template>
 
 <script setup lang="ts">
-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";
+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();
+const { lgAndUp } = useDisplay()
 
-const reviewCarousel: Ref<typeof Carousel | null> = ref(null);
+const reviewCarousel: Ref<typeof Carousel | null> = ref(null)
 
 const state = ref({
   activeIndex: 0,
-});
+})
 
 const goToNext = () => {
-  reviewCarousel.value!.next();
-  state.value.activeIndex = (state.value.activeIndex + 1) % cards.length;
-};
+  reviewCarousel.value!.next()
+  state.value.activeIndex = (state.value.activeIndex + 1) % cards.length
+}
 
 const goToPrevious = () => {
-  reviewCarousel.value!.prev();
+  reviewCarousel.value!.prev()
   state.value.activeIndex =
     state.value.activeIndex - 1 < 0
       ? cards.length - 1
-      : state.value.activeIndex - 1;
-};
+      : state.value.activeIndex - 1
+}
 
 const cards: Array<Review> = [
   {
-    name: "Patrice CATHELIN",
+    name: 'Patrice CATHELIN',
     review:
       "C'est un logiciel très bien conçu et efficace avec une équipe ouverte, dynamique et à l'écoute. L’assistance est très réactive, j'ai toujours eu une réponse rapide à mes besoins, ce qui est fort appréciable.",
-    status: "Directeur administratif & pédagogique",
-    structure: "Conservatoire de Musique & de Danse de Sens (78)",
+    status: 'Directeur administratif & pédagogique',
+    structure: 'Conservatoire de Musique & de Danse de Sens (78)',
   },
   {
-    name: "Karine GIRAUD",
+    name: 'Karine GIRAUD',
     review:
       "Étant présente depuis presque le début, je suis fière d'avoir vu grandir ce logiciel et d'avoir évoluée avec lui. De plus, je me suis sentie écoutée lors de mes propositions d'amélioration, car beaucoup ont vu le jour. Enfin, l'accompagnement et la réactivité n'ont jamais faibli depuis toutes ces années",
-    status: "Secrétaire administrative",
-    structure: "Association Musicale Sainte Cécile de Lagord (17)",
+    status: 'Secrétaire administrative',
+    structure: 'Association Musicale Sainte Cécile de Lagord (17)',
   },
   {
-    name: "Laurent BEL",
+    name: 'Laurent BEL',
     review:
       "Logiciel très complet qui permet de faire beaucoup de choses. J’apprécie particulièrement la réactivité, la bienveillance et le fait que l’équipe soit à l'écoute pour faire évoluer l'outil en fonction de nos besoins. Si besoin, la FAQ est vraiment utile. Elle permet de trouver rapidement une solution face à un problème rencontré.",
-    status: "Directeur administratif & pédagogique",
-    structure: "École de Musique EPIC Musique en 4 Rivières (74)",
+    status: 'Directeur administratif & pédagogique',
+    structure: 'École de Musique EPIC Musique en 4 Rivières (74)',
   },
   {
-    name: "Philippe BORY",
+    name: 'Philippe BORY',
     review:
       "Opentalent est une entreprise avec de vraies valeurs humaines, à l'écoute de chaque structure et qui ne cesse de s'améliorer pour toujours coller aux besoins de ses clients. Plus qu'une relation commerciale, c'est pour nous un véritable partenaire au quotidien.",
-    status: "Personnel administratif",
+    status: 'Personnel administratif',
     structure: "École d'Arts de Saint-Michel-sur-Orge (91)",
   },
-];
+]
 
 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_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_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_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_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_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",
+    src: '/images/pages/home/reviews/Logo_Conservatoire_de_Musique_d_Annemasse.jpg',
+    alt: 'Logo du Conservatoire d’Annemasse',
   },
-]);
+])
 </script>
 
 <style scoped>

+ 46 - 46
components/Home/Solution.vue

@@ -78,67 +78,67 @@ Section "Solutions" de la page d'accueil
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-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> = [
   {
-    name: "Artist",
-    description: "Orchestres, chorales, compagnies et troupes artistiques",
-    image: "/images/logos/Logo_Opentalent_Artist-blanc.png",
-    alt: "Partition tenue par une femme dans une chorale",
-    link: "/opentalent_artist",
-    class: "artist-image",
+    name: 'Artist',
+    description: 'Orchestres, chorales, compagnies et troupes artistiques',
+    image: '/images/logos/Logo_Opentalent_Artist-blanc.png',
+    alt: 'Partition tenue par une femme dans une chorale',
+    link: '/opentalent_artist',
+    class: 'artist-image',
     solutions: [
-      "Gestion des membres",
-      "Agenda de la structure",
-      "Matériel & médiathèque",
-      "Export de données",
-      "Communication",
-      "Statistiques",
-      "Site internet intégré",
-      "Partage de données en réseau",
+      'Gestion des membres',
+      'Agenda de la structure',
+      'Matériel & médiathèque',
+      'Export de données',
+      'Communication',
+      'Statistiques',
+      'Site internet intégré',
+      'Partage de données en réseau',
     ],
   },
   {
-    name: "School",
+    name: 'School',
     description: "Petits et grands établissements d'enseignement artistique",
-    image: "/images/logos/Logo_Opentalent_School-blanc",
-    alt: "Deux jeunes filles jouant du violon",
-    link: "/opentalent_school",
-    class: "school-image",
+    image: '/images/logos/Logo_Opentalent_School-blanc',
+    alt: 'Deux jeunes filles jouant du violon',
+    link: '/opentalent_school',
+    class: 'school-image',
     solutions: [
-      "Gestion des membres",
-      "Préinscription en ligne *",
-      "Agenda de la structure",
-      "Suivi pédagogique",
-      "Gestion administrative et financière",
-      "Communication",
-      "Site internet intégré",
-      "Statistiques",
+      'Gestion des membres',
+      'Préinscription en ligne *',
+      'Agenda de la structure',
+      'Suivi pédagogique',
+      'Gestion administrative et financière',
+      'Communication',
+      'Site internet intégré',
+      'Statistiques',
     ],
   },
   {
-    name: "Manager",
-    description: "Fédérations, confédérations et collectivités",
-    image: "/images/logos/Logo_Opentalent_Manager-blanc.png",
-    alt: "Carte de réseau des structures de la confédération musicale de France",
-    link: "/opentalent_manager",
-    class: "manager-image",
+    name: 'Manager',
+    description: 'Fédérations, confédérations et collectivités',
+    image: '/images/logos/Logo_Opentalent_Manager-blanc.png',
+    alt: 'Carte de réseau des structures de la confédération musicale de France',
+    link: '/opentalent_manager',
+    class: 'manager-image',
     solutions: [
-      "Gestion des membres",
-      "Agenda du réseau",
-      "Matériel & médiathèque",
-      "Gestion administrative",
-      "Statistiques du réseau",
-      "Cotisations",
-      "Site internet intégré",
-      "Communication",
+      'Gestion des membres',
+      'Agenda du réseau',
+      'Matériel & médiathèque',
+      'Gestion administrative',
+      'Statistiques du réseau',
+      'Cotisations',
+      'Site internet intégré',
+      'Communication',
     ],
   },
-];
+]
 </script>
 
 <style scoped lang="scss">
@@ -236,7 +236,7 @@ h4 {
   }
 
   .image-container::before {
-    content: "";
+    content: '';
     position: absolute;
     top: 0;
     left: 0;

+ 34 - 35
components/JoinUs/Form.vue

@@ -86,79 +86,78 @@
 </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";
+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<HTMLElement | 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));
+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),
-);
+    (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";
+  !!surname || 'Le prénom est obligatoire'
 
 const validateEmail = (email: string | null) =>
-  (!!email && /.+@.+\..+/.test(email)) || "L'adresse e-mail doit être valide";
+  (!!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";
+  '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";
+  "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";
+  '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 = (message: string | null) =>
   (!!message && message.length <= maxMessageLength) ||
-  "Le message ne doit pas dépasser " + maxMessageLength + " caractères";
+  'Le message ne doit pas dépasser ' + maxMessageLength + ' caractères'
 
 /**
  * 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 =
@@ -168,7 +167,7 @@ const submit = async () => {
           name: resumeUpload.value[0].name,
           content: await FileUtils.blobToBase64(resumeUpload.value[0]),
         }
-      : null;
+      : null
 
   jobApplication.motivationLetter =
     motivationLetterUpload.value !== null &&
@@ -177,17 +176,17 @@ const submit = async () => {
           // @ts-ignore
           name: motivationLetterUpload.value[0].name,
           content: await FileUtils.blobToBase64(
-            motivationLetterUpload.value[0],
+            motivationLetterUpload.value[0]
           ),
         }
-      : null;
+      : null
 
-  await em.persist(JobApplication, jobApplication);
+  await em.persist(JobApplication, jobApplication)
 
-  jobApplicationSent.value = true;
+  jobApplicationSent.value = true
 
-  emit("submit");
-};
+  emit('submit')
+}
 </script>
 
 <style scoped lang="scss">

+ 16 - 16
components/JoinUs/MissionDetail.vue

@@ -48,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>
 
@@ -96,31 +96,31 @@
 </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 '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'
 
-const { mdAndUp, smAndDown } = useDisplay();
+const { mdAndUp, smAndDown } = useDisplay()
 
-const route = useRoute();
-const { fetch } = useEntityFetch();
+const route = useRoute()
+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>
 
 <style scoped lang="scss">

+ 22 - 22
components/JoinUs/Missions.vue

@@ -87,54 +87,54 @@
 </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";
+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 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);
+} = 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[])
-    : [];
-});
+    : []
+})
 
 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 dialog = ref(false)
+const jobApplicationSent: Ref<boolean> = ref(false)
 
 const onFormSubmit = () => {
-  jobApplicationSent.value = true;
-};
+  jobApplicationSent.value = true
+}
 </script>
 
 <style scoped lang="scss">

+ 16 - 16
components/Layout/AnchoredSection.vue

@@ -5,47 +5,47 @@
 </template>
 
 <script setup lang="ts">
-import type { Ref } from "vue";
-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,
   },
-});
+})
 
 if (!props.id) {
-  throw new Error("Anchor's id is missing");
+  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)
 
 // @ts-ignore
 const onScroll = (scroll) => {
-  top.value = section.value!.offsetTop;
-  bottom.value = section.value!.offsetTop + section.value!.offsetHeight;
+  top.value = section.value!.offsetTop
+  bottom.value = section.value!.offsetTop + section.value!.offsetHeight
 
   if (top.value === null || bottom.value === null) {
-    return;
+    return
   }
 
   const screenVerticalCenter =
-    scroll.target.documentElement.scrollTop + window.innerHeight / 2;
+    scroll.target.documentElement.scrollTop + window.innerHeight / 2
 
   const active =
-    screenVerticalCenter > top.value && screenVerticalCenter < bottom.value;
+    screenVerticalCenter > top.value && screenVerticalCenter < bottom.value
   if (active !== layoutStore.isAnchoredSectionOnScreen[props.id]) {
-    layoutStore.setIsAnchoredSectionOnScreen(props.id, active);
+    layoutStore.setIsAnchoredSectionOnScreen(props.id, active)
   }
-};
+}
 </script>
 
 <style scoped></style>

+ 30 - 30
components/Layout/Captcha.vue

@@ -16,58 +16,58 @@
 </template>
 
 <script setup lang="ts">
-import VueHcaptcha from "@hcaptcha/vue3-hcaptcha";
-import type { Ref } from "vue";
+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);
-const token: Ref<string> = ref("");
-const eKey: Ref<string> = ref("");
-const error: Ref<string> = ref("");
+const verified: Ref<boolean> = ref(false)
+const expired: Ref<boolean> = ref(false)
+const token: Ref<string> = ref('')
+const eKey: Ref<string> = ref('')
+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) ||
-  "Veuillez procéder à la vérification";
+  'Veuillez procéder à la vérification'
 
 function onVerify(tokenStr: string, ekey: string) {
-  verified.value = true;
-  token.value = tokenStr;
-  eKey.value = ekey;
-  emit("update", true);
+  verified.value = true
+  token.value = tokenStr
+  eKey.value = ekey
+  emit('update', true)
 }
 
 function onExpire() {
-  verified.value = false;
-  token.value = "";
-  eKey.value = "";
-  expired.value = true;
+  verified.value = false
+  token.value = ''
+  eKey.value = ''
+  expired.value = true
 }
 
 function onChallengeExpire() {
-  verified.value = false;
-  token.value = "";
-  eKey.value = "";
-  expired.value = true;
+  verified.value = false
+  token.value = ''
+  eKey.value = ''
+  expired.value = true
 }
 
 function onError(err: string) {
-  token.value = "";
-  eKey.value = "";
-  error.value = err;
-  console.log(`Error: ${err}`);
+  token.value = ''
+  eKey.value = ''
+  error.value = err
+  console.log(`Error: ${err}`)
 
   if (process.dev) {
-    console.log("Dev mode: force captcha validation");
-    verified.value = true;
+    console.log('Dev mode: force captcha validation')
+    verified.value = true
   }
 }
 </script>

+ 2 - 2
components/Layout/FAQ.vue

@@ -62,7 +62,7 @@
 
 .main {
   min-height: 600px;
-  background-image: url("/images/components/faq/Orchestre_de_rue_avec_danseuse.jpg");
+  background-image: url('/images/components/faq/Orchestre_de_rue_avec_danseuse.jpg');
   background-size: cover;
   background-position: center 15%;
   background-repeat: no-repeat;
@@ -75,7 +75,7 @@
 }
 
 .main::after {
-  content: "";
+  content: '';
   position: absolute;
   top: 0;
   left: 0;

+ 39 - 39
components/Layout/Footer/Footer.vue

@@ -221,96 +221,96 @@
 </template>
 
 <script setup>
-import { useDisplay } from "vuetify";
-import { useLayoutStore } from "~/stores/layoutStore";
-import AgendaLink from "~/components/Common/AgendaLink.vue";
+import { useDisplay } from 'vuetify'
+import { useLayoutStore } from '~/stores/layoutStore'
+import AgendaLink from '~/components/Common/AgendaLink.vue'
 
-const { mdAndDown, lgAndUp } = useDisplay();
+const { mdAndDown, lgAndUp } = useDisplay()
 
 const footerLinks = ref([
   {
-    label: "AGENDA CULTUREL",
+    label: 'AGENDA CULTUREL',
     sublink: [
       {
-        label: "Annuaire",
-        link: "/annuaire",
+        label: 'Annuaire',
+        link: '/annuaire',
       },
       {
-        label: "Actualités",
-        link: "/actualites",
+        label: 'Actualités',
+        link: '/actualites',
       },
       {
-        label: "Annonces",
-        link: "/annonces",
+        label: 'Annonces',
+        link: '/annonces',
       },
     ],
   },
   {
-    label: "LOGICIELS CULTURELS ",
+    label: 'LOGICIELS CULTURELS ',
     sublink: [
       {
-        label: "Opentalent Artist",
-        link: "/opentalent_artist",
+        label: 'Opentalent Artist',
+        link: '/opentalent_artist',
       },
       {
-        label: "Opentalent School",
-        link: "/opentalent_school",
+        label: 'Opentalent School',
+        link: '/opentalent_school',
       },
       {
-        label: "Opentalent Manager",
-        link: "/opentalent_manager",
+        label: 'Opentalent Manager',
+        link: '/opentalent_manager',
       },
     ],
   },
   {
-    label: "À PROPOS ",
+    label: 'À PROPOS ',
     sublink: [
       {
-        label: "Qui sommes-nous",
-        link: "/qui-sommes-nous",
+        label: 'Qui sommes-nous',
+        link: '/qui-sommes-nous',
       },
       {
-        label: "Nous rejoindre",
-        link: "/nous-rejoindre",
+        label: 'Nous rejoindre',
+        link: '/nous-rejoindre',
       },
       {
-        label: "Nous contacter",
-        link: "/nous-contacter",
+        label: 'Nous contacter',
+        link: '/nous-contacter',
       },
     ],
   },
   {
-    label: "ESPACE CLIENT ",
+    label: 'ESPACE CLIENT ',
     sublink: [
       {
-        label: "Foire Aux Questions ",
-        link: "/ https://ressources.opentalent.fr",
+        label: 'Foire Aux Questions ',
+        link: '/ https://ressources.opentalent.fr',
       },
       {
-        label: "Support en ligne ",
-        link: "/https://ressources.opentalent.fr/?contact",
+        label: 'Support en ligne ',
+        link: '/https://ressources.opentalent.fr/?contact',
       },
       {
-        label: "Nous contacter ",
-        link: "/nous-contacter",
+        label: 'Nous contacter ',
+        link: '/nous-contacter',
       },
     ],
   },
-]);
+])
 
-const activeIndex = ref(-1);
+const activeIndex = ref(-1)
 function toggleSection(index) {
-  activeIndex.value = activeIndex.value === index ? -1 : index;
+  activeIndex.value = activeIndex.value === index ? -1 : index
 }
 
 function isActive(index) {
-  return activeIndex.value === 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">

+ 2 - 2
components/Layout/Footer/Prefooter.vue

@@ -92,9 +92,9 @@ Première section du footer (galerie des logiciels)
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
components/Layout/Footer/Solutions.vue

@@ -130,7 +130,7 @@ defineProps({
     required: false,
     default: true,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">

+ 20 - 20
components/Layout/Navigation.vue

@@ -16,43 +16,43 @@ Menu Navigation
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import type { MainMenuItem } from "~/types/interface";
-import { useLayoutStore } from "~/stores/layoutStore";
+import { useDisplay } from 'vuetify'
+import type { MainMenuItem } from '~/types/interface'
+import { useLayoutStore } from '~/stores/layoutStore'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
 const menu: Array<MainMenuItem> = [
   {
-    label: "Nos logiciels",
+    label: 'Nos logiciels',
     children: [
-      { label: "Opentalent Artist", to: "/opentalent_artist" },
-      { label: "Opentalent School", to: "/opentalent_school" },
-      { label: "Opentalent Manager", to: "/opentalent_manager" },
+      { label: 'Opentalent Artist', to: '/opentalent_artist' },
+      { label: 'Opentalent School', to: '/opentalent_school' },
+      { label: 'Opentalent Manager', to: '/opentalent_manager' },
     ],
   },
   {
-    label: "Nos services",
+    label: 'Nos services',
     children: [
-      { label: "Formations", to: "/formations" },
-      { label: "Webinaires", to: "/webinaires" },
+      { label: 'Formations', to: '/formations' },
+      { label: 'Webinaires', to: '/webinaires' },
     ],
   },
   {
-    label: "À propos",
+    label: 'À propos',
     children: [
-      { label: "Qui sommes-nous", to: "/qui-sommes-nous" },
-      { label: "Nous rejoindre", to: "/nous-rejoindre" },
+      { label: 'Qui sommes-nous', to: '/qui-sommes-nous' },
+      { label: 'Nous rejoindre', to: '/nous-rejoindre' },
     ],
   },
-  { label: "Actualités", to: "/actualites" },
-  { label: "Contact", to: "/nous-contacter" },
-];
+  { 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>

+ 3 - 3
components/Layout/Navigation/Lg.vue

@@ -45,15 +45,15 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "vue";
-import type { MainMenuItem } from "~/types/interface";
+import type { PropType } from 'vue'
+import type { MainMenuItem } from '~/types/interface'
 
 defineProps({
   menu: {
     type: Array as PropType<Array<MainMenuItem>>,
     required: true,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">

+ 23 - 23
components/Layout/Navigation/Md.vue

@@ -71,32 +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 { MainMenuItem } from "~/types/interface";
+import type { PropType, Ref } from 'vue'
+import { useDisplay } from 'vuetify'
+import AgendaLink from '~/components/Common/AgendaLink.vue'
+import type { MainMenuItem } from '~/types/interface'
 
-const { smAndUp } = useDisplay();
+const { smAndUp } = useDisplay()
 
 const props = defineProps({
   menu: {
     type: Array as PropType<Array<MainMenuItem>>,
     required: true,
   },
-});
+})
 
-const isMenuOpen: Ref<boolean> = ref(false);
+const isMenuOpen: Ref<boolean> = ref(false)
 const toggleMenu = () => {
-  isMenuOpen.value = !isMenuOpen.value;
-};
+  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,
-);
+    : props.menu
+)
 
 /**
  * Determines if the is active menu is a sub-menu .
@@ -104,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.
@@ -115,29 +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();
+  isMenuOpen.value = false
+  callback()
   setTimeout(() => {
-    isMenuOpen.value = true;
-  }, 85);
-};
+    isMenuOpen.value = true
+  }, 85)
+}
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
components/Layout/Navigation/Topbar.vue

@@ -17,7 +17,7 @@
 </template>
 
 <script setup lang="ts">
-import AgendaLink from "~/components/Common/AgendaLink.vue";
+import AgendaLink from '~/components/Common/AgendaLink.vue'
 </script>
 
 <style scoped lang="scss">

+ 6 - 6
components/Layout/Pagination.vue

@@ -9,8 +9,8 @@
 </template>
 
 <script setup lang="ts">
-import type { PropType } from "vue";
-import type { Pagination } from "~/types/data";
+import type { PropType } from 'vue'
+import type { Pagination } from '~/types/data'
 
 defineProps({
   modelValue: {
@@ -21,13 +21,13 @@ defineProps({
     type: Object as PropType<Pagination>,
     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>

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

@@ -16,13 +16,13 @@ Titre H4 précédé d'une puce
 defineProps({
   icon: {
     type: String,
-    default: "fas fa-circle",
+    default: 'fas fa-circle',
   },
   iconSize: {
     type: [String, Number],
     default: 5,
   },
-});
+})
 </script>
 
 <style scoped lang="scss">

+ 2 - 2
components/Layout/UI/TitlePage.vue

@@ -10,9 +10,9 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
-const { mdAndDown } = useDisplay();
+const { mdAndDown } = useDisplay()
 </script>
 
 <style scoped lang="scss">

+ 3 - 3
components/Logiciels/Artist/Abonnement.vue

@@ -63,10 +63,10 @@
 </template>
 
 <script setup>
-import { useDisplay } from "vuetify";
-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">

+ 18 - 18
components/Logiciels/Artist/Avantages.vue

@@ -8,37 +8,37 @@ 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";
+import type { Ref } from 'vue'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Benefit } from '~/types/interface'
 
 const benefits: Ref<Array<Benefit>> = ref([
   {
-    title: "Un gain de temps",
-    number: "01",
+    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: "Main tenant un mini réveil",
+      '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: 'Main tenant un mini réveil',
     isMemberCMF: true,
   },
   {
-    title: "Une activité structurée",
-    number: "02",
+    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: "Empilement de cube transparent structuré au-dessus d’un plan de maison",
+      '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: 'Empilement de cube transparent structuré au-dessus d’un plan de maison',
     isMemberCMF: false,
   },
   {
-    title: "Une gestion collaborative",
-    number: "03",
+    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: "Mains de plusieurs couleurs posées les unes à côté des autres",
+    image: '/images/components/avantages/une_gestion_collaborative.jpg',
+    alt: 'Mains de plusieurs couleurs posées les unes à côté des autres',
     isMemberCMF: true,
   },
-]);
+])
 </script>

+ 26 - 26
components/Logiciels/Artist/Comparatif.vue

@@ -15,76 +15,76 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { ComparisonItem } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { ComparisonItem } from '~/types/interface'
 
 const comparisonItems: Array<ComparisonItem> = [
   {
-    label: "GESTION DU RÉPERTOIRE",
+    label: 'GESTION DU RÉPERTOIRE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "AGENDA",
+    label: 'AGENDA',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "GESTION DU PARC MATÉRIEL",
+    label: 'GESTION DU PARC MATÉRIEL',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "COMMUNICATION",
+    label: 'COMMUNICATION',
     includedInStandard: false,
     includedInPremium: true,
   },
   {
-    label: "SMS",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'SMS',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "NOM DE DOMAINE",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'NOM DE DOMAINE',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "SITE INTERNET",
+    label: 'SITE INTERNET',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "STATISTIQUES",
+    label: 'STATISTIQUES',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "FONCTIONNALITÉ DU RÉSEAU CMF",
+    label: 'FONCTIONNALITÉ DU RÉSEAU CMF',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SAUVEGARDE",
+    label: 'SAUVEGARDE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "EXTRANET UTILISATEURS",
-    includedInStandard: "75 comptes",
-    includedInPremium: "150 comptes",
+    label: 'EXTRANET UTILISATEURS',
+    includedInStandard: '75 comptes',
+    includedInPremium: '150 comptes',
   },
   {
-    label: "ESPACE DE STOCKAGE",
-    includedInStandard: "100 Mo",
-    includedInPremium: "1 Go",
+    label: 'ESPACE DE STOCKAGE',
+    includedInStandard: '100 Mo',
+    includedInPremium: '1 Go',
   },
   {
-    label: "PAGES DU SITE INTERNET",
-    includedInStandard: "Restreint",
-    includedInPremium: "Illimité",
+    label: 'PAGES DU SITE INTERNET',
+    includedInStandard: 'Restreint',
+    includedInPremium: 'Illimité',
   },
-];
+]
 </script>
 
 <style scoped>

+ 54 - 54
components/Logiciels/Artist/Fonctionnalites.vue

@@ -9,99 +9,99 @@
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Functionality } from "~/types/interface";
+import 'vue3-carousel/dist/carousel.css'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Functionality } from '~/types/interface'
 
 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"],
-    options: ["*Disponible sur tous supports"],
+    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'],
+    options: ['*Disponible sur tous supports'],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_repertoire.svg",
-    logoAlt: "Icône carnet annuaire",
-    title: "RÉPERTOIRE",
+    logo: '/images/components/fonctionnalites/Icone_repertoire.svg',
+    logoAlt: 'Icône carnet annuaire',
+    title: 'RÉPERTOIRE',
     list: [
-      "Membres",
-      "Personnel administratif ",
-      "Contacts extérieurs, partenaires & donateurs",
+      'Membres',
+      'Personnel administratif ',
+      'Contacts extérieurs, partenaires & donateurs',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_agenda.svg",
-    logoAlt: "Icône calendrier",
-    title: "AGENDA",
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône calendrier',
+    title: 'AGENDA',
     list: [
-      "Création et gestion des événements internes et externes",
-      "Invitation aux événements",
-      "Gestion des présences ",
+      'Création et gestion des événements internes et externes',
+      'Invitation aux événements',
+      'Gestion des présences ',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_parc_materiel.svg",
-    logoAlt: "Icône carton avec stylos et cahier à l’intérieur",
-    title: "PARC MATÉRIEL ",
+    logo: '/images/components/fonctionnalites/Icone_parc_materiel.svg',
+    logoAlt: 'Icône carton avec stylos et cahier à l’intérieur',
+    title: 'PARC MATÉRIEL ',
     list: [
-      "Gestion de votre parc matériel (instruments, costumes, accessoires..)",
-      "Locations et prêts de matériel",
-      "Partage de partitions",
+      'Gestion de votre parc matériel (instruments, costumes, accessoires..)',
+      'Locations et prêts de matériel',
+      'Partage de partitions',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_communication.svg",
-    logoAlt: "Icône enveloppe, téléphone et bulle SMS",
-    title: "COMMUNICATION *",
+    logo: '/images/components/fonctionnalites/Icone_communication.svg',
+    logoAlt: 'Icône enveloppe, téléphone et bulle SMS',
+    title: 'COMMUNICATION *',
     list: [
-      "Édition et envoi de courriers, de mails ou de SMS**",
-      "Création de modèles de courriers, mails ou SMS **",
-      "Outil de publipostage intégré pour un envoi personnalisé",
+      'Édition et envoi de courriers, de mails ou de SMS**',
+      'Création de modèles de courriers, mails ou SMS **',
+      'Outil de publipostage intégré pour un envoi personnalisé',
     ],
-    options: ["* version Artist Premium ", "** en option"],
+    options: ['* version Artist Premium ', '** en option'],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_site_internet.svg",
-    logoAlt: "Icône site internet",
-    title: "SITE INTERNET ",
+    logo: '/images/components/fonctionnalites/Icone_site_internet.svg',
+    logoAlt: 'Icône site internet',
+    title: 'SITE INTERNET ',
     list: [
-      "Gestion intégrée au logiciel",
-      "Mise à jour automatique des membres et événements sur votre site",
-      "Possibilité de personnalisé votre template",
+      'Gestion intégrée au logiciel',
+      'Mise à jour automatique des membres et événements sur votre site',
+      'Possibilité de personnalisé votre template',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_statistiques.svg",
-    logoAlt: "Icône graphique à barre avec ligne ascendante",
-    title: "STATISTIQUES",
+    logo: '/images/components/fonctionnalites/Icone_statistiques.svg',
+    logoAlt: 'Icône graphique à barre avec ligne ascendante',
+    title: 'STATISTIQUES',
     list: [
       "Rapport d'activité complet en fonction de vos activités",
       "Personnalisation du rapport d'activité grâce aux différents formats proposés lors du téléchargement",
-      "Export des données du logiciel pour une analyse complète",
+      'Export des données du logiciel pour une analyse complète',
     ],
   },
   {
-    logo: "/images/logos/cmf/Icone_CMF_reseau_BLACK.png",
-    logoAlt: "Icône du logo de la CMF (confédération musicale de France)",
-    title: "RÉSEAU CMF *",
+    logo: '/images/logos/cmf/Icone_CMF_reseau_BLACK.png',
+    logoAlt: 'Icône du logo de la CMF (confédération musicale de France)',
+    title: 'RÉSEAU CMF *',
     list: [
-      "Accès au répertoire du réseau",
-      "Renouvellement de votre adhésion fédérale",
+      'Accès au répertoire du réseau',
+      '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",
-    logoAlt: "Icône mégaphone",
-    title: "PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ",
+    logo: '/images/components/fonctionnalites/Icone_promotion.svg',
+    logoAlt: 'Icône mégaphone',
+    title: 'PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ',
     list: [
-      "Sur votre site internet intégré",
+      'Sur votre site internet intégré',
       "Sur l'agenda de la CMF",
       "Sur l'agenda culturel Opentalent ",
     ],
   },
-];
+]
 </script>

+ 1 - 1
components/Logiciels/Artist/Formations.vue

@@ -46,7 +46,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

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

@@ -17,32 +17,32 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { FeaturePicto } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { FeaturePicto } from '~/types/interface'
 
 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,...)",
+  '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",
-];
+]
 
 const pictos: Array<FeaturePicto> = [
   {
-    src: "/images/pages/opentalent_artist/presentation/Logiciel_multi-support.png",
-    text: "Logiciel de gestion et communication full web",
+    src: '/images/pages/opentalent_artist/presentation/Logiciel_multi-support.png',
+    text: 'Logiciel de gestion et communication full web',
   },
   {
-    src: "/images/pages/opentalent_artist/presentation/Site_internet_integre.png",
+    src: '/images/pages/opentalent_artist/presentation/Site_internet_integre.png',
     text: "Site web intégré & simple d'usage",
   },
   {
-    src: "/images/pages/opentalent_artist/presentation/Boostez_votre_visibilite_et_communication.png",
-    text: "Boostez votre visibilité & communication",
+    src: '/images/pages/opentalent_artist/presentation/Boostez_votre_visibilite_et_communication.png',
+    text: 'Boostez votre visibilité & communication',
   },
   {
-    src: "/images/pages/opentalent_artist/presentation/Communication_en_reseau.png",
-    text: "Communiquez en réseau",
+    src: '/images/pages/opentalent_artist/presentation/Communication_en_reseau.png',
+    text: 'Communiquez en réseau',
   },
-];
+]
 </script>

+ 8 - 8
components/Logiciels/Artist/Reviews.vue

@@ -11,25 +11,25 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
       "L'outil répond à toutes les demandes d'une structure de notre taille et la connexion avec le site internet est très pratique.",
-    name: "Patrice MONTESSUIT",
-    status: "Directeur musical ",
+    name: 'Patrice MONTESSUIT',
+    status: 'Directeur musical ',
     structure: "Orchestre d'Harmonie de Cluses (74)",
   },
   {
     review:
       "C'est un outil de travail très intéressant, complet et intuitif quand on comprend certaines subtilités. Il a très bien évolué aussi bien pour les chorales que les harmonie. Mes remarques ont toujours été prises en compte.",
-    name: "Gérard LEFÈBVRE ",
-    status: "Président",
-    structure: "Le choeur du Brevon (74)",
+    name: 'Gérard LEFÈBVRE ',
+    status: 'Président',
+    structure: 'Le choeur du Brevon (74)',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 16 - 16
components/Logiciels/Artist/SomeNumbers.vue

@@ -30,38 +30,38 @@
 </template>
 
 <script setup lang="ts">
-import type { Ref } from "vue";
+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_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_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_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_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_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_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",
+    src: '/images/pages/opentalent_artist/reviews/Logo_Union_Musicale_Wattrelosienne.jpg',
+    alt: 'Logo de l’Union Musicale Wattrelosienne',
   },
-]);
+])
 </script>
 
 <style scoped lang="scss">

+ 30 - 30
components/Logiciels/Manager/Avantages.vue

@@ -8,62 +8,62 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Benefit } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Benefit } from '~/types/interface'
 
 const benefits: Array<Benefit> = [
   {
-    title: "Sur-mesure",
-    number: "01",
+    title: 'Sur-mesure',
+    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",
+      '/images/pages/opentalent_manager/avantages/Un_logiciel_sur-mesure.jpg',
+    alt: 'Mètre ruban de couture',
   },
   {
-    title: "Adapté",
-    number: "02",
+    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",
+      '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",
+      '/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",
-    number: "03",
+    title: 'Économique',
+    number: '03',
     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",
+      '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',
   },
   {
-    title: "De pilotage",
-    number: "04",
+    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",
+      '/images/pages/opentalent_manager/avantages/Un_pilotage_des_structures_simple.jpg',
+    alt: 'Commandant de bord posant en uniforme',
   },
   {
-    title: "En réseau",
-    number: "05",
+    title: 'En réseau',
+    number: '05',
     description:
-      "Mise à jour automatique des coordonnées publiques entre les membres du réseau.",
+      '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",
+      '/images/pages/opentalent_manager/avantages/Un_logiciel_adapte_a_chaque_reseau.jpg',
+    alt: 'Multi-réseau',
   },
   {
-    title: "Confidentiel",
-    number: "06",
+    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",
+      '/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>

+ 56 - 56
components/Logiciels/Manager/Fonctionnalites.vue

@@ -13,99 +13,99 @@
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Functionality } from "~/types/interface";
+import 'vue3-carousel/dist/carousel.css'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Functionality } from '~/types/interface'
 
 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", "Membres / Adhérents"],
-    options: ["*Disponible sur tous supports "],
+    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'],
+    options: ['*Disponible sur tous supports '],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_repertoire.svg",
-    logoAlt: "Icône carnet annuaire",
-    title: "RÉPERTOIRE",
+    logo: '/images/components/fonctionnalites/Icone_repertoire.svg',
+    logoAlt: 'Icône carnet annuaire',
+    title: 'RÉPERTOIRE',
     list: [
-      "Membres",
-      "Personnel administratif ",
-      "Contacts extérieurs, partenaires & donateurs",
+      'Membres',
+      'Personnel administratif ',
+      'Contacts extérieurs, partenaires & donateurs',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_agenda.svg",
-    logoAlt: "Icône calendrier",
-    title: "AGENDA",
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône calendrier',
+    title: 'AGENDA',
     list: [
-      "Création et gestion des événements internes et externes",
-      "Invitation aux événements",
-      "Gestion des présences ",
+      'Création et gestion des événements internes et externes',
+      'Invitation aux événements',
+      'Gestion des présences ',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_parc_materiel.svg",
-    logoAlt: "Icône carton avec stylos et cahier à l’intérieur",
-    title: "PARC MATÉRIEL ",
+    logo: '/images/components/fonctionnalites/Icone_parc_materiel.svg',
+    logoAlt: 'Icône carton avec stylos et cahier à l’intérieur',
+    title: 'PARC MATÉRIEL ',
     list: [
-      "Gestion de votre parc matériel (instruments, costumes, accessoires..)",
-      "Locations et prêts de matériel",
-      "Partage de partitions",
+      'Gestion de votre parc matériel (instruments, costumes, accessoires..)',
+      'Locations et prêts de matériel',
+      'Partage de partitions',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_communication_en_reseau.svg",
-    logoAlt: "Icône enveloppe, téléphone et bulle SMS",
-    title: "COMMUNICATION RÉSEAU",
+    logo: '/images/components/fonctionnalites/Icone_communication_en_reseau.svg',
+    logoAlt: 'Icône enveloppe, téléphone et bulle SMS',
+    title: 'COMMUNICATION RÉSEAU',
     list: [
-      "Édition et envoi de courriers, de mails ou de SMS*",
-      "Édition et envoi de newsletter au adhérent du réseau",
-      "Création de modèles de courriers, mails ou SMS",
-      "Outil de publipostage intégré pour un envoi personnalisé",
+      'Édition et envoi de courriers, de mails ou de SMS*',
+      'Édition et envoi de newsletter au adhérent du réseau',
+      '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",
-    logoAlt: "Icône site internet",
-    title: "SITE INTERNET ",
+    logo: '/images/components/fonctionnalites/Icone_site_internet.svg',
+    logoAlt: 'Icône site internet',
+    title: 'SITE INTERNET ',
     list: [
-      "Gestion intégrée au logiciel",
-      "Mise à jour automatique des membres et événements sur votre site",
-      "Possibilité de personnalisé votre template",
+      'Gestion intégrée au logiciel',
+      'Mise à jour automatique des membres et événements sur votre site',
+      'Possibilité de personnalisé votre template',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_statistiques.svg",
-    logoAlt: "Icône graphique à barre avec ligne ascendante",
-    title: "STATISTIQUES",
+    logo: '/images/components/fonctionnalites/Icone_statistiques.svg',
+    logoAlt: 'Icône graphique à barre avec ligne ascendante',
+    title: 'STATISTIQUES',
     list: [
       "Rapport d'activité complet en fonction de vos activités",
       "Personnalisation du rapport d'activité grâce aux différents formats proposés lors du téléchargement",
-      "Export des données du logiciel pour une analyse complète",
+      'Export des données du logiciel pour une analyse complète',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_cotisation.svg",
-    logoAlt: "Icône d’une main donnant de l’argent à une autre main",
-    title: "COTISATION CMF ",
+    logo: '/images/components/fonctionnalites/Icone_cotisation.svg',
+    logoAlt: 'Icône d’une main donnant de l’argent à une autre main',
+    title: 'COTISATION CMF ',
     list: [
-      "Paramétrage des cotisations",
-      "Lancement de la campagne",
-      "Gestion des règlement & envoi de justificatif (adhésion/assurance...)",
+      'Paramétrage des cotisations',
+      'Lancement de la campagne',
+      'Gestion des règlement & envoi de justificatif (adhésion/assurance...)',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_fonctionnement_pyramidal.svg",
-    logoAlt: "Icône graphique pyramidale",
-    title: "FONCTIONNEMENT PYRAMIDAL ",
+    logo: '/images/components/fonctionnalites/Icone_fonctionnement_pyramidal.svg',
+    logoAlt: 'Icône graphique pyramidale',
+    title: 'FONCTIONNEMENT PYRAMIDAL ',
     list: [
-      "Mise en relation des logiciels (Artist, School et Manager)",
+      'Mise en relation des logiciels (Artist, School et Manager)',
       "Mise en place d'un système d'adhésion",
-      "Communication en réseau",
+      'Communication en réseau',
     ],
   },
-];
+]
 </script>

+ 16 - 16
components/Logiciels/Manager/Formation.vue

@@ -43,34 +43,34 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Formation } from "~/types/interface.js";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Formation } from '~/types/interface.js'
 
 const formations: Array<Formation> = [
   {
     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",
-    title: " Des formations adaptées à votre projet - en ligne",
+      '/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',
+    title: ' Des formations adaptées à votre projet - en ligne',
     description:
       "Chaque projet de solution de mise en réseau d'organisation nécessite un accompagnement sur-mesure par notre équipe de formation en fonction de vos besoins.",
-    buttonText: "Formation sur-mesure",
-    link: "/nous-contacter",
+    buttonText: 'Formation sur-mesure',
+    link: '/nous-contacter',
   },
   {
-    image: "/images/components/formations/Webinaires_visioconferences.jpg",
-    alt: "Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes",
-    overlayClass: "image-overlay2",
-    sessions: "Webinaire CMF Réseau",
+    image: '/images/components/formations/Webinaires_visioconferences.jpg',
+    alt: 'Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes',
+    overlayClass: 'image-overlay2',
+    sessions: 'Webinaire CMF Réseau',
     title: "Trouvez le webinaire qu'il vous faut ",
     description:
       "Des explications précises sur certains modules du logiciel Opentalent Manager, c'est possible pour aller encore plus loin... ",
-    buttonText: "Découvrir nos webinaires ",
-    link: "/webinaires",
+    buttonText: 'Découvrir nos webinaires ',
+    link: '/webinaires',
   },
-];
+]
 </script>
 
 <style scoped>

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

@@ -30,7 +30,7 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 </script>
 
 <style scoped lang="scss">

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

@@ -24,40 +24,40 @@
 </template>
 
 <script setup lang="ts">
-import type { FeaturePicto } from "~/types/interface";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
+import type { FeaturePicto } from '~/types/interface'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
 
 const features: Array<string> = [
-  "Logiciel de gestion et communication en ligne ",
-  "Répond aux besoins globaux des réseaux culturels ",
-  "Gestion collaborative ",
-  "Mise en valeur des activités des membres du réseau ",
-];
+  'Logiciel de gestion et communication en ligne ',
+  '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> = [
   {
-    src: "/images/pages/opentalent_manager/presentation/picto1.png",
-    text: "Logiciel de gestion et communication full web",
+    src: '/images/pages/opentalent_manager/presentation/picto1.png',
+    text: 'Logiciel de gestion et communication full web',
   },
   {
-    src: "/images/pages/opentalent_manager/presentation/picto2.png",
+    src: '/images/pages/opentalent_manager/presentation/picto2.png',
     text: "Site web intégré & simple d'usage",
   },
   {
-    src: "/images/pages/opentalent_manager/presentation/picto3.png",
-    text: "Boostez votre visibilité & communication",
+    src: '/images/pages/opentalent_manager/presentation/picto3.png',
+    text: 'Boostez votre visibilité & communication',
   },
   {
-    src: "/images/pages/opentalent_manager/presentation/picto4.png",
-    text: "Communiquez en réseau",
+    src: '/images/pages/opentalent_manager/presentation/picto4.png',
+    text: 'Communiquez en réseau',
   },
   // {
   //   src: "/images/logiciels/manager/picto5.png",
   //   text: "Sur-mesure",
   // },
   {
-    src: "/images/pages/opentalent_manager/presentation/picto6.png",
-    text: "Pout tout type de réseau pyramidal",
+    src: '/images/pages/opentalent_manager/presentation/picto6.png',
+    text: 'Pout tout type de réseau pyramidal',
   },
-];
+]
 </script>

+ 18 - 18
components/Logiciels/Manager/Reviews.vue

@@ -11,46 +11,46 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
       "L'outil répond à toutes les demandes d'une structure de notre taille et la connexion avec le site internet est très pratique.",
-    name: "Christophe MORIZOT",
-    status: "Président ",
-    structure: "Confédération Musicale de France (92)",
+    name: 'Christophe MORIZOT',
+    status: 'Président ',
+    structure: 'Confédération Musicale de France (92)',
   },
   {
     review:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.",
-    name: "Eric TAUVRON ",
-    status: "Vice-président",
-    structure: "CMF Rhône - Grand Lyon (69)",
+      'Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.',
+    name: 'Eric TAUVRON ',
+    status: 'Vice-président',
+    structure: 'CMF Rhône - Grand Lyon (69)',
   },
   {
     review:
       "C'est un outil de travail très intéressant, complet et intuitif quand on comprend certaines subtilités. Il a très bien évolué aussi bien pour les chorales que les harmonie. Mes remarques ont toujours été prises en compte.",
-    name: "Noëlle ROBERT",
-    status: "Président",
+    name: 'Noëlle ROBERT',
+    status: 'Président',
     structure: "CMF Côte d'or (21)",
   },
   {
     review:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.",
-    name: "Laurent Lebon",
+      'Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.',
+    name: 'Laurent Lebon',
     status: "Chef d'orchestre",
-    structure: "Conservatoire de Lyon",
+    structure: 'Conservatoire de Lyon',
   },
   {
     review:
-      "Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.",
-    name: "Laurent Lebon",
+      'Lorem ipsum dolor sit amet consectetur adipisicing elit.Provident porro fuga incidunt quae, doloremque tenetur aliquam  exercitationem deleniti aspernatur illo rem deserunt sapiente empore dolorem ipsa aliquid vel nihil eius.',
+    name: 'Laurent Lebon',
     status: "Chef d'orchestre",
-    structure: "Conservatoire de Lyon",
+    structure: 'Conservatoire de Lyon',
   },
-];
+]
 </script>
 
 <style scoped>

+ 18 - 18
components/Logiciels/School/Avantages.vue

@@ -8,38 +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";
+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",
+    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: "",
+      '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",
+    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: "",
+      '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",
+    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: "",
+    image: '/images/components/avantages/une_gestion_collaborative.jpg',
+    alt: '',
     isMemberCMF: true,
   },
-]);
+])
 </script>

+ 33 - 33
components/Logiciels/School/Comparatif.vue

@@ -19,95 +19,95 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { ComparisonItem } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { ComparisonItem } from '~/types/interface'
 
 const comparisonItems: Array<ComparisonItem> = [
   {
-    label: "GESTION DU RÉPERTOIRE",
+    label: 'GESTION DU RÉPERTOIRE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "AGENDA",
+    label: 'AGENDA',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SUIVI PÉDAGOGIQUE",
+    label: 'SUIVI PÉDAGOGIQUE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "GESTION DU PARC MATÉRIEL",
+    label: 'GESTION DU PARC MATÉRIEL',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "COMMUNICATION",
+    label: 'COMMUNICATION',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SMS",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'SMS',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "NOM DE DOMAINE",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'NOM DE DOMAINE',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "SITE INTERNET",
+    label: 'SITE INTERNET',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "STATISTIQUES",
+    label: 'STATISTIQUES',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "FONCTIONNALITÉ DU RÉSEAU CMF",
+    label: 'FONCTIONNALITÉ DU RÉSEAU CMF',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "SAUVEGARDE",
+    label: 'SAUVEGARDE',
     includedInStandard: true,
     includedInPremium: true,
   },
   {
-    label: "EXTRANET UTILISATEURS",
+    label: 'EXTRANET UTILISATEURS',
     includedInStandard: false,
-    includedInPremium: "Option",
+    includedInPremium: 'Option',
   },
   {
-    label: "PRÉINSCRIPTION EN LIGNE",
+    label: 'PRÉINSCRIPTION EN LIGNE',
     includedInStandard: false,
-    includedInPremium: "Option",
+    includedInPremium: 'Option',
   },
   {
     label: "GRILLES D'ÉVALUATION",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "GESTION DES RÈGLEMENTS",
-    includedInStandard: "Option",
-    includedInPremium: "Option",
+    label: 'GESTION DES RÈGLEMENTS',
+    includedInStandard: 'Option',
+    includedInPremium: 'Option',
   },
   {
-    label: "ESPACE DE STOCKAGE",
-    includedInStandard: "500 Mo",
-    includedInPremium: "1 Go",
+    label: 'ESPACE DE STOCKAGE',
+    includedInStandard: '500 Mo',
+    includedInPremium: '1 Go',
   },
   {
-    label: "PAGE DU SITE INTERNET",
-    includedInStandard: "Restreint",
-    includedInPremium: "Illimité",
+    label: 'PAGE DU SITE INTERNET',
+    includedInStandard: 'Restreint',
+    includedInPremium: 'Illimité',
   },
-];
+]
 </script>
 <style scoped></style>

+ 71 - 71
components/Logiciels/School/Fonctionnalites.vue

@@ -7,131 +7,131 @@
 </template>
 
 <script setup lang="ts">
-import "vue3-carousel/dist/carousel.css";
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Functionality } from "~/types/interface";
+import 'vue3-carousel/dist/carousel.css'
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Functionality } from '~/types/interface'
 
 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"],
-    options: ["* Disponible sur tous supports"],
+    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'],
+    options: ['* Disponible sur tous supports'],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_repertoire.svg",
-    logoAlt: "Icône carnet annuaire",
-    title: "RÉPERTOIRE",
+    logo: '/images/components/fonctionnalites/Icone_repertoire.svg',
+    logoAlt: 'Icône carnet annuaire',
+    title: 'RÉPERTOIRE',
     list: [
-      "Élèves et responsable légaux",
-      "Personnel administratif et professeurs",
-      "Contacts extérieurs, partenaires & donateurs",
+      'Élèves et responsable légaux',
+      'Personnel administratif et professeurs',
+      'Contacts extérieurs, partenaires & donateurs',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_preinscription_en_ligne.svg",
+    logo: '/images/components/fonctionnalites/Icone_preinscription_en_ligne.svg',
     logoAlt: "Icône d'un fichier devant un écran d'ordinateur",
-    title: "PRÉINSCRIPTION EN LIGNE *",
+    title: 'PRÉINSCRIPTION EN LIGNE *',
     list: [
-      "Paramétrage personnalisé des formulaires & mails automatiques",
-      "Gestion des réinscriptions et des nouvelles inscriptions",
-      "Gestion des quotas et du suivi des préinscriptions en ligne",
+      'Paramétrage personnalisé des formulaires & mails automatiques',
+      '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",
-    logoAlt: "Icône calendrier",
-    title: "AGENDA",
+    logo: '/images/components/fonctionnalites/Icone_agenda.svg',
+    logoAlt: 'Icône calendrier',
+    title: 'AGENDA',
     list: [
-      "Création et gestion des cours, examens, événements et prestations pédagogiques",
-      "Planning interactif avec un contrôle de cohérence",
-      "Gestion des présences et absences",
+      'Création et gestion des cours, examens, événements et prestations pédagogiques',
+      'Planning interactif avec un contrôle de cohérence',
+      'Gestion des présences et absences',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_parc_materiel.svg",
-    logoAlt: "Icône carton avec stylos et cahier à l’intérieur",
-    title: "PARC MATÉRIEL ",
+    logo: '/images/components/fonctionnalites/Icone_parc_materiel.svg',
+    logoAlt: 'Icône carton avec stylos et cahier à l’intérieur',
+    title: 'PARC MATÉRIEL ',
     list: [
-      "Gestion de votre parc matériel (instruments, costumes, accessoires..)",
-      "Planning interactif avec un contrôle de cohérence",
-      "Gestion des présences et absences",
+      'Gestion de votre parc matériel (instruments, costumes, accessoires..)',
+      'Planning interactif avec un contrôle de cohérence',
+      'Gestion des présences et absences',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_suivi_pedagogique.svg",
-    logoAlt: "Chapeau de diplômé américain",
-    title: "SUIVI PÉDAGOGIQUE",
+    logo: '/images/components/fonctionnalites/Icone_suivi_pedagogique.svg',
+    logoAlt: 'Chapeau de diplômé américain',
+    title: 'SUIVI PÉDAGOGIQUE',
     list: [
-      "Gestion du cursus pédagogique (critères personnalisables)",
-      "Création des examens et envoi des convocations",
-      "Édition des bulletins de notes",
+      'Gestion du cursus pédagogique (critères personnalisables)',
+      'Création des examens et envoi des convocations',
+      'Édition des bulletins de notes',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_facturation_et_reglement.svg",
+    logo: '/images/components/fonctionnalites/Icone_facturation_et_reglement.svg',
     logoAlt:
       "Fichier arborant un symbole monétaire devant un écran d'ordinateur",
-    title: "FACTURATION",
+    title: 'FACTURATION',
     list: [
-      "Facturation automatisée selon différents critères",
-      "Suivi des règlements et gestion des relances",
-      "En option : de nombreux moyens de paiement",
+      'Facturation automatisée selon différents critères',
+      'Suivi des règlements et gestion des relances',
+      'En option : de nombreux moyens de paiement',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_communication.svg",
-    logoAlt: "Icône enveloppe, téléphone et bulle SMS",
-    title: "COMMUNICATION",
+    logo: '/images/components/fonctionnalites/Icone_communication.svg',
+    logoAlt: 'Icône enveloppe, téléphone et bulle SMS',
+    title: 'COMMUNICATION',
     list: [
-      "Édition et envoi de courriers, de mails ou de SMS*",
-      "Création de modèles de courriers, mails ou SMS",
-      "Outil de publipostage intégré pour un envoi personnalisé",
+      'Édition et envoi de courriers, de mails ou de SMS*',
+      '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",
-    logoAlt: "Icône site internet",
-    title: "SITE INTERNET ",
+    logo: '/images/components/fonctionnalites/Icone_site_internet.svg',
+    logoAlt: 'Icône site internet',
+    title: 'SITE INTERNET ',
     list: [
-      "Gestion intégrée au logiciel",
-      "Mise à jour automatique des membres et événements sur votre site",
-      "Possibilité de personnalisé votre template",
+      'Gestion intégrée au logiciel',
+      'Mise à jour automatique des membres et événements sur votre site',
+      'Possibilité de personnalisé votre template',
     ],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_statistiques.svg",
-    logoAlt: "Icône graphique à barre avec ligne ascendante",
-    title: "STATISTIQUES",
+    logo: '/images/components/fonctionnalites/Icone_statistiques.svg',
+    logoAlt: 'Icône graphique à barre avec ligne ascendante',
+    title: 'STATISTIQUES',
     list: [
       "Rapport d'activité complet en fonction de vos activités",
       "Personnalisation du rapport d'activité grâce aux différents formats proposés lors du téléchargement",
-      "Export des données du logiciel pour une analyse complète",
+      'Export des données du logiciel pour une analyse complète',
     ],
   },
   {
-    logo: "/images/logos/cmf/Icone_CMF_reseau_BLACK.png",
-    logoAlt: "Logo CMF",
-    title: "RÉSEAU CMF *",
+    logo: '/images/logos/cmf/Icone_CMF_reseau_BLACK.png',
+    logoAlt: 'Logo CMF',
+    title: 'RÉSEAU CMF *',
     list: [
-      "Accès au répertoire du réseau",
-      "Renouvellement de votre adhésion fédérale",
+      'Accès au répertoire du réseau',
+      'Renouvellement de votre adhésion fédérale',
       "Gestion de l'assurance CMF",
     ],
-    options: ["* Uniquement dédié au adhérents CMF"],
+    options: ['* Uniquement dédié au adhérents CMF'],
   },
   {
-    logo: "/images/components/fonctionnalites/Icone_promotion.svg",
-    logoAlt: "Icône mégaphone",
-    title: "PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ",
+    logo: '/images/components/fonctionnalites/Icone_promotion.svg',
+    logoAlt: 'Icône mégaphone',
+    title: 'PROMOTION DE VOTRE STRUCTURE & VOS ÉVÉNEMENTS ',
     list: [
-      "Sur votre site internet intégré",
+      'Sur votre site internet intégré',
       "Sur l'agenda de la CMF",
       "Sur l'agenda culturel Opentalent",
     ],
   },
-];
+]
 </script>

+ 17 - 17
components/Logiciels/School/Formations.vue

@@ -46,34 +46,34 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Formation } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Formation } from '~/types/interface'
 
 const formations: Array<Formation> = [
   {
     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",
-    title: "Des formations adaptées à chacun - en ligne",
+      '/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',
+    title: 'Des formations adaptées à chacun - en ligne',
     description:
-      "Parce qu’on sait qu’appréhender un nouvel outil peut-être fastidieux et que vous n’avez pas de temps à perdre,...",
-    buttonText: "Découvrir toutes nos formations",
-    link: "/formations",
+      'Parce qu’on sait qu’appréhender un nouvel outil peut-être fastidieux et que vous n’avez pas de temps à perdre,...',
+    buttonText: 'Découvrir toutes nos formations',
+    link: '/formations',
   },
   {
-    image: "/images/components/formations/Webinaires_visioconferences.jpg",
-    alt: "Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes",
-    overlayClass: "image-overlay2",
-    sessions: "Toutes nos sessions",
+    image: '/images/components/formations/Webinaires_visioconferences.jpg',
+    alt: 'Femme sur son bureau avec devant deux écrans d’ordinateur de bureau en visioconférence devant 12 personnes',
+    overlayClass: 'image-overlay2',
+    sessions: 'Toutes nos sessions',
     title: "Trouvez le webinaire qu'il vous faut ",
     description:
       "Des explications précises sur certains modules du logiciel Opentalent School, c'est possible pour aller encore plus loin...",
-    buttonText: "Découvrir nos webinaires ",
-    link: "/webinaires",
+    buttonText: 'Découvrir nos webinaires ',
+    link: '/webinaires',
   },
-];
+]
 </script>
 
 <style scoped>

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

@@ -16,32 +16,32 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { FeaturePicto } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { FeaturePicto } from '~/types/interface'
 
 const features = [
-  "Logiciel de gestion et communication en ligne",
+  'Logiciel de gestion et communication en ligne',
   "Destiné aux établissements d'enseignement artistique",
-  "Gestion quotidienne et en temps réel",
-  "Pilotage complet de votre structure",
-];
+  'Gestion quotidienne et en temps réel',
+  'Pilotage complet de votre structure',
+]
 
 const pictos: Array<FeaturePicto> = [
   {
-    src: "/images/pages/opentalent_school/presentation/picto1.png",
-    text: "Logiciel de gestion et communication full web",
+    src: '/images/pages/opentalent_school/presentation/picto1.png',
+    text: 'Logiciel de gestion et communication full web',
   },
   {
-    src: "/images/pages/opentalent_school/presentation/picto3.png",
+    src: '/images/pages/opentalent_school/presentation/picto3.png',
     text: "Site web intégré & simple d'usage",
   },
   {
-    src: "/images/pages/opentalent_school/presentation/picto2.png",
-    text: "Boostez votre visibilité & communication",
+    src: '/images/pages/opentalent_school/presentation/picto2.png',
+    text: 'Boostez votre visibilité & communication',
   },
   {
-    src: "/images/pages/opentalent_school/presentation/picto4.png",
-    text: "Communiquez en réseau",
+    src: '/images/pages/opentalent_school/presentation/picto4.png',
+    text: 'Communiquez en réseau',
   },
-];
+]
 </script>

+ 14 - 14
components/Logiciels/School/Reviews.vue

@@ -11,39 +11,39 @@
 </template>
 
 <script setup lang="ts">
-import AnchoredSection from "~/components/Layout/AnchoredSection.vue";
-import type { Review } from "~/types/interface";
+import AnchoredSection from '~/components/Layout/AnchoredSection.vue'
+import type { Review } from '~/types/interface'
 
 const cards: Array<Review> = [
   {
     review:
       "C'est un logiciel simple d'utilisation après la formation. Pensé pour la musique, il s'adapte rès bien conçu et efficace avec une équipe ouverte, dynamique et à l'écoute. L’assistance est très réactive, j'ai toujours eu une réponse rapide à mes besoins, ce qui est fort appréciable.",
-    name: "Patrice CATHELIN ",
-    status: "Directeur administratif & pédagogique ",
-    structure: "Conservatoire de Musique & de Danse de Sens (78)",
+    name: 'Patrice CATHELIN ',
+    status: 'Directeur administratif & pédagogique ',
+    structure: 'Conservatoire de Musique & de Danse de Sens (78)',
   },
   {
     review:
       "Étant présente depuis presque le début, je suis fière d'avoir vu grandir ce logiciel et d'avoir évoluée avec lui. De plus, je me suis sentie écoutée lors de mes propositions d'amélioration, car beaucoup ont vu le jour. Enfin, l'accompagnement et la réactivité n'ont jamais faibli depuis toutes ces années",
-    name: "Karine GIRAUD",
-    status: "Secrétaire administrative",
-    structure: "Association Musicale Sainte Cécile de Lagord (17)",
+    name: 'Karine GIRAUD',
+    status: 'Secrétaire administrative',
+    structure: 'Association Musicale Sainte Cécile de Lagord (17)',
   },
   {
     review:
       "Logiciel très complet qui permet de faire beaucoup de choses. J’apprécie particulièrement la réactivité, la bienveillance et le fait que l’équipe soit à l'écoute pour faire évoluer l'outil en fonction de nos besoins. Si besoin, la FAQ est vraiment utile. Elle permet de trouver rapidement une solution face à un problème rencontré..",
-    name: "Laurent BEL",
-    status: "Directeur administratif & pédagogique",
-    structure: " École de Musique EPIC Musique en 4 Rivières (74)",
+    name: 'Laurent BEL',
+    status: 'Directeur administratif & pédagogique',
+    structure: ' École de Musique EPIC Musique en 4 Rivières (74)',
   },
   {
     review:
       "Opentalent est une entreprise avec de vraies valeurs humaines, à l'écoute de chaque structure et qui ne cesse de s'améliorer pour toujours coller aux besoins de ses clients. Plus qu'une relation commerciale, c'est pour nous un véritable partenaire au quotidien..",
-    name: "Philippe BORY",
-    status: "Personnel administratif",
+    name: 'Philippe BORY',
+    status: 'Personnel administratif',
     structure: "École d'Arts de Saint-Michel-sur-Orge (91)",
   },
-];
+]
 </script>
 
 <style scoped>

+ 15 - 15
components/Logiciels/School/SomeNumbers.vue

@@ -45,34 +45,34 @@
 <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_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_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_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_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_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_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",
+    src: '/images/pages/opentalent_school/reviews/Logo_EBAG-Ecole_des_Beaux-Arts_du_Genevois.png',
+    alt: 'Ecole des Beaux-Arts du Genevois',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 2 - 2
components/Logiciels/Title.vue

@@ -21,9 +21,9 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
+import { useDisplay } from 'vuetify'
 
-const { mdAndUp } = useDisplay();
+const { mdAndUp } = useDisplay()
 </script>
 
 <style scoped lang="scss">

+ 13 - 13
components/News/Details.vue

@@ -89,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'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import News from '~/models/Maestro/News'
 
-const { mdAndUp, smAndDown } = useDisplay();
+const { mdAndUp, smAndDown } = useDisplay()
 
-const route = useRoute();
-const { fetch } = useEntityFetch();
-const config = useRuntimeConfig();
+const route = useRoute()
+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>

+ 20 - 20
components/News/List.vue

@@ -92,44 +92,44 @@
 </template>
 
 <script setup lang="ts">
-import type { ComputedRef, Ref } from "vue";
-import { useEntityFetch } from "~/composables/data/useEntityFetch";
-import News from "~/models/Maestro/News";
+import type { ComputedRef, Ref } from 'vue'
+import { useEntityFetch } from '~/composables/data/useEntityFetch'
+import News from '~/models/Maestro/News'
 
-const config = useRuntimeConfig();
-const { fetchCollection } = useEntityFetch();
+const config = useRuntimeConfig()
+const { fetchCollection } = useEntityFetch()
 
 const getImageUrl = (attachment: string) =>
-  `${config.public.apiBaseUrl}/uploads/news/${attachment}`;
+  `${config.public.apiBaseUrl}/uploads/news/${attachment}`
 
-const page: Ref<number> = ref(1);
+const page: Ref<number> = ref(1)
 
 const query: ComputedRef<Record<string, string | number>> = computed(() => {
   return {
     page: page.value,
-    type: "BUSINESS",
-    "startPublication[before]": "now",
-    "endPublication[after]": "now",
-  };
-});
+    type: 'BUSINESS',
+    'startPublication[before]': 'now',
+    'endPublication[after]': 'now',
+  }
+})
 
 const {
   data: newsCollection,
   pending,
   refresh,
-} = fetchCollection(News, null, query);
+} = 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">

+ 62 - 62
components/Webinaire/Catalogue.vue

@@ -109,140 +109,140 @@
 </template>
 
 <script setup lang="ts">
-import type { Ref } from "vue";
-import type { Training } from "~/types/interface";
+import type { Ref } from 'vue'
+import type { Training } from '~/types/interface'
 
 const courses: Array<Training> = [
   {
-    imageUrl: "/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png",
-    imageAlt: "Esperluette du logo Opentalent Artist",
-    title: "Webinaire Artist ",
+    imageUrl: '/images/logos/opentalent/Logo_Opentalent_Artist_Griffe.png',
+    imageAlt: 'Esperluette du logo Opentalent Artist',
+    title: 'Webinaire Artist ',
     description:
-      "Ce webinaire est destiné aux acteurs culturels tels que les orchestres, les chorales, les compagnies et troupes de danse, théâtre et cirque. Il vous permettra de découvrir les fonctionnalités du logiciels, les avantages et les différentes versions.. ",
+      'Ce webinaire est destiné aux acteurs culturels tels que les orchestres, les chorales, les compagnies et troupes de danse, théâtre et cirque. Il vous permettra de découvrir les fonctionnalités du logiciels, les avantages et les différentes versions.. ',
     objectives: [
-      "Obtenir une présentation du logiciel Opentalent Artist",
-      "Présentation des principales fonctionnalités",
+      'Obtenir une présentation du logiciel Opentalent Artist',
+      'Présentation des principales fonctionnalités',
       "Qu'est ce que l'agenda culturel et l'annuaire ? ",
-      "Quelles différences entre la version Standard & Premium ?",
+      'Quelles différences entre la version Standard & Premium ?',
     ],
-    duration: "1H30",
+    duration: '1H30',
     additionalObjectives: [
       {
         id: 1,
         objectives: [
-          "Accès et interface",
-          "Configuration",
-          "Répertoire",
-          "Agenda",
+          'Accès et interface',
+          'Configuration',
+          'Répertoire',
+          'Agenda',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Parc matériel",
-          "Rapport d’activité",
-          "Communication",
-          "Site internet",
+          'Parc matériel',
+          'Rapport d’activité',
+          'Communication',
+          'Site internet',
         ],
       },
     ],
-    price: "Gratuit",
+    price: 'Gratuit',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf",
+      'https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_2-jours.pdf',
   },
   {
     // number: "02",
-    title: "Webinaire School",
-    imageUrl: "/images/logos/opentalent/Logo_Opentalent_School_Griffe.png",
-    imageAlt: "Esperluette du logo Opentalent School",
+    title: 'Webinaire School',
+    imageUrl: '/images/logos/opentalent/Logo_Opentalent_School_Griffe.png',
+    imageAlt: 'Esperluette du logo Opentalent School',
     description:
       " Rejoignez notre webinaire dédié aux petits comme aux GRANDS établissements d'enseignement artistique et découvrez comment optimiser votre travail grâce à un outil professionnel.",
     objectives: [
-      "Obtenir une présentation du logiciel Opentalent School",
+      'Obtenir une présentation du logiciel Opentalent School',
       "Comprendre l'écosystème de l'outil",
       "Identifier les avantages qu'offre ce logiciel pour votre structure",
-      "Apprendre à gérer votre propre site internet",
+      'Apprendre à gérer votre propre site internet',
     ],
-    duration: "1h",
+    duration: '1h',
     additionalObjectives: [
       {
         id: 1,
         objectives: [
-          "Accès et interface",
-          "Configuration",
-          "Répertoire",
-          "Agenda",
+          'Accès et interface',
+          'Configuration',
+          'Répertoire',
+          'Agenda',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Parc matériel",
-          "Facturation",
-          "Communication",
-          "Site internet",
+          'Parc matériel',
+          'Facturation',
+          'Communication',
+          'Site internet',
         ],
       },
     ],
-    price: "Gratuit",
+    price: 'Gratuit',
     downloadLink:
-      "https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf",
+      'https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-School-2023-02_1-jour.pdf',
   },
   {
-    title: "Webinaire Manager",
-    imageUrl: "/images/logos/opentalent/Logo_Opentalent_Manager_Griffe.png",
-    imageAlt: "Esperluette du logo Opentalent Manager",
+    title: 'Webinaire Manager',
+    imageUrl: '/images/logos/opentalent/Logo_Opentalent_Manager_Griffe.png',
+    imageAlt: 'Esperluette du logo Opentalent Manager',
     description:
       "Ces webinaires  sont spécialement conçues pour les utilisateurs du logiciel fédéral de la CMF (Confédération Musicale de France). Gagner en temps administratif, booster vos performances et optimiser l'utilisation du logiciel.",
     objectives: [
       "Configurer l'appel de cotisation",
       "Suivre l'appel de cotisation",
-      "Gérer votre site internet (pour les débutants)",
-      "Gérer votre site internet (pour les confirmés)",
+      'Gérer votre site internet (pour les débutants)',
+      'Gérer votre site internet (pour les confirmés)',
     ],
-    duration: "1H30",
+    duration: '1H30',
     additionalObjectives: [
       {
         id: 1,
         objectives: [
-          "Mieux connaitre votre logiciel",
-          "Optimiser votre temps administratif",
+          'Mieux connaitre votre logiciel',
+          'Optimiser votre temps administratif',
         ],
       },
       {
         id: 2,
         objectives: [
-          "Communiquer avec votre réseau",
-          "Promouvoir votre organisation",
+          'Communiquer avec votre réseau',
+          'Promouvoir votre organisation',
         ],
       },
     ],
-    price: "Gratuit",
+    price: 'Gratuit',
     downloadLink:
-      " https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf",
+      ' https://www.opentalent.fr/fileadmin/stockage/stockage/support/programme/PF-Typo3-2023-02_1-jour.pdf',
   },
-];
+]
 
-const selectedWebinar: Ref<string | null> = ref(null);
+const selectedWebinar: Ref<string | null> = ref(null)
 
 const webinaireCalendars: Record<string, string> = {
-  "Webinaire Artist":
-    "https://widget.weezevent.com/ticket/E920851/?code=62708&locale=fr-FR&width_auto=1&color_primary=0e2d32",
-  "Webinaire School":
-    "https://widget.weezevent.com/ticket/E963899/?code=47365&locale=fr-FR&width_auto=1&color_primary=0e2d32",
-  "Webinaire Manager":
-    "https://widget.weezevent.com/ticket/E923624/?code=4857&locale=fr-FR&width_auto=1&color_primary=0e2d32",
-};
+  'Webinaire Artist':
+    'https://widget.weezevent.com/ticket/E920851/?code=62708&locale=fr-FR&width_auto=1&color_primary=0e2d32',
+  'Webinaire School':
+    'https://widget.weezevent.com/ticket/E963899/?code=47365&locale=fr-FR&width_auto=1&color_primary=0e2d32',
+  'Webinaire Manager':
+    'https://widget.weezevent.com/ticket/E923624/?code=4857&locale=fr-FR&width_auto=1&color_primary=0e2d32',
+}
 
 const showModal = (webinaireTitle: string) => {
-  selectedWebinar.value = webinaireTitle.trim();
-};
+  selectedWebinar.value = webinaireTitle.trim()
+}
 
-const modalShowing = computed(() => selectedWebinar.value);
+const modalShowing = computed(() => selectedWebinar.value)
 
 const closeModal = () => {
-  selectedWebinar.value = null;
-};
+  selectedWebinar.value = null
+}
 </script>
 
 <style scoped lang="scss">

+ 13 - 13
components/Webinaire/FAQ.vue

@@ -33,31 +33,31 @@ Foire aux questions
 </template>
 
 <script setup lang="ts">
-import type { Ref } from "vue";
-import type { FaqEntry } from "~/types/interface";
+import type { Ref } from 'vue'
+import type { FaqEntry } from '~/types/interface'
 
 const faqItems: Array<FaqEntry> = [
   {
-    question: "Comment s’inscrire à un webinaire?",
+    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 ?",
+    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.",
+      '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 ?",
+    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. " +
+      '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.",
+      '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 ?",
+    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.",
   },
@@ -71,16 +71,16 @@ const faqItems: Array<FaqEntry> = [
     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);
+const activeIndex: Ref<number | null> = ref(null)
 
 function toggle(index: number) {
-  activeIndex.value = activeIndex.value === index ? null : index;
+  activeIndex.value = activeIndex.value === index ? null : index
 }
 
 function isOpen(index: number) {
-  return activeIndex.value === index;
+  return activeIndex.value === index
 }
 </script>
 

+ 30 - 31
composables/data/useEntityFetch.ts

@@ -1,59 +1,58 @@
-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 { useEntityManager } from '~/composables/data/useEntityManager'
+import ApiResource from '~/models/ApiResource'
+import type { AssociativeArray, Collection } from '~/types/data'
 
 interface useEntityFetchReturnType {
   fetch: (
     model: typeof ApiResource,
-    id: number,
-  ) => AsyncData<ApiResource, ApiResource | true>;
+    id: number
+  ) => AsyncData<ApiResource | null, Error | null>
+
   fetchCollection: (
     model: typeof ApiResource,
     parent?: ApiResource | null,
-    query?: Ref<AssociativeArray>,
-  ) => AsyncData<Collection, any>;
-  // @ts-ignore
+    query?: Ref<AssociativeArray>
+  ) => AsyncData<Collection | null, Error | null>
+
   getRef: <T extends ApiResource>(
-    model: typeof T,
-    id: Ref<number | null>,
-  ) => ComputedRef<null | T>;
+    model: new () => 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,
+  lazy: boolean = false
 ): useEntityFetchReturnType => {
-  const { em } = useEntityManager();
+  const { em } = useEntityManager()
 
   const fetch = (model: typeof ApiResource, id: number) =>
     useAsyncData(
-      model.entity + "_" + id + "_" + uuid4(),
+      model.entity + '_' + id + '_' + uuid4(),
       () => em.fetch(model, id, true),
-      { lazy },
-    );
+      { lazy }
+    )
 
   const fetchCollection = (
     model: typeof ApiResource,
     parent: ApiResource | null = null,
-    query: Ref<AssociativeArray | null> = ref(null),
+    query: Ref<AssociativeArray | null> = ref(null)
   ) =>
     useAsyncData(
-      model.entity + "_many_" + uuid4(),
+      model.entity + '_many_' + uuid4(),
       () => em.fetchCollection(model, parent, query.value ?? undefined),
-      { lazy },
-    );
+      { lazy }
+    )
 
-  // @ts-ignore
   const getRef = <T extends ApiResource>(
-    model: typeof T,
-    id: Ref<number | null>,
+    model: new () => T,
+    id: Ref<number | null>
   ): ComputedRef<T | null> => {
-    return computed(() => (id.value ? (em.find(model, id.value) as T) : null));
-  };
+    return computed(() => (id.value ? (em.find(model, id.value) as T) : null))
+  }
 
-  // @ts-ignore
-  return { fetch, fetchCollection, getRef };
-};
+  return { fetch, fetchCollection, getRef }
+}

+ 9 - 9
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 EntityManager from '~/services/data/entityManager'
+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 }
+}

+ 8 - 8
composables/data/useEnumFetch.ts

@@ -1,17 +1,17 @@
-import type { AsyncData } from "#app";
-import { useEnumManager } from "~/composables/data/useEnumManager";
-import type { Enum } from "~/types/data";
+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 });
+    useAsyncData(enumName, () => enumManager.fetch(enumName), { lazy })
 
   // @ts-ignore
-  return { fetch };
-};
+  return { fetch }
+}

+ 10 - 9
composables/data/useEnumManager.ts

@@ -1,15 +1,16 @@
-import { useI18n } from "vue-i18n";
-import { useMaestroRequestService } from "~/composables/data/useMaestroRequestService";
-import EnumManager from "~/services/data/enumManager";
+import { useI18n } from 'vue-i18n'
+import { useMaestroRequestService } from '~/composables/data/useMaestroRequestService'
+import EnumManager from '~/services/data/enumManager'
 
-let enumManager: EnumManager | null = null;
+let enumManager: EnumManager | null = null
 
 export const useEnumManager = () => {
   // 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()
+    // @ts-expect-error TODO: explain the error of conversion from useI18n result to VueI18n
+    enumManager = new EnumManager(apiRequestService, i18n)
   }
-  return { enumManager };
-};
+  return { enumManager }
+}

+ 20 - 24
composables/data/useMaestroRequestService.ts

@@ -1,20 +1,20 @@
-import type { Ref } from "vue";
-import type { FetchContext, FetchOptions } from "ofetch";
-import ApiRequestService from "~/services/data/apiRequestService";
+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 runtimeConfig = useRuntimeConfig()
 
-  const baseURL = runtimeConfig.apiBaseUrl ?? runtimeConfig.public.apiBaseUrl;
+  const baseURL = runtimeConfig.apiBaseUrl ?? runtimeConfig.public.apiBaseUrl
 
-  const pending: Ref<boolean> = ref(false);
+  const pending: Ref<boolean> = ref(false)
 
   /**
    * Peuple les headers avant l'envoi de la requête
@@ -22,23 +22,19 @@ export const useMaestroRequestService = () => {
    * @param request
    * @param options
    */
-  const onRequest = async function ({ request, options }: FetchContext) {
+  const onRequest = function ({ request, options }: FetchContext) {
     // @ts-ignore
     if (options && options.noXaccessId) {
-      return;
+      return
     }
 
-    pending.value = true;
-    console.log("Request : " + request + " (SSR: " + process.server + ")");
-  };
+    pending.value = true
+    console.log('Request : ' + request + ' (SSR: ' + process.server + ')')
+  }
 
-  const onResponse = async function ({
-    request,
-    options,
-    response,
-  }: FetchContext) {
-    pending.value = false;
-  };
+  const onResponse = function (_: FetchContext) {
+    pending.value = false
+  }
 
   /**
    * Gère les erreurs retournées par l'api
@@ -52,15 +48,15 @@ export const useMaestroRequestService = () => {
     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);
+    const fetcher = $fetch.create(config)
     // @ts-ignore
-    apiRequestServiceClass = new ApiRequestService(fetcher);
+    apiRequestServiceClass = new ApiRequestService(fetcher)
   }
 
-  return { apiRequestService: apiRequestServiceClass, pending };
-};
+  return { apiRequestService: apiRequestServiceClass, pending }
+}

+ 4 - 4
composables/useClientDevice.ts

@@ -1,11 +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,
-  };
+  }
 }

+ 2 - 2
models/ApiModel.ts

@@ -1,4 +1,4 @@
-import ApiResource from "~/models/ApiResource";
+import ApiResource from '~/models/ApiResource'
 
 /**
  * Entities from the API
@@ -7,4 +7,4 @@ import ApiResource from "~/models/ApiResource";
  */
 class ApiModel extends ApiResource {}
 
-export default ApiModel;
+export default ApiModel

+ 11 - 10
models/ApiResource.ts

@@ -1,20 +1,21 @@
-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>;
+class ApiResource extends Model {
+  // eslint-disable-next-line no-use-before-define
+  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,7 +24,7 @@ export class ApiResource extends Model {
    * @see https://github.com/vuex-orm/vuex-orm/issues/255#issuecomment-876378684
    */
   toJSON() {
-    return { ...this };
+    return { ...this }
   }
 
   /**
@@ -33,9 +34,9 @@ export class ApiResource extends Model {
    */
   public isNew(): boolean {
     return (
-      !this.id || (typeof this.id === "string" && this.id.slice(0, 3) === "tmp")
-    );
+      !this.id || (typeof this.id === 'string' && this.id.slice(0, 3) === 'tmp')
+    )
   }
 }
 
-export default ApiResource;
+export default ApiResource

+ 17 - 17
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 } from 'pinia-orm/dist/decorators'
+import ApiModel from '~/models/ApiModel'
 
 /**
  * Maestro Model : ContactRequest
@@ -7,47 +7,47 @@ import ApiModel from "~/models/ApiModel";
  * @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
 }

+ 11 - 11
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, Attr } from 'pinia-orm/dist/decorators'
+import ApiModel from '~/models/ApiModel'
 
 /**
  * Maestro Model : JobApplication
@@ -7,29 +7,29 @@ import ApiModel from "~/models/ApiModel";
  * @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
 }

+ 21 - 21
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'
+import ApiModel from '~/models/ApiModel'
 
 /**
  * Maestro Model : JobPosting
@@ -7,59 +7,59 @@ import ApiModel from "~/models/ApiModel";
  * @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: string[]
 
   @Str(null)
-  declare structureName: string | null;
+  declare structureName: string | null
 
   @Str(null)
-  declare structureNameText: any;
+  declare structureNameText: string
 
   @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
 }

+ 24 - 24
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'
+import ApiModel from '~/models/ApiModel'
 
 /**
  * Maestro Model : News
@@ -7,68 +7,68 @@ import ApiModel from "~/models/ApiModel";
  * @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: object
 
   @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
 }

+ 5 - 5
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 } from 'pinia-orm/dist/decorators'
+import ApiModel from '~/models/ApiModel'
 
 /**
  * Maestro Model : News
@@ -7,11 +7,11 @@ import ApiModel from "~/models/ApiModel";
  * @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
 }

+ 7 - 6
models/decorators.ts

@@ -1,4 +1,4 @@
-import ApiResource from "~/models/ApiResource";
+import ApiResource from '~/models/ApiResource'
 
 /**
  * Decorates an ApiResource's property to signal it as a field that is provided
@@ -8,11 +8,12 @@ import ApiResource from "~/models/ApiResource";
  * to get the id(s), then re-encode it as IRI(s) when re-normalizing.
  */
 export function IriEncoded(apiResource: typeof ApiResource): PropertyDecorator {
+  // We have to comply with the PropertyDecorator return type
+  // eslint-disable-next-line @typescript-eslint/ban-types
   return (target: Object, propertyKey: string | symbol) => {
-    // @ts-ignore
-    const self = target.$self();
+    // @ts-expect-error The object is an ApiResource
+    const self = target.$self()
 
-    // @ts-ignore
-    self.addIriEncodedField(propertyKey, apiResource);
-  };
+    self.addIriEncodedField(propertyKey as string, apiResource)
+  }
 }

+ 9 - 7
models/models.ts

@@ -1,12 +1,14 @@
-import ApiResource from "~/models/ApiResource";
-const modules = import.meta.glob("~/models/*/*.ts");
+import ApiResource from '~/models/ApiResource'
 
-const models: Record<string, typeof ApiResource> = {};
+const modules = import.meta.glob('~/models/*/*.ts')
+
+const models: Record<string, typeof ApiResource> = {}
 
 for (const path in modules) {
-  modules[path]().then((mod: any) => {
-    models[mod.default.entity] = mod.default;
-  });
+  modules[path]().then((mod) => {
+    // @ts-expect-error On est dépendant du retour de import.meta.glob pour le type
+    models[mod.default.entity] = mod.default
+  })
 }
 
-export default models;
+export default models

+ 64 - 63
nuxt.config.ts

@@ -1,22 +1,22 @@
-import fs from "fs";
-import vuetify from "vite-plugin-vuetify";
-import type { NuxtI18nOptions } from "@nuxtjs/i18n";
+import fs from 'fs'
+import vuetify from 'vite-plugin-vuetify'
+import type { NuxtI18nOptions } from '@nuxtjs/i18n'
 
-let https = {};
+let https = {}
 
-const transpile = ["vuetify", "pinia", "pinia-orm", "date-fns"];
+const transpile = ['vuetify', 'pinia', 'pinia-orm', 'date-fns']
 
 if (!process.env.NUXT_ENV) {
-  throw new 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')
 }
 
 /**
@@ -26,38 +26,38 @@ if (process.env.NUXT_ENV === "dev") {
  */
 export default defineNuxtConfig({
   ssr: false,
-  title: "Opentalent",
+  title: 'Opentalent',
   runtimeConfig: {
     // Private config that is only available on the server
-    env: "",
-    apiBaseUrl: "",
-    agendaBaseUrl: "",
-    hCaptchaSiteKey: "35360874-ebb1-4748-86e3-9b156d5bfc53",
+    env: '',
+    apiBaseUrl: '',
+    agendaBaseUrl: '',
+    hCaptchaSiteKey: '35360874-ebb1-4748-86e3-9b156d5bfc53',
     // Config within public will be also exposed to the client
     public: {
-      env: "",
-      apiBaseUrl: "",
-      agendaBaseUrl: "",
-      hCaptchaSiteKey: "35360874-ebb1-4748-86e3-9b156d5bfc53",
+      env: '',
+      apiBaseUrl: '',
+      agendaBaseUrl: '',
+      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,
+    'builder:watch': console.log,
   },
   app: {
     head: {
-      title: "Opentalent",
+      title: 'Opentalent',
       meta: [
-        { charset: "utf-8" },
-        { name: "viewport", content: "width=device-width, initial-scale=1" },
-        { hid: "description", name: "description", content: "" },
+        { charset: 'utf-8' },
+        { name: 'viewport', content: 'width=device-width, initial-scale=1' },
+        { hid: 'description', name: 'description', content: '' },
       ],
       link: [
-        { rel: "icon", type: "image/x-icon", href: "/favicon.ico" },
+        { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
         {
-          rel: "stylesheet",
-          href: "https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;700&display=swap",
+          rel: 'stylesheet',
+          href: 'https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;700&display=swap',
         },
       ],
     },
@@ -66,45 +66,46 @@ export default defineNuxtConfig({
     strict: true,
   },
   modules: [
-    async (options, nuxt) => {
-      nuxt.hooks.hook(
-        "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..
-            // 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,
-      );
+    // eslint-disable-next-line require-await
+    async (_, nuxt) => {
+      nuxt.hooks.hook('vite:extendConfig', (config) =>
+        // @ts-expect-error A revoir après que les lignes aient été décommentées
+        (config.plugins ?? []).push(
+          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
+          // voir aussi : https://github.com/jrutila/nuxt3-vuetify3-bug
+          // vuetify({
+          //     styles: { configFile: './assets/css/settings.scss' }
+          // })
+        )
+      )
     },
     [
-      "@pinia/nuxt",
+      '@pinia/nuxt',
       {
         autoImports: [
           // automatically imports `usePinia()`
-          "defineStore",
+          'defineStore',
           // automatically imports `usePinia()` as `usePiniaStore()`
-          ["defineStore", "definePiniaStore"],
+          ['defineStore', 'definePiniaStore'],
         ],
       },
     ],
-    "@pinia-orm/nuxt",
-    "nuxt-lodash",
-    "@nuxtjs/i18n",
-    "@nuxt/devtools",
-    "nuxt3-leaflet",
+    '@pinia-orm/nuxt',
+    'nuxt-lodash',
+    '@nuxtjs/i18n',
+    '@nuxt/devtools',
+    'nuxt3-leaflet',
   ],
   router: {
     options: {
-      scrollBehaviorType: "smooth",
+      scrollBehaviorType: 'smooth',
     },
   },
   webfontloader: {
     google: {
-      families: ["Barlow:300,400,500,700&display=swap"],
+      families: ['Barlow:300,400,500,700&display=swap'],
     },
   },
   devtools: {
@@ -113,7 +114,7 @@ export default defineNuxtConfig({
   },
   vite: {
     esbuild: {
-      drop: process.env.DEBUG ? [] : ["console", "debugger"],
+      drop: process.env.DEBUG ? [] : ['console', 'debugger'],
       tsconfigRaw: {
         compilerOptions: {
           experimentalDecorators: true,
@@ -121,36 +122,36 @@ export default defineNuxtConfig({
       },
     },
     ssr: {
-      noExternal: ["vuetify"],
+      noExternal: ['vuetify'],
     },
     server: {
       https,
       // @ts-ignore
       port: 443,
       hmr: {
-        protocol: "wss",
+        protocol: 'wss',
         port: 24680,
       },
     },
   },
   vuetify: {
-    styles: { configFile: "src/vuetify.scss" },
+    styles: { configFile: 'src/vuetify.scss' },
   },
   i18n: {
-    langDir: "lang",
+    langDir: 'lang',
     lazy: true,
     locales: [
       {
-        code: "fr",
-        iso: "fr-FR",
-        file: "fr.json",
-        name: "Français",
+        code: 'fr',
+        iso: 'fr-FR',
+        file: 'fr.json',
+        name: 'Français',
       },
     ],
-    defaultLocale: "fr",
+    defaultLocale: 'fr',
     detectBrowserLanguage: false,
   } as NuxtI18nOptions,
   build: {
     transpile,
   },
-});
+})

+ 10 - 10
pages/formations.vue

@@ -40,17 +40,17 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import type { MenuScroll } from "~/types/interface";
+import { useDisplay } from 'vuetify'
+import type { MenuScroll } from '~/types/interface'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
 const menus: Array<MenuScroll> = [
-  { anchor: "presentation", label: "Présentation" },
-  { anchor: "catalog", label: "Catalogue" },
-  { anchor: "financing", label: "Financement" },
-  { anchor: "certification", label: "Certification" },
-  { anchor: "inscription", label: "Inscription" },
-  { anchor: "testimonials", label: "Témoignages" },
-];
+  { anchor: 'presentation', label: 'Présentation' },
+  { anchor: 'catalog', label: 'Catalogue' },
+  { anchor: 'financing', label: 'Financement' },
+  { anchor: 'certification', label: 'Certification' },
+  { anchor: 'inscription', label: 'Inscription' },
+  { anchor: 'testimonials', label: 'Témoignages' },
+]
 </script>

+ 21 - 21
pages/opentalent_artist.vue

@@ -48,38 +48,38 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import { ActionMenuItemType } from "~/types/enum/layout";
-import type { MenuScroll, ActionMenuItem } from "~/types/interface";
+import { useDisplay } from 'vuetify'
+import { ActionMenuItemType } from '~/types/enum/layout'
+import type { MenuScroll, ActionMenuItem } from '~/types/interface'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
 const menus: Array<MenuScroll> = [
-  { anchor: "presentation", label: "Présentation" },
-  { anchor: "benefits", label: "Avantages" },
-  { anchor: "functionalities", label: "Fonctionnalités" },
-  { anchor: "comparative", label: "Comparatif" },
-  { anchor: "subscription", label: "Abonnement" },
-  { anchor: "webinars", label: "Webinaires" },
-  { anchor: "testimonials", label: "Témoignages" },
-];
+  { anchor: 'presentation', label: 'Présentation' },
+  { anchor: 'benefits', label: 'Avantages' },
+  { anchor: 'functionalities', label: 'Fonctionnalités' },
+  { anchor: 'comparative', label: 'Comparatif' },
+  { anchor: 'subscription', label: 'Abonnement' },
+  { anchor: 'webinars', label: 'Webinaires' },
+  { anchor: 'testimonials', label: 'Témoignages' },
+]
 
 const stickyMenuActions: Array<ActionMenuItem> = [
   {
     type: ActionMenuItemType.FOLLOW_LINK,
-    color: "primary",
-    icon: "far fa-comments",
-    text: "Nous contacter",
-    url: "/nous-contacter",
+    color: 'primary',
+    icon: 'far fa-comments',
+    text: 'Nous contacter',
+    url: '/nous-contacter',
   },
   {
     type: ActionMenuItemType.FOLLOW_LINK,
-    color: "primary",
-    icon: "fa-brands fa-readme icon",
-    text: "Brochure",
-    url: "/files/Depliant_Opentalent_Artist_2024.pdf",
+    color: 'primary',
+    icon: 'fa-brands fa-readme icon',
+    text: 'Brochure',
+    url: '/files/Depliant_Opentalent_Artist_2024.pdf',
   },
-];
+]
 </script>
 
 <style scoped lang="scss">

+ 23 - 23
pages/opentalent_manager.vue

@@ -46,43 +46,43 @@
 </template>
 
 <script setup lang="ts">
-import { useDisplay } from "vuetify";
-import type { MenuScroll, ActionMenuItem } from "~/types/interface";
-import { ActionMenuItemType } from "~/types/enum/layout";
+import { useDisplay } from 'vuetify'
+import type { MenuScroll, ActionMenuItem } from '~/types/interface'
+import { ActionMenuItemType } from '~/types/enum/layout'
 
-const { lgAndUp } = useDisplay();
+const { lgAndUp } = useDisplay()
 
 const menus: Array<MenuScroll> = ref([
-  { anchor: "presentation", label: "Présentation" },
-  { anchor: "benefits", label: "Avantages" },
-  { anchor: "functionalities", label: "Fonctionnalités" },
-  { anchor: "network", label: "Réseau" },
-  { anchor: "webinars", label: "Formations" },
-  { anchor: "testimonials", label: "Témoignages" },
-]).value;
+  { anchor: 'presentation', label: 'Présentation' },
+  { anchor: 'benefits', label: 'Avantages' },
+  { anchor: 'functionalities', label: 'Fonctionnalités' },
+  { anchor: 'network', label: 'Réseau' },
+  { anchor: 'webinars', label: 'Formations' },
+  { anchor: 'testimonials', label: 'Témoignages' },
+]).value
 
 const stickyMenuActions: Array<ActionMenuItem> = [
   {
     type: ActionMenuItemType.FOLLOW_LINK,
-    color: "primary",
-    icon: "fa-regular fa-comments icon",
-    text: "Nous contacter",
-    url: "/nous-contacter",
+    color: 'primary',
+    icon: 'fa-regular fa-comments icon',
+    text: 'Nous contacter',
+    url: '/nous-contacter',
   },
   {
     type: ActionMenuItemType.FOLLOW_LINK,
-    color: "primary",
-    icon: "fa-brands fa-readme icon",
-    text: "Brochure",
-    url: "/files/Depliant_Opentalent_Manager_2024.pdf",
+    color: 'primary',
+    icon: 'fa-brands fa-readme icon',
+    text: 'Brochure',
+    url: '/files/Depliant_Opentalent_Manager_2024.pdf',
   },
   {
     type: ActionMenuItemType.CALL_US,
-    color: "secondary",
-    icon: "fa-solid fa-phone icon",
-    text: "Nous appeler",
+    color: 'secondary',
+    icon: 'fa-solid fa-phone icon',
+    text: 'Nous appeler',
   },
-];
+]
 </script>
 
 <style scoped>

部分文件因为文件数量过多而无法显示