From 6d9fa9061d8e20659d35db8bdd2d8523033a5f0b Mon Sep 17 00:00:00 2001 From: David Katrinka Date: Fri, 26 Dec 2025 22:02:37 +0100 Subject: [PATCH] added tests by test and polished adaptivity --- src/api/categoryApi.ts | 7 +- src/api/testApi.ts | 35 ++++++-- src/components/Header/Header.tsx | 18 ++++ src/components/Question/Question.styles.ts | 14 +-- .../StartTestForm/StartTestForm.tsx | 3 + src/components/TestCard/TestCard.tsx | 8 +- src/components/TestListCard/TestListCard.tsx | 88 +++++++++++++++++++ src/components/shared/types/TestTypes.ts | 27 +++++- src/hooks/Tests/useGetTestById.ts | 10 +++ src/hooks/Tests/useGetTests.ts | 15 ++++ src/hooks/Tests/useStartTestById.ts | 20 +++++ src/pages/IndexPage/IndexPage.tsx | 63 +++++++++++-- .../QuestionsPage/QuestionsPage.styles.ts | 0 src/pages/QuestionsPage/QuestionsPage.tsx | 10 --- src/pages/TestsPage/TestsPage.tsx | 83 +++++++++++++++++ src/router/router.tsx | 5 ++ 16 files changed, 376 insertions(+), 30 deletions(-) create mode 100644 src/components/TestListCard/TestListCard.tsx create mode 100644 src/hooks/Tests/useGetTestById.ts create mode 100644 src/hooks/Tests/useGetTests.ts create mode 100644 src/hooks/Tests/useStartTestById.ts delete mode 100644 src/pages/QuestionsPage/QuestionsPage.styles.ts delete mode 100644 src/pages/QuestionsPage/QuestionsPage.tsx create mode 100644 src/pages/TestsPage/TestsPage.tsx diff --git a/src/api/categoryApi.ts b/src/api/categoryApi.ts index 1948693..6fa22ab 100644 --- a/src/api/categoryApi.ts +++ b/src/api/categoryApi.ts @@ -1,6 +1,11 @@ +import type { CategoryType } from "../components/shared/types/TestTypes"; import axiosInstance from "./axiosInstance"; +interface CategoriesResponse { + data: CategoryType[]; +} + export const getCategories = async () => { - const res = await axiosInstance.get("/api/categories"); + const res = await axiosInstance.get("/api/categories"); return res.data.data; }; diff --git a/src/api/testApi.ts b/src/api/testApi.ts index 489d1e6..75f6c3d 100644 --- a/src/api/testApi.ts +++ b/src/api/testApi.ts @@ -1,7 +1,9 @@ -import type { - StartTestPayload, - SubmitAnswerPayload, - UserTestType, +import { + type TestType, + type PaginatedTests, + type StartTestPayload, + type SubmitAnswerPayload, + type UserTestType, } from "../components/shared/types/TestTypes"; import axiosInstance from "./axiosInstance"; @@ -13,6 +15,14 @@ export const startTest = async (data: StartTestPayload) => { return res.data.data; }; +export const startTestById = async (id: number) => { + const res = await axiosInstance.post<{ data: UserTestType }>( + "/api/user-tests/by-test", + { test_id: id } + ); + return res.data.data; +}; + export const completeUserTest = async (userTestId: number) => { const res = await axiosInstance.post<{ message: string }>( `/api/user-tests/${userTestId}/complete` @@ -28,7 +38,9 @@ export const getUserTestById = async (userTestId: number) => { }; export const getUserTests = async () => { - const res = await axiosInstance.get<{data: UserTestType[]}>("/api/user-tests/me"); + const res = await axiosInstance.get<{ data: UserTestType[] }>( + "/api/user-tests/me" + ); return res.data.data; }; @@ -39,3 +51,16 @@ export const submitAnswer = async (data: SubmitAnswerPayload) => { ); return res.data; }; + +export const getTests = async (categoryId?: number, page = 1) => { + const params: Record = { page }; + if (categoryId !== undefined) params.category_id = categoryId; + + const res = await axiosInstance.get("/api/tests", { params }); + return res.data; +}; + +export const getTestById = async (id: number) => { + const res = await axiosInstance.get<{ data: TestType }>(`/api/tests/${id}`); + return res.data.data; +}; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index b1fe9a6..2267d2c 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -109,6 +109,15 @@ function Header() { )} )} + + { + handleCloseNavMenu(); + navigate("/tests"); + }} + > + Tests + @@ -160,6 +169,15 @@ function Header() { )} )} + diff --git a/src/components/Question/Question.styles.ts b/src/components/Question/Question.styles.ts index 7cb4580..114c55d 100644 --- a/src/components/Question/Question.styles.ts +++ b/src/components/Question/Question.styles.ts @@ -1,4 +1,5 @@ import styled from "@emotion/styled"; +import { Box } from "@mui/material"; import { Link } from "react-router-dom"; export const QuestionWrapper = styled(Link)({ @@ -6,24 +7,27 @@ export const QuestionWrapper = styled(Link)({ flexDirection: "column", justifyContent: "center", padding: "15px", - border: "3px solid #4B2981", + border: "1px solid #ccc", borderRadius: "10px", marginBottom: "10px", textDecoration: "none", - color: "inherit" + color: "inherit", }); -export const QuestionTitle = styled("div")({ +export const QuestionTitle = styled(Box)({ display: "flex", alignItems: "center", - marginBottom: "10px" + marginBottom: "10px", + "@media (max-width:600px)": { + flexDirection: "column", + }, }); export const QuestionMetadata = styled("div")({ display: "flex", justifyContent: "space-between", color: "#4c4c4c", - marginTop: "10px" + marginTop: "10px", }); export const AuthorMeta = styled("div")({ diff --git a/src/components/StartTestForm/StartTestForm.tsx b/src/components/StartTestForm/StartTestForm.tsx index 0b8b13a..40c8126 100644 --- a/src/components/StartTestForm/StartTestForm.tsx +++ b/src/components/StartTestForm/StartTestForm.tsx @@ -75,6 +75,7 @@ const StartTestForm = () => { Category { Max Difficulty + All + {categories?.map((category) => ( + + {category.name} + + ))} + + + {loading && Loading questions...} {error && {error}} {questions.map((q: QuestionType) => ( - + ))} {meta && meta.last_page > 1 && ( diff --git a/src/pages/QuestionsPage/QuestionsPage.styles.ts b/src/pages/QuestionsPage/QuestionsPage.styles.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/pages/QuestionsPage/QuestionsPage.tsx b/src/pages/QuestionsPage/QuestionsPage.tsx deleted file mode 100644 index 1c30ce9..0000000 --- a/src/pages/QuestionsPage/QuestionsPage.tsx +++ /dev/null @@ -1,10 +0,0 @@ - -import StartTestForm from "../../components/StartTestForm/StartTestForm"; - -const QuestionsPage = () => { - return( - - ) -} - -export default QuestionsPage; \ No newline at end of file diff --git a/src/pages/TestsPage/TestsPage.tsx b/src/pages/TestsPage/TestsPage.tsx new file mode 100644 index 0000000..17b1a25 --- /dev/null +++ b/src/pages/TestsPage/TestsPage.tsx @@ -0,0 +1,83 @@ +import { useState } from "react"; +import Pagination from "@mui/material/Pagination"; +import CircularProgress from "@mui/material/CircularProgress"; +import Alert from "@mui/material/Alert"; +import Box from "@mui/material/Box"; +import { useGetTests } from "../../hooks/Tests/useGetTests"; +import Container from "../../components/shared/Container"; +import TestListCard from "../../components/TestListCard/TestListCard"; +import { + FormControl, + InputLabel, + MenuItem, + Select, + Typography, + type SelectChangeEvent, +} from "@mui/material"; +import { useCategories } from "../../hooks/Question/useCategories"; + +const TestsPage = () => { + const [currentPage, setCurrentPage] = useState(1); + const [selectedCategory, setSelectedCategory] = useState( + "all" + ); + + const { data: categories } = useCategories(); + const { data, isLoading, isError } = useGetTests({ + categoryId: selectedCategory === "all" ? undefined : selectedCategory, + page: currentPage, + }); + + const handleCategoryChange = (event: SelectChangeEvent) => { + const value = event.target.value; + setSelectedCategory(value === "all" ? "all" : Number(value)); + setCurrentPage(1); + }; + if (isLoading) return ; + if (isError) return Failed to load tests; + + return ( + + Curated tests + + + Category + + + + {isLoading ? ( +
Loading tests...
+ ) : isError ? ( +
Failed to load tests
+ ) : ( + data?.data.map((test) => ) + )} + + {data?.meta?.last_page && data.meta.last_page > 1 && ( + setCurrentPage(value)} + sx={{ mt: 3, mb: 3, display: "flex", justifyContent: "center" }} + /> + )} +
+
+ ); +}; + +export default TestsPage; diff --git a/src/router/router.tsx b/src/router/router.tsx index ff800c0..b78f072 100644 --- a/src/router/router.tsx +++ b/src/router/router.tsx @@ -11,6 +11,7 @@ import NotFoundPage from "../pages/NotFoundPage/NotFoundPage"; import ResetPasswordPage from "../pages/ResetPasswordPage/ResetPasswordPage"; import SingleQuestionPage from "../pages/SingleQuestionPage/SingleQuestionPage"; import { TestPage } from "../pages/TestPage/TestPage"; +import TestsPage from "../pages/TestsPage/TestsPage"; const router = createBrowserRouter([ { @@ -57,6 +58,10 @@ const router = createBrowserRouter([ path: "/tests/:id", element: }, + { + path: "/tests", + element: + }, { path: "*", element: ,