Gestion de cours
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
<!-- <link rel="preload" href="/src/assets/vendor-BFTbvl5C.js" as="script"> -->
|
<!-- <link rel="preload" href="/src/assets/vendor-BFTbvl5C.js" as="script"> -->
|
||||||
<link rel="preload" href="/assets/index-CfManBR6.css" as="style">
|
<link rel="preload" href="/assets/index-CfManBR6.css" as="style">
|
||||||
<link rel="stylesheet" href="/assets/index-CfManBR6.css">
|
<link rel="stylesheet" href="/assets/index-CfManBR6.css">
|
||||||
|
<script src="https://unpkg.com/html2pdf.js@0.10.1/dist/html2pdf.bundle.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -26,4 +26,27 @@ span {
|
|||||||
.MuiTypography-h6{
|
.MuiTypography-h6{
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4lv-remember {
|
||||||
|
background-color: #d7d9eb;
|
||||||
|
margin: 24px auto 8px auto;
|
||||||
|
padding: 24px 30px;
|
||||||
|
max-width: 75%;
|
||||||
|
border: 2px solid #315397;
|
||||||
|
border-radius: 16px;
|
||||||
|
color: #315397;
|
||||||
|
font-family: Poppins, sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4lv-remember::before {
|
||||||
|
content: "🧠 À retenir";
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #315397;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap');
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-family: "Nunito", sans-serif !important;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2,
|
||||||
|
span {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-family: "Nunito", sans-serif !important;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
font-style: normal;
|
||||||
|
color: #315397;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
h6{
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-family: "Nunito", sans-serif !important;
|
||||||
|
font-optical-sizing: auto;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
font-style: normal;
|
||||||
|
color: #315397 !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li{
|
||||||
|
list-style: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.css-1ulggnf h2,
|
||||||
|
.MuiTypography-span,
|
||||||
|
.MuiTypography-h6{
|
||||||
|
color: #ffffff;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4lv-remember {
|
||||||
|
background-color: #d7d9eb;
|
||||||
|
margin: 24px auto 8px auto;
|
||||||
|
padding: 24px 30px;
|
||||||
|
border: 2px solid #315397;
|
||||||
|
border-radius: 16px 0 16px 16px;
|
||||||
|
color: #315397;
|
||||||
|
font-family: Poppins, sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c4lv-remember::before {
|
||||||
|
content: url(https://res.cloudinary.com/dh5qgexjo/image/upload/v1752833757/Formao_info.5a175e98_drna5l.svg)" À retenir";
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #315397;
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
TextField,
|
||||||
|
Button,
|
||||||
|
CircularProgress,
|
||||||
|
Alert,
|
||||||
|
} from "@mui/material";
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const API_URL = "https://www.formations.octopusdesign.fr/webservice/rest/server.php";
|
||||||
|
const TOKEN = "685e1b5d794b558b60e971581154c3b2";
|
||||||
|
|
||||||
|
const EditeurCours = () => {
|
||||||
|
const [titre, setTitre] = useState("");
|
||||||
|
const [contenu, setContenu] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!titre || !contenu) return;
|
||||||
|
setLoading(true);
|
||||||
|
setSuccess(false);
|
||||||
|
setError("");
|
||||||
|
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append("wstoken", TOKEN);
|
||||||
|
params.append("wsfunction", "core_course_create_courses");
|
||||||
|
params.append("moodlewsrestformat", "json");
|
||||||
|
|
||||||
|
params.append("courses[0][fullname]", titre);
|
||||||
|
params.append("courses[0][shortname]", titre.replace(/\s+/g, "_").toLowerCase());
|
||||||
|
params.append("courses[0][categoryid]", 1);
|
||||||
|
params.append("courses[0][summary]", contenu);
|
||||||
|
params.append("courses[0][summaryformat]", 1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.post(API_URL, params);
|
||||||
|
setSuccess(true);
|
||||||
|
setTitre("");
|
||||||
|
setContenu("");
|
||||||
|
} catch (err) {
|
||||||
|
setError("Erreur lors de la création du cours.");
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ padding: 4, maxWidth: 800, margin: "auto" }}>
|
||||||
|
<Typography variant="h4" gutterBottom>
|
||||||
|
Ajouter un cours dans Moodle
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{success && <Alert severity="success">Cours enregistré avec succès !</Alert>}
|
||||||
|
{error && <Alert severity="error">{error}</Alert>}
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="Titre du cours"
|
||||||
|
value={titre}
|
||||||
|
onChange={(e) => setTitre(e.target.value)}
|
||||||
|
sx={{ mb: 3 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ReactQuill theme="snow" value={contenu} onChange={setContenu} style={{ height: 200, marginBottom: 30 }} />
|
||||||
|
|
||||||
|
<Button variant="contained" onClick={handleSubmit} disabled={loading}>
|
||||||
|
{loading ? <CircularProgress size={24} /> : "Enregistrer le cours"}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EditeurCours;
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
CircularProgress,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
Grid,
|
||||||
|
Modal,
|
||||||
|
Fade,
|
||||||
|
Backdrop,
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Pagination,
|
||||||
|
Autocomplete,
|
||||||
|
TextField,
|
||||||
|
FormControlLabel,
|
||||||
|
Checkbox,
|
||||||
|
} from "@mui/material";
|
||||||
|
import axios from "axios";
|
||||||
|
import '../../assets/styleCours.css';
|
||||||
|
|
||||||
|
const API_URL = "https://www.formations.octopusdesign.fr/webservice/rest/server.php";
|
||||||
|
const TOKEN = "685e1b5d794b558b60e971581154c3b2";
|
||||||
|
const moodleBaseUrl = "https://www.formations.octopusdesign.fr";
|
||||||
|
|
||||||
|
const ListeCours = () => {
|
||||||
|
const [cours, setCours] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [selected, setSelected] = useState(null);
|
||||||
|
const [pages, setPages] = useState([]);
|
||||||
|
const [loadingPages, setLoadingPages] = useState(false);
|
||||||
|
const [selectedPage, setSelectedPage] = useState(null);
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
const [showOnlyMedia, setShowOnlyMedia] = useState(false);
|
||||||
|
const itemsPerPage = 5;
|
||||||
|
const pdfRef = useRef();
|
||||||
|
|
||||||
|
const pageHasMedia = (html) => {
|
||||||
|
return /<img|<video|<audio|pluginfile\.php/.test(html);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchCours = async () => {
|
||||||
|
try {
|
||||||
|
const res = await axios.get(API_URL, {
|
||||||
|
params: {
|
||||||
|
wstoken: TOKEN,
|
||||||
|
wsfunction: "core_course_get_courses",
|
||||||
|
moodlewsrestformat: "json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setCours(res.data);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur chargement cours :", err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchPages = async (courseId) => {
|
||||||
|
setLoadingPages(true);
|
||||||
|
try {
|
||||||
|
const res = await axios.get(API_URL, {
|
||||||
|
params: {
|
||||||
|
wstoken: TOKEN,
|
||||||
|
wsfunction: "mod_page_get_pages_by_courses",
|
||||||
|
moodlewsrestformat: "json",
|
||||||
|
courseids: [courseId],
|
||||||
|
},
|
||||||
|
paramsSerializer: (params) => {
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach((v, i) => searchParams.append(`${key}[${i}]`, v));
|
||||||
|
} else {
|
||||||
|
searchParams.append(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return searchParams.toString();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setPages(res.data.pages || []);
|
||||||
|
setCurrentPage(1);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Erreur chargement pages :", err);
|
||||||
|
} finally {
|
||||||
|
setLoadingPages(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelect = (cours) => {
|
||||||
|
setSelected(cours);
|
||||||
|
fetchPages(cours.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const exportPagePDF = (page) => {
|
||||||
|
const now = new Date().toLocaleDateString();
|
||||||
|
|
||||||
|
const container = document.createElement("div");
|
||||||
|
container.style.padding = "20px";
|
||||||
|
container.style.fontFamily = "Nunito, sans-serif";
|
||||||
|
container.style.width = "100%";
|
||||||
|
container.style.maxWidth = "800px";
|
||||||
|
container.style.boxSizing = "border-box";
|
||||||
|
container.style.overflowWrap = "break-word";
|
||||||
|
|
||||||
|
const title = document.createElement("h3");
|
||||||
|
title.textContent = page.name;
|
||||||
|
container.appendChild(title);
|
||||||
|
|
||||||
|
const body = document.createElement("div");
|
||||||
|
body.innerHTML = page.content;
|
||||||
|
container.appendChild(body);
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.textContent = `
|
||||||
|
img { max-width: 100%; height: auto; }
|
||||||
|
h1, h2, h3, h4, p { page-break-inside: avoid; }
|
||||||
|
div { page-break-inside: auto; }
|
||||||
|
.c4lv-remember {
|
||||||
|
background-color: #d7d9eb;
|
||||||
|
margin: 24px auto 8px auto;
|
||||||
|
padding: 24px 30px;
|
||||||
|
max-width: 75%;
|
||||||
|
border: 2px solid #315397;
|
||||||
|
border-radius: 16px 0 16px 16px;
|
||||||
|
color: #315397;
|
||||||
|
font-family: Poppins, sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.c4lv-remember::before {
|
||||||
|
content: url(https://res.cloudinary.com/dh5qgexjo/image/upload/v1752833757/Formao_info.5a175e98_drna5l.svg)"À retenir";
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #315397;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
container.appendChild(style);
|
||||||
|
|
||||||
|
const opt = {
|
||||||
|
margin: 0.5,
|
||||||
|
filename: `${page.name}_${now}.pdf`,
|
||||||
|
image: { type: "jpeg", quality: 0.98 },
|
||||||
|
html2canvas: { scale: 2, useCORS: true },
|
||||||
|
jsPDF: { unit: "in", format: "letter", orientation: "portrait" },
|
||||||
|
};
|
||||||
|
|
||||||
|
window.html2pdf().set(opt).from(container).save();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCours();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const filteredPages = pages.filter((page) => {
|
||||||
|
const nameMatch = page.name.toLowerCase().includes(searchQuery.toLowerCase());
|
||||||
|
const mediaMatch = showOnlyMedia ? pageHasMedia(page.content) : true;
|
||||||
|
return nameMatch && mediaMatch;
|
||||||
|
});
|
||||||
|
|
||||||
|
const paginatedPages = filteredPages.slice(
|
||||||
|
(currentPage - 1) * itemsPerPage,
|
||||||
|
currentPage * itemsPerPage
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box sx={{ padding: 4, fontFamily: 'Nunito, sans-serif', mt:5}}>
|
||||||
|
<Typography variant="h4" gutterBottom align="center">
|
||||||
|
Cours
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
<Box sx={{ textAlign: "center" }}>
|
||||||
|
<CircularProgress />
|
||||||
|
</Box>
|
||||||
|
) : (
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
{cours.map((cours) => (
|
||||||
|
<Grid item xs={12} md={6} key={cours.id}>
|
||||||
|
<Card sx={{ cursor: "pointer" }} onClick={() => handleSelect(cours)}>
|
||||||
|
<CardContent>
|
||||||
|
<Typography variant="h6">{cours.fullname}</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={!!selected}
|
||||||
|
onClose={() => {
|
||||||
|
setSelected(null);
|
||||||
|
setPages([]);
|
||||||
|
}}
|
||||||
|
closeAfterTransition
|
||||||
|
BackdropComponent={Backdrop}
|
||||||
|
BackdropProps={{ timeout: 300 }}
|
||||||
|
>
|
||||||
|
<Fade in={!!selected}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
bgcolor: "background.paper",
|
||||||
|
p: 4,
|
||||||
|
width: "90%",
|
||||||
|
maxWidth: 900,
|
||||||
|
borderRadius: 2,
|
||||||
|
boxShadow: 24,
|
||||||
|
maxHeight: "90vh",
|
||||||
|
overflowY: "auto",
|
||||||
|
fontFamily: 'Nunito, sans-serif',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h5" gutterBottom>
|
||||||
|
{selected?.fullname}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Autocomplete
|
||||||
|
options={pages.map((p) => p.name)}
|
||||||
|
freeSolo
|
||||||
|
onInputChange={(event, value) => setSearchQuery(value)}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField {...params} label="Rechercher une page" sx={{ mb: 2 }} />
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Checkbox checked={showOnlyMedia} onChange={(e) => setShowOnlyMedia(e.target.checked)} />}
|
||||||
|
label="Afficher uniquement les pages avec médias"
|
||||||
|
sx={{ mb: 3 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{loadingPages ? (
|
||||||
|
<CircularProgress />
|
||||||
|
) : filteredPages.length > 0 ? (
|
||||||
|
<>
|
||||||
|
{paginatedPages.map((page) => (
|
||||||
|
<Box key={page.id} sx={{ mb: 4 }}>
|
||||||
|
<Typography variant="h6" sx={{ mb: 1 }}>
|
||||||
|
{page.name}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
sx={{ whiteSpace: "pre-line" }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: page.content }}
|
||||||
|
/>
|
||||||
|
<Box sx={{ display: "flex", gap: 1, mt: 1 }}>
|
||||||
|
<Button size="small" variant="outlined" onClick={() => setSelectedPage(page)}>
|
||||||
|
Visualiser
|
||||||
|
</Button>
|
||||||
|
<Button size="small" variant="contained" onClick={() => exportPagePDF(page)}>
|
||||||
|
Exporter en PDF
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Divider sx={{ mt: 3 }} />
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
<Box display="flex" justifyContent="center" mt={2}>
|
||||||
|
<Pagination
|
||||||
|
count={Math.ceil(filteredPages.length / itemsPerPage)}
|
||||||
|
page={currentPage}
|
||||||
|
onChange={(e, value) => setCurrentPage(value)}
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Typography>Aucune page trouvée pour ce cours.</Typography>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Box sx={{ mt: 3, textAlign: "right" }}>
|
||||||
|
<Button variant="outlined" onClick={() => setSelected(null)}>
|
||||||
|
Fermer
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Fade>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
open={!!selectedPage}
|
||||||
|
onClose={() => setSelectedPage(null)}
|
||||||
|
closeAfterTransition
|
||||||
|
BackdropComponent={Backdrop}
|
||||||
|
BackdropProps={{ timeout: 300 }}
|
||||||
|
>
|
||||||
|
<Fade in={!!selectedPage}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
width: "100vw",
|
||||||
|
height: "100vh",
|
||||||
|
bgcolor: "background.paper",
|
||||||
|
p: 4,
|
||||||
|
overflowY: "auto",
|
||||||
|
fontFamily: 'Nunito, sans-serif',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 2 }}>
|
||||||
|
<Typography variant="h6">{selectedPage?.name}</Typography>
|
||||||
|
<Button onClick={() => setSelectedPage(null)}>Fermer</Button>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{ maxWidth: "900px", margin: "0 auto", paddingBottom: 8 }}
|
||||||
|
dangerouslySetInnerHTML={{ __html: selectedPage?.content || "" }}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Fade>
|
||||||
|
</Modal>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ListeCours;
|
||||||
@@ -204,6 +204,36 @@ function Dashboard() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{/* ✅ Gérer les Cours - Nouvelle carte */}
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<Card
|
||||||
|
onClick={() => navigate("/admin/liste-cours")}
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
textAlign: "center",
|
||||||
|
padding: 2,
|
||||||
|
transition: "0.3s",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: "#0e467f",
|
||||||
|
color: "#ffffff",
|
||||||
|
transform: "scale(1.05)",
|
||||||
|
boxShadow: 8,
|
||||||
|
},
|
||||||
|
"&:hover svg": {
|
||||||
|
fill: "#ffffff",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CardContent>
|
||||||
|
<IconButton sx={{ fontSize: 40, color: "#0e467f" }}>
|
||||||
|
<DashboardIcon fontSize="inherit" />
|
||||||
|
</IconButton>
|
||||||
|
<Typography variant="h6" sx={{ fontWeight: "bold" }}>
|
||||||
|
Cours
|
||||||
|
</Typography>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ import GestionPagesACF from "./components/GestionPagesACF";
|
|||||||
import GestionBureauEtudeACF from "./components/GestionBureauEtudeACF";
|
import GestionBureauEtudeACF from "./components/GestionBureauEtudeACF";
|
||||||
import EditPageACF from "./components/Pages/EditPageACF";
|
import EditPageACF from "./components/Pages/EditPageACF";
|
||||||
|
|
||||||
|
// Ajoutez les autres pages Admin
|
||||||
|
import GestionCours from "./components/Admin/GestionCours";
|
||||||
|
import ListeCours from "./components/Admin/ListeCours";
|
||||||
|
|
||||||
// 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"));
|
||||||
@@ -74,6 +78,8 @@ function YourApp() {
|
|||||||
<Route path="/admin/pages-acf" element={<GestionPagesACF />} />
|
<Route path="/admin/pages-acf" element={<GestionPagesACF />} />
|
||||||
<Route path="/admin/bureau-etude-acf" element={<GestionBureauEtudeACF />} />
|
<Route path="/admin/bureau-etude-acf" element={<GestionBureauEtudeACF />} />
|
||||||
<Route path="/admin/edit-page/:id" element={<EditPageACF />} />
|
<Route path="/admin/edit-page/:id" element={<EditPageACF />} />
|
||||||
|
<Route path="/admin/gestion-cours" element={<GestionCours />} />
|
||||||
|
<Route path="/admin/liste-cours" element={<ListeCours />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
<Footer />
|
<Footer />
|
||||||
</Router>
|
</Router>
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user