diff --git a/frontend/index.html b/frontend/index.html index 5c3bad9..7c699a9 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,6 +5,18 @@ bureau d’études Maîtrise d’oeuvre + + + + + + + + + + + + diff --git a/frontend/src/api.js b/frontend/src/api.js index e0e5d53..6cd5f37 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -6,17 +6,7 @@ const api = axios.create({ withCredentials: true, }); -// Méthode pour récupérer les données OpenGraph d'un article spécifique -export const fetchPostWithOG = async (postId) => { - try { - const response = await api.get(`/wp/v2/posts/${postId}`); - const { opengraph } = response.data; // Les métadonnées OpenGraph doivent être disponibles ici - return opengraph; - } catch (error) { - console.error('Erreur lors de la récupération des données OpenGraph :', error); - throw error; - } -}; + // Exportation de l'instance Axios par défaut export default api; diff --git a/frontend/src/components/Pages/Home.jsx b/frontend/src/components/Pages/Home.jsx index 7b3065c..ad78ba5 100644 --- a/frontend/src/components/Pages/Home.jsx +++ b/frontend/src/components/Pages/Home.jsx @@ -5,107 +5,33 @@ import api from "../../api"; import ModernSpinner from "../SpinnerModerne"; import Expertises from "../Expertises"; import ConstructSection from "../ConstructSection"; -import { - Box, - Grid, - Typography, - Button, - Card, - CardContent, -} from "@mui/material"; +import { Box, Grid, Typography, Button, Card, CardContent } from "@mui/material"; import Logo from "../../assets/logo-in3-mobil.svg"; const Home = () => { - const [backgroundImage, setBackgroundImage] = useState(null); - const [useGradient, setUseGradient] = useState(false); - const [heroTitle, setHeroTitle] = useState("Titre par défaut"); - const [heroTitleColor, setHeroTitleColor] = useState("#ffffff"); - const [heroText, setHeroText] = useState("Texte par défaut"); - const [heroTextColor, setHeroTextColor] = useState("#ffffff"); - const [metaTitle, setMetaTitle] = useState("Titre par défaut"); - const [metaDescription, setMetaDescription] = useState( - "Description par défaut." - ); - - //optionally - const [canonicalUrl, setCanonicalUrl] = useState(null); + const [pageData, setPageData] = useState(null); + const [heroImage, setHeroImage] = useState(null); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); - //Construction - const [constructTitle, setConstructTitle] = useState("Construisons vos projets"); - const [constructSubtitle, setConstructSubtitle] = useState("ensemble"); - const [constructSector, setConstructSector] = useState("Industriel | Tertiaire | Privée"); - const [constructText, setConstructText] = useState("IN3, bureau d'études Ingénierie et Maîtrise d’œuvre, est implanté depuis 20 ans sur Le Mans. Nous étudions vos projets en structure, gros œuvre, électricité courants forts et faibles, et fluides, tout corps d'état."); - const [constructNoteText, setConstructNoteText] = useState("À votre écoute, nous travaillons avec et pour vous dans le but de satisfaire vos besoins tant sur le plan architectural que technique, méthodologique et/ou économique."); - const [missionTitle, setMissionTitle] = useState("Nos missions principales"); - const [missionItems, setMissionItems] = useState([ - { label: "Diagnostics | Sécurité", top: "20%", left: "50%" }, - { label: "Études techniques", top: "50%", left: "30%" }, - { label: "Bureau d'études | Maîtrise d’œuvre", top: "70%", left: "60%" }, - ]); - - // ACF Expertise - const [expertiseTitle, setExpertiseTitle] = useState( - "Titre Pourquoi Nous Choisir ?" - ); - const [expertise1Title, setExpertise1Title] = useState("Titre Expertise 1"); - const [expertise1Text, setExpertise1Text] = useState("Text Expertise 1"); - const [expertise2Title, setExpertise2Title] = useState("Titre Expertise 2"); - const [expertise2Text, setExpertise2Text] = useState("Text Expertise 2"); - const [expertise3Title, setExpertise3Title] = useState("Titre Expertise 3"); - const [expertise3Text, setExpertise3Text] = useState("Text Expertise 3"); - useEffect(() => { const fetchPageData = async () => { try { setIsLoading(true); setError(null); - const response = await api.get( - "wp/v2/pages/13?_fields=acf,rank_math_title,rank_math_description" - ); - const { acf, rank_math_title, rank_math_description } = response.data; + const response = await api.get("wp/v2/pages/13?_fields=acf,rank_math_title,rank_math_description"); + const pageContent = response.data; + setPageData(pageContent); - // Métadonnées SEO - setMetaTitle(rank_math_title || "Titre par défaut"); - setMetaDescription(rank_math_description || "Description par défaut."); - - // Récupération de l'URL canonique - setCanonicalUrl(acf?.canonical_url || window.location.href); - - // Données Hero - setUseGradient(acf?.enable_gradient ?? false); - setHeroTitle(acf?.hero_title || "Titre principal"); - setHeroTitleColor(acf?.hero_title_color || "#ffffff"); - setHeroText(acf?.hero_text || "Texte par défaut"); - setHeroTextColor(acf?.hero_text_color || "#ffffff"); - - // Image de fond - if (acf?.img_hero) { - const mediaResponse = await api.get(`wp/v2/media/${acf.img_hero}`); - setBackgroundImage(mediaResponse.data.source_url); + // Vérification et récupération de l'image Hero depuis l'API media de WordPress + const heroImageId = pageContent.acf?.img_hero; + if (heroImageId) { + const mediaResponse = await api.get(`wp/v2/media/${heroImageId}`); + setHeroImage(mediaResponse.data.source_url); } else { - setBackgroundImage(null); + setHeroImage(null); } - - // Section Construction - setConstructTitle(acf?.gdc_construct.construct_title || "Construisons vos projets"); - setConstructSubtitle(acf?.gdc_construct.construct_subtitle || "ensemble"); - setConstructText(acf?.gdc_construct.construct_text || "Texte par défaut"); - setConstructSector(acf?.gdc_construct.construct_sector || "Secteurs"); - setConstructNoteText(acf?.gdc_construct.construct_note || "Note société"); - setMissionTitle(acf?.mission_title || "Nos missions principales"); - setMissionItems(acf?.mission_items || []); - - // Récupération du titre de la deuxième section Expertise - setExpertiseTitle(acf?.titre_expertise || "Pourquoi Nous Choisir ?"); - setExpertise1Title(acf?.gdc_expert.titre_expertise_1 || "Expertise 1"); - setExpertise1Text(acf?.gdc_expert.text_expertise_1 || "Text Expertise 1"); - setExpertise2Title(acf?.gdc_expert.titre_expertise_2 || "Expertise 2"); - setExpertise2Text(acf?.gdc_expert.text_expertise_2 || "Text Expertise 2"); - setExpertise3Title(acf?.gdc_expert.titre_expertise_3 || "Expertise 3"); - setExpertise3Text(acf?.gdc_expert.text_expertise_3 || "Text Expertise 3"); } catch (error) { console.error("Erreur lors de la récupération des données :", error); setError("Impossible de charger les données. Veuillez réessayer."); @@ -129,106 +55,82 @@ const Home = () => { if (error) { return (
- Logo + Logo

{error}

); } + const { acf, rank_math_title, rank_math_description } = pageData || {}; + return (
{/* SEO */} - + {/* Section Héros */} {/* Section Construisons */} + {/* Section Expertises */} - {/* Section Désir : Témoignages */} + {/* Section Témoignages */} - + Ce que disent nos clients - + - "Un service exceptionnel, une équipe formidable !" + "Un service exceptionnel, une équipe formidable !" - + - Client 1 - + "Des résultats impressionnants pour notre projet." - + - Client 2 @@ -239,12 +141,7 @@ const Home = () => { {/* Section Action */} - + Prêt à Commencer ? @@ -268,4 +165,4 @@ const Home = () => { ); }; -export default Home; +export default Home; \ No newline at end of file diff --git a/frontend/src/components/Pages/PostPage.jsx b/frontend/src/components/Pages/PostPage.jsx deleted file mode 100644 index 7496b4a..0000000 --- a/frontend/src/components/Pages/PostPage.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { Helmet } from "react-helmet-async"; -import { useParams } from "react-router-dom"; -import { fetchPostWithOG } from "../../api"; // Assure-toi que le chemin est correct - -const PostPage = () => { - const { id } = useParams(); - const [ogData, setOgData] = useState(null); - - useEffect(() => { - const getOgData = async () => { - try { - const data = await fetchPostWithOG(id); - setOgData(data); - } catch (error) { - console.error("Erreur lors de la récupération des métadonnées OpenGraph :", error); - } - }; - - getOgData(); - }, [id]); - - if (!ogData) return
Chargement...
; - - return ( -
- - - - - -

{ogData.title}

-

{ogData.description}

- {ogData.title} -
- ); -}; - -export default PostPage; diff --git a/frontend/src/components/SEO.jsx b/frontend/src/components/SEO.jsx index af369d2..34c9129 100644 --- a/frontend/src/components/SEO.jsx +++ b/frontend/src/components/SEO.jsx @@ -2,14 +2,21 @@ import React, { useEffect, useState } from "react"; import { Helmet } from "react-helmet-async"; import axios from "axios"; -const SEO = ({ postId, defaultTitle, defaultDescription, defaultCanonicalUrl, defaultOgImage }) => { +const SEO = ({ + postId, + defaultTitle = "Titre par défaut", + defaultDescription = "Description par défaut", + defaultCanonicalUrl = "", + defaultOgImage = "https://preprod.octopusdesign.fr/api-octopus/server/wp-content/uploads/2025/01/Construction-logements-au-Mans-01.avif" +}) => { + const [metaData, setMetaData] = useState({ - title: defaultTitle || "Titre par défaut", - description: defaultDescription || "Description par défaut", - canonicalUrl: defaultCanonicalUrl || "", - ogTitle: "", - ogDescription: "", - ogImage: defaultOgImage || "https://votre-site.com/default-image.jpg", + title: defaultTitle, + description: defaultDescription, + canonicalUrl: defaultCanonicalUrl, + ogTitle: defaultTitle, + ogDescription: defaultDescription, + ogImage: defaultOgImage, }); useEffect(() => { @@ -17,21 +24,23 @@ const SEO = ({ postId, defaultTitle, defaultDescription, defaultCanonicalUrl, de const fetchMetaData = async () => { try { - const response = await axios.get( + const { data } = await axios.get( `https://preprod.octopusdesign.fr/api-octopus/server/wp-json/wp/v2/pages/${postId}` ); - const ogData = response.data.rank_math_og || {}; - setMetaData((prev) => ({ - ...prev, - title: ogData.og_title || prev.title, - description: ogData.og_description || prev.description, - ogTitle: ogData.og_title || "", - ogDescription: ogData.og_description || "", - ogImage: ogData.og_image || prev.ogImage, - })); + if (data && data.rank_math_og) { + setMetaData((prev) => ({ + ...prev, + title: data.rank_math_og.og_title || prev.title, + description: data.rank_math_og.og_description || prev.description, + ogTitle: data.rank_math_og.og_title || prev.title, + ogDescription: data.rank_math_og.og_description || prev.description, + ogImage: data.rank_math_og.og_image || prev.ogImage, + canonicalUrl: data.acf?.canonical_url || window.location.href + })); + } } catch (error) { - console.error("Erreur lors de la récupération des données SEO :", error); + console.error("⚠️ Erreur lors de la récupération des métadonnées SEO :", error); } }; @@ -40,12 +49,23 @@ const SEO = ({ postId, defaultTitle, defaultDescription, defaultCanonicalUrl, de return ( + {/* SEO standard */} {metaData.title} {metaData.canonicalUrl && } - - + + {/* Open Graph (Facebook, LinkedIn) */} + + + + + + {/* Twitter Cards */} + + + + ); }; diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index 710cfad..f2c8af7 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -11,7 +11,6 @@ const Home = lazy(() => import('./components/pages/Home.jsx')); const About = lazy(() => import('./components/Pages/About')); const Contact = lazy(() => import('./components/Pages/Contact')); const Post = lazy(() => import('./components/Pages/Post')); -const PostPage = lazy(() => import('./components/Pages/PostPage')); // Nouveau composant pour un post spécifique const Search = lazy(() => import('./components/Pages/Search')); // Nouveau composant pour la recherche // Import des services @@ -31,7 +30,6 @@ function YourApp() { } /> } /> - } /> {/* Route dynamique pour un post spécifique */} } /> } /> } /> {/* Route pour les recherches */} diff --git a/frontend/stats.html b/frontend/stats.html deleted file mode 100644 index 623950e..0000000 --- a/frontend/stats.html +++ /dev/null @@ -1,4949 +0,0 @@ - - - - - - - - Rollup Visualizer - - - -
- - - - - diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..615719e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,78 @@ +{ + "name": "Octopus-React-Wp", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "react-helmet-async": "^2.0.5" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet-async": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-2.0.5.tgz", + "integrity": "sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg==", + "license": "Apache-2.0", + "dependencies": { + "invariant": "^2.2.4", + "react-fast-compare": "^3.2.2", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..cb5c1fc --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "react-helmet-async": "^2.0.5" + } +}