maj de la gestion des articles add mofif et suppr
This commit is contained in:
@@ -1,33 +1,135 @@
|
||||
import { useState } from "react";
|
||||
import { updatePost } from "../wordpress";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { getPostById, updatePost, uploadImage } from "../wordpress";
|
||||
import { getToken } from "../auth";
|
||||
import {
|
||||
Box, Container, Typography, TextField, Button, Paper, Input, IconButton
|
||||
} from "@mui/material";
|
||||
import { ArrowBack, Publish } from "@mui/icons-material";
|
||||
|
||||
function EditPost({ post }) {
|
||||
const [title, setTitle] = useState(post.title.rendered);
|
||||
const [content, setContent] = useState(post.content.rendered);
|
||||
function EditPost() {
|
||||
const { id } = useParams(); // ✅ Récupère l'ID de l'article depuis l'URL
|
||||
const navigate = useNavigate();
|
||||
const [title, setTitle] = useState("");
|
||||
const [content, setContent] = useState("");
|
||||
const [file, setFile] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const handleUpdate = async () => {
|
||||
const success = await updatePost(post.id, title, content);
|
||||
if (success) {
|
||||
alert("Article mis à jour !");
|
||||
} else {
|
||||
alert("Échec de la mise à jour.");
|
||||
// ✅ Vérification de l'authentification
|
||||
useEffect(() => {
|
||||
if (!getToken()) {
|
||||
navigate("/admin/login");
|
||||
}
|
||||
}, [navigate]);
|
||||
|
||||
// ✅ Récupérer les données de l'article
|
||||
useEffect(() => {
|
||||
const fetchPost = async () => {
|
||||
try {
|
||||
const post = await getPostById(id);
|
||||
setTitle(post.title.rendered);
|
||||
setContent(post.content.rendered.replace(/(<([^>]+)>)/gi, "")); // Enlever le HTML
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Erreur chargement article :", error);
|
||||
navigate("/admin/gestion-articles"); // Redirige si erreur
|
||||
}
|
||||
};
|
||||
|
||||
fetchPost();
|
||||
}, [id, navigate]);
|
||||
|
||||
const handleUpdate = async (e) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const updatedPost = await updatePost(id, title, content, file);
|
||||
alert("✅ Article mis à jour avec succès !");
|
||||
navigate("/admin/gestion-articles"); // Redirige après modification
|
||||
} catch (error) {
|
||||
alert("❌ Erreur lors de la mise à jour de l'article.");
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) return <Typography>Chargement...</Typography>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Modifier l’article</h1>
|
||||
<input
|
||||
type="text"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
/>
|
||||
<textarea
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
/>
|
||||
<button onClick={handleUpdate}>Mettre à jour</button>
|
||||
</div>
|
||||
<Box
|
||||
sx={{
|
||||
minHeight: "100vh",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundImage: "url('https://source.unsplash.com/1600x900/?office,writing')",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
>
|
||||
<Container maxWidth="sm">
|
||||
<Paper elevation={6} sx={{ padding: 4, borderRadius: 3 }}>
|
||||
<Button
|
||||
startIcon={<ArrowBack />}
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => navigate("/admin/gestion-articles")}
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
Retour à la gestion des articles
|
||||
</Button>
|
||||
|
||||
<Typography variant="h4" sx={{ fontWeight: "bold", textAlign: "center", mb: 3 }}>
|
||||
Modifier l'article
|
||||
</Typography>
|
||||
|
||||
<form onSubmit={handleUpdate}>
|
||||
<TextField
|
||||
label="Titre de l'article"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Contenu"
|
||||
fullWidth
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
multiline
|
||||
rows={4}
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
required
|
||||
/>
|
||||
|
||||
{/* Upload de l'image */}
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="body1" sx={{ fontWeight: "bold", mb: 1 }}>
|
||||
Nouvelle image (facultatif) :
|
||||
</Typography>
|
||||
<Input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={(e) => setFile(e.target.files[0])}
|
||||
sx={{ display: "block", mb: 2 }}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
fullWidth
|
||||
startIcon={<Publish />}
|
||||
sx={{ mt: 3 }}
|
||||
>
|
||||
Mettre à jour
|
||||
</Button>
|
||||
</form>
|
||||
</Paper>
|
||||
</Container>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { Add, ArrowBack, Edit, Delete } from "@mui/icons-material";
|
||||
import api from "../../api";
|
||||
import { getToken } from "../../auth";
|
||||
import { deletePost } from "../../wordpress";
|
||||
|
||||
const GestionArticles = () => {
|
||||
const [posts, setPosts] = useState([]);
|
||||
@@ -54,41 +55,17 @@ const GestionArticles = () => {
|
||||
|
||||
// ✅ Supprimer un article et son image associée
|
||||
const handleDeletePost = async (postId, imageId) => {
|
||||
if (!window.confirm("⚠ Es-tu sûr de vouloir supprimer cet article ?")) return;
|
||||
|
||||
try {
|
||||
const token = getToken(); // 🔑 Récupérer le token JWT
|
||||
if (!token) {
|
||||
alert("❌ Erreur : utilisateur non authentifié !");
|
||||
navigate("/admin/login");
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = {
|
||||
Authorization: `Bearer ${token}`, // ✅ Ajout du token dans l'en-tête
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
console.log(`📢 Suppression de l'article ID: ${postId}`);
|
||||
|
||||
// ✅ Suppression de l'article (avec force=true)
|
||||
await api.delete(`wp/v2/posts/${postId}?force=true`, { headers });
|
||||
|
||||
// ✅ Suppression de l'image associée si elle existe
|
||||
if (imageId) {
|
||||
console.log(`📢 Suppression de l'image ID: ${imageId}`);
|
||||
await api.delete(`wp/v2/media/${imageId}?force=true`, { headers });
|
||||
}
|
||||
|
||||
// ✅ Mise à jour de la liste après suppression
|
||||
setPosts(posts.filter((post) => post.id !== postId));
|
||||
|
||||
alert("✅ Article supprimé avec succès !");
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur suppression article :", error);
|
||||
alert(`⚠ Erreur : impossible de supprimer l'article.\n\nDétails: ${error.response?.data?.message || error.message}`);
|
||||
if (window.confirm("Es-tu sûr de vouloir supprimer cet article ?")) {
|
||||
try {
|
||||
await deletePost(postId, imageId); // ✅ Appel de la fonction deletePost
|
||||
setPosts(posts.filter((post) => post.id !== postId)); // ✅ Met à jour la liste après suppression
|
||||
alert("✅ Article supprimé avec succès !");
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur suppression article :", error);
|
||||
alert("⚠ Erreur : impossible de supprimer l'article.");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// ✅ Filtrage des articles
|
||||
const filteredPosts = posts.filter((post) =>
|
||||
@@ -152,7 +129,12 @@ const GestionArticles = () => {
|
||||
</TableCell>
|
||||
{/* ✅ Boutons Modifier et Supprimer */}
|
||||
<TableCell sx={{ textAlign: "center" }}>
|
||||
<Button startIcon={<Edit />} variant="outlined" color="warning" sx={{ mr: 1 }} >
|
||||
<Button startIcon={<Edit />}
|
||||
variant="outlined"
|
||||
color="warning"
|
||||
sx={{ mr: 1 }}
|
||||
onClick={() => navigate(`/admin/edit-post/${post.id}`)}
|
||||
>
|
||||
Modifier
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HelmetProvider } from "react-helmet-async";
|
||||
import SimpleReactLightbox from "simple-react-lightbox";
|
||||
import NotFound from "./components/Pages/NotFound.jsx";
|
||||
import GestionArticles from "./components/Pages/GestionArticles";
|
||||
import EditPost from "./components/EditPost";
|
||||
|
||||
|
||||
// Lazy loading des pages
|
||||
@@ -39,6 +40,7 @@ function YourApp() {
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/posts" element={<Post />} />
|
||||
<Route path="/admin/edit-post/:id" element={<EditPost />} />
|
||||
<Route path="/bureauEtude" element={<BureauEtude />} />
|
||||
<Route path="/about" element={<About />} />
|
||||
<Route path="/contact" element={<Contact />} />
|
||||
|
||||
+117
-31
@@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import { getToken } from "./auth"; // 🔥 Import du token depuis auth.js
|
||||
import { getToken } from "./auth"; // 🔥 Import du token pour l'authentification
|
||||
|
||||
const API_URL = "https://preprod.octopusdesign.fr/api-octopus/server/wp-json/wp/v2";
|
||||
|
||||
@@ -9,9 +9,9 @@ const API_URL = "https://preprod.octopusdesign.fr/api-octopus/server/wp-json/wp/
|
||||
* @returns {Promise<number>} - L'ID de l'image uploadée
|
||||
*/
|
||||
export async function uploadImage(file) {
|
||||
const token = getToken(); // 🔥 Récupération automatique du token
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
console.error("❌ Aucun token trouvé ! L'utilisateur doit se reconnecter.");
|
||||
console.error("❌ Aucun token trouvé !");
|
||||
throw new Error("Utilisateur non authentifié.");
|
||||
}
|
||||
|
||||
@@ -19,24 +19,21 @@ export async function uploadImage(file) {
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("title", "Nouvelle image");
|
||||
formData.append("title", file.name);
|
||||
formData.append("status", "publish");
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${API_URL}/media`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`, // 🔥 Authentification Basic
|
||||
}
|
||||
const response = await axios.post(`${API_URL}/media`, formData, {
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`, // ✅ Garder `Basic` si ça fonctionnait avant
|
||||
"Content-Type": "multipart/form-data"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
console.log("✅ Image uploadée avec succès :", response.data);
|
||||
return response.data.id; // Retourne l'ID de l'image
|
||||
return response.data.id; // ✅ Retourne l'ID de l'image
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur d'upload :", error.response ? error.response.data : error.message);
|
||||
console.error("❌ Erreur d'upload :", error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -49,33 +46,122 @@ export async function uploadImage(file) {
|
||||
* @returns {Promise<Object>} - Le post créé
|
||||
*/
|
||||
export async function createPost(title, content, imageId) {
|
||||
const token = getToken(); // 🔥 Récupération automatique du token
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
console.error("❌ Aucun token trouvé ! L'utilisateur doit se reconnecter.");
|
||||
console.error("❌ Aucun token trouvé !");
|
||||
throw new Error("Utilisateur non authentifié.");
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${API_URL}/posts`,
|
||||
{
|
||||
title: title,
|
||||
content: content,
|
||||
status: "publish",
|
||||
featured_media: imageId, // 🔥 Associer l'image mise en avant
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
const response = await axios.post(`${API_URL}/posts`, {
|
||||
title,
|
||||
content,
|
||||
status: "publish",
|
||||
featured_media: imageId,
|
||||
}, {
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`, // ✅ Garder `Basic` si ça fonctionnait avant
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
console.log("✅ Post créé avec succès :", response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur lors de la création du post :", error.response ? error.response.data : error.message);
|
||||
console.error("❌ Erreur création post :", error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔹 Récupère un article WordPress par son ID
|
||||
* @param {number} postId - L'ID du post à récupérer
|
||||
* @returns {Promise<Object>} - Données du post récupéré
|
||||
*/
|
||||
export async function getPostById(postId) {
|
||||
try {
|
||||
const response = await axios.get(`${API_URL}/posts/${postId}`);
|
||||
console.log("✅ Article récupéré :", response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur récupération article :", error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔹 Met à jour un article WordPress
|
||||
* @param {number} postId - L'ID de l'article à modifier
|
||||
* @param {string} title - Le nouveau titre
|
||||
* @param {string} content - Le nouveau contenu
|
||||
* @returns {Promise<Object>} - L'article mis à jour
|
||||
*/
|
||||
export async function updatePost(postId, title, content) {
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
console.error("❌ Aucun token trouvé !");
|
||||
throw new Error("Utilisateur non authentifié.");
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.post(`${API_URL}/posts/${postId}`, { // ✅ Rester sur `POST`
|
||||
title,
|
||||
content,
|
||||
status: "publish",
|
||||
}, {
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`, // ✅ Garder `Basic` si ça fonctionnait avant
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
console.log("✅ Article mis à jour avec succès :", response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur mise à jour article :", error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔹 Supprime un article WordPress et son image associée
|
||||
* @param {number} postId - L'ID de l'article à supprimer
|
||||
* @param {number} imageId - L'ID de l'image en vedette à supprimer (facultatif)
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function deletePost(postId, imageId) {
|
||||
const token = getToken();
|
||||
if (!token) {
|
||||
console.error("❌ Aucun token trouvé !");
|
||||
throw new Error("Utilisateur non authentifié.");
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`📢 Suppression article ID: ${postId}...`);
|
||||
|
||||
// ✅ Suppression du post
|
||||
await axios.delete(`${API_URL}/posts/${postId}?force=true`, {
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`, // ✅ Garder `Basic` si ça fonctionnait avant
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`✅ Article ${postId} supprimé.`);
|
||||
|
||||
// ✅ Suppression de l'image associée si elle existe
|
||||
if (imageId) {
|
||||
console.log(`📢 Suppression image ID: ${imageId}...`);
|
||||
await axios.delete(`${API_URL}/media/${imageId}?force=true`, {
|
||||
headers: {
|
||||
"Authorization": `Basic ${token}`, // ✅ Garder `Basic` si ça fonctionnait avant
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
});
|
||||
console.log(`✅ Image ${imageId} supprimée.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur suppression :", error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user