mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Compare commits
No commits in common. "99c64321052f645b2a7988c752d52045852c2335" and "e03da0c808a6aa289a9cfc1cae31ea5d65a828bd" have entirely different histories.
99c6432105
...
e03da0c808
26 changed files with 335 additions and 647 deletions
208
client/package-lock.json
generated
208
client/package-lock.json
generated
|
|
@ -53,7 +53,6 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
||||||
"@typescript-eslint/parser": "^8.25.0",
|
"@typescript-eslint/parser": "^8.25.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.21.0",
|
||||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||||
"eslint-plugin-jest": "^28.11.0",
|
"eslint-plugin-jest": "^28.11.0",
|
||||||
|
|
@ -2537,7 +2536,7 @@
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz",
|
||||||
"integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
|
"integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint-visitor-keys": "^3.4.3"
|
"eslint-visitor-keys": "^3.4.3"
|
||||||
|
|
@ -2556,7 +2555,7 @@
|
||||||
"version": "4.12.1",
|
"version": "4.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
|
||||||
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
|
"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||||
|
|
@ -2566,7 +2565,7 @@
|
||||||
"version": "0.19.2",
|
"version": "0.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
|
||||||
"integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
|
"integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/object-schema": "^2.1.6",
|
"@eslint/object-schema": "^2.1.6",
|
||||||
|
|
@ -2581,7 +2580,7 @@
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
|
|
@ -2592,7 +2591,7 @@
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
|
|
@ -2605,7 +2604,7 @@
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz",
|
||||||
"integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
|
"integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/json-schema": "^7.0.15"
|
"@types/json-schema": "^7.0.15"
|
||||||
|
|
@ -2618,7 +2617,7 @@
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz",
|
||||||
"integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
|
"integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
|
|
@ -2642,7 +2641,7 @@
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
|
|
@ -2653,7 +2652,7 @@
|
||||||
"version": "14.0.0",
|
"version": "14.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
|
@ -2666,7 +2665,7 @@
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
|
|
@ -2679,7 +2678,7 @@
|
||||||
"version": "9.21.0",
|
"version": "9.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
|
||||||
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
|
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|
@ -2689,7 +2688,7 @@
|
||||||
"version": "2.1.6",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
|
||||||
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
|
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|
@ -2699,7 +2698,7 @@
|
||||||
"version": "0.2.7",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz",
|
||||||
"integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
|
"integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/core": "^0.12.0",
|
"@eslint/core": "^0.12.0",
|
||||||
|
|
@ -2806,7 +2805,7 @@
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||||
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
|
"integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.18.0"
|
"node": ">=18.18.0"
|
||||||
|
|
@ -2816,7 +2815,7 @@
|
||||||
"version": "0.16.6",
|
"version": "0.16.6",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
|
||||||
"integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
|
"integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@humanfs/core": "^0.19.1",
|
"@humanfs/core": "^0.19.1",
|
||||||
|
|
@ -2830,7 +2829,7 @@
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
|
||||||
"integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
|
"integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.18"
|
"node": ">=18.18"
|
||||||
|
|
@ -2844,7 +2843,7 @@
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||||
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
|
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.22"
|
"node": ">=12.22"
|
||||||
|
|
@ -2858,7 +2857,7 @@
|
||||||
"version": "0.4.2",
|
"version": "0.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
|
||||||
"integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
|
"integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.18"
|
"node": ">=18.18"
|
||||||
|
|
@ -3860,6 +3859,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3873,6 +3873,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3886,6 +3887,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3899,6 +3901,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3912,6 +3915,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3925,6 +3929,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3938,6 +3943,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3951,6 +3957,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3964,6 +3971,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3977,6 +3985,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -3990,6 +3999,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4003,6 +4013,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4016,6 +4027,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4029,6 +4041,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4042,6 +4055,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4055,6 +4069,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4068,6 +4083,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4081,6 +4097,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4094,6 +4111,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4134,7 +4152,7 @@
|
||||||
"version": "1.11.5",
|
"version": "1.11.5",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.5.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.5.tgz",
|
||||||
"integrity": "sha512-EVY7zfpehxhTZXOfy508gb3D78ihoGGmvyiTWtlBPjgIaidP1Xw0naHMD78CWiFlZmeDjKXJufGtsEGOnZdmNA==",
|
"integrity": "sha512-EVY7zfpehxhTZXOfy508gb3D78ihoGGmvyiTWtlBPjgIaidP1Xw0naHMD78CWiFlZmeDjKXJufGtsEGOnZdmNA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -4176,6 +4194,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4192,6 +4211,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4208,6 +4228,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4224,6 +4245,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4240,6 +4262,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4256,6 +4279,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4272,6 +4296,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4288,6 +4313,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4304,6 +4330,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4320,6 +4347,7 @@
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0 AND MIT",
|
"license": "Apache-2.0 AND MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|
@ -4333,14 +4361,14 @@
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||||
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
|
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@swc/types": {
|
"node_modules/@swc/types": {
|
||||||
"version": "0.1.19",
|
"version": "0.1.19",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.19.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.19.tgz",
|
||||||
"integrity": "sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==",
|
"integrity": "sha512-WkAZaAfj44kh/UFdAQcrMP1I0nwRqpt27u+08LMBYMqmQfwwMofYoMh/48NGkMMRfC4ynpfwRbJuu8ErfNloeA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@swc/counter": "^0.1.3"
|
"@swc/counter": "^0.1.3"
|
||||||
|
|
@ -4534,6 +4562,7 @@
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/graceful-fs": {
|
"node_modules/@types/graceful-fs": {
|
||||||
|
|
@ -4640,7 +4669,7 @@
|
||||||
"version": "7.0.15",
|
"version": "7.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/katex": {
|
"node_modules/@types/katex": {
|
||||||
|
|
@ -4689,6 +4718,7 @@
|
||||||
"version": "18.3.18",
|
"version": "18.3.18",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
|
||||||
"integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==",
|
"integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
|
|
@ -5022,7 +5052,7 @@
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
|
|
@ -5056,7 +5086,7 @@
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
|
@ -5147,7 +5177,7 @@
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Python-2.0"
|
"license": "Python-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/aria-query": {
|
"node_modules/aria-query": {
|
||||||
|
|
@ -5533,7 +5563,7 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
|
|
@ -5868,7 +5898,7 @@
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/convert-source-map": {
|
"node_modules/convert-source-map": {
|
||||||
|
|
@ -5944,30 +5974,11 @@
|
||||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cross-env": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"cross-spawn": "^7.0.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"cross-env": "src/bin/cross-env.js",
|
|
||||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.14",
|
|
||||||
"npm": ">=6",
|
|
||||||
"yarn": ">=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
|
|
@ -6138,7 +6149,7 @@
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||||
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/deepmerge": {
|
"node_modules/deepmerge": {
|
||||||
|
|
@ -6704,7 +6715,7 @@
|
||||||
"version": "9.21.0",
|
"version": "9.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz",
|
||||||
"integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
|
"integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
|
|
@ -6934,7 +6945,7 @@
|
||||||
"version": "8.2.0",
|
"version": "8.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz",
|
||||||
"integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
|
"integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esrecurse": "^4.3.0",
|
"esrecurse": "^4.3.0",
|
||||||
|
|
@ -6951,7 +6962,7 @@
|
||||||
"version": "3.4.3",
|
"version": "3.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
||||||
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
|
@ -6964,7 +6975,7 @@
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
|
|
@ -6975,7 +6986,7 @@
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
||||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|
@ -6988,7 +6999,7 @@
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
|
|
@ -7001,7 +7012,7 @@
|
||||||
"version": "10.3.0",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
||||||
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
"integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.14.0",
|
||||||
|
|
@ -7019,7 +7030,7 @@
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
|
||||||
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
"integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
|
@ -7045,7 +7056,7 @@
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
|
||||||
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
|
"integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"estraverse": "^5.1.0"
|
"estraverse": "^5.1.0"
|
||||||
|
|
@ -7058,7 +7069,7 @@
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||||
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"estraverse": "^5.2.0"
|
"estraverse": "^5.2.0"
|
||||||
|
|
@ -7151,7 +7162,7 @@
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-glob": {
|
"node_modules/fast-glob": {
|
||||||
|
|
@ -7188,14 +7199,14 @@
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-levenshtein": {
|
"node_modules/fast-levenshtein": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
|
||||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fastq": {
|
"node_modules/fastq": {
|
||||||
|
|
@ -7236,7 +7247,7 @@
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
|
||||||
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
|
"integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flat-cache": "^4.0.0"
|
"flat-cache": "^4.0.0"
|
||||||
|
|
@ -7290,7 +7301,7 @@
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||||
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"locate-path": "^6.0.0",
|
"locate-path": "^6.0.0",
|
||||||
|
|
@ -7307,7 +7318,7 @@
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
|
||||||
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
|
"integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flatted": "^3.2.9",
|
"flatted": "^3.2.9",
|
||||||
|
|
@ -7321,7 +7332,7 @@
|
||||||
"version": "3.3.3",
|
"version": "3.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
|
|
@ -7386,6 +7397,7 @@
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
|
|
@ -7569,7 +7581,7 @@
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-glob": "^4.0.3"
|
"is-glob": "^4.0.3"
|
||||||
|
|
@ -7854,7 +7866,7 @@
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
|
|
@ -7900,7 +7912,7 @@
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||||
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.19"
|
"node": ">=0.8.19"
|
||||||
|
|
@ -8094,7 +8106,7 @@
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|
@ -8159,7 +8171,7 @@
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"is-extglob": "^2.1.1"
|
"is-extglob": "^2.1.1"
|
||||||
|
|
@ -8394,7 +8406,7 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/istanbul-lib-coverage": {
|
"node_modules/istanbul-lib-coverage": {
|
||||||
|
|
@ -9506,7 +9518,7 @@
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
|
|
@ -9576,7 +9588,7 @@
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/json-parse-even-better-errors": {
|
"node_modules/json-parse-even-better-errors": {
|
||||||
|
|
@ -9589,14 +9601,14 @@
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/json-stable-stringify-without-jsonify": {
|
"node_modules/json-stable-stringify-without-jsonify": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
|
||||||
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
|
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
|
|
@ -9656,7 +9668,7 @@
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"json-buffer": "3.0.1"
|
"json-buffer": "3.0.1"
|
||||||
|
|
@ -9686,7 +9698,7 @@
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
|
"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prelude-ls": "^1.2.1",
|
"prelude-ls": "^1.2.1",
|
||||||
|
|
@ -9706,7 +9718,7 @@
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"p-locate": "^5.0.0"
|
"p-locate": "^5.0.0"
|
||||||
|
|
@ -9743,7 +9755,7 @@
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/longest-streak": {
|
"node_modules/longest-streak": {
|
||||||
|
|
@ -10533,7 +10545,7 @@
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-int64": {
|
"node_modules/node-int64": {
|
||||||
|
|
@ -10715,7 +10727,7 @@
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
|
"integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deep-is": "^0.1.3",
|
"deep-is": "^0.1.3",
|
||||||
|
|
@ -10751,7 +10763,7 @@
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yocto-queue": "^0.1.0"
|
"yocto-queue": "^0.1.0"
|
||||||
|
|
@ -10767,7 +10779,7 @@
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
|
||||||
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"p-limit": "^3.0.2"
|
"p-limit": "^3.0.2"
|
||||||
|
|
@ -10835,7 +10847,7 @@
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
|
@ -10855,7 +10867,7 @@
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
|
@ -10999,6 +11011,7 @@
|
||||||
"version": "8.5.3",
|
"version": "8.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
|
||||||
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
|
@ -11027,6 +11040,7 @@
|
||||||
"version": "3.3.8",
|
"version": "3.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
|
@ -11045,7 +11059,7 @@
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
|
|
@ -11556,6 +11570,7 @@
|
||||||
"version": "4.34.8",
|
"version": "4.34.8",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz",
|
||||||
"integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
|
"integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.6"
|
"@types/estree": "1.0.6"
|
||||||
|
|
@ -11759,7 +11774,7 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"shebang-regex": "^3.0.0"
|
"shebang-regex": "^3.0.0"
|
||||||
|
|
@ -11772,7 +11787,7 @@
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
|
@ -11952,6 +11967,7 @@
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
|
"dev": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|
@ -12183,7 +12199,7 @@
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
|
@ -12467,7 +12483,7 @@
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
|
"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prelude-ls": "^1.2.1"
|
"prelude-ls": "^1.2.1"
|
||||||
|
|
@ -12580,6 +12596,7 @@
|
||||||
"version": "5.7.3",
|
"version": "5.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
||||||
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
|
|
@ -12825,7 +12842,7 @@
|
||||||
"version": "4.4.1",
|
"version": "4.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||||
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
|
|
@ -12914,6 +12931,7 @@
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
|
||||||
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
|
"integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
|
|
@ -13191,7 +13209,7 @@
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
|
|
@ -13295,7 +13313,7 @@
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||||
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
|
|
@ -13443,7 +13461,7 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,6 @@
|
||||||
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
||||||
"@typescript-eslint/parser": "^8.25.0",
|
"@typescript-eslint/parser": "^8.25.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.8.0",
|
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||||
"cross-env": "^7.0.3",
|
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.21.0",
|
||||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||||
"eslint-plugin-jest": "^28.11.0",
|
"eslint-plugin-jest": "^28.11.0",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import { AnswerType } from "src/pages/Student/JoinRoom/JoinRoom";
|
|
||||||
|
|
||||||
export interface Answer {
|
export interface Answer {
|
||||||
answer: AnswerType;
|
answer: string | number | boolean;
|
||||||
isCorrect: boolean;
|
isCorrect: boolean;
|
||||||
idQuestion: number;
|
idQuestion: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { act } from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { MultipleChoiceQuestion, parse } from 'gift-pegjs';
|
import { MultipleChoiceQuestion, parse } from 'gift-pegjs';
|
||||||
import MultipleChoiceQuestionDisplay from 'src/components/QuestionsDisplay/MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplay';
|
import MultipleChoiceQuestionDisplay from 'src/components/QuestionsDisplay/MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplay';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
const questions = parse(
|
const questions = parse(
|
||||||
`::Sample Question 1:: Question stem
|
`::Sample Question 1:: Question stem
|
||||||
|
|
@ -22,7 +21,7 @@ describe('MultipleChoiceQuestionDisplay', () => {
|
||||||
const TestWrapper = ({ showAnswer }: { showAnswer: boolean }) => {
|
const TestWrapper = ({ showAnswer }: { showAnswer: boolean }) => {
|
||||||
const [showAnswerState, setShowAnswerState] = useState(showAnswer);
|
const [showAnswerState, setShowAnswerState] = useState(showAnswer);
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType) => {
|
const handleOnSubmitAnswer = (answer: string) => {
|
||||||
mockHandleOnSubmitAnswer(answer);
|
mockHandleOnSubmitAnswer(answer);
|
||||||
setShowAnswerState(true);
|
setShowAnswerState(true);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import '@testing-library/jest-dom';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import TrueFalseQuestionDisplay from 'src/components/QuestionsDisplay/TrueFalseQuestionDisplay/TrueFalseQuestionDisplay';
|
import TrueFalseQuestionDisplay from 'src/components/QuestionsDisplay/TrueFalseQuestionDisplay/TrueFalseQuestionDisplay';
|
||||||
import { parse, TrueFalseQuestion } from 'gift-pegjs';
|
import { parse, TrueFalseQuestion } from 'gift-pegjs';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
describe('TrueFalseQuestion Component', () => {
|
describe('TrueFalseQuestion Component', () => {
|
||||||
const mockHandleSubmitAnswer = jest.fn();
|
const mockHandleSubmitAnswer = jest.fn();
|
||||||
|
|
@ -17,7 +16,7 @@ describe('TrueFalseQuestion Component', () => {
|
||||||
const TestWrapper = ({ showAnswer }: { showAnswer: boolean }) => {
|
const TestWrapper = ({ showAnswer }: { showAnswer: boolean }) => {
|
||||||
const [showAnswerState, setShowAnswerState] = useState(showAnswer);
|
const [showAnswerState, setShowAnswerState] = useState(showAnswer);
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType) => {
|
const handleOnSubmitAnswer = (answer: boolean) => {
|
||||||
mockHandleSubmitAnswer(answer);
|
mockHandleSubmitAnswer(answer);
|
||||||
setShowAnswerState(true);
|
setShowAnswerState(true);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { MemoryRouter } from 'react-router-dom';
|
||||||
import StudentModeQuiz from 'src/components/StudentModeQuiz/StudentModeQuiz';
|
import StudentModeQuiz from 'src/components/StudentModeQuiz/StudentModeQuiz';
|
||||||
import { BaseQuestion, parse } from 'gift-pegjs';
|
import { BaseQuestion, parse } from 'gift-pegjs';
|
||||||
import { QuestionType } from 'src/Types/QuestionType';
|
import { QuestionType } from 'src/Types/QuestionType';
|
||||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
|
||||||
|
|
||||||
const mockGiftQuestions = parse(
|
const mockGiftQuestions = parse(
|
||||||
`::Sample Question 1:: Sample Question 1 {=Option A ~Option B}
|
`::Sample Question 1:: Sample Question 1 {=Option A ~Option B}
|
||||||
|
|
@ -16,26 +15,21 @@ const mockQuestions: QuestionType[] = mockGiftQuestions.map((question, index) =>
|
||||||
if (question.type !== "Category")
|
if (question.type !== "Category")
|
||||||
question.id = (index + 1).toString();
|
question.id = (index + 1).toString();
|
||||||
const newMockQuestion = question;
|
const newMockQuestion = question;
|
||||||
return { question: newMockQuestion as BaseQuestion };
|
return {question : newMockQuestion as BaseQuestion};
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockSubmitAnswer = jest.fn();
|
const mockSubmitAnswer = jest.fn();
|
||||||
const mockDisconnectWebSocket = jest.fn();
|
const mockDisconnectWebSocket = jest.fn();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
// Clear local storage before each test
|
|
||||||
// localStorage.clear();
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<StudentModeQuiz
|
<StudentModeQuiz
|
||||||
questions={mockQuestions}
|
questions={mockQuestions}
|
||||||
answers={Array(mockQuestions.length).fill({} as AnswerSubmissionToBackendType)}
|
|
||||||
submitAnswer={mockSubmitAnswer}
|
submitAnswer={mockSubmitAnswer}
|
||||||
disconnectWebSocket={mockDisconnectWebSocket}
|
disconnectWebSocket={mockDisconnectWebSocket}
|
||||||
/>
|
/>
|
||||||
</MemoryRouter>
|
</MemoryRouter>);
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('StudentModeQuiz', () => {
|
describe('StudentModeQuiz', () => {
|
||||||
|
|
@ -57,49 +51,6 @@ describe('StudentModeQuiz', () => {
|
||||||
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
|
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles shows feedback for an already answered question', async () => {
|
|
||||||
// Answer the first question
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(screen.getByText('Option A'));
|
|
||||||
});
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(screen.getByText('Répondre'));
|
|
||||||
});
|
|
||||||
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
|
|
||||||
|
|
||||||
const firstButtonA = screen.getByRole("button", {name: '✅ A Option A'});
|
|
||||||
expect(firstButtonA).toBeInTheDocument();
|
|
||||||
expect(firstButtonA.querySelector('.selected')).toBeInTheDocument();
|
|
||||||
|
|
||||||
expect(screen.getByRole("button", {name: '❌ B Option B'})).toBeInTheDocument();
|
|
||||||
expect(screen.queryByText('Répondre')).not.toBeInTheDocument();
|
|
||||||
|
|
||||||
// Navigate to the next question
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(screen.getByText('Question suivante'));
|
|
||||||
});
|
|
||||||
expect(screen.getByText('Sample Question 2')).toBeInTheDocument();
|
|
||||||
expect(screen.getByText('Répondre')).toBeInTheDocument();
|
|
||||||
|
|
||||||
// Navigate back to the first question
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(screen.getByText('Question précédente'));
|
|
||||||
});
|
|
||||||
expect(await screen.findByText('Sample Question 1')).toBeInTheDocument();
|
|
||||||
|
|
||||||
// Since answers are mocked, the it doesn't recognize the question as already answered
|
|
||||||
// TODO these tests are partially faked, need to be fixed if we can mock the answers
|
|
||||||
// const buttonA = screen.getByRole("button", {name: '✅ A Option A'});
|
|
||||||
const buttonA = screen.getByRole("button", {name: 'A Option A'});
|
|
||||||
expect(buttonA).toBeInTheDocument();
|
|
||||||
// const buttonB = screen.getByRole("button", {name: '❌ B Option B'});
|
|
||||||
const buttonB = screen.getByRole("button", {name: 'B Option B'});
|
|
||||||
expect(buttonB).toBeInTheDocument();
|
|
||||||
// // "Option A" div inside the name of button should have selected class
|
|
||||||
// expect(buttonA.querySelector('.selected')).toBeInTheDocument();
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
test('handles quit button click', async () => {
|
test('handles quit button click', async () => {
|
||||||
act(() => {
|
act(() => {
|
||||||
fireEvent.click(screen.getByText('Quitter'));
|
fireEvent.click(screen.getByText('Quitter'));
|
||||||
|
|
@ -114,12 +65,16 @@ describe('StudentModeQuiz', () => {
|
||||||
});
|
});
|
||||||
act(() => {
|
act(() => {
|
||||||
fireEvent.click(screen.getByText('Répondre'));
|
fireEvent.click(screen.getByText('Répondre'));
|
||||||
});
|
});
|
||||||
act(() => {
|
act(() => {
|
||||||
fireEvent.click(screen.getByText('Question suivante'));
|
fireEvent.click(screen.getByText('Question suivante'));
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(screen.getByText('Sample Question 2')).toBeInTheDocument();
|
const sampleQuestionElements = screen.queryAllByText(/Sample question 2/i);
|
||||||
expect(screen.getByText('Répondre')).toBeInTheDocument();
|
expect(sampleQuestionElements.length).toBeGreaterThan(0);
|
||||||
|
expect(screen.getByText('V')).toBeInTheDocument();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,52 +3,41 @@ import React from 'react';
|
||||||
import { render, fireEvent, act } from '@testing-library/react';
|
import { render, fireEvent, act } from '@testing-library/react';
|
||||||
import { screen } from '@testing-library/dom';
|
import { screen } from '@testing-library/dom';
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
import { BaseQuestion, MultipleChoiceQuestion, parse } from 'gift-pegjs';
|
import { MultipleChoiceQuestion, parse } from 'gift-pegjs';
|
||||||
|
|
||||||
import TeacherModeQuiz from 'src/components/TeacherModeQuiz/TeacherModeQuiz';
|
import TeacherModeQuiz from 'src/components/TeacherModeQuiz/TeacherModeQuiz';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { QuestionType } from 'src/Types/QuestionType';
|
// import { mock } from 'node:test';
|
||||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
|
||||||
|
|
||||||
const mockGiftQuestions = parse(
|
const mockGiftQuestions = parse(
|
||||||
`::Sample Question 1:: Sample Question 1 {=Option A ~Option B}
|
`::Sample Question:: Sample Question {=Option A ~Option B}`);
|
||||||
|
|
||||||
::Sample Question 2:: Sample Question 2 {=Option A ~Option B}`);
|
|
||||||
|
|
||||||
const mockQuestions: QuestionType[] = mockGiftQuestions.map((question, index) => {
|
|
||||||
if (question.type !== "Category")
|
describe('TeacherModeQuiz', () => {
|
||||||
question.id = (index + 1).toString();
|
it ('renders the initial question as MultipleChoiceQuestion', () => {
|
||||||
const newMockQuestion = question;
|
expect(mockGiftQuestions[0].type).toBe('MC');
|
||||||
return {question : newMockQuestion as BaseQuestion};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('TeacherModeQuiz', () => {
|
|
||||||
|
|
||||||
|
|
||||||
let mockQuestion = mockQuestions[0].question as MultipleChoiceQuestion;
|
const mockQuestion = mockGiftQuestions[0] as MultipleChoiceQuestion;
|
||||||
mockQuestion.id = '1';
|
mockQuestion.id = '1';
|
||||||
|
|
||||||
const mockSubmitAnswer = jest.fn();
|
const mockSubmitAnswer = jest.fn();
|
||||||
const mockDisconnectWebSocket = jest.fn();
|
const mockDisconnectWebSocket = jest.fn();
|
||||||
|
|
||||||
let rerender: (ui: React.ReactElement) => void;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const utils = render(
|
render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<TeacherModeQuiz
|
<TeacherModeQuiz
|
||||||
questionInfos={{ question: mockQuestion }}
|
questionInfos={{ question: mockQuestion }}
|
||||||
answers={Array(mockQuestions.length).fill({} as AnswerSubmissionToBackendType)}
|
|
||||||
submitAnswer={mockSubmitAnswer}
|
submitAnswer={mockSubmitAnswer}
|
||||||
disconnectWebSocket={mockDisconnectWebSocket} />
|
disconnectWebSocket={mockDisconnectWebSocket} />
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
rerender = utils.rerender;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders the initial question', () => {
|
test('renders the initial question', () => {
|
||||||
|
|
||||||
expect(screen.getByText('Question 1')).toBeInTheDocument();
|
expect(screen.getByText('Question 1')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Sample Question 1')).toBeInTheDocument();
|
expect(screen.getByText('Sample Question')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Option A')).toBeInTheDocument();
|
expect(screen.getByText('Option A')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Option B')).toBeInTheDocument();
|
expect(screen.getByText('Option B')).toBeInTheDocument();
|
||||||
expect(screen.getByText('Quitter')).toBeInTheDocument();
|
expect(screen.getByText('Quitter')).toBeInTheDocument();
|
||||||
|
|
@ -64,51 +53,9 @@ describe('TeacherModeQuiz', () => {
|
||||||
fireEvent.click(screen.getByText('Répondre'));
|
fireEvent.click(screen.getByText('Répondre'));
|
||||||
});
|
});
|
||||||
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
|
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
|
||||||
|
expect(screen.getByText('Votre réponse est:')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles shows feedback for an already answered question', () => {
|
|
||||||
// Answer the first question
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(screen.getByText('Option A'));
|
|
||||||
});
|
|
||||||
act(() => {
|
|
||||||
fireEvent.click(screen.getByText('Répondre'));
|
|
||||||
});
|
|
||||||
expect(mockSubmitAnswer).toHaveBeenCalledWith('Option A', 1);
|
|
||||||
mockQuestion = mockQuestions[1].question as MultipleChoiceQuestion;
|
|
||||||
// Navigate to the next question by re-rendering with new props
|
|
||||||
act(() => {
|
|
||||||
rerender(
|
|
||||||
<MemoryRouter>
|
|
||||||
<TeacherModeQuiz
|
|
||||||
questionInfos={{ question: mockQuestion }}
|
|
||||||
answers={Array(mockQuestions.length).fill({} as AnswerSubmissionToBackendType)}
|
|
||||||
submitAnswer={mockSubmitAnswer}
|
|
||||||
disconnectWebSocket={mockDisconnectWebSocket}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
mockQuestion = mockQuestions[0].question as MultipleChoiceQuestion;
|
|
||||||
|
|
||||||
act(() => {
|
|
||||||
rerender(
|
|
||||||
<MemoryRouter>
|
|
||||||
<TeacherModeQuiz
|
|
||||||
questionInfos={{ question: mockQuestion }}
|
|
||||||
answers={Array(mockQuestions.length).fill({} as AnswerSubmissionToBackendType)}
|
|
||||||
submitAnswer={mockSubmitAnswer}
|
|
||||||
disconnectWebSocket={mockDisconnectWebSocket}
|
|
||||||
/>
|
|
||||||
</MemoryRouter>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if the feedback dialog is shown again
|
|
||||||
expect(screen.getByText('Rétroaction')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('handles disconnect button click', () => {
|
test('handles disconnect button click', () => {
|
||||||
act(() => {
|
act(() => {
|
||||||
fireEvent.click(screen.getByText('Quitter'));
|
fireEvent.click(screen.getByText('Quitter'));
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
//WebsocketService.test.tsx
|
//WebsocketService.test.tsx
|
||||||
import { BaseQuestion, parse } from 'gift-pegjs';
|
|
||||||
import WebsocketService from '../../services/WebsocketService';
|
import WebsocketService from '../../services/WebsocketService';
|
||||||
import { io, Socket } from 'socket.io-client';
|
import { io, Socket } from 'socket.io-client';
|
||||||
import { ENV_VARIABLES } from 'src/constants';
|
import { ENV_VARIABLES } from 'src/constants';
|
||||||
import { QuestionType } from 'src/Types/QuestionType';
|
|
||||||
|
|
||||||
jest.mock('socket.io-client');
|
jest.mock('socket.io-client');
|
||||||
|
|
||||||
|
|
@ -47,16 +45,10 @@ describe('WebSocketService', () => {
|
||||||
|
|
||||||
test('nextQuestion should emit next-question event with correct parameters', () => {
|
test('nextQuestion should emit next-question event with correct parameters', () => {
|
||||||
const roomName = 'testRoom';
|
const roomName = 'testRoom';
|
||||||
const mockGiftQuestions = parse('A {T}');
|
const question = { id: 1, text: 'Sample Question' };
|
||||||
const mockQuestions: QuestionType[] = mockGiftQuestions.map((question, index) => {
|
|
||||||
if (question.type !== "Category")
|
|
||||||
question.id = (index + 1).toString();
|
|
||||||
const newMockQuestion = question;
|
|
||||||
return {question : newMockQuestion as BaseQuestion};
|
|
||||||
});
|
|
||||||
mockSocket = WebsocketService.connect(ENV_VARIABLES.VITE_BACKEND_URL);
|
mockSocket = WebsocketService.connect(ENV_VARIABLES.VITE_BACKEND_URL);
|
||||||
WebsocketService.nextQuestion({roomName, questions: mockQuestions, questionIndex: 0, isLaunch: false});
|
WebsocketService.nextQuestion(roomName, question);
|
||||||
const question = mockQuestions[0];
|
|
||||||
expect(mockSocket.emit).toHaveBeenCalledWith('next-question', { roomName, question });
|
expect(mockSocket.emit).toHaveBeenCalledWith('next-question', { roomName, question });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,21 @@ import { Button } from '@mui/material';
|
||||||
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
||||||
import { MultipleChoiceQuestion } from 'gift-pegjs';
|
import { MultipleChoiceQuestion } from 'gift-pegjs';
|
||||||
import { StudentType } from 'src/Types/StudentType';
|
import { StudentType } from 'src/Types/StudentType';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: MultipleChoiceQuestion;
|
question: MultipleChoiceQuestion;
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
handleOnSubmitAnswer?: (answer: string) => void;
|
||||||
showAnswer?: boolean;
|
showAnswer?: boolean;
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
students?: StudentType[];
|
students?: StudentType[];
|
||||||
isDisplayOnly?: boolean;
|
isDisplayOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, students, isDisplayOnly, passedAnswer } = props;
|
const { question, showAnswer, handleOnSubmitAnswer, students, isDisplayOnly } = props;
|
||||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
|
const [answer, setAnswer] = useState<string>();
|
||||||
const [pickRates, setPickRates] = useState<number[]>([]);
|
const [pickRates, setPickRates] = useState<number[]>([]);
|
||||||
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
|
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
|
||||||
|
|
||||||
let disableButton = false;
|
|
||||||
if(handleOnSubmitAnswer === undefined){
|
|
||||||
disableButton = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOnClickAnswer = (choice: string) => {
|
const handleOnClickAnswer = (choice: string) => {
|
||||||
setAnswer(choice);
|
setAnswer(choice);
|
||||||
};
|
};
|
||||||
|
|
@ -54,25 +47,19 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (passedAnswer !== undefined) {
|
setAnswer(undefined);
|
||||||
setAnswer(passedAnswer);
|
calculatePickRates();
|
||||||
} else {
|
}, [students, question, showCorrectAnswers]);
|
||||||
setAnswer('');
|
|
||||||
calculatePickRates();
|
|
||||||
}
|
|
||||||
}, [passedAnswer, students, question, showCorrectAnswers]);
|
|
||||||
|
|
||||||
|
|
||||||
const alpha = Array.from(Array(26)).map((_e, i) => i + 65);
|
const alpha = Array.from(Array(26)).map((_e, i) => i + 65);
|
||||||
const alphabet = alpha.map((x) => String.fromCharCode(x));
|
const alphabet = alpha.map((x) => String.fromCharCode(x));
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<div className="question-container">
|
<div className="question-container">
|
||||||
<div className="question content">
|
<div className="question content">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedStem) }} />
|
||||||
</div>
|
</div>
|
||||||
<div className="choices-wrapper mb-1">
|
<div className="choices-wrapper mb-1">
|
||||||
|
|
||||||
{question.choices.map((choice, i) => {
|
{question.choices.map((choice, i) => {
|
||||||
const selected = answer === choice.formattedText.text ? 'selected' : '';
|
const selected = answer === choice.formattedText.text ? 'selected' : '';
|
||||||
const rateStyle = showCorrectAnswers ? {
|
const rateStyle = showCorrectAnswers ? {
|
||||||
|
|
@ -84,7 +71,6 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
{/* <Button
|
{/* <Button
|
||||||
variant="text"
|
variant="text"
|
||||||
className="button-wrapper"
|
className="button-wrapper"
|
||||||
disabled={disableButton}
|
|
||||||
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}>
|
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}>
|
||||||
{showAnswer? (<div> {(choice.isCorrect ? '✅' : '❌')}</div>)
|
{showAnswer? (<div> {(choice.isCorrect ? '✅' : '❌')}</div>)
|
||||||
:``}
|
:``}
|
||||||
|
|
@ -101,7 +87,6 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
className={`button-wrapper ${selected}`}
|
className={`button-wrapper ${selected}`}
|
||||||
disabled={disableButton}
|
|
||||||
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}
|
onClick={() => !showAnswer && handleOnClickAnswer(choice.formattedText.text)}
|
||||||
>
|
>
|
||||||
<div className={`circle ${selected}`}>{alphabet[i]}</div>
|
<div className={`circle ${selected}`}>{alphabet[i]}</div>
|
||||||
|
|
@ -136,9 +121,9 @@ const MultipleChoiceQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
answer !== "" && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
|
answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
|
||||||
}
|
}
|
||||||
disabled={answer === '' || answer === null}
|
disabled={answer === undefined}
|
||||||
>
|
>
|
||||||
Répondre
|
Répondre
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,21 +6,21 @@ import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemp
|
||||||
import { NumericalQuestion, SimpleNumericalAnswer, RangeNumericalAnswer, HighLowNumericalAnswer } from 'gift-pegjs';
|
import { NumericalQuestion, SimpleNumericalAnswer, RangeNumericalAnswer, HighLowNumericalAnswer } from 'gift-pegjs';
|
||||||
import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer, isMultipleNumericalAnswer } from 'gift-pegjs/typeGuards';
|
import { isSimpleNumericalAnswer, isRangeNumericalAnswer, isHighLowNumericalAnswer, isMultipleNumericalAnswer } from 'gift-pegjs/typeGuards';
|
||||||
import { StudentType } from 'src/Types/StudentType';
|
import { StudentType } from 'src/Types/StudentType';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: NumericalQuestion;
|
question: NumericalQuestion;
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
handleOnSubmitAnswer?: (answer: number) => void;
|
||||||
showAnswer?: boolean;
|
showAnswer?: boolean;
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
students?: StudentType[];
|
students?: StudentType[];
|
||||||
isDisplayOnly?: boolean;
|
isDisplayOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, isDisplayOnly } =
|
const { question, showAnswer, handleOnSubmitAnswer, students, isDisplayOnly } =
|
||||||
props;
|
props;
|
||||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
|
|
||||||
|
const [answer, setAnswer] = useState<number>();
|
||||||
|
|
||||||
const correctAnswers = question.choices;
|
const correctAnswers = question.choices;
|
||||||
let correctAnswer = '';
|
let correctAnswer = '';
|
||||||
|
|
||||||
|
|
@ -32,13 +32,10 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (passedAnswer !== null && passedAnswer !== undefined) {
|
|
||||||
setAnswer(passedAnswer);
|
|
||||||
}
|
|
||||||
if (showCorrectAnswers && students) {
|
if (showCorrectAnswers && students) {
|
||||||
calculateCorrectAnswerRate();
|
calculateCorrectAnswerRate();
|
||||||
}
|
}
|
||||||
}, [passedAnswer, showCorrectAnswers, students]);
|
}, [showCorrectAnswers, students]);
|
||||||
|
|
||||||
const calculateCorrectAnswerRate = () => {
|
const calculateCorrectAnswerRate = () => {
|
||||||
if (!students || students.length === 0) {
|
if (!students || students.length === 0) {
|
||||||
|
|
@ -78,16 +75,10 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
</div>
|
</div>
|
||||||
{showAnswer ? (
|
{showAnswer ? (
|
||||||
<>
|
<>
|
||||||
<div className="correct-answer-text mb-2">
|
<div className="correct-answer-text mb-2">{correctAnswer}</div>
|
||||||
<strong>La bonne réponse est: </strong>
|
|
||||||
{correctAnswer}</div>
|
|
||||||
<span>
|
|
||||||
<strong>Votre réponse est: </strong>{answer.toString()}
|
|
||||||
</span>
|
|
||||||
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|
@ -115,7 +106,7 @@ const NumericalQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
handleOnSubmitAnswer &&
|
handleOnSubmitAnswer &&
|
||||||
handleOnSubmitAnswer(answer)
|
handleOnSubmitAnswer(answer)
|
||||||
}
|
}
|
||||||
disabled={answer === "" || isNaN(answer as number)}
|
disabled={answer === undefined || isNaN(answer)}
|
||||||
>
|
>
|
||||||
Répondre
|
Répondre
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -5,19 +5,16 @@ import TrueFalseQuestionDisplay from './TrueFalseQuestionDisplay/TrueFalseQuesti
|
||||||
import MultipleChoiceQuestionDisplay from './MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplay';
|
import MultipleChoiceQuestionDisplay from './MultipleChoiceQuestionDisplay/MultipleChoiceQuestionDisplay';
|
||||||
import NumericalQuestionDisplay from './NumericalQuestionDisplay/NumericalQuestionDisplay';
|
import NumericalQuestionDisplay from './NumericalQuestionDisplay/NumericalQuestionDisplay';
|
||||||
import ShortAnswerQuestionDisplay from './ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplay';
|
import ShortAnswerQuestionDisplay from './ShortAnswerQuestionDisplay/ShortAnswerQuestionDisplay';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
// import useCheckMobileScreen from '../../services/useCheckMobileScreen';
|
// import useCheckMobileScreen from '../../services/useCheckMobileScreen';
|
||||||
|
|
||||||
import { StudentType } from '../../Types/StudentType';
|
import { StudentType } from '../../Types/StudentType';
|
||||||
|
|
||||||
interface QuestionProps {
|
interface QuestionProps {
|
||||||
question: Question;
|
question: Question;
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
handleOnSubmitAnswer?: (answer: string | number | boolean) => void;
|
||||||
showAnswer?: boolean;
|
showAnswer?: boolean;
|
||||||
students?: StudentType[];
|
students?: StudentType[];
|
||||||
isDisplayOnly?: boolean;
|
isDisplayOnly?: boolean;
|
||||||
answer?: AnswerType;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
const QuestionDisplay: React.FC<QuestionProps> = ({
|
const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
question,
|
question,
|
||||||
|
|
@ -25,7 +22,6 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
showAnswer,
|
showAnswer,
|
||||||
students,
|
students,
|
||||||
isDisplayOnly = false
|
isDisplayOnly = false
|
||||||
answer,
|
|
||||||
}) => {
|
}) => {
|
||||||
// const isMobile = useCheckMobileScreen();
|
// const isMobile = useCheckMobileScreen();
|
||||||
// const imgWidth = useMemo(() => {
|
// const imgWidth = useMemo(() => {
|
||||||
|
|
@ -42,12 +38,10 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
showAnswer={showAnswer}
|
showAnswer={showAnswer}
|
||||||
students={students}
|
students={students}
|
||||||
isDisplayOnly={isDisplayOnly}
|
isDisplayOnly={isDisplayOnly}
|
||||||
passedAnswer={answer}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'MC':
|
case 'MC':
|
||||||
|
|
||||||
questionTypeComponent = (
|
questionTypeComponent = (
|
||||||
<MultipleChoiceQuestionDisplay
|
<MultipleChoiceQuestionDisplay
|
||||||
question={question}
|
question={question}
|
||||||
|
|
@ -55,22 +49,32 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
showAnswer={showAnswer}
|
showAnswer={showAnswer}
|
||||||
students={students}
|
students={students}
|
||||||
isDisplayOnly={isDisplayOnly}
|
isDisplayOnly={isDisplayOnly}
|
||||||
passedAnswer={answer}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'Numerical':
|
case 'Numerical':
|
||||||
if (question.choices) {
|
if (question.choices) {
|
||||||
|
if (!Array.isArray(question.choices)) {
|
||||||
questionTypeComponent = (
|
questionTypeComponent = (
|
||||||
<NumericalQuestionDisplay
|
<NumericalQuestionDisplay
|
||||||
question={question}
|
question={question}
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
||||||
showAnswer={showAnswer}
|
showAnswer={showAnswer}
|
||||||
passedAnswer={answer}
|
|
||||||
students={students}
|
students={students}
|
||||||
isDisplayOnly={isDisplayOnly}
|
isDisplayOnly={isDisplayOnly}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
questionTypeComponent = ( // TODO fix NumericalQuestion (correctAnswers is borked)
|
||||||
|
<NumericalQuestionDisplay
|
||||||
|
question={question}
|
||||||
|
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
||||||
|
showAnswer={showAnswer}
|
||||||
|
students={students}
|
||||||
|
isDisplayOnly={isDisplayOnly}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Short':
|
case 'Short':
|
||||||
|
|
@ -81,7 +85,6 @@ const QuestionDisplay: React.FC<QuestionProps> = ({
|
||||||
showAnswer={showAnswer}
|
showAnswer={showAnswer}
|
||||||
students={students}
|
students={students}
|
||||||
isDisplayOnly={isDisplayOnly}
|
isDisplayOnly={isDisplayOnly}
|
||||||
passedAnswer={answer}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,21 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import '../questionStyle.css';
|
import '../questionStyle.css';
|
||||||
import { Button, TextField } from '@mui/material';
|
import { Button, TextField } from '@mui/material';
|
||||||
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
import { FormattedTextTemplate } from '../../GiftTemplate/templates/TextTypeTemplate';
|
||||||
import { ShortAnswerQuestion } from 'gift-pegjs';
|
import { ShortAnswerQuestion } from 'gift-pegjs';
|
||||||
import { StudentType } from 'src/Types/StudentType';
|
import { StudentType } from 'src/Types/StudentType';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: ShortAnswerQuestion;
|
question: ShortAnswerQuestion;
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
handleOnSubmitAnswer?: (answer: string) => void;
|
||||||
showAnswer?: boolean;
|
showAnswer?: boolean;
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
students?: StudentType[];
|
students?: StudentType[];
|
||||||
isDisplayOnly?: boolean;
|
isDisplayOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, isDisplayOnly } = props;
|
const { question, showAnswer, handleOnSubmitAnswer, students, isDisplayOnly } = props;
|
||||||
const [answer, setAnswer] = useState<AnswerType>(passedAnswer || '');
|
const [answer, setAnswer] = useState<string>();
|
||||||
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
|
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
|
||||||
const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0);
|
const [correctAnswerRate, setCorrectAnswerRate] = useState<number>(0);
|
||||||
|
|
||||||
|
|
@ -26,16 +24,10 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (passedAnswer !== undefined) {
|
|
||||||
setAnswer(passedAnswer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showCorrectAnswers && students) {
|
if (showCorrectAnswers && students) {
|
||||||
calculateCorrectAnswerRate();
|
calculateCorrectAnswerRate();
|
||||||
}
|
}
|
||||||
|
}, [showCorrectAnswers, students]);
|
||||||
}, [passedAnswer, showCorrectAnswers, students, answer]);
|
|
||||||
console.log("Answer", answer);
|
|
||||||
|
|
||||||
const calculateCorrectAnswerRate = () => {
|
const calculateCorrectAnswerRate = () => {
|
||||||
if (!students || students.length === 0) {
|
if (!students || students.length === 0) {
|
||||||
|
|
@ -60,18 +52,11 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
{showAnswer ? (
|
{showAnswer ? (
|
||||||
<>
|
<>
|
||||||
<div className="correct-answer-text mb-1">
|
<div className="correct-answer-text mb-1">
|
||||||
<span>
|
|
||||||
<strong>La bonne réponse est: </strong>
|
|
||||||
|
|
||||||
{question.choices.map((choice) => (
|
{question.choices.map((choice) => (
|
||||||
<div key={choice.text} className="mb-1">
|
<div key={choice.text} className="mb-1">
|
||||||
{choice.text}
|
{choice.text}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong>Votre réponse est: </strong>{answer}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
{question.formattedGlobalFeedback && <div className="global-feedback mb-2">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||||
|
|
@ -99,7 +84,7 @@ const ShortAnswerQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
handleOnSubmitAnswer &&
|
handleOnSubmitAnswer &&
|
||||||
handleOnSubmitAnswer(answer)
|
handleOnSubmitAnswer(answer)
|
||||||
}
|
}
|
||||||
disabled={answer === null || answer === ''}
|
disabled={answer === undefined || answer === ''}
|
||||||
>
|
>
|
||||||
Répondre
|
Répondre
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,29 @@
|
||||||
// TrueFalseQuestion.tsx
|
// TrueFalseQuestion.tsx
|
||||||
import React, { useState,useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import '../questionStyle.css';
|
import '../questionStyle.css';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { TrueFalseQuestion } from 'gift-pegjs';
|
import { TrueFalseQuestion } from 'gift-pegjs';
|
||||||
import { FormattedTextTemplate } from 'src/components/GiftTemplate/templates/TextTypeTemplate';
|
import { FormattedTextTemplate } from 'src/components/GiftTemplate/templates/TextTypeTemplate';
|
||||||
import { StudentType } from 'src/Types/StudentType';
|
import { StudentType } from 'src/Types/StudentType';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: TrueFalseQuestion;
|
question: TrueFalseQuestion;
|
||||||
handleOnSubmitAnswer?: (answer: AnswerType) => void;
|
handleOnSubmitAnswer?: (answer: boolean) => void;
|
||||||
showAnswer?: boolean;
|
showAnswer?: boolean;
|
||||||
passedAnswer?: AnswerType;
|
|
||||||
students?: StudentType[];
|
students?: StudentType[];
|
||||||
isDisplayOnly?: boolean;
|
isDisplayOnly?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
const { question, showAnswer, handleOnSubmitAnswer, students, passedAnswer, isDisplayOnly } = props;
|
const { question, showAnswer, handleOnSubmitAnswer, students, isDisplayOnly } = props;
|
||||||
const [answer, setAnswer] = useState<boolean | undefined>(undefined);
|
const [answer, setAnswer] = useState<boolean | undefined>(undefined);
|
||||||
const [pickRates, setPickRates] = useState<{ trueRate: number, falseRate: number }>({ trueRate: 0, falseRate: 0 });
|
const [pickRates, setPickRates] = useState<{ trueRate: number, falseRate: number }>({ trueRate: 0, falseRate: 0 });
|
||||||
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
|
const [showCorrectAnswers, setShowCorrectAnswers] = useState(false);
|
||||||
|
|
||||||
let disableButton = false;
|
|
||||||
if(handleOnSubmitAnswer === undefined){
|
|
||||||
disableButton = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOnClickAnswer = (choice: boolean) => {
|
|
||||||
setAnswer(choice);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("passedAnswer", passedAnswer);
|
setAnswer(undefined);
|
||||||
if (passedAnswer === true || passedAnswer === false) {
|
calculatePickRates();
|
||||||
setAnswer(passedAnswer);
|
}, [question, students]);
|
||||||
} else {
|
|
||||||
setAnswer(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!passedAnswer && passedAnswer !== false) {
|
|
||||||
setAnswer(undefined);
|
|
||||||
calculatePickRates();
|
|
||||||
}
|
|
||||||
}, [passedAnswer, question, students]);
|
|
||||||
|
|
||||||
const selectedTrue = answer ? 'selected' : '';
|
const selectedTrue = answer ? 'selected' : '';
|
||||||
const selectedFalse = answer !== undefined && !answer ? 'selected' : '';
|
const selectedFalse = answer !== undefined && !answer ? 'selected' : '';
|
||||||
|
|
@ -88,38 +68,28 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="choices-wrapper mb-1">
|
<div className="choices-wrapper mb-1">
|
||||||
<Button
|
<Button
|
||||||
className="button-wrapper"
|
className={`button-wrapper ${selectedTrue}`}
|
||||||
onClick={() => !showAnswer && handleOnClickAnswer(true)}
|
onClick={() => !showCorrectAnswers && setAnswer(true)}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={disableButton}
|
|
||||||
>
|
>
|
||||||
<div className={`circle ${selectedTrue}`}>V</div>
|
<div className={`circle ${selectedTrue}`}>V</div>
|
||||||
<div className={`answer-text ${selectedTrue}`}
|
<div
|
||||||
|
className={`answer-text ${selectedTrue}`}
|
||||||
style={showCorrectAnswers ? {
|
style={showCorrectAnswers ? {
|
||||||
backgroundImage: `linear-gradient(to right, ${question.isTrue ? 'lightgreen' : 'lightcoral'} ${pickRates.trueRate}%, transparent ${pickRates.trueRate}%)`
|
backgroundImage: `linear-gradient(to right, ${question.isTrue ? 'lightgreen' : 'lightcoral'} ${pickRates.trueRate}%, transparent ${pickRates.trueRate}%)`
|
||||||
} : {}}
|
} : {}}
|
||||||
>
|
>
|
||||||
Vrai
|
Vrai
|
||||||
</div>
|
</div>
|
||||||
|
{showCorrectAnswers && <div>{question.isTrue ? '✅' : '❌'}</div>}
|
||||||
{showCorrectAnswers && (
|
{showCorrectAnswers && (
|
||||||
<>
|
<div className="pick-rate">{pickRates.trueRate.toFixed(1)}%</div>
|
||||||
<div>{question.isTrue ? '✅' : '❌'}</div>
|
|
||||||
<div className="pick-rate">{pickRates.trueRate.toFixed(1)}%</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{showAnswer && answer && question.trueFormattedFeedback && (
|
|
||||||
<div className="true-feedback mb-2">
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.trueFormattedFeedback) }} />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className={`button-wrapper ${selectedFalse}`}
|
className={`button-wrapper ${selectedFalse}`}
|
||||||
onClick={() => !showCorrectAnswers && handleOnClickAnswer(false)}
|
onClick={() => !showCorrectAnswers && setAnswer(false)}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={disableButton}
|
|
||||||
|
|
||||||
>
|
>
|
||||||
<div className={`circle ${selectedFalse}`}>F</div>
|
<div className={`circle ${selectedFalse}`}>F</div>
|
||||||
<div
|
<div
|
||||||
|
|
@ -130,23 +100,26 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
>
|
>
|
||||||
Faux
|
Faux
|
||||||
</div>
|
</div>
|
||||||
|
{showCorrectAnswers && <div>{!question.isTrue ? '✅' : '❌'}</div>}
|
||||||
{showCorrectAnswers && (
|
{showCorrectAnswers && (
|
||||||
<>
|
<div className="pick-rate">{pickRates.falseRate.toFixed(1)}%</div>
|
||||||
<div>{!question.isTrue ? '✅' : '❌'}</div>
|
|
||||||
<div className="pick-rate">{pickRates.falseRate.toFixed(1)}%</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{showAnswer && !answer && question.falseFormattedFeedback && (
|
|
||||||
<div className="false-feedback mb-2">
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.falseFormattedFeedback) }} />
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{/* selected TRUE, show True feedback if it exists */}
|
||||||
|
{showAnswer && answer && question.trueFormattedFeedback && (
|
||||||
|
<div className="true-feedback mb-2">
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.trueFormattedFeedback) }} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* selected FALSE, show False feedback if it exists */}
|
||||||
|
{showAnswer && !answer && question.falseFormattedFeedback && (
|
||||||
|
<div className="false-feedback mb-2">
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.falseFormattedFeedback) }} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{question.formattedGlobalFeedback && showAnswer && (
|
{question.formattedGlobalFeedback && showAnswer && (
|
||||||
<div className="global-feedback mb-2">
|
<div className="global-feedback mb-2">
|
||||||
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
<div dangerouslySetInnerHTML={{ __html: FormattedTextTemplate(question.formattedGlobalFeedback) }} />
|
||||||
|
|
@ -157,7 +130,6 @@ const TrueFalseQuestionDisplay: React.FC<Props> = (props) => {
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
|
answer !== undefined && handleOnSubmitAnswer && handleOnSubmitAnswer(answer)
|
||||||
|
|
||||||
}
|
}
|
||||||
disabled={answer === undefined}
|
disabled={answer === undefined}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -147,25 +147,6 @@
|
||||||
box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
|
box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.true-feedback {
|
|
||||||
position: relative;
|
|
||||||
padding: 0 1rem;
|
|
||||||
background-color: hsl(43, 100%, 94%);
|
|
||||||
color: hsl(43, 95%, 9%);
|
|
||||||
border: hsl(36, 84%, 93%) 1px solid;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
|
|
||||||
}
|
|
||||||
.false-feedback {
|
|
||||||
position: relative;
|
|
||||||
padding: 0 1rem;
|
|
||||||
background-color: hsl(43, 100%, 94%);
|
|
||||||
color: hsl(43, 95%, 9%);
|
|
||||||
border: hsl(36, 84%, 93%) 1px solid;
|
|
||||||
border-radius: 6px;
|
|
||||||
box-shadow: 0px 2px 5px hsl(0, 0%, 74%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices-wrapper {
|
.choices-wrapper {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,47 +3,41 @@ import React, { useEffect, useState } from 'react';
|
||||||
import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
||||||
import '../../pages/Student/JoinRoom/joinRoom.css';
|
import '../../pages/Student/JoinRoom/joinRoom.css';
|
||||||
import { QuestionType } from '../../Types/QuestionType';
|
import { QuestionType } from '../../Types/QuestionType';
|
||||||
|
// import { QuestionService } from '../../services/QuestionService';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
//import QuestionNavigation from '../QuestionNavigation/QuestionNavigation';
|
//import QuestionNavigation from '../QuestionNavigation/QuestionNavigation';
|
||||||
|
//import { ChevronLeft, ChevronRight } from '@mui/icons-material';
|
||||||
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
||||||
import { Question } from 'gift-pegjs';
|
import { Question } from 'gift-pegjs';
|
||||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface StudentModeQuizProps {
|
interface StudentModeQuizProps {
|
||||||
questions: QuestionType[];
|
questions: QuestionType[];
|
||||||
answers: AnswerSubmissionToBackendType[];
|
submitAnswer: (_answer: string | number | boolean, _idQuestion: number) => void;
|
||||||
submitAnswer: (_answer: AnswerType, _idQuestion: number) => void;
|
|
||||||
disconnectWebSocket: () => void;
|
disconnectWebSocket: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
||||||
questions,
|
questions,
|
||||||
answers,
|
|
||||||
submitAnswer,
|
submitAnswer,
|
||||||
disconnectWebSocket
|
disconnectWebSocket
|
||||||
}) => {
|
}) => {
|
||||||
//Ajouter type AnswerQuestionType en remplacement de QuestionType
|
|
||||||
const [questionInfos, setQuestion] = useState<QuestionType>(questions[0]);
|
const [questionInfos, setQuestion] = useState<QuestionType>(questions[0]);
|
||||||
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
||||||
// const [answer, setAnswer] = useState<AnswerType>('');
|
// const [imageUrl, setImageUrl] = useState('');
|
||||||
|
|
||||||
|
|
||||||
const previousQuestion = () => {
|
// const previousQuestion = () => {
|
||||||
setQuestion(questions[Number(questionInfos.question?.id) - 2]);
|
// setQuestion(questions[Number(questionInfos.question?.id) - 2]);
|
||||||
};
|
// setIsAnswerSubmitted(false);
|
||||||
|
// };
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {}, [questionInfos]);
|
||||||
const savedAnswer = answers[Number(questionInfos.question.id)-1]?.answer;
|
|
||||||
console.log(`StudentModeQuiz: useEffect: savedAnswer: ${savedAnswer}`);
|
|
||||||
setIsAnswerSubmitted(savedAnswer !== undefined);
|
|
||||||
}, [questionInfos.question, answers]);
|
|
||||||
|
|
||||||
const nextQuestion = () => {
|
const nextQuestion = () => {
|
||||||
setQuestion(questions[Number(questionInfos.question?.id)]);
|
setQuestion(questions[Number(questionInfos.question?.id)]);
|
||||||
|
setIsAnswerSubmitted(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType) => {
|
const handleOnSubmitAnswer = (answer: string | number | boolean) => {
|
||||||
const idQuestion = Number(questionInfos.question.id) || -1;
|
const idQuestion = Number(questionInfos.question.id) || -1;
|
||||||
submitAnswer(answer, idQuestion);
|
submitAnswer(answer, idQuestion);
|
||||||
setIsAnswerSubmitted(true);
|
setIsAnswerSubmitted(true);
|
||||||
|
|
@ -52,13 +46,11 @@ const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
||||||
return (
|
return (
|
||||||
<div className='room'>
|
<div className='room'>
|
||||||
<div className='roomHeader'>
|
<div className='roomHeader'>
|
||||||
|
|
||||||
<DisconnectButton
|
<DisconnectButton
|
||||||
onReturn={disconnectWebSocket}
|
onReturn={disconnectWebSocket}
|
||||||
message={`Êtes-vous sûr de vouloir quitter?`} />
|
message={`Êtes-vous sûr de vouloir quitter?`} />
|
||||||
|
|
||||||
</div>
|
|
||||||
<div >
|
|
||||||
<b>Question {questionInfos.question.id}/{questions.length}</b>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="overflow-auto">
|
<div className="overflow-auto">
|
||||||
<div className="question-component-container">
|
<div className="question-component-container">
|
||||||
|
|
@ -74,30 +66,31 @@ const StudentModeQuiz: React.FC<StudentModeQuizProps> = ({
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
||||||
question={questionInfos.question as Question}
|
question={questionInfos.question as Question}
|
||||||
showAnswer={isAnswerSubmitted}
|
showAnswer={isAnswerSubmitted}
|
||||||
answer={answers[Number(questionInfos.question.id)-1]?.answer}
|
|
||||||
/>
|
/>
|
||||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: '1rem' }}>
|
<div className="center-h-align mt-1/2">
|
||||||
<div>
|
<div className="w-12">
|
||||||
<Button
|
{/* <Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
onClick={previousQuestion}
|
onClick={previousQuestion}
|
||||||
fullWidth
|
fullWidth
|
||||||
disabled={Number(questionInfos.question.id) <= 1}
|
startIcon={<ChevronLeft />}
|
||||||
>
|
disabled={Number(questionInfos.question.id) <= 1}
|
||||||
Question précédente
|
>
|
||||||
</Button>
|
Question précédente
|
||||||
|
</Button> */}
|
||||||
|
</div>
|
||||||
|
<div className="w-12">
|
||||||
|
<Button style={{ display: isAnswerSubmitted ? 'block' : 'none' }}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={nextQuestion}
|
||||||
|
fullWidth
|
||||||
|
//endIcon={<ChevronRight />}
|
||||||
|
disabled={Number(questionInfos.question.id) >= questions.length}
|
||||||
|
>
|
||||||
|
Question suivante
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
onClick={nextQuestion}
|
|
||||||
fullWidth
|
|
||||||
disabled={Number(questionInfos.question.id) >= questions.length}
|
|
||||||
>
|
|
||||||
Question suivante
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,55 @@
|
||||||
// TeacherModeQuiz.tsx
|
// TeacherModeQuiz.tsx
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
import QuestionComponent from '../QuestionsDisplay/QuestionDisplay';
|
||||||
|
|
||||||
import '../../pages/Student/JoinRoom/joinRoom.css';
|
import '../../pages/Student/JoinRoom/joinRoom.css';
|
||||||
import { QuestionType } from '../../Types/QuestionType';
|
import { QuestionType } from '../../Types/QuestionType';
|
||||||
|
// import { QuestionService } from '../../services/QuestionService';
|
||||||
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
import DisconnectButton from 'src/components/DisconnectButton/DisconnectButton';
|
||||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@mui/material';
|
||||||
import { Question } from 'gift-pegjs';
|
import { Question } from 'gift-pegjs';
|
||||||
import { AnswerSubmissionToBackendType } from 'src/services/WebsocketService';
|
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
// import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
interface TeacherModeQuizProps {
|
interface TeacherModeQuizProps {
|
||||||
questionInfos: QuestionType;
|
questionInfos: QuestionType;
|
||||||
answers: AnswerSubmissionToBackendType[];
|
submitAnswer: (_answer: string | number | boolean, _idQuestion: number) => void;
|
||||||
submitAnswer: (_answer: AnswerType, _idQuestion: number) => void;
|
|
||||||
disconnectWebSocket: () => void;
|
disconnectWebSocket: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
questionInfos,
|
questionInfos,
|
||||||
answers,
|
|
||||||
submitAnswer,
|
submitAnswer,
|
||||||
disconnectWebSocket
|
disconnectWebSocket
|
||||||
}) => {
|
}) => {
|
||||||
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
const [isAnswerSubmitted, setIsAnswerSubmitted] = useState(false);
|
||||||
const [isFeedbackDialogOpen, setIsFeedbackDialogOpen] = useState(false);
|
const [isFeedbackDialogOpen, setIsFeedbackDialogOpen] = useState(false);
|
||||||
const [answer, setAnswer] = useState<AnswerType>();
|
const [feedbackMessage, setFeedbackMessage] = useState<React.ReactNode>('');
|
||||||
|
|
||||||
|
const renderFeedbackMessage = (answer: string) => {
|
||||||
|
|
||||||
|
if(answer === 'true' || answer === 'false'){
|
||||||
// arrive here the first time after waiting for next question
|
return (<span>
|
||||||
|
<strong>Votre réponse est: </strong>{answer==="true" ? 'Vrai' : 'Faux'}
|
||||||
|
</span>)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<strong>Votre réponse est: </strong>{answer.toString()}
|
||||||
|
</span>
|
||||||
|
);}
|
||||||
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(`TeacherModeQuiz: useEffect: answers: ${JSON.stringify(answers)}`);
|
// Close the feedback dialog when the question changes
|
||||||
console.log(`TeacherModeQuiz: useEffect: questionInfos.question.id: ${questionInfos.question.id} answer: ${answer}`);
|
handleFeedbackDialogClose();
|
||||||
const oldAnswer = answers[Number(questionInfos.question.id) -1 ]?.answer;
|
setIsAnswerSubmitted(false);
|
||||||
console.log(`TeacherModeQuiz: useEffect: oldAnswer: ${oldAnswer}`);
|
|
||||||
setAnswer(oldAnswer);
|
}, [questionInfos.question]);
|
||||||
setIsFeedbackDialogOpen(false);
|
|
||||||
}, [questionInfos.question, answers]);
|
|
||||||
|
|
||||||
// handle showing the feedback dialog
|
const handleOnSubmitAnswer = (answer: string | number | boolean) => {
|
||||||
useEffect(() => {
|
|
||||||
console.log(`TeacherModeQuiz: useEffect: answer: ${answer}`);
|
|
||||||
setIsAnswerSubmitted(answer !== undefined);
|
|
||||||
setIsFeedbackDialogOpen(answer !== undefined);
|
|
||||||
}, [answer]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(`TeacherModeQuiz: useEffect: isAnswerSubmitted: ${isAnswerSubmitted}`);
|
|
||||||
setIsFeedbackDialogOpen(isAnswerSubmitted);
|
|
||||||
}, [isAnswerSubmitted]);
|
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType) => {
|
|
||||||
const idQuestion = Number(questionInfos.question.id) || -1;
|
const idQuestion = Number(questionInfos.question.id) || -1;
|
||||||
submitAnswer(answer, idQuestion);
|
submitAnswer(answer, idQuestion);
|
||||||
// setAnswer(answer);
|
setFeedbackMessage(renderFeedbackMessage(answer.toString()));
|
||||||
setIsFeedbackDialogOpen(true);
|
setIsFeedbackDialogOpen(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -64,21 +60,21 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='room'>
|
<div className='room'>
|
||||||
<div className='roomHeader'>
|
<div className='roomHeader'>
|
||||||
|
|
||||||
<DisconnectButton
|
<DisconnectButton
|
||||||
onReturn={disconnectWebSocket}
|
onReturn={disconnectWebSocket}
|
||||||
message={`Êtes-vous sûr de vouloir quitter?`} />
|
message={`Êtes-vous sûr de vouloir quitter?`} />
|
||||||
|
|
||||||
|
<div className='centerTitle'>
|
||||||
|
<div className='title'>Question {questionInfos.question.id}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='dumb'></div>
|
||||||
|
|
||||||
<div className='centerTitle'>
|
|
||||||
<div className='title'>Question {questionInfos.question.id}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='dumb'></div>
|
{isAnswerSubmitted ? (
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isAnswerSubmitted ? (
|
|
||||||
<div>
|
<div>
|
||||||
En attente pour la prochaine question...
|
En attente pour la prochaine question...
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -86,7 +82,6 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
<QuestionComponent
|
<QuestionComponent
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
||||||
question={questionInfos.question as Question}
|
question={questionInfos.question as Question}
|
||||||
answer={answer}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -97,21 +92,20 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
<DialogTitle>Rétroaction</DialogTitle>
|
<DialogTitle>Rétroaction</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div style={{
|
<div style={{
|
||||||
wordWrap: 'break-word',
|
wordWrap: 'break-word',
|
||||||
whiteSpace: 'pre-wrap',
|
whiteSpace: 'pre-wrap',
|
||||||
maxHeight: '400px',
|
maxHeight: '400px',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
}}>
|
}}>
|
||||||
<div style={{ textAlign: 'left', fontWeight: 'bold', marginTop: '10px' }}
|
{feedbackMessage}
|
||||||
>Question : </div>
|
<div style={{ textAlign: 'left', fontWeight: 'bold', marginTop: '10px'}}
|
||||||
|
>Question : </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<QuestionComponent
|
<QuestionComponent
|
||||||
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
handleOnSubmitAnswer={handleOnSubmitAnswer}
|
||||||
question={questionInfos.question as Question}
|
question={questionInfos.question as Question}
|
||||||
showAnswer={true}
|
showAnswer={true}
|
||||||
answer={answer}
|
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|
@ -120,7 +114,7 @@ const TeacherModeQuiz: React.FC<TeacherModeQuizProps> = ({
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@ import LoginContainer from 'src/components/LoginContainer/LoginContainer'
|
||||||
|
|
||||||
import ApiService from '../../../services/ApiService'
|
import ApiService from '../../../services/ApiService'
|
||||||
|
|
||||||
export type AnswerType = string | number | boolean;
|
|
||||||
|
|
||||||
const JoinRoom: React.FC = () => {
|
const JoinRoom: React.FC = () => {
|
||||||
const [roomName, setRoomName] = useState('');
|
const [roomName, setRoomName] = useState('');
|
||||||
const [username, setUsername] = useState(ApiService.getUsername());
|
const [username, setUsername] = useState(ApiService.getUsername());
|
||||||
|
|
@ -27,7 +25,6 @@ const JoinRoom: React.FC = () => {
|
||||||
const [question, setQuestion] = useState<QuestionType>();
|
const [question, setQuestion] = useState<QuestionType>();
|
||||||
const [quizMode, setQuizMode] = useState<string>();
|
const [quizMode, setQuizMode] = useState<string>();
|
||||||
const [questions, setQuestions] = useState<QuestionType[]>([]);
|
const [questions, setQuestions] = useState<QuestionType[]>([]);
|
||||||
const [answers, setAnswers] = useState<AnswerSubmissionToBackendType[]>([]);
|
|
||||||
const [connectionError, setConnectionError] = useState<string>('');
|
const [connectionError, setConnectionError] = useState<string>('');
|
||||||
const [isConnecting, setIsConnecting] = useState<boolean>(false);
|
const [isConnecting, setIsConnecting] = useState<boolean>(false);
|
||||||
|
|
||||||
|
|
@ -38,12 +35,6 @@ const JoinRoom: React.FC = () => {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(`JoinRoom: useEffect: questions: ${JSON.stringify(questions)}`);
|
|
||||||
setAnswers(questions ? Array(questions.length).fill({} as AnswerSubmissionToBackendType) : []);
|
|
||||||
}, [questions]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleCreateSocket = () => {
|
const handleCreateSocket = () => {
|
||||||
console.log(`JoinRoom: handleCreateSocket: ${ENV_VARIABLES.VITE_BACKEND_URL}`);
|
console.log(`JoinRoom: handleCreateSocket: ${ENV_VARIABLES.VITE_BACKEND_URL}`);
|
||||||
const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_URL);
|
const socket = webSocketService.connect(ENV_VARIABLES.VITE_BACKEND_URL);
|
||||||
|
|
@ -54,25 +45,16 @@ const JoinRoom: React.FC = () => {
|
||||||
console.log(`on(join-success): Successfully joined the room ${roomJoinedName}`);
|
console.log(`on(join-success): Successfully joined the room ${roomJoinedName}`);
|
||||||
});
|
});
|
||||||
socket.on('next-question', (question: QuestionType) => {
|
socket.on('next-question', (question: QuestionType) => {
|
||||||
console.log('JoinRoom: on(next-question): Received next-question:', question);
|
console.log('on(next-question): Received next-question:', question);
|
||||||
setQuizMode('teacher');
|
setQuizMode('teacher');
|
||||||
setIsWaitingForTeacher(false);
|
setIsWaitingForTeacher(false);
|
||||||
setQuestion(question);
|
setQuestion(question);
|
||||||
});
|
});
|
||||||
socket.on('launch-teacher-mode', (questions: QuestionType[]) => {
|
|
||||||
console.log('on(launch-teacher-mode): Received launch-teacher-mode:', questions);
|
|
||||||
setQuizMode('teacher');
|
|
||||||
setIsWaitingForTeacher(true);
|
|
||||||
setQuestions([]); // clear out from last time (in case quiz is repeated)
|
|
||||||
setQuestions(questions);
|
|
||||||
// wait for next-question
|
|
||||||
});
|
|
||||||
socket.on('launch-student-mode', (questions: QuestionType[]) => {
|
socket.on('launch-student-mode', (questions: QuestionType[]) => {
|
||||||
console.log('on(launch-student-mode): Received launch-student-mode:', questions);
|
console.log('on(launch-student-mode): Received launch-student-mode:', questions);
|
||||||
|
|
||||||
setQuizMode('student');
|
setQuizMode('student');
|
||||||
setIsWaitingForTeacher(false);
|
setIsWaitingForTeacher(false);
|
||||||
setQuestions([]); // clear out from last time (in case quiz is repeated)
|
|
||||||
setQuestions(questions);
|
setQuestions(questions);
|
||||||
setQuestion(questions[0]);
|
setQuestion(questions[0]);
|
||||||
});
|
});
|
||||||
|
|
@ -101,7 +83,6 @@ const JoinRoom: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const disconnect = () => {
|
const disconnect = () => {
|
||||||
// localStorage.clear();
|
|
||||||
webSocketService.disconnect();
|
webSocketService.disconnect();
|
||||||
setSocket(null);
|
setSocket(null);
|
||||||
setQuestion(undefined);
|
setQuestion(undefined);
|
||||||
|
|
@ -126,22 +107,14 @@ const JoinRoom: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnSubmitAnswer = (answer: AnswerType, idQuestion: number) => {
|
const handleOnSubmitAnswer = (answer: string | number | boolean, idQuestion: number) => {
|
||||||
console.info(`JoinRoom: handleOnSubmitAnswer: answer: ${answer}, idQuestion: ${idQuestion}`);
|
|
||||||
const answerData: AnswerSubmissionToBackendType = {
|
const answerData: AnswerSubmissionToBackendType = {
|
||||||
roomName: roomName,
|
roomName: roomName,
|
||||||
answer: answer,
|
answer: answer,
|
||||||
username: username,
|
username: username,
|
||||||
idQuestion: idQuestion
|
idQuestion: idQuestion
|
||||||
};
|
};
|
||||||
// localStorage.setItem(`Answer${idQuestion}`, JSON.stringify(answer));
|
|
||||||
setAnswers((prevAnswers) => {
|
|
||||||
console.log(`JoinRoom: handleOnSubmitAnswer: prevAnswers: ${JSON.stringify(prevAnswers)}`);
|
|
||||||
const newAnswers = [...prevAnswers]; // Create a copy of the previous answers array
|
|
||||||
newAnswers[idQuestion - 1] = answerData; // Update the specific answer
|
|
||||||
return newAnswers; // Return the new array
|
|
||||||
});
|
|
||||||
console.log(`JoinRoom: handleOnSubmitAnswer: answers: ${JSON.stringify(answers)}`);
|
|
||||||
webSocketService.submitAnswer(answerData);
|
webSocketService.submitAnswer(answerData);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -179,7 +152,6 @@ const JoinRoom: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<StudentModeQuiz
|
<StudentModeQuiz
|
||||||
questions={questions}
|
questions={questions}
|
||||||
answers={answers}
|
|
||||||
submitAnswer={handleOnSubmitAnswer}
|
submitAnswer={handleOnSubmitAnswer}
|
||||||
disconnectWebSocket={disconnect}
|
disconnectWebSocket={disconnect}
|
||||||
/>
|
/>
|
||||||
|
|
@ -189,7 +161,6 @@ const JoinRoom: React.FC = () => {
|
||||||
question && (
|
question && (
|
||||||
<TeacherModeQuiz
|
<TeacherModeQuiz
|
||||||
questionInfos={question}
|
questionInfos={question}
|
||||||
answers={answers}
|
|
||||||
submitAnswer={handleOnSubmitAnswer}
|
submitAnswer={handleOnSubmitAnswer}
|
||||||
disconnectWebSocket={disconnect}
|
disconnectWebSocket={disconnect}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import QuestionDisplay from 'src/components/QuestionsDisplay/QuestionDisplay';
|
||||||
import ApiService from '../../../services/ApiService';
|
import ApiService from '../../../services/ApiService';
|
||||||
import { QuestionType } from 'src/Types/QuestionType';
|
import { QuestionType } from 'src/Types/QuestionType';
|
||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
|
|
||||||
const ManageRoom: React.FC = () => {
|
const ManageRoom: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -36,40 +35,8 @@ const ManageRoom: React.FC = () => {
|
||||||
const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher');
|
const [quizMode, setQuizMode] = useState<'teacher' | 'student'>('teacher');
|
||||||
const [connectingError, setConnectingError] = useState<string>('');
|
const [connectingError, setConnectingError] = useState<string>('');
|
||||||
const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined);
|
const [currentQuestion, setCurrentQuestion] = useState<QuestionType | undefined>(undefined);
|
||||||
const [quizStarted, setQuizStarted] = useState<boolean>(false);
|
const [quizStarted, setQuizStarted] = useState(false);
|
||||||
const [formattedRoomName, setFormattedRoomName] = useState("");
|
const [formattedRoomName, setFormattedRoomName] = useState("");
|
||||||
const [newlyConnectedUser, setNewlyConnectedUser] = useState<StudentType | null>(null);
|
|
||||||
|
|
||||||
// Handle the newly connected user in useEffect, because it needs state info
|
|
||||||
// not available in the socket.on() callback
|
|
||||||
useEffect(() => {
|
|
||||||
if (newlyConnectedUser) {
|
|
||||||
console.log(`Handling newly connected user: ${newlyConnectedUser.name}`);
|
|
||||||
setStudents((prevStudents) => [...prevStudents, newlyConnectedUser]);
|
|
||||||
|
|
||||||
// only send nextQuestion if the quiz has started
|
|
||||||
if (!quizStarted) {
|
|
||||||
console.log(`!quizStarted: returning.... `);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quizMode === 'teacher') {
|
|
||||||
webSocketService.nextQuestion({
|
|
||||||
roomName: formattedRoomName,
|
|
||||||
questions: quizQuestions,
|
|
||||||
questionIndex: Number(currentQuestion?.question.id) - 1,
|
|
||||||
isLaunch: true // started late
|
|
||||||
});
|
|
||||||
} else if (quizMode === 'student') {
|
|
||||||
webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
|
|
||||||
} else {
|
|
||||||
console.error('Invalid quiz mode:', quizMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the newly connected user state
|
|
||||||
setNewlyConnectedUser(null);
|
|
||||||
}
|
|
||||||
}, [newlyConnectedUser]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const verifyLogin = async () => {
|
const verifyLogin = async () => {
|
||||||
|
|
@ -142,17 +109,6 @@ const ManageRoom: React.FC = () => {
|
||||||
const roomNameUpper = roomName.toUpperCase();
|
const roomNameUpper = roomName.toUpperCase();
|
||||||
setFormattedRoomName(roomNameUpper);
|
setFormattedRoomName(roomNameUpper);
|
||||||
console.log(`Creating WebSocket room named ${roomNameUpper}`);
|
console.log(`Creating WebSocket room named ${roomNameUpper}`);
|
||||||
|
|
||||||
/**
|
|
||||||
* ATTENTION: Lire les variables d'état dans
|
|
||||||
* les .on() n'est pas une bonne pratique.
|
|
||||||
* Les valeurs sont celles au moment de la création
|
|
||||||
* de la fonction et non au moment de l'exécution.
|
|
||||||
* Il faut utiliser des refs pour les valeurs qui
|
|
||||||
* changent fréquemment. Sinon, utiliser un trigger
|
|
||||||
* de useEffect pour mettre déclencher un traitement
|
|
||||||
* (voir user-joined plus bas).
|
|
||||||
*/
|
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
webSocketService.createRoom(roomNameUpper);
|
webSocketService.createRoom(roomNameUpper);
|
||||||
});
|
});
|
||||||
|
|
@ -167,9 +123,19 @@ const ManageRoom: React.FC = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('user-joined', (student: StudentType) => {
|
socket.on('user-joined', (student: StudentType) => {
|
||||||
setNewlyConnectedUser(student);
|
console.log(`Student joined: name = ${student.name}, id = ${student.id}, quizMode = ${quizMode}, quizStarted = ${quizStarted}`);
|
||||||
});
|
|
||||||
|
|
||||||
|
setStudents((prevStudents) => [...prevStudents, student]);
|
||||||
|
|
||||||
|
// only send nextQuestion if the quiz has started
|
||||||
|
if (!quizStarted) return;
|
||||||
|
|
||||||
|
if (quizMode === 'teacher') {
|
||||||
|
webSocketService.nextQuestion(formattedRoomName, currentQuestion);
|
||||||
|
} else if (quizMode === 'student') {
|
||||||
|
webSocketService.launchStudentModeQuiz(formattedRoomName, quizQuestions);
|
||||||
|
}
|
||||||
|
});
|
||||||
socket.on('join-failure', (message) => {
|
socket.on('join-failure', (message) => {
|
||||||
setConnectingError(message);
|
setConnectingError(message);
|
||||||
setSocket(null);
|
setSocket(null);
|
||||||
|
|
@ -258,10 +224,7 @@ const ManageRoom: React.FC = () => {
|
||||||
if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return;
|
if (nextQuestionIndex === undefined || nextQuestionIndex > quizQuestions.length - 1) return;
|
||||||
|
|
||||||
setCurrentQuestion(quizQuestions[nextQuestionIndex]);
|
setCurrentQuestion(quizQuestions[nextQuestionIndex]);
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName,
|
webSocketService.nextQuestion(formattedRoomName, quizQuestions[nextQuestionIndex]);
|
||||||
questions: quizQuestions,
|
|
||||||
questionIndex: nextQuestionIndex,
|
|
||||||
isLaunch: false});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const previousQuestion = () => {
|
const previousQuestion = () => {
|
||||||
|
|
@ -271,7 +234,7 @@ const ManageRoom: React.FC = () => {
|
||||||
|
|
||||||
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
|
if (prevQuestionIndex === undefined || prevQuestionIndex < 0) return;
|
||||||
setCurrentQuestion(quizQuestions[prevQuestionIndex]);
|
setCurrentQuestion(quizQuestions[prevQuestionIndex]);
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: prevQuestionIndex, isLaunch: false});
|
webSocketService.nextQuestion(formattedRoomName, quizQuestions[prevQuestionIndex]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeQuizQuestion = () => {
|
const initializeQuizQuestion = () => {
|
||||||
|
|
@ -299,7 +262,7 @@ const ManageRoom: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentQuestion(quizQuestions[0]);
|
setCurrentQuestion(quizQuestions[0]);
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex: 0, isLaunch: true});
|
webSocketService.nextQuestion(formattedRoomName, quizQuestions[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const launchStudentMode = () => {
|
const launchStudentMode = () => {
|
||||||
|
|
@ -315,19 +278,21 @@ const ManageRoom: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const launchQuiz = () => {
|
const launchQuiz = () => {
|
||||||
setQuizStarted(true);
|
|
||||||
if (!socket || !formattedRoomName || !quiz?.content || quiz?.content.length === 0) {
|
if (!socket || !formattedRoomName || !quiz?.content || quiz?.content.length === 0) {
|
||||||
// TODO: This error happens when token expires! Need to handle it properly
|
// TODO: This error happens when token expires! Need to handle it properly
|
||||||
console.log(
|
console.log(
|
||||||
`Error launching quiz. socket: ${socket}, roomName: ${formattedRoomName}, quiz: ${quiz}`
|
`Error launching quiz. socket: ${socket}, roomName: ${formattedRoomName}, quiz: ${quiz}`
|
||||||
);
|
);
|
||||||
|
setQuizStarted(true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(`Launching quiz in ${quizMode} mode...`);
|
|
||||||
switch (quizMode) {
|
switch (quizMode) {
|
||||||
case 'student':
|
case 'student':
|
||||||
|
setQuizStarted(true);
|
||||||
return launchStudentMode();
|
return launchStudentMode();
|
||||||
case 'teacher':
|
case 'teacher':
|
||||||
|
setQuizStarted(true);
|
||||||
return launchTeacherMode();
|
return launchTeacherMode();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -335,8 +300,9 @@ const ManageRoom: React.FC = () => {
|
||||||
const showSelectedQuestion = (questionIndex: number) => {
|
const showSelectedQuestion = (questionIndex: number) => {
|
||||||
if (quiz?.content && quizQuestions) {
|
if (quiz?.content && quizQuestions) {
|
||||||
setCurrentQuestion(quizQuestions[questionIndex]);
|
setCurrentQuestion(quizQuestions[questionIndex]);
|
||||||
|
|
||||||
if (quizMode === 'teacher') {
|
if (quizMode === 'teacher') {
|
||||||
webSocketService.nextQuestion({roomName: formattedRoomName, questions: quizQuestions, questionIndex, isLaunch: false});
|
webSocketService.nextQuestion(formattedRoomName, quizQuestions[questionIndex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -347,7 +313,7 @@ const ManageRoom: React.FC = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function checkIfIsCorrect(
|
function checkIfIsCorrect(
|
||||||
answer: AnswerType,
|
answer: string | number | boolean,
|
||||||
idQuestion: number,
|
idQuestion: number,
|
||||||
questions: QuestionType[]
|
questions: QuestionType[]
|
||||||
): boolean {
|
): boolean {
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
import { io, Socket } from 'socket.io-client';
|
import { io, Socket } from 'socket.io-client';
|
||||||
import { AnswerType } from 'src/pages/Student/JoinRoom/JoinRoom';
|
|
||||||
import { QuestionType } from 'src/Types/QuestionType';
|
|
||||||
|
|
||||||
// Must (manually) sync these types to server/socket/socket.js
|
// Must (manually) sync these types to server/socket/socket.js
|
||||||
|
|
||||||
export type AnswerSubmissionToBackendType = {
|
export type AnswerSubmissionToBackendType = {
|
||||||
roomName: string;
|
roomName: string;
|
||||||
username: string;
|
username: string;
|
||||||
answer: AnswerType;
|
answer: string | number | boolean;
|
||||||
idQuestion: number;
|
idQuestion: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AnswerReceptionFromBackendType = {
|
export type AnswerReceptionFromBackendType = {
|
||||||
idUser: string;
|
idUser: string;
|
||||||
username: string;
|
username: string;
|
||||||
answer: AnswerType;
|
answer: string | number | boolean;
|
||||||
idQuestion: number;
|
idQuestion: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -61,19 +59,12 @@ class WebSocketService {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
nextQuestion(args: {roomName: string, questions: QuestionType[] | undefined, questionIndex: number, isLaunch: boolean}) {
|
nextQuestion(roomName: string, question: unknown) {
|
||||||
// deconstruct args
|
console.log('WebsocketService: nextQuestion', roomName, question);
|
||||||
const { roomName, questions, questionIndex, isLaunch } = args;
|
if (!question) {
|
||||||
console.log('WebsocketService: nextQuestion', roomName, questions, questionIndex, isLaunch);
|
|
||||||
if (!questions || !questions[questionIndex]) {
|
|
||||||
throw new Error('WebsocketService: nextQuestion: question is null');
|
throw new Error('WebsocketService: nextQuestion: question is null');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.socket) {
|
if (this.socket) {
|
||||||
if (isLaunch) {
|
|
||||||
this.socket.emit('launch-teacher-mode', { roomName, questions });
|
|
||||||
}
|
|
||||||
const question = questions[questionIndex];
|
|
||||||
this.socket.emit('next-question', { roomName, question });
|
this.socket.emit('next-question', { roomName, question });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,27 +109,15 @@ describe("websocket server", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should launch teacher mode", (done) => {
|
|
||||||
studentSocket.on("launch-teacher-mode", (questions) => {
|
|
||||||
expect(questions).toEqual([
|
|
||||||
{ question: "question1" },
|
|
||||||
{ question: "question2" },
|
|
||||||
]);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
teacherSocket.emit("launch-teacher-mode", {
|
|
||||||
roomName: "ROOM1",
|
|
||||||
questions: [{ question: "question1" }, { question: "question2" }],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should send next question", (done) => {
|
test("should send next question", (done) => {
|
||||||
studentSocket.on("next-question", ( question ) => {
|
studentSocket.on("next-question", (question) => {
|
||||||
expect(question).toBe("question2");
|
expect(question).toEqual({ question: "question2" });
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
teacherSocket.emit("next-question", { roomName: "ROOM1", question: 'question2'},
|
teacherSocket.emit("next-question", {
|
||||||
);
|
roomName: "ROOM1",
|
||||||
|
question: { question: "question2" },
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("should send answer", (done) => {
|
test("should send answer", (done) => {
|
||||||
|
|
|
||||||
|
|
@ -127,11 +127,4 @@ async function start() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Graceful shutdown on SIGINT (Ctrl+C)
|
|
||||||
process.on('SIGINT', async () => {
|
|
||||||
console.log('Shutting down...');
|
|
||||||
await db.closeConnection();
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
|
|
||||||
|
|
@ -73,15 +73,13 @@ class AuthManager{
|
||||||
console.info(`L'utilisateur '${userInfo.email}' vient de se connecter`)
|
console.info(`L'utilisateur '${userInfo.email}' vient de se connecter`)
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(userInfos, sendEmail=false){
|
async register(userInfos){
|
||||||
console.log(userInfos);
|
console.log(userInfos);
|
||||||
if (!userInfos.email || !userInfos.password) {
|
if (!userInfos.email || !userInfos.password) {
|
||||||
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
||||||
}
|
}
|
||||||
const user = await this.simpleregister.register(userInfos);
|
const user = await this.simpleregister.register(userInfos);
|
||||||
if(sendEmail){
|
emailer.registerConfirmation(user.email)
|
||||||
emailer.registerConfirmation(user.email);
|
|
||||||
}
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class SimpleAuth {
|
||||||
password: req.body.password,
|
password: req.body.password,
|
||||||
roles: req.body.roles
|
roles: req.body.roles
|
||||||
};
|
};
|
||||||
let user = await self.authmanager.register(userInfos, true);
|
let user = await self.authmanager.register(userInfos)
|
||||||
if (user) {
|
if (user) {
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
message: 'User created'
|
message: 'User created'
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,28 @@
|
||||||
const { MongoClient } = require('mongodb');
|
const { MongoClient } = require('mongodb');
|
||||||
const dotenv = require('dotenv');
|
const dotenv = require('dotenv')
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
class DBConnection {
|
class DBConnection {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.mongoURI = process.env.MONGO_URI;
|
this.mongoURI = process.env.MONGO_URI;
|
||||||
this.databaseName = process.env.MONGO_DATABASE;
|
this.databaseName = process.env.MONGO_DATABASE;
|
||||||
this.client = null;
|
|
||||||
this.connection = null;
|
this.connection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to the database, but don't reconnect if already connected
|
|
||||||
async connect() {
|
async connect() {
|
||||||
if (this.connection) {
|
const client = new MongoClient(this.mongoURI);
|
||||||
console.log('Using existing MongoDB connection');
|
this.connection = await client.connect();
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Create the MongoClient only if the connection does not exist
|
|
||||||
this.client = new MongoClient(this.mongoURI);
|
|
||||||
await this.client.connect();
|
|
||||||
this.connection = this.client.db(this.databaseName);
|
|
||||||
console.log('MongoDB connected');
|
|
||||||
return this.connection;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('MongoDB connection error:', error);
|
|
||||||
throw new Error('Failed to connect to MongoDB');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the current database connection
|
|
||||||
getConnection() {
|
getConnection() {
|
||||||
if (!this.connection) {
|
if (!this.connection) {
|
||||||
throw new Error('MongoDB connection not established');
|
throw new Error('Connexion MongoDB non établie');
|
||||||
}
|
|
||||||
return this.connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the MongoDB connection gracefully
|
|
||||||
async closeConnection() {
|
|
||||||
if (this.client) {
|
|
||||||
await this.client.close();
|
|
||||||
console.log('MongoDB connection closed');
|
|
||||||
}
|
}
|
||||||
|
return this.connection.db(this.databaseName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exporting the singleton instance
|
|
||||||
const instance = new DBConnection();
|
const instance = new DBConnection();
|
||||||
module.exports = instance;
|
module.exports = instance;
|
||||||
1
server/package-lock.json
generated
1
server/package-lock.json
generated
|
|
@ -2498,7 +2498,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cross-spawn": "^7.0.1"
|
"cross-spawn": "^7.0.1"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,6 @@ const setupWebsocket = (io) => {
|
||||||
socket.to(roomName).emit("next-question", question);
|
socket.to(roomName).emit("next-question", question);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("launch-teacher-mode", ({ roomName, questions }) => {
|
|
||||||
socket.to(roomName).emit("launch-teacher-mode", questions);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("launch-student-mode", ({ roomName, questions }) => {
|
socket.on("launch-student-mode", ({ roomName, questions }) => {
|
||||||
socket.to(roomName).emit("launch-student-mode", questions);
|
socket.to(roomName).emit("launch-student-mode", questions);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue