// Dashboard.tsx import { useNavigate } from 'react-router-dom'; import React, { useState, useEffect, useMemo } from 'react'; import { parse } from 'gift-pegjs'; import Template from 'src/components/GiftTemplate/templates'; import { QuizType } from '../../../Types/QuizType'; import { FolderType } from '../../../Types/FolderType'; // import { QuestionService } from '../../../services/QuestionService'; import ApiService from '../../../services/ApiService'; import './dashboard.css'; import ImportModal from 'src/components/ImportModal/ImportModal'; //import axios from 'axios'; import { RoomType } from 'src/Types/RoomType'; import { useRooms } from '../ManageRoom/RoomContext'; import { Dialog, DialogActions, DialogContent, DialogTitle, TextField, IconButton, InputAdornment, Button, Card, Tooltip, NativeSelect, CardContent, styled } from '@mui/material'; import { Search, DeleteOutline, FileDownload, Add, Upload, FolderCopy, ContentCopy, Edit, Share // DriveFileMove } from '@mui/icons-material'; // 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 }); const Dashboard: React.FC = () => { const navigate = useNavigate(); const [quizzes, setQuizzes] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [showImportModal, setShowImportModal] = useState(false); const [folders, setFolders] = useState([]); const [selectedFolderId, setSelectedFolderId] = useState(''); // Selected folder const [rooms, setRooms] = useState([]); const [openAddRoomDialog, setOpenAddRoomDialog] = useState(false); const [newRoomTitle, setNewRoomTitle] = useState(''); const { selectedRoom, selectRoom, createRoom } = useRooms(); // 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); useEffect(() => { const fetchData = async () => { if (!ApiService.isLoggedIn()) { navigate('/teacher/login'); return; } else { const userRooms = await ApiService.getUserRooms(); setRooms(userRooms as RoomType[]); // select the first room if it exists if (userRooms instanceof Array && userRooms.length > 0) { selectRoom(userRooms[0]._id); } const userFolders = await ApiService.getUserFolders(); setFolders(userFolders as FolderType[]); } }; fetchData(); }, []); const handleSelectRoom = (event: React.ChangeEvent) => { if (event.target.value === "add-room") { setOpenAddRoomDialog(true); } else { selectRoom(event.target.value); } }; const handleSubmitCreateRoom = async () => { if (newRoomTitle.trim()) { await createRoom(newRoomTitle); // reload the list of rooms const userRooms = await ApiService.getUserRooms(); setRooms(userRooms as RoomType[]); setOpenAddRoomDialog(false); setNewRoomTitle(''); } }; const handleSelectFolder = (event: React.ChangeEvent) => { setSelectedFolderId(event.target.value); }; useEffect(() => { const fetchQuizzesForFolder = async () => { if (selectedFolderId == '') { const folders = await ApiService.getUserFolders(); // HACK force user folders to load on first load //console.log("show all quizzes") let quizzes: QuizType[] = []; for (const folder of folders as FolderType[]) { const folderQuizzes = await ApiService.getFolderContent(folder._id); //console.log("folder: ", folder.title, " quiz: ", folderQuizzes); // add the folder.title to the QuizType if the folderQuizzes is an array addFolderTitleToQuizzes(folderQuizzes, folder.title); quizzes = quizzes.concat(folderQuizzes as QuizType[]); } setQuizzes(quizzes as QuizType[]); } else { console.log('show some quizzes'); const folderQuizzes = await ApiService.getFolderContent(selectedFolderId); console.log('folderQuizzes: ', folderQuizzes); // get the folder title from its id const folderTitle = folders.find((folder) => folder._id === selectedFolderId)?.title || ''; addFolderTitleToQuizzes(folderQuizzes, folderTitle); setQuizzes(folderQuizzes as QuizType[]); } }; fetchQuizzesForFolder(); }, [selectedFolderId]); const handleSearch = (event: React.ChangeEvent) => { 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); if (selectedFolderId == '') { const folders = await ApiService.getUserFolders(); // HACK force user folders to load on first load console.log('show all quizzes'); let quizzes: QuizType[] = []; for (const folder of folders as FolderType[]) { const folderQuizzes = await ApiService.getFolderContent(folder._id); console.log('folder: ', folder.title, ' quiz: ', folderQuizzes); addFolderTitleToQuizzes(folderQuizzes, folder.title); quizzes = quizzes.concat(folderQuizzes as QuizType[]); } setQuizzes(quizzes as QuizType[]); } else { console.log('show some quizzes'); const folderQuizzes = await ApiService.getFolderContent(selectedFolderId); addFolderTitleToQuizzes(folderQuizzes, selectedFolderId); 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 { // questions[i] = QuestionService.ignoreImgTags(questions[i]); const parsedItem = parse(questions[i]); Template(parsedItem[0]); // eslint-disable-next-line @typescript-eslint/no-unused-vars } 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 = ''; 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 () => { try { const folderTitle = prompt('Titre du dossier'); if (folderTitle) { await ApiService.createFolder(folderTitle); const userFolders = await ApiService.getUserFolders(); setFolders(userFolders as FolderType[]); const newlyCreatedFolder = userFolders[userFolders.length - 1] as FolderType; setSelectedFolderId(newlyCreatedFolder._id); } } catch (error) { console.error('Error creating folder:', error); } }; const handleDeleteFolder = async () => { try { const confirmed = window.confirm('Voulez-vous vraiment supprimer ce dossier?'); if (confirmed) { await ApiService.deleteFolder(selectedFolderId); const userFolders = await ApiService.getUserFolders(); setFolders(userFolders as FolderType[]); } const folders = await ApiService.getUserFolders(); // HACK force user folders to load on first load console.log('show all quizzes'); let quizzes: QuizType[] = []; 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[]); setSelectedFolderId(''); } catch (error) { console.error('Error deleting folder:', error); } }; const handleRenameFolder = async () => { try { // folderId: string GET THIS FROM CURRENT FOLDER // currentTitle: string GET THIS FROM CURRENT FOLDER const newTitle = prompt( 'Entrée le nouveau nom du fichier', folders.find((folder) => folder._id === selectedFolderId)?.title ); if (newTitle) { const renamedFolderId = selectedFolderId; const result = await ApiService.renameFolder(selectedFolderId, newTitle); if (result !== true) { window.alert(`Une erreur est survenue: ${result}`); return; } const userFolders = await ApiService.getUserFolders(); setFolders(userFolders as FolderType[]); // refresh the page setSelectedFolderId(''); setSelectedFolderId(renamedFolderId); } } catch (error) { console.error('Error renaming folder:', error); alert('Erreur lors du renommage du dossier: ' + error); } }; const handleDuplicateFolder = async () => { try { // folderId: string GET THIS FROM CURRENT FOLDER await ApiService.duplicateFolder(selectedFolderId); // TODO set the selected folder to be the duplicated folder const userFolders = await ApiService.getUserFolders(); setFolders(userFolders as FolderType[]); const newlyCreatedFolder = userFolders[userFolders.length - 1] as FolderType; setSelectedFolderId(newlyCreatedFolder._id); } 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 (
Tableau de bord
{/* */}
{selectedRoom && (

Salle sélectionnée: {selectedRoom.title}

)} setOpenAddRoomDialog(false)}> Créer une nouvelle salle setNewRoomTitle(e.target.value)} fullWidth />
) }} />
{folders.map((folder: FolderType) => ( ))}
{' '} {' '} {' '} {' '} {' '} {' '} {' '} {' '}
{Object.keys(quizzesByFolder).map((folderName) => (
{folderName}
{quizzesByFolder[folderName].map((quiz: QuizType) => (
downloadTxtFile(quiz)} > {' '} {' '} handleEditQuiz(quiz)} > {' '} {' '} handleDuplicateQuiz(quiz)} > {' '} {' '} handleRemoveQuiz(quiz)} > {' '} {' '} handleShareQuiz(quiz)} > {' '} {' '}
))}
))}
setShowImportModal(false)} handleOnImport={handleOnImport} selectedFolder={selectedFolderId} />
); }; export default Dashboard; 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}`); }); }