maj template page

This commit is contained in:
sebvtl728
2025-02-03 02:02:18 +01:00
parent f25b0fa6e4
commit 555a63b61d
12 changed files with 314 additions and 378 deletions
+23 -9
View File
@@ -19,6 +19,7 @@
"react-helmet-async": "^2.0.5",
"react-router-dom": "^7.1.1",
"react-simple-lightbox": "^1.0.26",
"react-toastify": "^11.0.3",
"simple-react-lightbox": "^3.6.8",
"svgo": "^3.3.2",
"swiper": "^10.3.1"
@@ -3392,6 +3393,15 @@
"node": ">=10"
}
},
"node_modules/cosmiconfig/node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/create-ecdh": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
@@ -9986,6 +9996,19 @@
"react": "^16.8.3 || ^17 || ^18"
}
},
"node_modules/react-toastify": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.3.tgz",
"integrity": "sha512-cbPtHJPfc0sGqVwozBwaTrTu1ogB9+BLLjd4dDXd863qYLj7DGrQ2sg5RAChjFUB4yc3w8iXOtWcJqPK/6xqRQ==",
"license": "MIT",
"dependencies": {
"clsx": "^2.1.1"
},
"peerDependencies": {
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -12865,15 +12888,6 @@
"node": ">=10"
}
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"license": "ISC",
"engines": {
"node": ">= 6"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+1
View File
@@ -21,6 +21,7 @@
"react-helmet-async": "^2.0.5",
"react-router-dom": "^7.1.1",
"react-simple-lightbox": "^1.0.26",
"react-toastify": "^11.0.3",
"simple-react-lightbox": "^3.6.8",
"svgo": "^3.3.2",
"swiper": "^10.3.1"
-3
View File
@@ -49,7 +49,6 @@ const Expertices = ({
<Grid item xs={12} md={4}>
<Card
sx={{
backgroundPosition: "center",
boxShadow: 3,
padding: 2,
textAlign: "center",
@@ -99,7 +98,6 @@ const Expertices = ({
<Grid item xs={12} md={4}>
<Card
sx={{
backgroundPosition: "center",
boxShadow: 3,
padding: 2,
textAlign: "center",
@@ -149,7 +147,6 @@ const Expertices = ({
<Grid item xs={12} md={4}>
<Card
sx={{
backgroundPosition: "center",
boxShadow: 3,
padding: 2,
textAlign: "center",
+9 -8
View File
@@ -1,4 +1,4 @@
import React, { useState } from "react";
import { useState } from "react";
import {
AppBar,
Toolbar,
@@ -179,7 +179,7 @@ const Header = () => {
</MenuItem>
<MenuItem
component={Link}
to="/services/formation-video"
to="/services/electricite"
onClick={handleMenuClose}
>
<WorkIcon sx={{ marginRight: 1}} />
@@ -350,25 +350,26 @@ const Header = () => {
<WorkIcon sx={{ marginRight: 0.5 }} />
<ListItemText primary="Prestation maitrise oeuvre" />
</ListItem>
<ListItem
button
component={Link}
to="/services/formation-ia"
selected={location.pathname.includes("/services/formation-ia")}
to="/services/structure-beton-charpente-metallique-bois"
selected={location.pathname.includes("/services/structure-beton-charpente-metallique-bois")}
>
<WorkIcon sx={{ marginRight: 0.5 }} />
<ListItemText primary="Formation IA" />
<ListItemText primary="Structure beton..." />
</ListItem>
<ListItem
button
component={Link}
to="/services/formation-video"
to="/services/electricite"
selected={location.pathname.includes(
"/services/formation-video"
"/services/electricite"
)}
>
<WorkIcon sx={{ marginRight: 0.5 }} />
<ListItemText primary="Formation Video" />
<ListItemText primary="Electricité..." />
</ListItem>
<ListItem
button
+1 -2
View File
@@ -356,10 +356,9 @@ const Contact = () => {
<Typography
variant="h2"
sx={{
fontSize: { xs: "2rem", md: "2rem", lg: "3rem" }, // Responsive
fontSize: { xs: "2rem", md: "2rem", lg: "2rem" }, // Responsive
fontWeight: "bold",
mb: 2,
fontSize: { xs: "1.5rem", md: "2rem" },
}}
>
Besoin d'une assistance immédiate?
+74 -12
View File
@@ -1,27 +1,89 @@
import { useEffect, useState } from "react";
import { fetchPosts, deletePost } from "../../wordpress";
import { Box, Typography, Button, CircularProgress, Paper, Grid } from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
function PostList() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function loadPosts() {
const data = await fetchPosts();
setPosts(data);
try {
const data = await fetchPosts();
setPosts(data);
} catch (err) {
setError("⚠️ Impossible de récupérer les articles.");
console.error("Erreur lors de la récupération des articles :", err);
} finally {
setLoading(false);
}
}
loadPosts();
}, []);
const handleDelete = async (postId) => {
if (window.confirm("❌ Es-tu sûr de vouloir supprimer cet article ?")) {
try {
await deletePost(postId);
setPosts(posts.filter((post) => post.id !== postId));
toast.success("✅ Article supprimé avec succès !");
} catch (err) {
console.error("Erreur suppression :", err);
toast.error("⚠️ Erreur lors de la suppression.");
}
}
};
return (
<div className="post-list">
<h2>Liste des Articles</h2>
{posts.map((post) => (
<div key={post.id} className="post-item">
<h3>{post.title.rendered}</h3>
<button onClick={() => deletePost(post.id)}>Supprimer</button>
</div>
))}
</div>
<Box sx={{ maxWidth: "900px", margin: "auto", mt: 5 }}>
<Typography variant="h4" sx={{ fontWeight: "bold", textAlign: "center", mb: 3 }}>
📋 Liste des Articles
</Typography>
{loading && (
<Box sx={{ textAlign: "center", mt: 4 }}>
<CircularProgress />
</Box>
)}
{error && (
<Typography color="error" textAlign="center" sx={{ mb: 3 }}>
{error}
</Typography>
)}
{!loading && posts.length === 0 && (
<Typography textAlign="center" sx={{ mt: 3 }}>
Aucun article trouvé.
</Typography>
)}
<Grid container spacing={3}>
{posts.map((post) => (
<Grid item xs={12} sm={6} md={4} key={post.id}>
<Paper sx={{ padding: 3, boxShadow: 3, textAlign: "center" }}>
<Typography variant="h6" sx={{ fontWeight: "bold", mb: 2 }}>
{post.title.rendered}
</Typography>
<Button
variant="contained"
color="error"
startIcon={<DeleteIcon />}
onClick={() => handleDelete(post.id)}
sx={{ fontWeight: "bold" }}
>
Supprimer
</Button>
</Paper>
</Grid>
))}
</Grid>
</Box>
);
}
export default PostList;
export default PostList;
+42 -30
View File
@@ -1,50 +1,62 @@
import React from 'react';
import ServicePageTemplate from '../ServicePageTemplate';
import React from "react";
import ServicePageTemplate from "../ServicePageTemplate";
const ServiceDeux = () => {
const serviceDetails = {
title: 'Structure béton charpente métallique & bois',
subtitle: 'Dominez lintelligence artificielle.',
description:
'Plongez dans le futur! Notre formation IA vous prépare aux outils modernes dintelligence artificielle comme Python, TensorFlow et OpenAI API. Apprenez à créer des modèles IA performants.',
// Hero
title: "Structure béton charpente métallique & bois",
subtitle: "Dominez lintelligence artificielle.",
image: "https://picsum.photos/id/239/1920/1080.webp",
ctaText: "Découvrir la formation IA",
ctaLink: "/contact",
// section 1
interestTitle: "Béton ou Charpente : Quel Matériau Choisir pour une Construction Durable ?", // ✅ Modifiable individuellement
description: "Le béton est le matériau de construction le plus répandu dans le monde. Il est présent dans tous les secteurs de la construction.\n Longtemps associé à limage négative des grands ensembles, gris et vieillissants, le béton a réalisé des progrès spectaculaires ces dernières années, tant au niveau de ses performances techniques que des aspects esthétiques. Il commence même à entrer dans les foyers comme produit de décoration !<br>Une charpente est un assemblage de pièces de bois et/ou de métal, servant à soutenir ou couvrir des constructions et faisant partie de la toiture.",
// section 2
desirTitle: "Ce que nous offrons",// ✅ Modifiable individuellement
features: [
{
title: 'Fondamentaux de lIA',
description: 'Concepts, algorithmes et applications.',
modalText: 'Découvrez les bases de lIA, des algorithmes aux applications concrètes dans divers domaines.',
modalImage: 'https://picsum.photos/id/200/800/400.webp',
title: "Fondamentaux de lIA",
description: "Concepts, algorithmes et applications.",
modalText:
"Découvrez les bases de lIA, des algorithmes aux applications concrètes dans divers domaines.",
modalImage: "https://picsum.photos/id/200/800/400.webp",
},
{
title: 'Python pour lIA',
description: 'Bibliothèques populaires: TensorFlow, PyTorch.',
modalText: 'Apprenez à utiliser Python et ses bibliothèques pour concevoir des modèles dIA puissants.',
modalImage: 'https://picsum.photos/id/201/800/400.webp',
title: "Python pour lIA",
description: "Bibliothèques populaires: TensorFlow, PyTorch.",
modalText:
"Apprenez à utiliser Python et ses bibliothèques pour concevoir des modèles dIA puissants.",
modalImage: "https://picsum.photos/id/201/800/400.webp",
},
{
title: 'Projets Pratiques',
description: 'Créez vos propres modèles IA.',
modalText: 'Mettez vos compétences en pratique en développant des projets IA réels.',
modalImage: 'https://picsum.photos/id/202/800/400.webp',
title: "Projets Pratiques",
description: "Créez vos propres modèles IA.",
modalText:
"Mettez vos compétences en pratique en développant des projets IA réels.",
modalImage: "https://picsum.photos/id/202/800/400.webp",
},
],
image: 'https://picsum.photos/id/239/1920/1080.webp',
ctaText: 'Découvrir la formation IA',
ctaLink: '/contact',
carouselItems: [
{
title: 'Site E-commerce',
description: 'Un projet e-commerce performant et moderne.',
image: 'https://picsum.photos/id/453/800/400.webp',
title: "Site E-commerce",
description: "Un projet e-commerce performant et moderne.",
image: "https://picsum.photos/id/453/800/400.webp",
},
{
title: 'Portfolio Personnel',
description: 'Montrez vos compétences avec un portfolio sur mesure.',
image: 'https://picsum.photos/id/454/800/400.webp',
title: "Portfolio Personnel",
description: "Montrez vos compétences avec un portfolio sur mesure.",
image: "https://picsum.photos/id/454/800/400.webp",
},
{
title: 'Blog Dynamique',
description: 'Créez un blog interactif et optimisé pour le SEO.',
image: 'https://picsum.photos/id/455/800/400.webp',
title: "Blog Dynamique",
description: "Créez un blog interactif et optimisé pour le SEO.",
image: "https://picsum.photos/id/455/800/400.webp",
},
],
};
+47 -30
View File
@@ -1,52 +1,69 @@
import React from 'react';
import ServicePageTemplate from '../ServicePageTemplate';
import React from "react";
import ServicePageTemplate from "../ServicePageTemplate";
const ServiceTrois = () => {
const serviceDetails = {
title: 'Électricité',
subtitle: 'IN3 est un bureau d’études technique spécialisé dans lingénierie électrique du bâtiment.',
description:
'Plongez dans le futur! Notre formation IA vous prépare aux outils modernes dintelligence artificielle comme Python, TensorFlow et OpenAI API. Apprenez à créer des modèles IA performants.',
// Hero
title: "Électricité", // ✅ Modifiable individuellement
subtitle: "IN3 est un bureau d’études technique spécialisé dans lingénierie électrique du bâtiment.",
image: "https://picsum.photos/id/1018/1920/1080.webp",
ctaText: "En savoir plus",
ctaLink: "/contact",
// Section 1
interestTitle: "Comment réussir vos installations électriques \navec une assistance experte en maîtrise douvrage ?",
description: "Notre activité est lassistance aux maîtres douvrage à la réalisation des installations électriques courants forts et courants faibles.\n Définition des besoins / Audit si installations existantes Estimation du coût des ouvrages.\n \n Plans dimplantation du matériel et des canalisations schémas électriques unifilaires.\n Analyse des offres et assistance technique au choix de lentreprise d’électricité.",
// Section 2
desirTitle: "Réalisation et assistance électrique",
features: [
{
title: 'Chantier électricité industriel',
description: 'Réalisation dinstallations électriques.',
modalText: 'Réalisation dinstallations électriques pour des sites industriels, incluant le câblage, la pose d’équipements, et la mise en conformité selon les normes en vigueur..',
modalImage: 'https://picsum.photos/id/200/800/400.webp',
title: "Chantier électricité industriel",
description: "Réalisation dinstallations électriques.",
modalText: "Réalisation dinstallations électriques pour des sites industriels, incluant le câblage, la pose d’équipements, et la mise en conformité selon les normes en vigueur.",
modalImage: "https://picsum.photos/id/200/800/400.webp",
},
{
title: 'Python pour lIA',
description: 'Bibliothèques populaires: TensorFlow, PyTorch.',
modalText: 'Apprenez à utiliser Python et ses bibliothèques pour concevoir des modèles dIA puissants.',
modalImage: 'https://picsum.photos/id/201/800/400.webp',
title: "Dossier de Consultation",
description: "Réalisation du Dossier de Consultation des entreprises (DCE)",
modalText: "Réalisation du Dossier de Consultation des entreprises (DCE) cahier des clauses techniques particulières (CCTP) bordereau de décomposition du prix global et forfaitaire (DPGF, servant de base à tous les devis).",
modalImage: "https://picsum.photos/id/201/800/400.webp",
},
{
title: 'Projets Pratiques',
description: 'Créez vos propres modèles IA.',
modalText: 'Mettez vos compétences en pratique en développant des projets IA réels.',
modalImage: 'https://picsum.photos/id/202/800/400.webp',
title: "L'électricité & Suivi de chantier",
description: "Assistance à lentreprise et vérification des documents",
modalText: "Assistance à lentreprise et vérification des documents dexécution. Réception des ouvrages exécutés. Nous pouvons également assister lentreprise titulaire du marché à la réalisation des documents dexécution (plans dimplantation, schématique électrique, notes de calculs réglementaires, …)",
modalImage: "https://picsum.photos/id/202/800/400.webp",
},
],
image: 'https://picsum.photos/id/239/1920/1080.webp',
ctaText: 'En savoir plus !',
ctaLink: '/contact',
carouselItems: [
{
title: 'Site E-commerce',
description: 'Un projet e-commerce performant et moderne.',
image: 'https://picsum.photos/id/453/800/400.webp',
title: "Site E-commerce",
description: "Un projet e-commerce performant et moderne.",
image: "https://picsum.photos/id/453/800/400.webp",
},
{
title: 'Portfolio Personnel',
description: 'Montrez vos compétences avec un portfolio sur mesure.',
image: 'https://picsum.photos/id/454/800/400.webp',
title: "Portfolio Personnel",
description: "Montrez vos compétences avec un portfolio sur mesure.",
image: "https://picsum.photos/id/454/800/400.webp",
},
{
title: 'Blog Dynamique',
description: 'Créez un blog interactif et optimisé pour le SEO.',
image: 'https://picsum.photos/id/455/800/400.webp',
title: "Blog Dynamique",
description: "Créez un blog interactif et optimisé pour le SEO.",
image: "https://picsum.photos/id/455/800/400.webp",
},
],
// ✅ Métadonnées SEO
seo: {
metaTitle: "Formation Électricité | Expertise en ingénierie électrique",
metaDescription: "Découvrez notre expertise en ingénierie électrique et maîtrisez l'installation et la gestion des systèmes électriques.",
keywords: "électricité, ingénierie électrique, installation électrique, suivi de chantier",
ogImage: "https://picsum.photos/1200/630",
},
};
return <ServicePageTemplate {...serviceDetails} />;
+40 -28
View File
@@ -1,45 +1,57 @@
import React from 'react';
import ServicePageTemplate from '../ServicePageTemplate';
import React from "react";
import ServicePageTemplate from "../ServicePageTemplate";
const ServiceUn = () => {
const serviceDetails = {
title: 'Prestation-maitrise-oeuvre',
subtitle: 'Apprenez à maîtriser les technologies du web.',
description:
'Notre formation web vous permet de développer vos compétences en développement frontend, backend et design. Rejoignez notre programme pour apprendre HTML, CSS, JavaScript et bien plus.',
// Hero
title: 'Titre héros', // ✅ Modifiable individuellement
subtitle: 'Description, héros', // ✅ Modifiable individuellement
image: "https://picsum.photos/id/1018/1920/1080.webp",
ctaText: "En savoir plus",
ctaLink: "/contact",
// section 1
interestTitle: 'Titre interet', // ✅ Modifiable individuellement
description: 'Description interet', // ✅ Modifiable individuellement
// section 2
desirTitle: 'Titre Désir', // ✅ Modifiable individuellement
features: [
{
title: 'Frontend Development',
description: 'HTML, CSS, JavaScript, React et plus encore.',
modalText: 'Apprenez à construire des interfaces utilisateurs modernes avec les technologies frontend.',
modalImage: 'https://picsum.photos/id/300/800/400.webp',
title: "Frontend Development",
description: "HTML, CSS, JavaScript, React et plus encore.",
modalText:
"Apprenez à construire des interfaces utilisateurs modernes avec les technologies frontend.",
modalImage: "https://picsum.photos/id/300/800/400.webp",
},
{
title: 'Backend Development',
description: 'Node.js, Express, MongoDB et bases de données.',
modalText: 'Développez des applications robustes avec des technologies backend performantes.',
modalImage: 'https://picsum.photos/id/301/800/400.webp',
title: "Backend Development",
description: "Node.js, Express, MongoDB et bases de données.",
modalText:
"Développez des applications robustes avec des technologies backend performantes.",
modalImage: "https://picsum.photos/id/301/800/400.webp",
},
{
title: 'Responsive Design',
description: 'Apprenez à créer des designs modernes et adaptatifs.',
modalText: 'Maîtrisez les principes du responsive design pour des expériences utilisateur optimales.',
modalImage: 'https://picsum.photos/id/302/800/400.webp',
title: "Responsive Design",
description: "Apprenez à créer des designs modernes et adaptatifs.",
modalText:
"Maîtrisez les principes du responsive design pour des expériences utilisateur optimales.",
modalImage: "https://picsum.photos/id/302/800/400.webp",
},
],
image: 'https://picsum.photos/id/1018/1920/1080.webp',
ctaText: 'En savoir plus',
ctaLink: '/contact',
carouselItems: [
{
title: 'Portfolio Modern',
description: 'Montrez vos compétences avec un portfolio unique.',
image: 'https://picsum.photos/id/305/800/400.webp',
title: "Portfolio Modern",
description: "Montrez vos compétences avec un portfolio unique.",
image: "https://picsum.photos/id/305/800/400.webp",
},
{
title: 'Blog SEO',
description: 'Optimisez vos articles pour le référencement.',
image: 'https://picsum.photos/id/306/800/400.webp',
title: "Blog SEO",
description: "Optimisez vos articles pour le référencement.",
image: "https://picsum.photos/id/306/800/400.webp",
},
],
};
@@ -47,4 +59,4 @@ const ServiceUn = () => {
return <ServicePageTemplate {...serviceDetails} />;
};
export default ServiceUn;
export default ServiceUn;
+70 -255
View File
@@ -1,40 +1,37 @@
import React, { useState } from "react";
import {
Box,
Typography,
Button,
Grid,
Card,
CardContent,
Modal,
Fade,
Backdrop,
} from "@mui/material";
import { useState } from "react";
import { Box, Typography, Button, Grid, Card, CardContent, Modal, Fade, Backdrop, CircularProgress } from "@mui/material";
import { Swiper, SwiperSlide } from "swiper/react";
import { Navigation, Pagination, Autoplay } from "swiper/modules";
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/pagination";
import PropTypes from "prop-types";
import { Helmet } from "react-helmet-async";
const ServicePageTemplate = ({
title,
subtitle,
interestTitle,
description,
desirTitle,
features,
image,
ctaText,
ctaLink,
carouselItems,
seo, // ✅ Ajout de l'objet SEO
}) => {
const [openModal, setOpenModal] = useState(false);
const [modalContent, setModalContent] = useState({});
const [loadingImage, setLoadingImage] = useState(true);
const handleCardClick = (feature) => {
setModalContent({
title: feature.title,
text: feature.modalText || "Texte non disponible.",
image: feature.modalImage || "https://picsum.photos/id/43/800/400.webp", // Image par défaut
image: feature.modalImage || "https://picsum.photos/id/43/800/400.webp",
});
setLoadingImage(true);
setOpenModal(true);
};
@@ -43,14 +40,23 @@ const ServicePageTemplate = ({
};
return (
<Box
sx={{
backgroundColor: "#f5f5f5",
color: "#333",
fontFamily: "Arial, sans-serif",
}}
>
{/* Section Attention */}
<Box sx={{ backgroundColor: "#f5f5f5", color: "#333", fontFamily: "Arial, sans-serif" }}>
{/* ✅ SEO META TAGS */}
<Helmet>
<title>{seo?.metaTitle || title}</title>
<meta name="description" content={seo?.metaDescription || ""} />
<meta name="keywords" content={seo?.keywords || ""} />
<meta property="og:title" content={seo?.metaTitle || title} />
<meta property="og:description" content={seo?.metaDescription || ""} />
<meta property="og:image" content={seo?.ogImage || image} />
<meta property="og:type" content="website" />
<meta name="twitter:title" content={seo?.metaTitle || title} />
<meta name="twitter:description" content={seo?.metaDescription || ""} />
<meta name="twitter:image" content={seo?.ogImage || image} />
<meta name="twitter:card" content="summary_large_image" />
</Helmet>
{/* Section Hero */}
<Box
sx={{
backgroundImage: `url(${image})`,
@@ -66,116 +72,56 @@ const ServicePageTemplate = ({
}}
>
<Box sx={{ maxWidth: "800px" }}>
<Typography
variant="h1"
sx={{
fontWeight: "bold",
mb: 2,
fontSize: { xs: '2rem', md: '3rem', lg: '4rem' }, // Responsive
}}
>
<Typography variant="h1" sx={{ fontWeight: "bold", mb: 2, fontSize: { xs: "2rem", md: "3rem", lg: "4rem" } }}>
{title}
</Typography>
<Typography
variant="body1"
sx={{
mb: 4
}}
>
<Typography variant="body1" sx={{ mb: 4 }}>
{subtitle}
</Typography>
<Button
href={ctaLink}
variant="contained"
color="secondary"
size="large"
sx={{
textTransform: "none",
fontWeight: "bold",
backgroundColor: " #0e467f",
"&:hover": { backgroundColor: "#00bcd4" },
}}
sx={{ textTransform: "none", fontWeight: "bold", backgroundColor: "#0e467f", "&:hover": { backgroundColor: "#00bcd4" } }}
>
{ctaText}
</Button>
</Box>
</Box>
{/* Section Interest */}
{/* Section numero 1 */}
<Box sx={{ padding: "40px 20px", textAlign: "center" }}>
<Typography variant="h2"
sx={{
fontWeight: "bold",
mb: 2,
fontSize: { xs: '2rem', md: '3rem', lg: '3rem' }, // Responsive
}}
>
Pourquoi choisir notre formation ?
<Typography variant="h2" sx={{ fontWeight: "bold", mb: 2, fontSize: { xs: "2rem", md: "2rem", lg: "2rem" }, whiteSpace: "pre-line" }}>
{interestTitle}
</Typography>
<Typography
variant="body1"
sx={{ maxWidth: "800px", margin: "0 auto", mb: 4 }}
>
<Typography variant="body1" sx={{ maxWidth: "1000px", margin: "0 auto", mb: 4, whiteSpace: "pre-line" }}>
{description}
</Typography>
</Box>
{/* Section Desire */}
{/* Section numero 2 */}
<Box sx={{ backgroundColor: "#ffffff", padding: "40px 20px" }}>
<Typography
variant="h2"
sx={{
fontWeight: "bold",
textAlign: "center",
mb: 4,
fontSize: { xs: '2rem', md: '3rem', lg: '3rem' }, // Responsive
}}
>
Ce que nous offrons
<Typography variant="h2" sx={{ fontWeight: "bold", textAlign: "center", mb: 4, fontSize: { xs: "2rem", md: "3rem", lg: "2rem" } }}>
{desirTitle}
</Typography>
<Grid container spacing={4} justifyContent="center">
{features.map((feature, index) => (
<Grid item xs={12} md={4} key={index}>
<Card
onClick={() => handleCardClick(feature)}
sx={{
boxShadow: 2,
borderRadius: 2,
cursor: "pointer",
textAlign: "center",
padding: "20px",
backgroundColor: "#f9f9f9",
cursor: "pointer",
transition: "transform 0.3s ease, box-shadow 0.3s ease",
"&:hover": {
transform: {
xs: "none", // Pas d'hover sur mobile
md: "scale(1.05)", // Hover sur desktop uniquement
},
boxShadow: {
xs: 2, // Pas d'effet de hover sur mobile
md: 5, // Augmentation de l'ombre sur desktop
},
},
"&:active": {
transform: "scale(0.98)", // Effet de clic pour le tactile
boxShadow: 3,
},
transition: "0.3s",
"&:hover": { transform: "scale(1.05)", boxShadow: 5 },
}}
onClick={() => handleCardClick(feature)}
>
<CardContent>
<Typography
variant="h3"
sx={{
fontWeight: "bold",
mb: 2,
fontSize: 26,
}}
>
<Typography variant="h3" sx={{ fontWeight: "bold", mb: 2, fontSize: 26 }}>
{feature.title}
</Typography>
<Typography variant="body2" sx={{ color: "#555" }}>
@@ -189,177 +135,46 @@ const ServicePageTemplate = ({
</Box>
{/* Modal */}
<Modal
open={openModal}
onClose={handleCloseModal}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Modal open={openModal} onClose={handleCloseModal} closeAfterTransition BackdropComponent={Backdrop} BackdropProps={{ timeout: 500 }}>
<Fade in={openModal}>
<Box
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "90%",
maxWidth: "600px",
p: 4,
display: "flex",
flexDirection: "column",
alignItems: "center",
textAlign: "center",
background: "rgb(255, 255, 255)",
boxShadow: "0 4px 30px rgba(0, 0, 0, 0.1)",
backdropFilter: "blur(10px)",
borderRadius: 2,
border: "1px solid rgba(255, 255, 255, 0.3)",
color: "rgb(0, 0, 0)",
}}
>
<img
src={modalContent.image}
alt={modalContent.title}
style={{
width: "100%",
borderRadius: "8px",
marginBottom: "20px",
}}
/>
<Box sx={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", width: "90%", maxWidth: "600px", p: 4, textAlign: "center", background: "white", borderRadius: 2, boxShadow: 3 }}>
{loadingImage && <CircularProgress sx={{ mb: 2 }} />}
<img src={modalContent.image} alt={modalContent.title} style={{ width: "100%", borderRadius: "8px", display: loadingImage ? "none" : "block" }} onLoad={() => setLoadingImage(false)} />
<Typography variant="h3" sx={{ fontWeight: "bold", mb: 2 }}>
{modalContent.title}
</Typography>
<Typography variant="body1" sx={{ mb: 4 }}>
{modalContent.text}
</Typography>
<Button
onClick={handleCloseModal}
variant="contained"
color="secondary"
sx={{
textTransform: "none",
fontWeight: "bold",
backgroundColor: "#f44336",
"&:hover": { backgroundColor: "#d32f2f" },
}}
>
Quitter
<Button onClick={handleCloseModal} variant="contained" color="secondary">
Retour
</Button>
</Box>
</Fade>
</Modal>
{/* Carousel Section */}
{carouselItems && carouselItems.length > 0 && (
<Box
sx={{
padding: "40px 20px",
textAlign: "center",
backgroundColor: "#f9f9f9",
}}
>
<Typography variant="h2"
sx={{
marginBottom: 4,
fontSize: { xs: '2rem', md: '3rem', lg: '3rem' }, // Responsive
}}
>
Découvrez nos réalisations
</Typography>
<Swiper
modules={[Navigation, Pagination, Autoplay]}
spaceBetween={20}
slidesPerView={1}
navigation
pagination={{ clickable: true }}
autoplay={{ delay: 3000 }}
loop
>
{carouselItems.map((item, index) => (
<SwiperSlide key={index}>
<Card
sx={{
display: "flex",
alignItems: "center",
padding: "20px",
boxShadow: 3,
}}
>
<img
src={item.image}
alt={item.title}
style={{
width: "40%",
height: "auto",
objectFit: "cover",
borderRadius: "8px",
marginRight: "20px",
}}
/>
<CardContent>
<Typography variant="h3"
sx={{
fontWeight: "bold",
fontSize: { xs: '1.2rem', md: '2rem', lg: '2.5rem' }, // Responsive
}}
>
{item.title}
</Typography>
<Typography variant="body2">{item.description}</Typography>
</CardContent>
</Card>
</SwiperSlide>
))}
</Swiper>
</Box>
)}
{/* Section Action */}
<Box
sx={{
backgroundColor: "#0e467f",
color: "white",
textAlign: "center",
padding: "40px 20px",
}}
>
<Typography variant="h2"
sx={{
fontWeight: "bold",
mb: 2,
fontSize: { xs: '2rem', md: '3rem', lg: '3rem' }, // Responsive
}}
>
Prêt à démarrer ?
</Typography>
<Typography variant="body1" sx={{ mb: 4 }}>
Rejoignez-nous dès aujourdhui et profitez de nos services pour
booster votre activité.
</Typography>
<Button
href={ctaLink}
variant="contained"
color="secondary"
size="large"
sx={{
textTransform: "none",
fontWeight: "bold",
backgroundColor: "#00bcd4",
"&:hover": { backgroundColor: "#0288d1" },
}}
>
{ctaText}
</Button>
</Box>
</Box>
);
};
export default ServicePageTemplate;
// ✅ Définition des types des props avec PropTypes
ServicePageTemplate.propTypes = {
title: PropTypes.string.isRequired,
subtitle: PropTypes.string.isRequired,
interestTitle: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
desirTitle: PropTypes.string.isRequired,
features: PropTypes.arrayOf(PropTypes.shape({ title: PropTypes.string.isRequired, description: PropTypes.string.isRequired, modalText: PropTypes.string, modalImage: PropTypes.string })).isRequired,
image: PropTypes.string.isRequired,
ctaText: PropTypes.string.isRequired,
ctaLink: PropTypes.string.isRequired,
carouselItems: PropTypes.arrayOf(PropTypes.shape({ title: PropTypes.string.isRequired, description: PropTypes.string.isRequired, image: PropTypes.string.isRequired })),
seo: PropTypes.object, // ✅ Ajout du SEO en option
};
// ✅ Valeurs par défaut
ServicePageTemplate.defaultProps = {
carouselItems: [],
seo: {}, // ✅ SEO par défaut vide
};
export default ServicePageTemplate;
+1 -1
View File
@@ -49,7 +49,7 @@ function YourApp() {
{/* Routes pour les services */}
<Route path="/services/prestation-maitrise-oeuvre" element={<ServiceUn />} />
<Route path="/services/structure-beton-charpente-metallique-bois" element={<ServiceDeux />} />
<Route path="/services/formation-video" element={<ServiceTrois />} />
<Route path="/services/electricite" element={<ServiceTrois />} />
<Route path="/admin/create-post" element={<CreatePost />} />
<Route path="/post/:slug" element={<PostDetails />} />
<Route path="/admin/posts" element={<PostList />} />
+6
View File
@@ -38,6 +38,12 @@ export async function uploadImage(file) {
}
}
export async function fetchPosts() {
const response = await fetch("https://preprod.octopusdesign.fr/api-octopus/server/wp-json/wp/v2/posts");
if (!response.ok) throw new Error("Erreur lors de la récupération des articles");
return await response.json();
}
/**
* 🔹 Crée un post WordPress avec une image mise en avant
* @param {string} title - Le titre du post