diff --git a/site/package-lock.json b/site/package-lock.json
index 0f17ae8..d574ab3 100644
--- a/site/package-lock.json
+++ b/site/package-lock.json
@@ -8,17 +8,22 @@
"name": "site",
"version": "0.0.0",
"dependencies": {
+ "@dnd-kit/core": "^6.3.1",
+ "@dnd-kit/sortable": "^10.0.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^9.0.0",
"@mui/material": "^9.0.0",
"@mui/x-charts": "^9.0.1",
"@mui/x-data-grid": "^9.0.1",
+ "@reduxjs/toolkit": "^2.11.2",
"@types/d3": "^7.4.3",
"d3": "^7.9.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
- "react-router-dom": "^7.14.1"
+ "react-redux": "^9.2.0",
+ "react-router-dom": "^7.14.1",
+ "redux": "^5.0.1"
},
"devDependencies": {
"@babel/core": "^7.29.0",
@@ -278,6 +283,59 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@dnd-kit/accessibility": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
+ "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/core": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
+ "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@dnd-kit/accessibility": "^3.1.1",
+ "@dnd-kit/utilities": "^3.2.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/sortable": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
+ "integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
+ "license": "MIT",
+ "dependencies": {
+ "@dnd-kit/utilities": "^3.2.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "@dnd-kit/core": "^6.3.0",
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/@dnd-kit/utilities": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
+ "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"node_modules/@emnapi/core": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
@@ -1150,6 +1208,32 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.11.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz",
+ "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^11.0.0",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.0-rc.15",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz",
@@ -1463,6 +1547,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
"node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
@@ -1842,6 +1938,12 @@
"@types/react": "*"
}
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.1.tgz",
@@ -3403,6 +3505,16 @@
"node": ">= 4"
}
},
+ "node_modules/immer": {
+ "version": "11.1.4",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz",
+ "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -4196,6 +4308,29 @@
"integrity": "sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==",
"license": "MIT"
},
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-router": {
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.1.tgz",
@@ -4250,6 +4385,21 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT"
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
"node_modules/reselect": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
@@ -4487,9 +4637,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "dev": true,
- "license": "0BSD",
- "optional": true
+ "license": "0BSD"
},
"node_modules/type-check": {
"version": "0.4.0",
diff --git a/site/package.json b/site/package.json
index 3c439a0..e23e918 100644
--- a/site/package.json
+++ b/site/package.json
@@ -10,17 +10,22 @@
"preview": "vite preview"
},
"dependencies": {
+ "@dnd-kit/core": "^6.3.1",
+ "@dnd-kit/sortable": "^10.0.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^9.0.0",
"@mui/material": "^9.0.0",
"@mui/x-charts": "^9.0.1",
"@mui/x-data-grid": "^9.0.1",
+ "@reduxjs/toolkit": "^2.11.2",
"@types/d3": "^7.4.3",
"d3": "^7.9.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
- "react-router-dom": "^7.14.1"
+ "react-redux": "^9.2.0",
+ "react-router-dom": "^7.14.1",
+ "redux": "^5.0.1"
},
"devDependencies": {
"@babel/core": "^7.29.0",
diff --git a/site/src/main.tsx b/site/src/main.tsx
index 879e191..864fbac 100644
--- a/site/src/main.tsx
+++ b/site/src/main.tsx
@@ -1,6 +1,6 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
-
+import { Provider } from 'react-redux';
import {
createBrowserRouter,
RouterProvider,
@@ -9,8 +9,9 @@ import {
import List from "./list/List";
import Chart from "./chart/Chart";
import Main from "./main/Main";
+import Quiz from "./quiz/QuizPage";
import ProjectDetails from "./projectDetails/ProjectDetails";
-
+import store from './store';
const router = createBrowserRouter([
@@ -30,6 +31,10 @@ const router = createBrowserRouter([
path: "/chart",
element: ,
},
+ {
+ path: "/quiz",
+ element: ,
+ },
]);
@@ -37,6 +42,8 @@ const router = createBrowserRouter([
import './styles/index.css'
createRoot(document.getElementById('root')!).render(
-
+
+
+
,
)
diff --git a/site/testing/Testing.tsx b/site/src/quiz/QuizPage.tsx
similarity index 83%
rename from site/testing/Testing.tsx
rename to site/src/quiz/QuizPage.tsx
index ed3af39..4bff952 100644
--- a/site/testing/Testing.tsx
+++ b/site/src/quiz/QuizPage.tsx
@@ -2,7 +2,7 @@ import NavBar from "../components/Navbar";
import Footer from "../components/CustomFooter";
import Quiz from "./features/Quiz";
-function Testing() {
+function QuizPage() {
return (
<>
@@ -12,4 +12,4 @@ function Testing() {
);
}
-export default Testing;
\ No newline at end of file
+export default QuizPage;
\ No newline at end of file
diff --git a/site/testing/components/SortableItem.tsx b/site/src/quiz/components/SortableItem.tsx
similarity index 100%
rename from site/testing/components/SortableItem.tsx
rename to site/src/quiz/components/SortableItem.tsx
diff --git a/site/testing/features/Matching.tsx b/site/src/quiz/features/Matching.tsx
similarity index 95%
rename from site/testing/features/Matching.tsx
rename to site/src/quiz/features/Matching.tsx
index 928c9c8..c1893b8 100644
--- a/site/testing/features/Matching.tsx
+++ b/site/src/quiz/features/Matching.tsx
@@ -22,7 +22,7 @@ function Matching({tasks,index}: ComponentProps) {
}, []);
- const answers: string[] = tasks.map((item) => item.answer);
+ const answers: string[] = tasks.map((item) => String(item.answer));
return (
diff --git a/site/testing/features/Quiz.tsx b/site/src/quiz/features/Quiz.tsx
similarity index 100%
rename from site/testing/features/Quiz.tsx
rename to site/src/quiz/features/Quiz.tsx
diff --git a/site/testing/features/SortableList.tsx b/site/src/quiz/features/SortableList.tsx
similarity index 100%
rename from site/testing/features/SortableList.tsx
rename to site/src/quiz/features/SortableList.tsx
diff --git a/site/testing/features/quizSlice.tsx b/site/src/quiz/features/quizSlice.tsx
similarity index 51%
rename from site/testing/features/quizSlice.tsx
rename to site/src/quiz/features/quizSlice.tsx
index aa7d350..dccdbb5 100644
--- a/site/testing/features/quizSlice.tsx
+++ b/site/src/quiz/features/quizSlice.tsx
@@ -18,14 +18,14 @@ function shuffle(array:Array):Array {
return array;
}
-interface ListsState {
- lists: string[][]; // хранит перемещаемые элементы каждого списка ответов
- correctAnswers:string[][];
- isTestingDone:boolean
+interface QuizState {
+ userAnswers: string[][]; // хранит перемещаемые элементы каждого списка ответов
+ correctAnswers:string[][] |boolean[][];// ответы для вопрсов, в случае с matching просто правильная последоавтельность, для sorting аналогично, для choosе последоватеьность boolean
+ isTestingDone:boolean// запрет на взаимодействие с квизом после окончания тестирования, чтобю юзер не наглел
}
-const initialState: ListsState = {
- lists: [],
+const initialState: QuizState = {
+ userAnswers: [],
correctAnswers:[],
isTestingDone:false
};
@@ -36,18 +36,24 @@ const listsSlice = createSlice({
reducers: {
addList: (state, action: PayloadAction<{index: number; items: string[]}>)=>{
const { index, items } = action.payload;
- state.lists.splice(index, 1, items);
+ state.userAnswers.splice(index, 1, items); // с нулём создаётся по 2 экземпляра, видно в отладке
state.correctAnswers.splice(index, 1, items);
},
setDraggedItems: (state, action: PayloadAction<{ index: number; items: string[] }>) => {
const { index, items } = action.payload;
- if (index >= 0 && index < state.lists.length) {
- state.lists[index] = items; // обновляем конкретный список
+ if (index >= 0 && index < state.userAnswers.length) {
+ state.userAnswers[index] = items; // обновляем конкретный список
+ }
+ },
+ setCheckedItems: (state, action: PayloadAction<{ index: number; items: string[] }>) => {
+ const { index, items } = action.payload;
+ if (index >= 0 && index < state.userAnswers.length) {
+ state.userAnswers[index] = items; // обновляем конкретный список
}
},
mixUp: (state) => {
- state.lists=state.lists.map((list)=>
+ state.userAnswers=state.userAnswers.map((list)=>
{
return shuffle(list);
})
@@ -63,5 +69,5 @@ const listsSlice = createSlice({
// Экспортируем действия и редьюсер
export const { addList, setDraggedItems,mixUp,startTesting,stopTesting } = listsSlice.actions;
-export type {ListsState}
+export type {QuizState}
export default listsSlice.reducer;
\ No newline at end of file
diff --git a/site/src/quiz/quizData.tsx b/site/src/quiz/quizData.tsx
new file mode 100644
index 0000000..24d1db3
--- /dev/null
+++ b/site/src/quiz/quizData.tsx
@@ -0,0 +1,92 @@
+export type tTasks ={
+ "question": string; /* вопрос задания*/
+ "answer": string|number|boolean; /* ответ задания*/
+}[]
+
+export type tQuizzes = {
+ "id": number,
+ "type": "M" | "S" | "C", /* Match Sort Choose*/
+ "title": string, /* формулировка задания */
+ "tasks": tTasks,
+}[];
+
+export const quiz: tQuizzes = [
+ {
+ "id": 1,
+ "type": "M",
+ "title": "вопросй",
+ "tasks": [
+ {
+ "question": "адын?",
+ "answer": "адын"
+ },
+ {
+ "question": "2",
+ "answer": "2"
+ },
+ {
+ "question": "3",
+ "answer": "3"
+ },
+ {
+ "question": "4",
+ "answer": "4"
+ },
+ ]
+ },
+ {
+ "id": 2,
+ "type": "S",
+ "title": "Вопрос 2 СОРТИРУЙ",
+ "tasks": [
+ {
+ "question": "1",
+ "answer": 1
+ },
+ {
+ "question": "22",
+ "answer": 2
+ },
+ {
+ "question": "333",
+ "answer": 3
+ },
+ {
+ "question": "4444",
+ "answer": 4
+ },
+ {
+ "question": "5555",
+ "answer": 5
+ },
+ ]
+ }
+,
+ {
+ "id": 2,
+ "type": "C",
+ "title": "Вопрос 3 Выбирай!",
+ "tasks": [
+ {
+ "question": "да",
+ "answer": true
+ },
+ {
+ "question": "нет",
+ "answer": false
+ },
+ {
+ "question": "и снова да",
+ "answer": true
+ },
+ {
+ "question": "нет",
+ "answer": false
+ },
+ {
+ "question": "дааа",
+ "answer": true
+ },
+ ]
+ }
+]
\ No newline at end of file
diff --git a/site/src/store.tsx b/site/src/store.tsx
new file mode 100644
index 0000000..dc18872
--- /dev/null
+++ b/site/src/store.tsx
@@ -0,0 +1,15 @@
+import { configureStore } from '@reduxjs/toolkit';
+import listsReducer from './quiz/features/quizSlice';
+
+
+const store = configureStore({
+ reducer: {
+ quiz: listsReducer,
+ },
+ devTools: { trace: true ,traceLimit: 25},
+});
+
+export type RootState = ReturnType;
+export type AppDispatch = typeof store.dispatch;
+
+export default store;
\ No newline at end of file
diff --git a/site/testing/quizData.tsx b/site/testing/quizData.tsx
deleted file mode 100644
index 84fd9e3..0000000
--- a/site/testing/quizData.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-export type tTasks ={
- "question": string; /* вопрос задания*/
- "answer": string; /* ответ задания*/
-}[]
-
-export type tQuizzes = {
- "id": number,
- "type": "M" | "S", /* типы заданий, М - сопоставление*/
- "title": string, /* формулировка задания */
- "tasks": tTasks,
-}[];
-
-export const quiz: tQuizzes = [
- {
- "id": 1,
- "type": "M",
- "title": "Сопоставьте сооружение и город, в котором оно расположено.",
- "tasks": [
- {
- "question": "Башня Аль-Хамра",
- "answer": "Кувейт"
- },
- {
- "question": "Башня CITIC",
- "answer": "Гуанчжоу"
- },
- {
- "question": "Телебашня «Коктобе»",
- "answer": "Алматы"
- },
- {
- "question": "Си-Эн Тауэр",
- "answer": "Торонто"
- },
- ]
- },
- {
- "id": 2,
- "type": "M",
- "title": "Сопоставьте сооружение и его высоту.",
- "tasks": [
- {
- "question": "Tokyo Skytree",
- "answer": "634"
- },
- {
- "question": "Бурдж-Халифа",
- "answer": "838"
- },
- {
- "question": "Эмпайр-стейт-билдинг",
- "answer": "448.7"
- },
- {
- "question": "Останкинская башня",
- "answer": "540.1"
- },
- {
- "question": "Lotte World Tower",
- "answer": "555"
- },
- ]
- }
-]
\ No newline at end of file