2024-03-29 20:08:34 -04:00
|
|
|
// Dashboard.tsx
|
|
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
|
import React, { useState, useEffect, useMemo } from 'react';
|
|
|
|
|
import { parse } from 'gift-pegjs';
|
|
|
|
|
|
2025-01-16 12:37:07 -05:00
|
|
|
import Template from 'src/components/GiftTemplate/templates';
|
2024-03-29 20:08:34 -04:00
|
|
|
import { QuizType } from '../../../Types/QuizType';
|
|
|
|
|
import { FolderType } from '../../../Types/FolderType';
|
2024-09-15 00:34:41 -04:00
|
|
|
// import { QuestionService } from '../../../services/QuestionService';
|
2024-03-29 20:08:34 -04:00
|
|
|
import ApiService from '../../../services/ApiService';
|
|
|
|
|
|
|
|
|
|
import './dashboard.css';
|
2025-01-16 12:37:07 -05:00
|
|
|
import ImportModal from 'src/components/ImportModal/ImportModal';
|
2024-03-29 20:08:34 -04:00
|
|
|
//import axios from 'axios';
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
TextField,
|
|
|
|
|
IconButton,
|
|
|
|
|
InputAdornment,
|
|
|
|
|
Button,
|
2024-10-19 22:58:49 -04:00
|
|
|
Card,
|
2024-03-29 20:08:34 -04:00
|
|
|
Tooltip,
|
2024-10-19 22:58:49 -04:00
|
|
|
NativeSelect,
|
|
|
|
|
CardContent,
|
|
|
|
|
styled,
|
2024-03-29 20:08:34 -04:00
|
|
|
} from '@mui/material';
|
|
|
|
|
import {
|
|
|
|
|
Search,
|
|
|
|
|
DeleteOutline,
|
|
|
|
|
FileDownload,
|
|
|
|
|
Add,
|
|
|
|
|
Upload,
|
2025-01-08 10:35:56 -05:00
|
|
|
FolderCopy,
|
2024-03-29 20:08:34 -04:00
|
|
|
ContentCopy,
|
|
|
|
|
Edit,
|
|
|
|
|
Share,
|
|
|
|
|
// DriveFileMove
|
|
|
|
|
} from '@mui/icons-material';
|
|
|
|
|
|
2024-10-19 22:58:49 -04:00
|
|
|
// Create a custom-styled Card component
|
|
|
|
|
const CustomCard = styled(Card)({
|
|
|
|
|
overflow: 'visible', // Override the overflow property
|
|
|
|
|
position: 'relative',
|
|
|
|
|
margin: '40px 0 20px 0', // Add top margin to make space for the tab
|
|
|
|
|
borderRadius: '8px',
|
|
|
|
|
paddingTop: '20px', // Ensure content inside the card doesn't overlap with the tab
|
|
|
|
|
});
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
const Dashboard: React.FC = () => {
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
const [quizzes, setQuizzes] = useState<QuizType[]>([]);
|
|
|
|
|
const [searchTerm, setSearchTerm] = useState('');
|
|
|
|
|
const [showImportModal, setShowImportModal] = useState<boolean>(false);
|
|
|
|
|
const [folders, setFolders] = useState<FolderType[]>([]);
|
2024-10-19 22:58:49 -04:00
|
|
|
const [selectedFolderId, setSelectedFolderId] = useState<string>(''); // Selected folder
|
|
|
|
|
|
|
|
|
|
// Filter quizzes based on search term
|
|
|
|
|
// const filteredQuizzes = quizzes.filter(quiz =>
|
|
|
|
|
// quiz.title.toLowerCase().includes(searchTerm.toLowerCase())
|
|
|
|
|
// );
|
|
|
|
|
const filteredQuizzes = useMemo(() => {
|
|
|
|
|
return quizzes.filter(
|
|
|
|
|
(quiz) =>
|
|
|
|
|
quiz && quiz.title && quiz.title.toLowerCase().includes(searchTerm.toLowerCase())
|
|
|
|
|
);
|
|
|
|
|
}, [quizzes, searchTerm]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Group quizzes by folder
|
|
|
|
|
const quizzesByFolder = filteredQuizzes.reduce((acc, quiz) => {
|
|
|
|
|
if (!acc[quiz.folderName]) {
|
|
|
|
|
acc[quiz.folderName] = [];
|
|
|
|
|
}
|
|
|
|
|
acc[quiz.folderName].push(quiz);
|
|
|
|
|
return acc;
|
|
|
|
|
}, {} as Record<string, QuizType[]>);
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const fetchData = async () => {
|
2024-09-15 21:56:48 -04:00
|
|
|
if (!ApiService.isLoggedIn()) {
|
2024-03-29 20:08:34 -04:00
|
|
|
navigate("/teacher/login");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2025-01-11 02:22:14 -05:00
|
|
|
const userFolders = await ApiService.getUserFolders();
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
setFolders(userFolders as FolderType[]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fetchData();
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const handleSelectFolder = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
2024-10-19 22:58:49 -04:00
|
|
|
setSelectedFolderId(event.target.value);
|
2024-03-29 20:08:34 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const fetchQuizzesForFolder = async () => {
|
|
|
|
|
|
2024-10-19 22:58:49 -04:00
|
|
|
if (selectedFolderId == '') {
|
2024-03-29 20:08:34 -04:00
|
|
|
const folders = await ApiService.getUserFolders(); // HACK force user folders to load on first load
|
2025-01-26 21:50:57 -05:00
|
|
|
//console.log("show all quizzes")
|
2025-01-11 02:22:14 -05:00
|
|
|
let quizzes: QuizType[] = [];
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
for (const folder of folders as FolderType[]) {
|
|
|
|
|
const folderQuizzes = await ApiService.getFolderContent(folder._id);
|
2025-01-26 21:50:57 -05:00
|
|
|
//console.log("folder: ", folder.title, " quiz: ", folderQuizzes);
|
2024-10-19 22:58:49 -04:00
|
|
|
// add the folder.title to the QuizType if the folderQuizzes is an array
|
|
|
|
|
addFolderTitleToQuizzes(folderQuizzes, folder.title);
|
2024-03-29 20:08:34 -04:00
|
|
|
quizzes = quizzes.concat(folderQuizzes as QuizType[])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setQuizzes(quizzes as QuizType[]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-10-02 10:23:56 -04:00
|
|
|
console.log("show some quizzes")
|
2024-10-19 22:58:49 -04:00
|
|
|
const folderQuizzes = await ApiService.getFolderContent(selectedFolderId);
|
2024-10-02 10:23:56 -04:00
|
|
|
console.log("folderQuizzes: ", folderQuizzes);
|
2024-10-19 22:58:49 -04:00
|
|
|
// get the folder title from its id
|
|
|
|
|
const folderTitle = folders.find((folder) => folder._id === selectedFolderId)?.title || '';
|
|
|
|
|
addFolderTitleToQuizzes(folderQuizzes, folderTitle);
|
2024-03-29 20:08:34 -04:00
|
|
|
setQuizzes(folderQuizzes as QuizType[]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fetchQuizzesForFolder();
|
2024-10-19 22:58:49 -04:00
|
|
|
}, [selectedFolderId]);
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
|
|
setSearchTerm(event.target.value);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleRemoveQuiz = async (quiz: QuizType) => {
|
|
|
|
|
try {
|
|
|
|
|
const confirmed = window.confirm('Voulez-vous vraiment supprimer ce quiz?');
|
|
|
|
|
if (confirmed) {
|
|
|
|
|
await ApiService.deleteQuiz(quiz._id);
|
|
|
|
|
const updatedQuizzes = quizzes.filter((q) => q._id !== quiz._id);
|
|
|
|
|
setQuizzes(updatedQuizzes);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error removing quiz:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleDuplicateQuiz = async (quiz: QuizType) => {
|
|
|
|
|
try {
|
|
|
|
|
await ApiService.duplicateQuiz(quiz._id);
|
2024-10-19 22:58:49 -04:00
|
|
|
if (selectedFolderId == '') {
|
2024-03-29 20:08:34 -04:00
|
|
|
const folders = await ApiService.getUserFolders(); // HACK force user folders to load on first load
|
2025-01-11 02:22:14 -05:00
|
|
|
console.log("show all quizzes")
|
|
|
|
|
let quizzes: QuizType[] = [];
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
for (const folder of folders as FolderType[]) {
|
|
|
|
|
const folderQuizzes = await ApiService.getFolderContent(folder._id);
|
|
|
|
|
console.log("folder: ", folder.title, " quiz: ", folderQuizzes);
|
2024-10-19 22:58:49 -04:00
|
|
|
addFolderTitleToQuizzes(folderQuizzes, folder.title);
|
|
|
|
|
quizzes = quizzes.concat(folderQuizzes as QuizType[]);
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setQuizzes(quizzes as QuizType[]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-10-02 10:23:56 -04:00
|
|
|
console.log("show some quizzes")
|
2024-10-19 22:58:49 -04:00
|
|
|
const folderQuizzes = await ApiService.getFolderContent(selectedFolderId);
|
|
|
|
|
addFolderTitleToQuizzes(folderQuizzes, selectedFolderId);
|
2024-03-29 20:08:34 -04:00
|
|
|
setQuizzes(folderQuizzes as QuizType[]);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error duplicating quiz:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleOnImport = () => {
|
|
|
|
|
setShowImportModal(true);
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const validateQuiz = (questions: string[]) => {
|
|
|
|
|
if (!questions || questions.length === 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if I can generate the Template for each question
|
|
|
|
|
// Otherwise the quiz is invalid
|
|
|
|
|
for (let i = 0; i < questions.length; i++) {
|
|
|
|
|
try {
|
2024-09-15 00:34:41 -04:00
|
|
|
// questions[i] = QuestionService.ignoreImgTags(questions[i]);
|
2024-03-29 20:08:34 -04:00
|
|
|
const parsedItem = parse(questions[i]);
|
|
|
|
|
Template(parsedItem[0]);
|
2025-01-11 02:22:14 -05:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
2024-03-29 20:08:34 -04:00
|
|
|
} catch (error) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 = "";
|
2025-01-11 02:22:14 -05:00
|
|
|
const title = selectedQuiz.title;
|
2024-03-29 20:08:34 -04:00
|
|
|
console.log(selectedQuiz.content);
|
|
|
|
|
selectedQuiz.content.forEach((question, qIndex) => {
|
|
|
|
|
const formattedQuestion = question.trim();
|
2024-09-15 23:06:01 -04:00
|
|
|
// console.log(formattedQuestion);
|
2024-03-29 20:08:34 -04:00
|
|
|
if (formattedQuestion !== '') {
|
2024-09-15 23:06:01 -04:00
|
|
|
quizContent += formattedQuestion + '\n';
|
2024-03-29 20:08:34 -04:00
|
|
|
if (qIndex !== selectedQuiz.content.length - 1) {
|
|
|
|
|
quizContent += '\n';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-09-15 23:06:01 -04:00
|
|
|
if (!validateQuiz(selectedQuiz.content)) {
|
|
|
|
|
window.alert('Attention! Ce quiz contient des questions invalides selon le format GIFT.');
|
|
|
|
|
}
|
2024-03-29 20:08:34 -04:00
|
|
|
const blob = new Blob([quizContent], { type: 'text/plain' });
|
|
|
|
|
const a = document.createElement('a');
|
|
|
|
|
const filename = title;
|
2024-09-15 23:06:01 -04:00
|
|
|
a.download = `${filename}.gift`;
|
2024-03-29 20:08:34 -04:00
|
|
|
a.href = window.URL.createObjectURL(blob);
|
|
|
|
|
a.click();
|
2024-09-15 23:06:01 -04:00
|
|
|
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error exporting selected quiz:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCreateFolder = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const folderTitle = prompt('Titre du dossier');
|
|
|
|
|
if (folderTitle) {
|
|
|
|
|
await ApiService.createFolder(folderTitle);
|
|
|
|
|
const userFolders = await ApiService.getUserFolders();
|
2024-04-07 15:57:54 -04:00
|
|
|
setFolders(userFolders as FolderType[]);
|
|
|
|
|
const newlyCreatedFolder = userFolders[userFolders.length - 1] as FolderType;
|
2024-10-19 22:58:49 -04:00
|
|
|
setSelectedFolderId(newlyCreatedFolder._id);
|
2024-04-07 15:57:54 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error creating folder:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-04-07 17:41:11 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
const handleDeleteFolder = async () => {
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const confirmed = window.confirm('Voulez-vous vraiment supprimer ce dossier?');
|
|
|
|
|
if (confirmed) {
|
2024-10-19 22:58:49 -04:00
|
|
|
await ApiService.deleteFolder(selectedFolderId);
|
2024-03-29 20:08:34 -04:00
|
|
|
const userFolders = await ApiService.getUserFolders();
|
|
|
|
|
setFolders(userFolders as FolderType[]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const folders = await ApiService.getUserFolders(); // HACK force user folders to load on first load
|
2024-10-19 22:58:49 -04:00
|
|
|
console.log("show all quizzes")
|
2025-01-11 02:22:14 -05:00
|
|
|
let quizzes: QuizType[] = [];
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
for (const folder of folders as FolderType[]) {
|
|
|
|
|
const folderQuizzes = await ApiService.getFolderContent(folder._id);
|
|
|
|
|
console.log("folder: ", folder.title, " quiz: ", folderQuizzes);
|
|
|
|
|
quizzes = quizzes.concat(folderQuizzes as QuizType[])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setQuizzes(quizzes as QuizType[]);
|
2024-10-19 22:58:49 -04:00
|
|
|
setSelectedFolderId('');
|
2024-03-29 20:08:34 -04:00
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error deleting folder:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-10-19 22:58:49 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
const handleRenameFolder = async () => {
|
|
|
|
|
try {
|
|
|
|
|
// folderId: string GET THIS FROM CURRENT FOLDER
|
|
|
|
|
// currentTitle: string GET THIS FROM CURRENT FOLDER
|
2025-01-26 21:50:57 -05:00
|
|
|
const newTitle = prompt('Entrée le nouveau nom du fichier', folders.find((folder) => folder._id === selectedFolderId)?.title);
|
2024-03-29 20:08:34 -04:00
|
|
|
if (newTitle) {
|
2025-01-26 21:50:57 -05:00
|
|
|
const renamedFolderId = selectedFolderId;
|
|
|
|
|
const result = await ApiService.renameFolder(selectedFolderId, newTitle);
|
|
|
|
|
|
|
|
|
|
if (result !== true ) {
|
|
|
|
|
window.alert(`Une erreur est survenue: ${result}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
const userFolders = await ApiService.getUserFolders();
|
|
|
|
|
setFolders(userFolders as FolderType[]);
|
2025-01-26 16:56:49 -05:00
|
|
|
// refresh the page
|
|
|
|
|
setSelectedFolderId('');
|
2025-01-26 21:50:57 -05:00
|
|
|
setSelectedFolderId(renamedFolderId);
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error renaming folder:', error);
|
2025-01-26 21:50:57 -05:00
|
|
|
alert('Erreur lors du renommage du dossier: ' + error);
|
2024-03-29 20:08:34 -04:00
|
|
|
}
|
|
|
|
|
};
|
2024-10-19 22:58:49 -04:00
|
|
|
|
2024-03-29 20:08:34 -04:00
|
|
|
const handleDuplicateFolder = async () => {
|
|
|
|
|
try {
|
|
|
|
|
// folderId: string GET THIS FROM CURRENT FOLDER
|
2024-10-19 22:58:49 -04:00
|
|
|
await ApiService.duplicateFolder(selectedFolderId);
|
2024-10-03 22:18:03 -04:00
|
|
|
// TODO set the selected folder to be the duplicated folder
|
2024-03-29 20:08:34 -04:00
|
|
|
const userFolders = await ApiService.getUserFolders();
|
|
|
|
|
setFolders(userFolders as FolderType[]);
|
2024-10-03 22:18:03 -04:00
|
|
|
const newlyCreatedFolder = userFolders[userFolders.length - 1] as FolderType;
|
2024-10-19 22:58:49 -04:00
|
|
|
setSelectedFolderId(newlyCreatedFolder._id);
|
2024-03-29 20:08:34 -04:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Error duplicating folder:', error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleCreateQuiz = () => {
|
|
|
|
|
navigate("/teacher/editor-quiz/new");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleEditQuiz = (quiz: QuizType) => {
|
|
|
|
|
navigate(`/teacher/editor-quiz/${quiz._id}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleLancerQuiz = (quiz: QuizType) => {
|
|
|
|
|
navigate(`/teacher/manage-room/${quiz._id}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleShareQuiz = async (quiz: QuizType) => {
|
|
|
|
|
try {
|
|
|
|
|
const email = prompt(`Veuillez saisir l'email de la personne avec qui vous souhaitez partager ce quiz`, "");
|
|
|
|
|
|
|
|
|
|
if (email) {
|
|
|
|
|
const result = await ApiService.ShareQuiz(quiz._id, email);
|
|
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
|
window.alert(`Une erreur est survenue.\n Veuillez réessayer plus tard`)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.alert(`Quiz partagé avec succès!`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Erreur lors du partage du quiz:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
|
|
<div className="dashboard">
|
|
|
|
|
|
|
|
|
|
<div className="title">Tableau de bord</div>
|
|
|
|
|
|
|
|
|
|
<div className="search-bar">
|
|
|
|
|
<TextField
|
|
|
|
|
onChange={handleSearch}
|
|
|
|
|
value={searchTerm}
|
2024-09-17 18:56:13 -04:00
|
|
|
placeholder="Rechercher un quiz par son titre"
|
2024-03-29 20:08:34 -04:00
|
|
|
fullWidth
|
|
|
|
|
InputProps={{
|
|
|
|
|
endAdornment: (
|
|
|
|
|
<InputAdornment position="end">
|
|
|
|
|
<IconButton>
|
|
|
|
|
<Search />
|
|
|
|
|
</IconButton>
|
|
|
|
|
</InputAdornment>
|
|
|
|
|
)
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className='folder'>
|
|
|
|
|
<div className='select'>
|
|
|
|
|
<NativeSelect
|
|
|
|
|
id="select-folder"
|
|
|
|
|
color="primary"
|
2024-10-19 22:58:49 -04:00
|
|
|
value={selectedFolderId}
|
2024-03-29 20:08:34 -04:00
|
|
|
onChange={handleSelectFolder}
|
|
|
|
|
>
|
|
|
|
|
<option value=""> Tous les dossiers... </option>
|
|
|
|
|
|
|
|
|
|
{folders.map((folder: FolderType) => (
|
|
|
|
|
<option value={folder._id} key={folder._id}> {folder.title} </option>
|
|
|
|
|
))}
|
|
|
|
|
</NativeSelect>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className='actions'>
|
|
|
|
|
<Tooltip title="Ajouter dossier" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={handleCreateFolder}
|
|
|
|
|
> <Add /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Tooltip title="Renommer dossier" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={handleRenameFolder}
|
2024-10-19 22:58:49 -04:00
|
|
|
disabled={selectedFolderId == ''} // cannot action on all
|
2024-03-29 20:08:34 -04:00
|
|
|
> <Edit /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Tooltip title="Dupliquer dossier" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={handleDuplicateFolder}
|
2025-01-10 11:09:06 -05:00
|
|
|
disabled={selectedFolderId == ''} // cannot action on all
|
2025-01-08 10:35:56 -05:00
|
|
|
> <FolderCopy /> </IconButton>
|
2024-03-29 20:08:34 -04:00
|
|
|
</Tooltip>
|
|
|
|
|
|
2024-10-03 22:18:03 -04:00
|
|
|
<Tooltip title="Supprimer dossier" placement="top">
|
2024-03-29 20:08:34 -04:00
|
|
|
<IconButton
|
|
|
|
|
aria-label="delete"
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={handleDeleteFolder}
|
2024-10-19 22:58:49 -04:00
|
|
|
disabled={selectedFolderId == ''} // cannot action on all
|
2024-03-29 20:08:34 -04:00
|
|
|
> <DeleteOutline /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className='ajouter'>
|
|
|
|
|
<Button
|
|
|
|
|
variant="outlined"
|
|
|
|
|
color="primary"
|
|
|
|
|
startIcon={<Add />}
|
|
|
|
|
onClick={handleCreateQuiz}
|
|
|
|
|
>
|
|
|
|
|
Ajouter un nouveau quiz
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
variant="outlined"
|
|
|
|
|
color="primary"
|
|
|
|
|
startIcon={<Upload />}
|
|
|
|
|
onClick={handleOnImport}
|
|
|
|
|
>
|
|
|
|
|
Import
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
<div className='list'>
|
2024-10-19 22:58:49 -04:00
|
|
|
{Object.keys(quizzesByFolder).map(folderName => (
|
|
|
|
|
<CustomCard key={folderName} className='folder-card'>
|
|
|
|
|
<div className='folder-tab'>{folderName}</div>
|
|
|
|
|
<CardContent>
|
|
|
|
|
{quizzesByFolder[folderName].map((quiz: QuizType) => (
|
|
|
|
|
<div className='quiz' key={quiz._id}>
|
|
|
|
|
<div className='title'>
|
|
|
|
|
<Tooltip title="Lancer quiz" placement="top">
|
|
|
|
|
<Button
|
|
|
|
|
variant="outlined"
|
|
|
|
|
onClick={() => handleLancerQuiz(quiz)}
|
|
|
|
|
disabled={!validateQuiz(quiz.content)}
|
|
|
|
|
>
|
|
|
|
|
{`${quiz.title} (${quiz.content.length} question${quiz.content.length > 1 ? 's' : ''})`}
|
|
|
|
|
</Button>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className='actions'>
|
|
|
|
|
<Tooltip title="Télécharger quiz" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={() => downloadTxtFile(quiz)}
|
|
|
|
|
> <FileDownload /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Tooltip title="Modifier quiz" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={() => handleEditQuiz(quiz)}
|
|
|
|
|
> <Edit /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Tooltip title="Dupliquer quiz" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={() => handleDuplicateQuiz(quiz)}
|
|
|
|
|
> <ContentCopy /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Tooltip title="Supprimer quiz" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
aria-label="delete"
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={() => handleRemoveQuiz(quiz)}
|
|
|
|
|
> <DeleteOutline /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
|
|
|
|
|
<Tooltip title="Partager quiz" placement="top">
|
|
|
|
|
<IconButton
|
|
|
|
|
color="primary"
|
|
|
|
|
onClick={() => handleShareQuiz(quiz)}
|
|
|
|
|
> <Share /> </IconButton>
|
|
|
|
|
</Tooltip>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</CardContent>
|
|
|
|
|
</CustomCard>
|
2024-03-29 20:08:34 -04:00
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
<ImportModal
|
|
|
|
|
open={showImportModal}
|
|
|
|
|
handleOnClose={() => setShowImportModal(false)}
|
|
|
|
|
handleOnImport={handleOnImport}
|
2024-10-19 22:58:49 -04:00
|
|
|
selectedFolder={selectedFolderId}
|
2024-03-29 20:08:34 -04:00
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default Dashboard;
|
2024-10-19 22:58:49 -04:00
|
|
|
function addFolderTitleToQuizzes(folderQuizzes: string | QuizType[], folderName: string) {
|
|
|
|
|
if (Array.isArray(folderQuizzes))
|
|
|
|
|
folderQuizzes.forEach((quiz) => {
|
|
|
|
|
quiz.folderName = folderName;
|
|
|
|
|
console.log(`quiz: ${quiz.title} folder: ${quiz.folderName}`);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|