MAJ Article
This commit is contained in:
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
@@ -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 />
|
||||||
|
|||||||
Reference in New Issue
Block a user