import { useState, useEffect } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { getPostById, updatePost, uploadImageFromUrl } from "../wordpress"; import { getToken } from "../auth"; import { Box, Typography, TextField, Button, Grid, Card, CardContent, Stack, Chip, Divider, } from "@mui/material"; import { ArrowBack, Publish, Image as ImageIcon, History } from "@mui/icons-material"; import ImageUploaderCloudinary from "./ImageUploaderCloudinary"; import CloudinaryGallerySelector from "./CloudinaryGallerySelector"; import RichTextEditor from "./common/RichTextEditor"; import "../assets/styleCours.css"; const BUTTON_BASE_SX = Object.freeze({ borderRadius: 999, textTransform: "none", fontWeight: 600, letterSpacing: 0.3, display: "inline-flex", alignItems: "center", gap: 0.75, transition: "transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease, border-color 0.2s ease", "&:hover": { transform: "translateY(-1px)", }, "&:active": { transform: "translateY(0)", }, }); const BUTTON_SIZE_SX = Object.freeze({ small: { px: 2.1, py: 0.55, fontSize: "0.78rem", minHeight: 30, }, medium: { px: 2.8, py: 0.8, fontSize: "0.86rem", minHeight: 36, }, large: { px: 3.4, py: 1, fontSize: "0.94rem", minHeight: 42, }, }); const BUTTON_VARIANT_SX = Object.freeze({ primary: { background: "linear-gradient(135deg, #315397, #7bc0ff)", color: "#ffffff", border: "1px solid rgba(255,255,255,0.35)", boxShadow: "0 18px 28px -18px rgba(11, 26, 61, 0.55)", "&:hover": { background: "linear-gradient(135deg, #26467d, #6fb6ff)", boxShadow: "0 22px 32px -18px rgba(11, 26, 61, 0.6)", }, "&.Mui-disabled": { color: "rgba(255,255,255,0.72)", background: "linear-gradient(135deg, rgba(49,83,151,0.35), rgba(123,192,255,0.35))", boxShadow: "none", border: "1px solid rgba(49,83,151,0.18)", }, }, ghost: { background: "rgba(255,255,255,0.16)", color: "rgba(255,255,255,0.92)", border: "1px solid rgba(255,255,255,0.28)", backdropFilter: "blur(8px)", "&:hover": { background: "rgba(255,255,255,0.24)", boxShadow: "0 18px 28px -18px rgba(6, 18, 38, 0.45)", }, }, outline: { background: "rgba(255,255,255,0.84)", color: "#315397", border: "1px solid rgba(49,83,151,0.26)", "&:hover": { background: "rgba(255,255,255,0.96)", borderColor: "rgba(49,83,151,0.46)", boxShadow: "0 14px 22px -18px rgba(11, 26, 61, 0.4)", }, }, }); const composeButtonSx = (variant, size = "medium") => ({ ...BUTTON_BASE_SX, ...(BUTTON_SIZE_SX[size] || BUTTON_SIZE_SX.medium), ...(BUTTON_VARIANT_SX[variant] || BUTTON_VARIANT_SX.primary), }); function EditPost() { const { id } = useParams(); const navigate = useNavigate(); const [title, setTitle] = useState(""); const [content, setContent] = useState(""); const [imageUrl, setImageUrl] = useState(null); // preview const [imageFile, setImageFile] = useState(null); // pour upload const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [postMeta, setPostMeta] = useState({ date: null, modified: null, status: "", }); // Auth useEffect(() => { if (!getToken()) navigate("/admin/login"); }, [navigate]); // Article useEffect(() => { const fetchPost = async () => { try { setLoading(true); const post = await getPostById(id); setTitle(post.title.rendered); setContent(post.content.rendered); setImageUrl(post?.jetpack_featured_media_url || null); setPostMeta({ date: post.date || null, modified: post.modified || null, status: post.status || "", }); } catch (error) { console.error("Erreur chargement article :", error); navigate("/admin/gestion-articles"); } finally { setLoading(false); } }; fetchPost(); }, [id, navigate]); // 🧠 convertit URL en File const convertUrlToFile = async (url) => { const res = await fetch(url); const blob = await res.blob(); return new File([blob], "image-cloudinary.jpg", { type: blob.type }); }; const toolbarOptions = [ [{ header: [1, 2, 3, false] }], ["bold", "italic", "underline", "strike"], [{ list: "ordered" }, { list: "bullet" }], ["link", "image"], ["clean"], ]; const canSubmit = title.trim().length > 0 && content.trim().length > 0 && Boolean(imageUrl); const handleUpdate = async (event) => { event.preventDefault(); if (!canSubmit || submitting) { return; } try { setSubmitting(true); let imageId = undefined; if (imageFile || imageUrl) { imageId = await uploadImageFromUrl(imageUrl); } await updatePost(id, title, content, imageId); alert("✅ Article mis à jour !"); navigate("/admin/gestion-articles"); } catch (error) { console.error("❌ Erreur update :", error); alert("❌ Erreur mise à jour."); } finally { setSubmitting(false); } }; return ( Publication Octopus Modifier l’article Ajustez votre contenu, remplacez le visuel mis en avant et publiez les mises à jour directement sur le site Octopus. } label={ postMeta.modified ? `Modifié le ${new Intl.DateTimeFormat("fr-FR", { day: "numeric", month: "long", year: "numeric", hour: "2-digit", minute: "2-digit", }).format(new Date(postMeta.modified))}` : "Modification en cours" } sx={{ bgcolor: "rgba(255,255,255,0.78)", color: "#0b1a3d", fontWeight: 600, }} /> {loading ? ( Chargement de l’article… ) : ( setTitle(event.target.value)} required sx={{ mb: 3, "& .MuiOutlinedInput-root": { borderRadius: 2, backgroundColor: "rgba(255,255,255,0.94)", }, }} /> Remplacer le visuel Importez une nouvelle image optimisée pour vos contenus. { setImageUrl(url); convertUrlToFile(url).then(setImageFile); }} /> Sélectionner depuis la médiathèque Choisissez un visuel existant dans Cloudinary. { setImageUrl(url); const file = await convertUrlToFile(url); setImageFile(file); }} /> )} Rappels éditoriaux • Vérifiez la cohérence des titres et sous-titres.
• Ajoutez des liens internes vers vos formations Octopus.
• N’oubliez pas de relire la mise en forme dans l’aperçu WordPress.
Aperçu visuel {imageUrl ? ( ) : ( Aucun visuel sélectionné pour le moment )} Ce visuel illustrera l’article dans la liste des publications et sur les réseaux sociaux.
); } export default EditPost;