mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
QuizToPDF modal and basic function done
This commit is contained in:
parent
cb069bebeb
commit
19130d8f44
5 changed files with 386 additions and 182 deletions
|
|
@ -1,2 +1,3 @@
|
||||||
VITE_BACKEND_URL=http://localhost:4400
|
VITE_BACKEND_URL=http://localhost:4400
|
||||||
VITE_BACKEND_SOCKET_URL=http://localhost:4400
|
VITE_BACKEND_SOCKET_URL=http://localhost:4400
|
||||||
|
VITE_AZURE_BACKEND_URL=http://localhost:4400
|
||||||
|
|
|
||||||
383
client/package-lock.json
generated
383
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -27,6 +27,7 @@
|
||||||
"esbuild": "^0.23.1",
|
"esbuild": "^0.23.1",
|
||||||
"gift-pegjs": "^2.0.0-beta.1",
|
"gift-pegjs": "^2.0.0-beta.1",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
|
"jspdf": "^2.5.2",
|
||||||
"katex": "^0.16.11",
|
"katex": "^0.16.11",
|
||||||
"marked": "^14.1.2",
|
"marked": "^14.1.2",
|
||||||
"nanoid": "^5.0.2",
|
"nanoid": "^5.0.2",
|
||||||
|
|
|
||||||
121
client/src/components/DownloadQuizModal/DownloadQuizModal.tsx
Normal file
121
client/src/components/DownloadQuizModal/DownloadQuizModal.tsx
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Dialog, DialogTitle, DialogActions, Button, Tooltip, IconButton } from '@mui/material';
|
||||||
|
import { FileDownload } from '@mui/icons-material';
|
||||||
|
|
||||||
|
import { QuizType } from '../../Types/QuizType';
|
||||||
|
import ApiService from '../../services/ApiService';
|
||||||
|
|
||||||
|
import jsPDF from 'jspdf';
|
||||||
|
|
||||||
|
interface DownloadQuizModalProps {
|
||||||
|
quiz: QuizType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DownloadQuizModal: React.FC<DownloadQuizModalProps> = ({ quiz }) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const handleOpenModal = () => setOpen(true);
|
||||||
|
|
||||||
|
const handleCloseModal = () => setOpen(false);
|
||||||
|
|
||||||
|
const handleDownload = async (format: 'txt' | 'pdf-with-answers' | 'pdf-without-answers') => {
|
||||||
|
switch (format) {
|
||||||
|
case 'txt':
|
||||||
|
await downloadTxtFile(quiz);
|
||||||
|
break;
|
||||||
|
case 'pdf-with-answers':
|
||||||
|
await downloadPdfFile(quiz, true);
|
||||||
|
break;
|
||||||
|
case 'pdf-without-answers':
|
||||||
|
await downloadPdfFile(quiz, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
handleCloseModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadTxtFile = async (quiz: QuizType) => {
|
||||||
|
try {
|
||||||
|
const selectedQuiz = await ApiService.getQuiz(quiz._id) as QuizType;
|
||||||
|
if (!selectedQuiz) throw new Error('Quiz not found');
|
||||||
|
|
||||||
|
let quizContent = "";
|
||||||
|
selectedQuiz.content.forEach((question) => {
|
||||||
|
const formattedQuestion = question.trim();
|
||||||
|
if (formattedQuestion !== '') quizContent += formattedQuestion + '\n\n';
|
||||||
|
});
|
||||||
|
|
||||||
|
const blob = new Blob([quizContent], { type: 'text/plain' });
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.download = `${selectedQuiz.title}.gift`;
|
||||||
|
a.href = window.URL.createObjectURL(blob);
|
||||||
|
a.click();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error exporting quiz:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadPdfFile = async (quiz: QuizType, withAnswers: boolean) => {
|
||||||
|
try {
|
||||||
|
const selectedQuiz = await ApiService.getQuiz(quiz._id) as QuizType;
|
||||||
|
if (!selectedQuiz) throw new Error('Quiz not found');
|
||||||
|
|
||||||
|
const doc = new jsPDF();
|
||||||
|
doc.setFont("helvetica", "bold");
|
||||||
|
doc.setFontSize(25);
|
||||||
|
doc.text(selectedQuiz.title, 10, 15);
|
||||||
|
|
||||||
|
let yPosition = 40;
|
||||||
|
doc.setFont("helvetica", "normal");
|
||||||
|
doc.setFontSize(16);
|
||||||
|
|
||||||
|
selectedQuiz.content.forEach((question, index) => {
|
||||||
|
let formattedQuestion = question.trim();
|
||||||
|
|
||||||
|
|
||||||
|
if (!withAnswers) {
|
||||||
|
formattedQuestion = formattedQuestion.replace(/::.*?::/g, '')
|
||||||
|
.replace(/\/\/.*$/gm, '')
|
||||||
|
.replace(/#[^\n]*/g, '')
|
||||||
|
.replace(/=/g, '')
|
||||||
|
.replace(/~/g, '')
|
||||||
|
.replace(/\{(.*?)\}/g, '{$1}');
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrappedText = doc.splitTextToSize(`${index + 1}. ${formattedQuestion}`, 180);
|
||||||
|
|
||||||
|
doc.text(wrappedText, 10, yPosition);
|
||||||
|
|
||||||
|
yPosition += wrappedText.length * 10;
|
||||||
|
});
|
||||||
|
|
||||||
|
const filename = withAnswers
|
||||||
|
? `${selectedQuiz.title}_avec_reponses.pdf`
|
||||||
|
: `${selectedQuiz.title}_sans_reponses.pdf`;
|
||||||
|
|
||||||
|
doc.save(filename);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error exporting quiz as PDF:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tooltip title="Télécharger quiz" placement="top">
|
||||||
|
<IconButton color="primary" onClick={handleOpenModal}>
|
||||||
|
<FileDownload />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Dialog open={open} onClose={handleCloseModal} fullWidth maxWidth="xs">
|
||||||
|
<DialogTitle sx={{ textAlign: "center" }}>Choisissez un format de téléchargement</DialogTitle>
|
||||||
|
<DialogActions sx={{ display: "flex", justifyContent: "center", gap: 2 }}>
|
||||||
|
<Button onClick={() => handleDownload('txt')}>GIFT</Button>
|
||||||
|
<Button onClick={() => handleDownload('pdf-with-answers')}> PDF avec réponses</Button>
|
||||||
|
<Button onClick={() => handleDownload('pdf-without-answers')}>PDF sans réponses</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DownloadQuizModal;
|
||||||
|
|
@ -27,7 +27,6 @@ import {
|
||||||
import {
|
import {
|
||||||
Search,
|
Search,
|
||||||
DeleteOutline,
|
DeleteOutline,
|
||||||
FileDownload,
|
|
||||||
Add,
|
Add,
|
||||||
Upload,
|
Upload,
|
||||||
FolderCopy,
|
FolderCopy,
|
||||||
|
|
@ -36,6 +35,7 @@ import {
|
||||||
Share,
|
Share,
|
||||||
// DriveFileMove
|
// DriveFileMove
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
import DownloadQuizModal from 'src/components/DownloadQuizModal/DownloadQuizModal';
|
||||||
|
|
||||||
// Create a custom-styled Card component
|
// Create a custom-styled Card component
|
||||||
const CustomCard = styled(Card)({
|
const CustomCard = styled(Card)({
|
||||||
|
|
@ -205,47 +205,6 @@ const Dashboard: React.FC = () => {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadTxtFile = async (quiz: QuizType) => {
|
|
||||||
|
|
||||||
try {
|
|
||||||
const selectedQuiz = await ApiService.getQuiz(quiz._id) as QuizType;
|
|
||||||
//quizzes.find((quiz) => quiz._id === quiz._id);
|
|
||||||
|
|
||||||
if (!selectedQuiz) {
|
|
||||||
throw new Error('Selected quiz not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
//const { title, content } = selectedQuiz;
|
|
||||||
let quizContent = "";
|
|
||||||
const title = selectedQuiz.title;
|
|
||||||
console.log(selectedQuiz.content);
|
|
||||||
selectedQuiz.content.forEach((question, qIndex) => {
|
|
||||||
const formattedQuestion = question.trim();
|
|
||||||
// console.log(formattedQuestion);
|
|
||||||
if (formattedQuestion !== '') {
|
|
||||||
quizContent += formattedQuestion + '\n';
|
|
||||||
if (qIndex !== selectedQuiz.content.length - 1) {
|
|
||||||
quizContent += '\n';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!validateQuiz(selectedQuiz.content)) {
|
|
||||||
window.alert('Attention! Ce quiz contient des questions invalides selon le format GIFT.');
|
|
||||||
}
|
|
||||||
const blob = new Blob([quizContent], { type: 'text/plain' });
|
|
||||||
const a = document.createElement('a');
|
|
||||||
const filename = title;
|
|
||||||
a.download = `${filename}.gift`;
|
|
||||||
a.href = window.URL.createObjectURL(blob);
|
|
||||||
a.click();
|
|
||||||
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error exporting selected quiz:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCreateFolder = async () => {
|
const handleCreateFolder = async () => {
|
||||||
try {
|
try {
|
||||||
const folderTitle = prompt('Titre du dossier');
|
const folderTitle = prompt('Titre du dossier');
|
||||||
|
|
@ -299,7 +258,7 @@ const Dashboard: React.FC = () => {
|
||||||
const renamedFolderId = selectedFolderId;
|
const renamedFolderId = selectedFolderId;
|
||||||
const result = await ApiService.renameFolder(selectedFolderId, newTitle);
|
const result = await ApiService.renameFolder(selectedFolderId, newTitle);
|
||||||
|
|
||||||
if (result !== true ) {
|
if (result !== true) {
|
||||||
window.alert(`Une erreur est survenue: ${result}`);
|
window.alert(`Une erreur est survenue: ${result}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -481,12 +440,9 @@ const Dashboard: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='actions'>
|
<div className='actions'>
|
||||||
<Tooltip title="Télécharger quiz" placement="top">
|
<div className="dashboard">
|
||||||
<IconButton
|
<DownloadQuizModal quiz={quiz} />
|
||||||
color="primary"
|
</div>
|
||||||
onClick={() => downloadTxtFile(quiz)}
|
|
||||||
> <FileDownload /> </IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
|
|
||||||
<Tooltip title="Modifier quiz" placement="top">
|
<Tooltip title="Modifier quiz" placement="top">
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue