1 Commits

Author SHA1 Message Date
sebvtl728 cf77437c89 MAJ Article 2025-01-31 17:28:21 +01:00
4 changed files with 214 additions and 66 deletions
+67
View File
@@ -0,0 +1,67 @@
import React, { useState, useEffect } from "react";
import { Box, Typography, Button, CircularProgress } from "@mui/material";
import { useParams, useNavigate } from "react-router-dom";
import api from "../api";
const PostDetails = () => {
const { id } = useParams();
const [post, setPost] = useState(null);
const [image, setImage] = useState(null);
const navigate = useNavigate();
useEffect(() => {
const fetchPost = async () => {
try {
const response = await api.get(`wp/v2/posts/${id}?_fields=title,content,featured_media,date`);
setPost(response.data);
// Récupération de l'image
if (response.data.featured_media) {
const mediaResponse = await api.get(`wp/v2/media/${response.data.featured_media}`);
setImage(mediaResponse.data.source_url);
}
} catch (error) {
console.error("Erreur lors de la récupération de l'article :", error);
}
};
fetchPost();
}, [id]);
if (!post) {
return <CircularProgress sx={{ display: "block", margin: "auto", mt: 5 }} />;
}
return (
<Box sx={{ padding: "40px 20px",display:"flex", flexDirection:"column" }}>
<Button onClick={() => navigate(-1)} variant="outlined" sx={{ mt:5, mb: 3, maxWidth:"200px" }}>
Retour
</Button>
<Typography variant="h1" sx={{
fontWeight: "bold",
textAlign: "center",
mb: 4,
fontSize: { xs: '3rem', md: '3rem', lg: '3rem' }, // Responsive
}}>
{post.title.rendered}
</Typography>
<Box sx={{ display:"flex", alignItems:"center", justifyContent:"center", padding: "40px 20px",margin:"auto" }}>
{image && (
<Box
component="img"
src={image}
alt={post.title.rendered}
sx={{ width: "33%", maxHeight: "400px", objectFit: "cover", borderRadius: "8px", mb: 3 }}
/>
)}
<Typography variant="body1" sx={{ maxWidth: "800px", mx: "auto" }} dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
</Box>
</Box>
);
};
export default PostDetails;
+61 -40
View File
@@ -1,57 +1,78 @@
import React, { useEffect, useState } from 'react'; import React, { useState, useEffect } from "react";
import { Grid, Card, CardContent, CardMedia, Typography, Box } from '@mui/material'; import { Box, Typography, Grid, Card, CardContent, CardMedia, Button } from "@mui/material";
import api from '../../api'; // Adaptez le chemin vers l'instance Axios import { useNavigate } from "react-router-dom";
import api from "../../api";
const Posts = () => {
const Post = () => {
const [posts, setPosts] = useState([]); const [posts, setPosts] = useState([]);
const navigate = useNavigate();
useEffect(() => { useEffect(() => {
api.get('wp/v2/posts?_embed') const fetchPosts = async () => {
.then((response) => { try {
setPosts(response.data); const response = await api.get("wp/v2/posts?_fields=id,title,excerpt,featured_media");
const postsData = response.data;
// Récupérer les images en vedette
const postsWithImages = await Promise.all(
postsData.map(async (post) => {
if (post.featured_media) {
try {
const mediaResponse = await api.get(`wp/v2/media/${post.featured_media}`);
return { ...post, image: mediaResponse.data.source_url };
} catch (error) {
console.error(`Erreur lors de la récupération de l'image pour l'article ${post.id}:`, error);
return { ...post, image: null };
}
}
return { ...post, image: null };
}) })
.catch((error) => { );
console.error('Erreur lors de la récupération des articles :', error);
}); setPosts(postsWithImages);
} catch (error) {
console.error("Erreur lors de la récupération des articles :", error);
}
};
fetchPosts();
}, []); }, []);
return ( // Fonction pour tronquer le texte à 70 caractères
const truncateText = (text, maxLength) => {
const strippedText = text.replace(/(<([^>]+)>)/gi, ""); // Suppression des balises HTML
return strippedText.length > maxLength ? `${strippedText.substring(0, maxLength)}...` : strippedText;
};
<Box sx={{ padding: 4 }}> return (
<Typography variant="h3" sx={{ marginBottom: 4, textAlign: 'center' }}> <Box sx={{ padding: "40px 20px" }}>
Nos réalisations <Typography variant="h2" sx={{ fontWeight: "bold", textAlign: "center", mb: 4 }}>
Nos Articles
</Typography> </Typography>
<Grid container spacing={4}>
<Grid container spacing={4} justifyContent="center">
{posts.map((post) => ( {posts.map((post) => (
<Grid item xs={12} sm={6} md={4} key={post.id}> <Grid item xs={12} sm={6} md={4} key={post.id}>
<Card sx={{ maxWidth: 345, <Card
boxShadow: 3, sx={{
transition: 'transform 0.3s ease, box-shadow 0.3s ease', cursor: "pointer",
'&:hover': { "&:hover": { backgroundColor: "#0e467f", color: "white", transform: "scale(1.05)", boxShadow: 6 },
transform: 'scale(1.05)', }}
boxShadow: 6, onClick={() => navigate(`/post/${post.id}`)}
}, >
}}> {post.image && (
{/* Image de l'article */} <CardMedia component="img" height="200" image={post.image} alt={post.title.rendered} />
{post._embedded?.['wp:featuredmedia']?.[0]?.source_url && (
<CardMedia
component="img"
height="200"
image={post._embedded['wp:featuredmedia'][0].source_url}
alt={post.title.rendered}
/>
)} )}
<CardContent> <CardContent>
<Typography variant="h5" component="div" gutterBottom> <Typography variant="h5" sx={{ fontWeight: "bold" }}>
{post.title.rendered} {post.title.rendered}
</Typography> </Typography>
<Typography <Typography variant="body2" sx={{ mt: 1 }}>
variant="body2" {truncateText(post.excerpt.rendered, 100)}
color="text.secondary" </Typography>
dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }} <Button variant="outlined" sx={{ mt: 2, color: "white", borderColor: "white" }}>
/> Lire plus
</Button>
</CardContent> </CardContent>
</Card> </Card>
</Grid> </Grid>
@@ -61,4 +82,4 @@ const Post = () => {
); );
}; };
export default Post; export default Posts;
+67
View File
@@ -0,0 +1,67 @@
import React, { useState, useEffect } from "react";
import { Box, Typography, Button, CircularProgress } from "@mui/material";
import { useParams, useNavigate } from "react-router-dom";
import api from "../api";
const PostDetails = () => {
const { id } = useParams();
const [post, setPost] = useState(null);
const [image, setImage] = useState(null);
const navigate = useNavigate();
useEffect(() => {
const fetchPost = async () => {
try {
const response = await api.get(`wp/v2/posts/${id}?_fields=title,content,featured_media,date`);
setPost(response.data);
// Récupération de l'image
if (response.data.featured_media) {
const mediaResponse = await api.get(`wp/v2/media/${response.data.featured_media}`);
setImage(mediaResponse.data.source_url);
}
} catch (error) {
console.error("Erreur lors de la récupération de l'article :", error);
}
};
fetchPost();
}, [id]);
if (!post) {
return <CircularProgress sx={{ display: "block", margin: "auto", mt: 5 }} />;
}
return (
<Box sx={{ padding: "40px 20px",display:"flex", flexDirection:"column" }}>
<Button onClick={() => navigate(-1)} variant="outlined" sx={{ mt:5, mb: 3, maxWidth:"200px" }}>
Retour
</Button>
<Typography variant="h1" sx={{
fontWeight: "bold",
textAlign: "center",
mb: 4,
fontSize: { xs: '3rem', md: '3rem', lg: '3rem' }, // Responsive
}}>
{post.title.rendered}
</Typography>
<Box sx={{ display:"flex", alignItems:"center", justifyContent:"center", padding: "40px 20px",margin:"auto" }}>
{image && (
<Box
component="img"
src={image}
alt={post.title.rendered}
sx={{ width: "33%", maxHeight: "400px", objectFit: "cover", borderRadius: "8px", mb: 3 }}
/>
)}
<Typography variant="body1" sx={{ maxWidth: "800px", mx: "auto" }} dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
</Box>
</Box>
);
};
export default PostDetails;
+2 -9
View File
@@ -7,18 +7,14 @@ import { HelmetProvider } from "react-helmet-async";
import SimpleReactLightbox from "simple-react-lightbox"; import SimpleReactLightbox from "simple-react-lightbox";
import NotFound from "./components/Pages/NotFound.jsx"; import NotFound from "./components/Pages/NotFound.jsx";
// Lazy loading des pages // Lazy loading des pages
const Home = lazy(() => import('./components/Pages/Home.jsx')); const Home = lazy(() => import('./components/Pages/Home.jsx'));
const About = lazy(() => import('./components/Pages/About')); const About = lazy(() => import('./components/Pages/About'));
const Contact = lazy(() => import('./components/Pages/Contact')); const Contact = lazy(() => import('./components/Pages/Contact'));
const Post = lazy(() => import('./components/Pages/Post')); const Post = lazy(() => import('./components/Pages/Post'));
const PostDetails = lazy(() => import('./components/PostDetails')) ;
const Search = lazy(() => import('./components/Pages/Search')); // Nouveau composant pour la recherche const Search = lazy(() => import('./components/Pages/Search')); // Nouveau composant pour la recherche
const BureauEtude = lazy(() => import('./components/Pages/BureauEtude')); const BureauEtude = lazy(() => import('./components/Pages/BureauEtude'));
const CreatePost = lazy(() => import('./components/Pages/CreatePost'));
const PostList = lazy(() => import("./components/Pages/PostList"));
const Login = lazy(() => import("./components/Pages/Login"));
const Dashboard = lazy(() => import("./components/Pages/Dashboard"));
// Import des services // Import des services
import ServiceUn from "./components/Pages/ServiceUn.jsx"; import ServiceUn from "./components/Pages/ServiceUn.jsx";
@@ -37,6 +33,7 @@ function YourApp() {
<Routes> <Routes>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route path="/posts" element={<Post />} /> <Route path="/posts" element={<Post />} />
<Route path="/post/:id" element={<PostDetails />} />
<Route path="/bureauEtude" element={<BureauEtude />} /> <Route path="/bureauEtude" element={<BureauEtude />} />
<Route path="/about" element={<About />} /> <Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} /> <Route path="/contact" element={<Contact />} />
@@ -45,10 +42,6 @@ function YourApp() {
<Route path="/services/prestation-maitrise-oeuvre" element={<ServiceUn />} /> <Route path="/services/prestation-maitrise-oeuvre" element={<ServiceUn />} />
<Route path="/services/structure-beton-charpente-metallique-bois" element={<ServiceDeux />} /> <Route path="/services/structure-beton-charpente-metallique-bois" element={<ServiceDeux />} />
<Route path="/services/formation-video" element={<ServiceTrois />} /> <Route path="/services/formation-video" element={<ServiceTrois />} />
<Route path="/create-post" element={<CreatePost />} />
<Route path="/admin/posts" element={<PostList />} />
<Route path="/admin/login" element={<Login />} />
<Route path="/admin/dashboard" element={<Dashboard />} />
<Route path="*" element={<NotFound />} /> <Route path="*" element={<NotFound />} />
</Routes> </Routes>
<Footer /> <Footer />