diff --git a/app/components/ContentSectionCompetences.tsx b/app/components/ContentSectionCompetences.tsx index 066a818..0ef053d 100644 --- a/app/components/ContentSectionCompetences.tsx +++ b/app/components/ContentSectionCompetences.tsx @@ -1,6 +1,10 @@ -import { fetchDataCompetences } from "../utils/fetchDataCompetences"; // ✅ Importation du bon fetch +"use client"; + +import { fetchDataCompetences, fetchDataGlossaire } from "../utils/fetchDataCompetences"; import CarouselCompetences from "./CarouselCompetences"; import ReactMarkdown from "react-markdown"; +import { useState, useEffect } from "react"; +import ModalGlossaire from "./ModalGlossaire"; // ✅ Import de la modale interface ContentSectionProps { collection: string; @@ -9,32 +13,82 @@ interface ContentSectionProps { contentClass?: string; } +// ✅ Définition du type Glossaire +interface GlossaireItem { + mot_clef: string; + slug: string; + variantes: string[]; + description: string; + images?: any[]; +} + export default async function ContentSectionCompetences({ collection, slug, titleClass, contentClass }: ContentSectionProps) { - const data = await fetchDataCompetences(collection, slug); // ✅ Utilisation du fetch spécifique + const data = await fetchDataCompetences(collection, slug); + const glossaireData: GlossaireItem[] = await fetchDataGlossaire(); + + const [selectedMot, setSelectedMot] = useState(null); if (!data) { return
❌ Compétence introuvable.
; } - const { name, content, picture } = data; // ✅ Assure-toi que `content` est bien récupéré au lieu de `Resum` + const { name, content, picture } = data; - // 🔹 Transformation des images pour le carrousel des compétences const images = picture?.map((img: any) => ({ url: `http://localhost:1337${img?.formats?.large?.url || img?.url}`, alt: img.name || "Image de compétence", })) || []; + // 🔥 Transformation du texte riche avec des cliquables + function transformMarkdownWithKeywords(text: string) { + if (!glossaireData || glossaireData.length === 0) return text; + + let modifiedText = text; + + glossaireData.forEach(({ mot_clef, variantes }) => { + const regexVariants = (variantes || []).map((v: string) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"); + const regex = new RegExp(`\\b(${mot_clef}|${regexVariants})\\b`, "gi"); + + modifiedText = modifiedText.replace(regex, (match) => { + return `${match}`; // 🔥 Span cliquable + }); + }); + + return modifiedText; + } + + const contentWithLinks = transformMarkdownWithKeywords(content); + + // ✅ Gestion des clics sur les mots-clés + useEffect(() => { + function handleKeywordClick(event: any) { + const target = event.target as HTMLElement; + if (target.classList.contains("keyword")) { + const mot = target.getAttribute("data-mot"); + if (mot) { + const glossaireMot = glossaireData.find((g) => g.mot_clef === mot); + setSelectedMot(glossaireMot || null); + } + } + } + + document.addEventListener("click", handleKeywordClick); + return () => document.removeEventListener("click", handleKeywordClick); + }, [glossaireData]); + return (

{name}

- {/* Carrousel spécifique aux compétences */} - {/* Contenu en Markdown */} + {/* 🔥 Affichage du texte riche avec mots-clés cliquables */}
- {content} {/* ✅ Utilisation de `content` au lieu de `Resum` */} + {contentWithLinks}
+ + {/* 🚀 Modale pour afficher les infos des mots-clés */} + {selectedMot && setSelectedMot(null)} />}
); } diff --git a/app/components/ModalGlossaire.tsx b/app/components/ModalGlossaire.tsx index bec9f9d..ad2fe27 100644 --- a/app/components/ModalGlossaire.tsx +++ b/app/components/ModalGlossaire.tsx @@ -1,55 +1,33 @@ -import { useState, useEffect } from "react"; import CarouselCompetences from "./CarouselCompetences"; interface ModalGlossaireProps { - glossaire: any[]; // Liste complète des mots-clés + mot: { + mot_clef: string; + description: string; + images?: any[]; + }; + onClose: () => void; } -export default function ModalGlossaire({ glossaire }: ModalGlossaireProps) { - const [selectedMot, setSelectedMot] = useState(null); - - useEffect(() => { - // 🔥 Détecter si un mot-clé est dans l'URL (#glossaire-mot) - function checkHash() { - const hash = window.location.hash.replace("#glossaire-", ""); - const mot = glossaire.find((g) => g.mot_clef.toLowerCase() === hash.toLowerCase()); - setSelectedMot(mot || null); - } - - window.addEventListener("hashchange", checkHash); - checkHash(); // Vérifier au chargement - - return () => { - window.removeEventListener("hashchange", checkHash); - }; - }, [glossaire]); - - if (!selectedMot) return null; - +export default function ModalGlossaire({ mot, onClose }: ModalGlossaireProps) { return (
{/* Bouton de fermeture */} - {/* Titre */} -

{selectedMot.mot_clef}

+

{mot.mot_clef}

{/* Description */} -

{selectedMot.description}

+

{mot.description}

{/* Carrousel d'images si disponible */} - {selectedMot.images && selectedMot.images.length > 0 && ( + {mot.images && mot.images.length > 0 && ( ({ + images={mot.images.map((img: any) => ({ url: `http://localhost:1337${img?.formats?.large?.url || img?.url}`, alt: img.name || "Illustration", }))}