diff --git a/client/package-lock.json b/client/package-lock.json index e2c6890..318f26e 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -16,7 +16,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@mui/icons-material": "^6.4.6", "@mui/lab": "^5.0.0-alpha.153", - "@mui/material": "^6.4.6", + "@mui/material": "^6.4.9", "@types/uuid": "^9.0.7", "axios": "^1.8.1", "dompurify": "^3.2.3", @@ -2044,7 +2044,6 @@ "version": "11.14.0", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", - "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -2087,7 +2086,6 @@ "version": "11.14.0", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", - "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -3397,10 +3395,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.6.tgz", - "integrity": "sha512-rho5Q4IscbrVmK9rCrLTJmjLjfH6m/NcqKr/mchvck0EIXlyYUB9+Z0oVmkt/+Mben43LMRYBH8q/Uzxj/c4Vw==", - "license": "MIT", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.9.tgz", + "integrity": "sha512-3UvsvOjqZJcokHKSzA1lskj2XMM/G5GBgge6ykwmAij2pGGxydGxAXirQlLaeoMwTKDS6BcrLqPZyPVwzri20A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" @@ -3474,16 +3471,15 @@ } }, "node_modules/@mui/material": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.6.tgz", - "integrity": "sha512-6UyAju+DBOdMogfYmLiT3Nu7RgliorimNBny1pN/acOjc+THNFVE7hlxLyn3RDONoZJNDi/8vO4AQQr6dLAXqA==", - "license": "MIT", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.9.tgz", + "integrity": "sha512-+5dExw9xUUFujIW889gB3qrfjeNo3YjYW7aWVZ6BlBIJnKpJ0jNcYZJpBUFoXt/FUV5Wy1V+/+XzR3Is2mXX2w==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.4.6", - "@mui/system": "^6.4.6", - "@mui/types": "^7.2.21", - "@mui/utils": "^6.4.6", + "@mui/core-downloads-tracker": "^6.4.9", + "@mui/system": "^6.4.9", + "@mui/types": "~7.2.24", + "@mui/utils": "^6.4.8", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", @@ -3502,7 +3498,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.4.6", + "@mui/material-pigment-css": "^6.4.9", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -3523,13 +3519,12 @@ } }, "node_modules/@mui/material/node_modules/@mui/private-theming": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.6.tgz", - "integrity": "sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==", - "license": "MIT", + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.8.tgz", + "integrity": "sha512-sWwQoNSn6elsPTAtSqCf+w5aaGoh7AASURNmpy+QTTD/zwJ0Jgwt0ZaaP6mXq2IcgHxYnYloM/+vJgHPMkRKTQ==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.4.6", + "@mui/utils": "^6.4.8", "prop-types": "^15.8.1" }, "engines": { @@ -3550,10 +3545,9 @@ } }, "node_modules/@mui/material/node_modules/@mui/styled-engine": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.6.tgz", - "integrity": "sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==", - "license": "MIT", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.9.tgz", + "integrity": "sha512-qZRWO0cT407NI4ZRjZcH+1SOu8f3JzLHqdMlg52GyEufM9pkSZFnf7xjpwnlvkixcGjco6wLlMD0VB43KRcBuA==", "dependencies": { "@babel/runtime": "^7.26.0", "@emotion/cache": "^11.13.5", @@ -3584,16 +3578,15 @@ } }, "node_modules/@mui/material/node_modules/@mui/system": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.6.tgz", - "integrity": "sha512-FQjWwPec7pMTtB/jw5f9eyLynKFZ6/Ej9vhm5kGdtmts1z5b7Vyn3Rz6kasfYm1j2TfrfGnSXRvvtwVWxjpz6g==", - "license": "MIT", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.9.tgz", + "integrity": "sha512-JOj7efXGtZn+NIzX8KDyMpO1QKc0DhilPBsxvci1xAvI1e5AtAtfzrEuV5ZvN+lz2BDuzngCWlllnqQ/cg40RQ==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.4.6", - "@mui/styled-engine": "^6.4.6", - "@mui/types": "^7.2.21", - "@mui/utils": "^6.4.6", + "@mui/private-theming": "^6.4.8", + "@mui/styled-engine": "^6.4.9", + "@mui/types": "~7.2.24", + "@mui/utils": "^6.4.8", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -3624,13 +3617,12 @@ } }, "node_modules/@mui/material/node_modules/@mui/utils": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz", - "integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==", - "license": "MIT", + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.8.tgz", + "integrity": "sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/types": "^7.2.21", + "@mui/types": "~7.2.24", "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -3753,10 +3745,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.21", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz", - "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==", - "license": "MIT", + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, diff --git a/client/package.json b/client/package.json index b6d62e4..0709fc8 100644 --- a/client/package.json +++ b/client/package.json @@ -20,7 +20,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@mui/icons-material": "^6.4.6", "@mui/lab": "^5.0.0-alpha.153", - "@mui/material": "^6.4.6", + "@mui/material": "^6.4.9", "@types/uuid": "^9.0.7", "axios": "^1.8.1", "dompurify": "^3.2.3", diff --git a/client/src/__tests__/pages/Teacher/EditorQuiz/EditorQuiz.test.tsx b/client/src/__tests__/pages/Teacher/EditorQuiz/EditorQuiz.test.tsx index bf9125e..be16435 100644 --- a/client/src/__tests__/pages/Teacher/EditorQuiz/EditorQuiz.test.tsx +++ b/client/src/__tests__/pages/Teacher/EditorQuiz/EditorQuiz.test.tsx @@ -60,3 +60,21 @@ describe('QuizForm Component', () => { }); }); + +test('template-select is present', async () => { + render( + + + + ); + + expect(screen.queryByText('Modèles de questions')).toBeInTheDocument(); + const templateButton = screen.getByTestId('template-select'); + fireEvent.mouseDown(templateButton); + + await waitFor(() => { + const vraiFauxTemplate = screen.queryAllByText(/Vrai\/Faux/i); + expect(vraiFauxTemplate.length).toBeGreaterThan(0); + }); + +}); diff --git a/client/src/components/Header/Header.tsx b/client/src/components/Header/Header.tsx index 016d23e..d69d9a0 100644 --- a/client/src/components/Header/Header.tsx +++ b/client/src/components/Header/Header.tsx @@ -29,7 +29,7 @@ const Header: React.FC = ({ isLoggedIn, handleLogout }) => { navigate('/'); }} > - Logout +

Déconnexion

)} diff --git a/client/src/pages/Teacher/EditorQuiz/EditorQuiz.tsx b/client/src/pages/Teacher/EditorQuiz/EditorQuiz.tsx index 89f822a..319ca4c 100644 --- a/client/src/pages/Teacher/EditorQuiz/EditorQuiz.tsx +++ b/client/src/pages/Teacher/EditorQuiz/EditorQuiz.tsx @@ -11,7 +11,7 @@ import GIFTTemplatePreview from 'src/components/GiftTemplate/GIFTTemplatePreview import { QuizType } from '../../../Types/QuizType'; import './editorQuiz.css'; -import { Button, TextField, NativeSelect, Divider, Dialog, DialogTitle, DialogActions, DialogContent } from '@mui/material'; +import { Button, TextField, NativeSelect, Divider, Dialog, DialogTitle, DialogActions, DialogContent, MenuItem, Select, Snackbar } from '@mui/material'; import ReturnButton from 'src/components/ReturnButton/ReturnButton'; import ApiService from '../../../services/ApiService'; @@ -41,11 +41,26 @@ const QuizForm: React.FC = () => { const fileInputRef = useRef(null); const [dialogOpen, setDialogOpen] = useState(false); const [showScrollButton, setShowScrollButton] = useState(false); + const [copySuccess, setCopySuccess] = useState(null); const scrollToTop = () => { window.scrollTo({ top: 0, behavior: 'smooth' }); }; + const QuestionVraiFaux = "::Exemple de question vrai/faux:: \n 2+2 \\= 4 ? {T} //Utilisez les valeurs {T}, {F}, {TRUE} et {FALSE}."; + const QuestionChoixMul = "::Ville capitale du Canada:: \nQuelle ville est la capitale du Canada? {\n~ Toronto\n~ Montréal\n= Ottawa #Rétroaction spécifique.\n} // Commentaire non visible (au besoin)"; + const QuestionChoixMulMany = "::Villes canadiennes:: \n Quelles villes trouve-t-on au Canada? { \n~ %33.3% Montréal \n ~ %33.3% Ottawa \n ~ %33.3% Vancouver \n ~ %-100% New York \n ~ %-100% Paris \n#### Rétroaction globale de la question. \n} // Utilisez tilde (signe de vague) pour toutes les réponses. // On doit indiquer le pourcentage de chaque réponse."; + const QuestionCourte = "::Clé et porte:: \n Avec quoi ouvre-t-on une porte? { \n= clé \n= clef \n} // Permet de fournir plusieurs bonnes réponses. // Note: La casse n'est pas prise en compte."; + const QuestionNum = "::Question numérique avec marge:: \nQuel est un nombre de 1 à 5 ? {\n#3:2\n}\n \n// Plage mathématique spécifiée avec des points de fin d'intervalle. \n ::Question numérique avec plage:: \n Quel est un nombre de 1 à 5 ? {\n#1..5\n} \n\n// Réponses numériques multiples avec crédit partiel et commentaires.\n::Question numérique avec plusieurs réponses::\nQuand est né Ulysses S. Grant ? {\n# =1822:0 # Correct ! Crédit complet. \n=%50%1822:2 # Il est né en 1822. Demi-crédit pour être proche.\n}"; + + const templates = [ + { label: 'Vrai/Faux', value: QuestionVraiFaux }, + { label: 'Choix multiples R1', value: QuestionChoixMul }, + { label: 'Choix multiples R2+', value: QuestionChoixMulMany }, + { label: 'Réponse courte', value: QuestionCourte }, + { label: 'Numérique', value: QuestionNum }, + ]; + useEffect(() => { const handleScroll = () => { if (window.scrollY > 300) { @@ -204,6 +219,18 @@ const QuizForm: React.FC = () => { navigator.clipboard.writeText(link); } + const copyToClipboard = (text: string, label: string) => { + navigator.clipboard.writeText(text) + .then(() => { + setCopySuccess(`Copié dans le presse-papier: ${label}`); + }) + .catch((error) => console.error('Clipboard error:', error)); + }; + + const handleSelectChange = (value: string, label: string) => { + copyToClipboard(value, label); + }; + return (
@@ -243,9 +270,33 @@ const QuizForm: React.FC = () => { ))} - +
+ + +
+ + setCopySuccess(null)} + message={copySuccess} + anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} + key={copySuccess ? 'open' : 'close'} + /> diff --git a/client/src/pages/Teacher/EditorQuiz/editorQuiz.css b/client/src/pages/Teacher/EditorQuiz/editorQuiz.css index 79157ff..f2c173c 100644 --- a/client/src/pages/Teacher/EditorQuiz/editorQuiz.css +++ b/client/src/pages/Teacher/EditorQuiz/editorQuiz.css @@ -83,3 +83,15 @@ input[type="file"] { overflow: auto; } + +.sticky-buttons { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; + position: sticky; + top: 0; + background: #fff; + z-index: 1000; + padding: 8px 0; +}