MAJ Article
This commit is contained in:
parent
841161cb9b
commit
cf77437c89
67
frontend/src/PostDetails.jsx
Normal file
67
frontend/src/PostDetails.jsx
Normal 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;
|
||||
@ -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;
|
||||
67
frontend/src/components/PostDetails.jsx
Normal file
67
frontend/src/components/PostDetails.jsx
Normal 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;
|
||||
@ -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 />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user