Compare commits

...

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

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;

View File

@ -1,64 +1,85 @@
import React, { useEffect, useState } from 'react';
import { Grid, Card, CardContent, CardMedia, Typography, Box } from '@mui/material';
import api from '../../api'; // Adaptez le chemin vers l'instance Axios
import React, { useState, useEffect } from "react";
import { Box, Typography, Grid, Card, CardContent, CardMedia, Button } from "@mui/material";
import { useNavigate } from "react-router-dom";
import api from "../../api";
const Posts = () => {
const [posts, setPosts] = useState([]);
const navigate = useNavigate();
useEffect(() => {
const fetchPosts = async () => {
try {
const response = await api.get("wp/v2/posts?_fields=id,title,excerpt,featured_media");
const postsData = response.data;
const Post = () => {
const [posts, setPosts] = useState([]);
// 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 };
})
);
useEffect(() => {
api.get('wp/v2/posts?_embed')
.then((response) => {
setPosts(response.data);
})
.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);
}
};
return (
<Box sx={{ padding: 4 }}>
<Typography variant="h3" sx={{ marginBottom: 4, textAlign: 'center' }}>
Nos réalisations
</Typography>
<Grid container spacing={4}>
{posts.map((post) => (
<Grid item xs={12} sm={6} md={4} key={post.id}>
<Card sx={{ maxWidth: 345,
boxShadow: 3,
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
'&:hover': {
transform: 'scale(1.05)',
boxShadow: 6,
},
}}>
{/* Image de l'article */}
{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>
<Typography variant="h5" component="div" gutterBottom>
{post.title.rendered}
</Typography>
<Typography
variant="body2"
color="text.secondary"
dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }}
/>
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Box>
);
fetchPosts();
}, []);
// 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;
};
return (
<Box sx={{ padding: "40px 20px" }}>
<Typography variant="h2" sx={{ fontWeight: "bold", textAlign: "center", mb: 4 }}>
Nos Articles
</Typography>
<Grid container spacing={4} justifyContent="center">
{posts.map((post) => (
<Grid item xs={12} sm={6} md={4} key={post.id}>
<Card
sx={{
cursor: "pointer",
"&:hover": { backgroundColor: "#0e467f", color: "white", transform: "scale(1.05)", boxShadow: 6 },
}}
onClick={() => navigate(`/post/${post.id}`)}
>
{post.image && (
<CardMedia component="img" height="200" image={post.image} alt={post.title.rendered} />
)}
<CardContent>
<Typography variant="h5" sx={{ fontWeight: "bold" }}>
{post.title.rendered}
</Typography>
<Typography variant="body2" sx={{ mt: 1 }}>
{truncateText(post.excerpt.rendered, 100)}
</Typography>
<Button variant="outlined" sx={{ mt: 2, color: "white", borderColor: "white" }}>
Lire plus
</Button>
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Box>
);
};
export default Post;
export default Posts;

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;

View File

@ -7,18 +7,14 @@ import { HelmetProvider } from "react-helmet-async";
import SimpleReactLightbox from "simple-react-lightbox";
import NotFound from "./components/Pages/NotFound.jsx";
// Lazy loading des pages
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 PostDetails = lazy(() => import('./components/PostDetails')) ;
const Search = lazy(() => import('./components/Pages/Search')); // Nouveau composant pour la recherche
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 ServiceUn from "./components/Pages/ServiceUn.jsx";
@ -37,6 +33,7 @@ function YourApp() {
<Routes>
<Route path="/" element={<Home />} />
<Route path="/posts" element={<Post />} />
<Route path="/post/:id" element={<PostDetails />} />
<Route path="/bureauEtude" element={<BureauEtude />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
@ -45,10 +42,6 @@ function YourApp() {
<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="/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 />} />
</Routes>
<Footer />