diff --git a/client/src/__tests__/components/ShareQuizModal/ShareQuizModal.test.tsx b/client/src/__tests__/components/ShareQuizModal/ShareQuizModal.test.tsx index 2a878a5..7027eaf 100644 --- a/client/src/__tests__/components/ShareQuizModal/ShareQuizModal.test.tsx +++ b/client/src/__tests__/components/ShareQuizModal/ShareQuizModal.test.tsx @@ -1,74 +1,81 @@ import React from 'react'; -import { render, fireEvent, screen, waitFor } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import ShareQuizModal from '../../../components/ShareQuizModal/ShareQuizModal'; +import { render, screen, fireEvent, act } from '@testing-library/react'; +import ShareQuizModal from '../../../components/ShareQuizModal/ShareQuizModal.tsx'; import { QuizType } from '../../../Types/QuizType'; -import ApiService from '../../../services/ApiService'; - -jest.mock('../../../services/ApiService'); - -Object.assign(navigator, { - clipboard: { - writeText: jest.fn().mockResolvedValue(undefined), - }, -}); - -window.alert = jest.fn(); - -const mockQuiz: QuizType = { - _id: '1', - title: 'Sample Quiz', - content: ['::Question 1:: What is 2+2? {=4 ~3 ~5}'], - folderId: 'folder1', - folderName: 'Sample Folder', - userId: 'user1', - created_at: new Date(), - updated_at: new Date(), -}; +import '@testing-library/jest-dom'; describe('ShareQuizModal', () => { + const mockQuiz: QuizType = { + _id: '123', + folderId: 'folder-123', + folderName: 'Test Folder', + userId: 'user-123', + title: 'Test Quiz', + content: ['Question 1', 'Question 2'], + created_at: new Date(), + updated_at: new Date(), + }; + beforeAll(() => { + // Properly mock the clipboard API + Object.defineProperty(navigator, 'clipboard', { + value: { + writeText: jest.fn().mockImplementation(() => Promise.resolve()), + }, + writable: true, + }); + }); - beforeEach(() => { - jest.clearAllMocks(); - }); + afterEach(() => { + jest.clearAllMocks(); + }); - it('should call ApiService.ShareQuiz when sharing by email', async () => { - render(); + it('renders the share button', () => { + render(); + expect(screen.getByLabelText('partager quiz')).toBeInTheDocument(); + expect(screen.getByTestId('ShareIcon')).toBeInTheDocument(); + }); - const shareButton = screen.getByRole('button', { name: /partager quiz/i }); - fireEvent.click(shareButton); + it('copies the quiz URL to clipboard when share button is clicked', async () => { + render(); + const shareButton = screen.getByLabelText('partager quiz'); + + await act(async () => { + fireEvent.click(shareButton); + }); + + expect(navigator.clipboard.writeText).toHaveBeenCalledWith( + `${window.location.origin}/teacher/share/${mockQuiz._id}` + ); + + // Check for feedback dialog content + expect(screen.getByText(/L'URL de partage pour le quiz/i)).toBeInTheDocument(); + expect(screen.getByText(mockQuiz.title)).toBeInTheDocument(); + expect(screen.getByText(/a été copiée\./i)).toBeInTheDocument(); + }); - const emailButton = screen.getByRole('button', { name: /partager par email/i }); - fireEvent.click(emailButton); - - const email = 'test@example.com'; - window.prompt = jest.fn().mockReturnValue(email); - - await fireEvent.click(emailButton); - - expect(ApiService.ShareQuiz).toHaveBeenCalledWith(mockQuiz._id, email); - }); - - it('copies the correct URL to the clipboard when sharing by URL', async () => { - render(); - - // Open the modal - const shareButton = screen.getByRole('button', { name: /partager quiz/i }); - fireEvent.click(shareButton); - - // Click the "Share by URL" button - const shareByUrlButton = screen.getByRole('button', { name: /partager par url/i }); - fireEvent.click(shareByUrlButton); - - // Check if the correct URL was copied - const expectedUrl = `${window.location.origin}/teacher/share/${mockQuiz._id}`; - expect(navigator.clipboard.writeText).toHaveBeenCalledWith(expectedUrl); - - // Check if the alert is shown - await waitFor(() => { - expect(window.alert).toHaveBeenCalledWith('URL a été copiée avec succès.'); - }); - }); + it('shows error message when clipboard write fails', async () => { + // Override the mock to reject + (navigator.clipboard.writeText as jest.Mock).mockRejectedValueOnce(new Error('Clipboard write failed')); + + render(); + const shareButton = screen.getByLabelText('partager quiz'); + + await act(async () => { + fireEvent.click(shareButton); + }); + + expect(screen.getByText(/Une erreur est survenue lors de la copie de l'URL\./i)).toBeInTheDocument(); + }); + it('displays the quiz title in the success message', async () => { + render(); + const shareButton = screen.getByLabelText('partager quiz'); + + await act(async () => { + fireEvent.click(shareButton); + }); + + expect(screen.getByText(mockQuiz.title)).toBeInTheDocument(); + }); }); \ No newline at end of file diff --git a/client/src/components/ShareQuizModal/ShareQuizModal.tsx b/client/src/components/ShareQuizModal/ShareQuizModal.tsx index 336aadb..7d752bc 100644 --- a/client/src/components/ShareQuizModal/ShareQuizModal.tsx +++ b/client/src/components/ShareQuizModal/ShareQuizModal.tsx @@ -1,67 +1,90 @@ import React, { useState } from 'react'; -import { Dialog, DialogTitle, DialogActions, Button, Tooltip, IconButton } from '@mui/material'; +import { Dialog, DialogTitle, DialogActions, Button, Tooltip, IconButton, Typography, Box } from '@mui/material'; import { Share } from '@mui/icons-material'; import { QuizType } from '../../Types/QuizType'; -import ApiService from '../../services/ApiService'; interface ShareQuizModalProps { quiz: QuizType; } const ShareQuizModal: React.FC = ({ quiz }) => { - const [open, setOpen] = useState(false); - - const handleOpenModal = () => setOpen(true); + const [_open, setOpen] = useState(false); + const [feedback, setFeedback] = useState({ + open: false, + title: '', + isError: false + }); const handleCloseModal = () => setOpen(false); - const handleShareByEmail = async () => { - const email = prompt(`Veuillez saisir l'email de la personne avec qui vous souhaitez partager ce quiz`, ""); - - if (email) { - try { - 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); - } - } - - handleCloseModal(); - }; - const handleShareByUrl = () => { const quizUrl = `${window.location.origin}/teacher/share/${quiz._id}`; navigator.clipboard.writeText(quizUrl) .then(() => { - window.alert('URL a été copiée avec succès.'); + setFeedback({ + open: true, + title: 'L\'URL de partage pour le quiz', + isError: false + }); }) .catch(() => { - window.alert('Une erreur est survenue lors de la copie de l\'URL.'); + setFeedback({ + open: true, + title: 'Une erreur est survenue lors de la copie de l\'URL.', + isError: true + }); }); handleCloseModal(); }; + const closeFeedback = () => { + setFeedback(prev => ({ ...prev, open: false })); + }; + return ( <> - - + + - - Choisissez une méthode de partage - - - + {/* Feedback Dialog */} + + + + {feedback.isError ? ( + + {feedback.title} + + ) : ( + <> + + L'URL de partage pour le quiz{' '} + + + {quiz.title} + + + {' '}a été copiée. + + + )} + + + + diff --git a/client/src/pages/Teacher/Dashboard/Dashboard.tsx b/client/src/pages/Teacher/Dashboard/Dashboard.tsx index d319515..3d4cc65 100644 --- a/client/src/pages/Teacher/Dashboard/Dashboard.tsx +++ b/client/src/pages/Teacher/Dashboard/Dashboard.tsx @@ -564,7 +564,7 @@ const Dashboard: React.FC = () => { {quizzesByFolder[folderName].map((quiz: QuizType) => (
- +
- + downloadTxtFile(quiz)} @@ -590,7 +590,7 @@ const Dashboard: React.FC = () => { - + handleEditQuiz(quiz)} @@ -600,7 +600,7 @@ const Dashboard: React.FC = () => { - + handleDuplicateQuiz(quiz)} @@ -610,7 +610,7 @@ const Dashboard: React.FC = () => { - + { const [quizTitle, setQuizTitle] = useState(''); const [selectedFolder, setSelectedFolder] = useState(''); - const [folders, setFolders] = useState([]); + const [quizExists, setQuizExists] = useState(false); + const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { - if (!id) { - window.alert(`Une erreur est survenue.\n Le quiz n'a pas été trouvé\nVeuillez réessayer plus tard`) - console.error('Quiz not found for id:', id); + try { + if (!id) { + window.alert(`Une erreur est survenue.\n Le quiz n'a pas été trouvé\nVeuillez réessayer plus tard`) + console.error('Quiz not found for id:', id); + navigate('/teacher/dashboard'); + return; + } + + if (!ApiService.isLoggedIn()) { + window.alert(`Vous n'êtes pas connecté.\nVeuillez vous connecter et revenir à ce lien`); + navigate("/login"); + return; + } + + const quizIds = await ApiService.getAllQuizIds(); + + if (quizIds.includes(id)) { + setQuizExists(true); + setLoading(false); + return; + } + + const userFolders = await ApiService.getUserFolders(); + + if (userFolders.length == 0) { + window.alert(`Vous n'avez aucun dossier.\nVeuillez en créer un et revenir à ce lien`) + navigate('/teacher/dashboard'); + return; + } + + setFolders(userFolders as FolderType[]); + + const title = await ApiService.getSharedQuiz(id); + + if (!title) { + window.alert(`Une erreur est survenue.\n Veuillez réessayer plus tard`) + console.error('Quiz not found for id:', id); + navigate('/teacher/dashboard'); + return; + } + + setQuizTitle(title); + setLoading(false); + } catch (error) { + console.error('Error fetching data:', error); + setLoading(false); navigate('/teacher/dashboard'); - return; } - - if (!ApiService.isLoggedIn()) { - window.alert(`Vous n'êtes pas connecté.\nVeuillez vous connecter et revenir à ce lien`); - navigate("/login"); - return; - } - - const quizIds = await ApiService.getAllQuizIds(); - - if (quizIds.includes(id)) { - window.alert(`Le quiz que vous essayez d'importer existe déjà sur votre compte.`) - navigate('/teacher/dashboard'); - return; - } - - const userFolders = await ApiService.getUserFolders(); - - if (userFolders.length == 0) { - window.alert(`Vous n'avez aucun dossier.\nVeuillez en créer un et revenir à ce lien`) - navigate('/teacher/dashboard'); - return; - } - - setFolders(userFolders as FolderType[]); - - const title = await ApiService.getSharedQuiz(id); - - if (!title) { - window.alert(`Une erreur est survenue.\n Veuillez réessayer plus tard`) - console.error('Quiz not found for id:', id); - navigate('/teacher/dashboard'); - return; - } - - setQuizTitle(title); }; fetchData(); - }, []); + }, [id, navigate]); const handleSelectFolder = (event: React.ChangeEvent) => { setSelectedFolder(event.target.value); @@ -69,7 +77,6 @@ const Share: React.FC = () => { const handleQuizSave = async () => { try { - if (selectedFolder == '') { alert("Veuillez choisir un dossier"); return; @@ -91,41 +98,87 @@ const Share: React.FC = () => { } }; + if (loading) { + return
Chargement...
; + } + + if (quizExists) { + return ( +
+
+ +
+
Quiz déjà existant
+
+
+
+ +
+ + + Le quiz que vous essayez d'importer existe déjà sur votre compte. + + + + + + Si vous souhaitiez créer une copie de ce quiz, + vous pouvez utiliser la fonction "Dupliquer" disponible + dans votre tableau de bord. + + +
+
+ ); + } + return ( -
-
- -
-
Importation du Quiz: {quizTitle}
-
- Vous êtes sur le point d'importer le quiz {quizTitle}, choisissez un dossier dans lequel enregistrer ce nouveau quiz. +
+
+ +
+
Importation du Quiz: {quizTitle}
+
+ Vous êtes sur le point d'importer le quiz {quizTitle}, choisissez un dossier dans lequel enregistrer ce nouveau quiz. +
+
+
+
+ +
+
+ + + {folders.map((folder: FolderType) => ( + + ))} + + + +
-
-
- -
-
- - - {folders.map((folder: FolderType) => ( - - ))} - - - -
-
-
); }; -export default Share; +export default Share; \ No newline at end of file