Compare commits

...

4 commits

Author SHA1 Message Date
lanahria
312164b0c2
Merge 36d0755105 into ee7a7a0544 2025-03-28 19:25:21 +00:00
Ana-Lucia Munteanu
36d0755105 Modèle de questions dans un dropdown 2025-03-28 15:24:58 -04:00
Ana-Lucia Munteanu
d6508826fc Changing header file encoding
Logout -> Déconnexion
2025-03-16 17:30:41 -04:00
Ana-Lucia Munteanu
b00985a8a3 Ajouté boutons copy
Ajouté les boutons en haut de la page suite à la demande de Geneviève
2025-03-16 13:18:30 -04:00
5 changed files with 98 additions and 48 deletions

View file

@ -16,7 +16,7 @@
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@mui/icons-material": "^6.4.6", "@mui/icons-material": "^6.4.6",
"@mui/lab": "^5.0.0-alpha.153", "@mui/lab": "^5.0.0-alpha.153",
"@mui/material": "^6.4.6", "@mui/material": "^6.4.9",
"@types/uuid": "^9.0.7", "@types/uuid": "^9.0.7",
"axios": "^1.8.1", "axios": "^1.8.1",
"dompurify": "^3.2.3", "dompurify": "^3.2.3",
@ -2044,7 +2044,6 @@
"version": "11.14.0", "version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.3", "@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5", "@emotion/babel-plugin": "^11.13.5",
@ -2087,7 +2086,6 @@
"version": "11.14.0", "version": "11.14.0",
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz",
"integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.3", "@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5", "@emotion/babel-plugin": "^11.13.5",
@ -3397,10 +3395,9 @@
} }
}, },
"node_modules/@mui/core-downloads-tracker": { "node_modules/@mui/core-downloads-tracker": {
"version": "6.4.6", "version": "6.4.9",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.9.tgz",
"integrity": "sha512-rho5Q4IscbrVmK9rCrLTJmjLjfH6m/NcqKr/mchvck0EIXlyYUB9+Z0oVmkt/+Mben43LMRYBH8q/Uzxj/c4Vw==", "integrity": "sha512-3UvsvOjqZJcokHKSzA1lskj2XMM/G5GBgge6ykwmAij2pGGxydGxAXirQlLaeoMwTKDS6BcrLqPZyPVwzri20A==",
"license": "MIT",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/mui-org" "url": "https://opencollective.com/mui-org"
@ -3474,16 +3471,15 @@
} }
}, },
"node_modules/@mui/material": { "node_modules/@mui/material": {
"version": "6.4.6", "version": "6.4.9",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.9.tgz",
"integrity": "sha512-6UyAju+DBOdMogfYmLiT3Nu7RgliorimNBny1pN/acOjc+THNFVE7hlxLyn3RDONoZJNDi/8vO4AQQr6dLAXqA==", "integrity": "sha512-+5dExw9xUUFujIW889gB3qrfjeNo3YjYW7aWVZ6BlBIJnKpJ0jNcYZJpBUFoXt/FUV5Wy1V+/+XzR3Is2mXX2w==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/core-downloads-tracker": "^6.4.6", "@mui/core-downloads-tracker": "^6.4.9",
"@mui/system": "^6.4.6", "@mui/system": "^6.4.9",
"@mui/types": "^7.2.21", "@mui/types": "~7.2.24",
"@mui/utils": "^6.4.6", "@mui/utils": "^6.4.8",
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.12", "@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -3502,7 +3498,7 @@
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.5.0", "@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.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", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"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" "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
@ -3523,13 +3519,12 @@
} }
}, },
"node_modules/@mui/material/node_modules/@mui/private-theming": { "node_modules/@mui/material/node_modules/@mui/private-theming": {
"version": "6.4.6", "version": "6.4.8",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.8.tgz",
"integrity": "sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==", "integrity": "sha512-sWwQoNSn6elsPTAtSqCf+w5aaGoh7AASURNmpy+QTTD/zwJ0Jgwt0ZaaP6mXq2IcgHxYnYloM/+vJgHPMkRKTQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/utils": "^6.4.6", "@mui/utils": "^6.4.8",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
}, },
"engines": { "engines": {
@ -3550,10 +3545,9 @@
} }
}, },
"node_modules/@mui/material/node_modules/@mui/styled-engine": { "node_modules/@mui/material/node_modules/@mui/styled-engine": {
"version": "6.4.6", "version": "6.4.9",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.9.tgz",
"integrity": "sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==", "integrity": "sha512-qZRWO0cT407NI4ZRjZcH+1SOu8f3JzLHqdMlg52GyEufM9pkSZFnf7xjpwnlvkixcGjco6wLlMD0VB43KRcBuA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@emotion/cache": "^11.13.5", "@emotion/cache": "^11.13.5",
@ -3584,16 +3578,15 @@
} }
}, },
"node_modules/@mui/material/node_modules/@mui/system": { "node_modules/@mui/material/node_modules/@mui/system": {
"version": "6.4.6", "version": "6.4.9",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.9.tgz",
"integrity": "sha512-FQjWwPec7pMTtB/jw5f9eyLynKFZ6/Ej9vhm5kGdtmts1z5b7Vyn3Rz6kasfYm1j2TfrfGnSXRvvtwVWxjpz6g==", "integrity": "sha512-JOj7efXGtZn+NIzX8KDyMpO1QKc0DhilPBsxvci1xAvI1e5AtAtfzrEuV5ZvN+lz2BDuzngCWlllnqQ/cg40RQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/private-theming": "^6.4.6", "@mui/private-theming": "^6.4.8",
"@mui/styled-engine": "^6.4.6", "@mui/styled-engine": "^6.4.9",
"@mui/types": "^7.2.21", "@mui/types": "~7.2.24",
"@mui/utils": "^6.4.6", "@mui/utils": "^6.4.8",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"csstype": "^3.1.3", "csstype": "^3.1.3",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
@ -3624,13 +3617,12 @@
} }
}, },
"node_modules/@mui/material/node_modules/@mui/utils": { "node_modules/@mui/material/node_modules/@mui/utils": {
"version": "6.4.6", "version": "6.4.8",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.8.tgz",
"integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==", "integrity": "sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "@babel/runtime": "^7.26.0",
"@mui/types": "^7.2.21", "@mui/types": "~7.2.24",
"@types/prop-types": "^15.7.14", "@types/prop-types": "^15.7.14",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
@ -3753,10 +3745,9 @@
} }
}, },
"node_modules/@mui/types": { "node_modules/@mui/types": {
"version": "7.2.21", "version": "7.2.24",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz", "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz",
"integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==", "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==",
"license": "MIT",
"peerDependencies": { "peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
}, },

View file

@ -20,7 +20,7 @@
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@mui/icons-material": "^6.4.6", "@mui/icons-material": "^6.4.6",
"@mui/lab": "^5.0.0-alpha.153", "@mui/lab": "^5.0.0-alpha.153",
"@mui/material": "^6.4.6", "@mui/material": "^6.4.9",
"@types/uuid": "^9.0.7", "@types/uuid": "^9.0.7",
"axios": "^1.8.1", "axios": "^1.8.1",
"dompurify": "^3.2.3", "dompurify": "^3.2.3",

View file

@ -29,7 +29,7 @@ const Header: React.FC<HeaderProps> = ({ isLoggedIn, handleLogout }) => {
navigate('/'); navigate('/');
}} }}
> >
Logout <p>Déconnexion</p>
</Button> </Button>
)} )}

View file

@ -11,7 +11,7 @@ import GIFTTemplatePreview from 'src/components/GiftTemplate/GIFTTemplatePreview
import { QuizType } from '../../../Types/QuizType'; import { QuizType } from '../../../Types/QuizType';
import './editorQuiz.css'; 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 ReturnButton from 'src/components/ReturnButton/ReturnButton';
import ApiService from '../../../services/ApiService'; import ApiService from '../../../services/ApiService';
@ -41,11 +41,26 @@ const QuizForm: React.FC = () => {
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
const [dialogOpen, setDialogOpen] = useState(false); const [dialogOpen, setDialogOpen] = useState(false);
const [showScrollButton, setShowScrollButton] = useState(false); const [showScrollButton, setShowScrollButton] = useState(false);
const [copySuccess, setCopySuccess] = useState<string | null>(null);
const scrollToTop = () => { const scrollToTop = () => {
window.scrollTo({ top: 0, behavior: 'smooth' }); 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(() => { useEffect(() => {
const handleScroll = () => { const handleScroll = () => {
if (window.scrollY > 300) { if (window.scrollY > 300) {
@ -204,6 +219,18 @@ const QuizForm: React.FC = () => {
navigator.clipboard.writeText(link); 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 ( return (
<div className='quizEditor'> <div className='quizEditor'>
@ -243,9 +270,29 @@ const QuizForm: React.FC = () => {
))} ))}
</NativeSelect></label> </NativeSelect></label>
<Button variant="contained" onClick={handleQuizSave}> <div className='sticky-buttons'>
Enregistrer <Select
</Button> value=""
displayEmpty
onChange={(e) => handleSelectChange(e.target.value, templates.find(t => t.value === e.target.value)?.label || '')}
style={{ width: '210px' }}
>
<MenuItem value="" disabled>Modèles de questions</MenuItem>
{templates.map((template, index) => (
<MenuItem key={index} value={template.value}>{template.label}</MenuItem>
))}
</Select>
<Button variant="contained" onClick={handleQuizSave}>Enregistrer</Button>
</div>
<Snackbar
open={!!copySuccess}
autoHideDuration={3000}
onClose={() => setCopySuccess(null)}
message={copySuccess}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
key={copySuccess ? 'open' : 'close'}
/>
<Divider style={{ margin: '16px 0' }} /> <Divider style={{ margin: '16px 0' }} />

View file

@ -83,3 +83,15 @@ input[type="file"] {
overflow: auto; 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;
}