From 5567d6e0a53a0911d8af2c5f7339956a69e18d5f Mon Sep 17 00:00:00 2001 From: SzymonBudziak Date: Fri, 23 Feb 2024 21:27:02 +0100 Subject: [PATCH 01/26] default parameters in search and user data --- src/components/layout/Header/NavButtons.tsx | 2 +- src/components/pages/Dashboard/Dashboard.tsx | 2 +- src/components/pages/Dashboard/UserQuizes.tsx | 32 +++++++++++++++++-- .../pages/Home/TileGrid/TileGrid.tsx | 2 +- .../pages/Quiz/Flashcards/Flashcards.tsx | 2 +- src/components/pages/Quiz/Quiz.tsx | 2 +- .../pages/QuizSearch/QuizSearch.tsx | 18 ++++++----- src/components/router/PersistLogin.tsx | 2 +- src/hooks/{ => auth}/useApiPrivate.tsx | 6 ++-- src/hooks/{ => auth}/useLogout.tsx | 2 +- src/hooks/{ => auth}/useRefreshToken.tsx | 0 src/hooks/{ => quizes}/useQuizData.tsx | 0 src/hooks/{ => quizes}/useQuizesPaging.tsx | 6 +++- src/hooks/{ => quizes}/useUserData.tsx | 0 14 files changed, 54 insertions(+), 22 deletions(-) rename src/hooks/{ => auth}/useApiPrivate.tsx (93%) rename src/hooks/{ => auth}/useLogout.tsx (89%) rename src/hooks/{ => auth}/useRefreshToken.tsx (100%) rename src/hooks/{ => quizes}/useQuizData.tsx (100%) rename src/hooks/{ => quizes}/useQuizesPaging.tsx (81%) rename src/hooks/{ => quizes}/useUserData.tsx (100%) diff --git a/src/components/layout/Header/NavButtons.tsx b/src/components/layout/Header/NavButtons.tsx index f498eb0..1230dd0 100644 --- a/src/components/layout/Header/NavButtons.tsx +++ b/src/components/layout/Header/NavButtons.tsx @@ -1,5 +1,5 @@ import { isAuthenticatedAtom, tokenDataAtom } from "@/atoms/auth"; -import useLogout from "@/hooks/useLogout"; +import useLogout from "@/hooks/auth/useLogout"; import { useAtomValue } from "jotai"; import { Link } from "react-router-dom"; diff --git a/src/components/pages/Dashboard/Dashboard.tsx b/src/components/pages/Dashboard/Dashboard.tsx index 6638233..56d40c8 100644 --- a/src/components/pages/Dashboard/Dashboard.tsx +++ b/src/components/pages/Dashboard/Dashboard.tsx @@ -1,4 +1,4 @@ -import useUserData from "@/hooks/useUserData"; +import useUserData from "@/hooks/quizes/useUserData"; import Loading from "../Status/Loading"; import Error from "../Status/Error"; import UserQuizes from "./UserQuizes"; diff --git a/src/components/pages/Dashboard/UserQuizes.tsx b/src/components/pages/Dashboard/UserQuizes.tsx index b8acb32..6f13856 100644 --- a/src/components/pages/Dashboard/UserQuizes.tsx +++ b/src/components/pages/Dashboard/UserQuizes.tsx @@ -1,16 +1,35 @@ import { QuizResponse } from "@/api/types/quiz"; -import { quizesAtom } from "@/atoms/quizSearch"; +import { paramsAtom, quizesAtom, updateParamsAtom } from "@/atoms/quizSearch"; import { useAtom } from "jotai"; import Loading from "../Status/Loading"; import Error from "../Status/Error"; import QuizStripe from "./QuizStripe"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import SearchInput from "../QuizSearch/SearchInput"; +import { useParams } from "react-router-dom"; export default function UserQuizes() { const [{ isLoading, isError, data }] = useAtom(quizesAtom); - const [input, setInput] = useState(""); + const [, setParams] = useAtom(updateParamsAtom); + const [params] = useAtom(paramsAtom); + const { userName } = useParams(); + + useEffect(() => { + setParams({ + pageNumber: 1, + pageSize: 6, + sortColumn: "createdAt", + sortOrder: "desc", + searchTerm: "", + userName: userName, + }); + }, []); + + const increaseQuery = () => { + const newSize = params.pageSize ? params.pageSize + 3 : 12; + setParams({ pageSize: newSize }); + }; return ( <> @@ -22,6 +41,13 @@ export default function UserQuizes() { return ; })} + {data?.data.hasNextPage ? ( +
+ +
+ ) : null} ); } diff --git a/src/components/pages/Home/TileGrid/TileGrid.tsx b/src/components/pages/Home/TileGrid/TileGrid.tsx index cf3460e..d6d0b8f 100644 --- a/src/components/pages/Home/TileGrid/TileGrid.tsx +++ b/src/components/pages/Home/TileGrid/TileGrid.tsx @@ -2,7 +2,7 @@ import Loading from "../../Status/Loading"; import { QuizResponse } from "@/api/types/quiz"; import QuizTile from "./QuizTile"; import NotFound from "../../Status/NotFound/NotFound"; -import useQuizesPaging from "@/hooks/useQuizesPaging"; +import useQuizesPaging from "@/hooks/quizes/useQuizesPaging"; export type TileGridViewProps = { quizes: QuizResponse[]; diff --git a/src/components/pages/Quiz/Flashcards/Flashcards.tsx b/src/components/pages/Quiz/Flashcards/Flashcards.tsx index 0160ee5..f7ef9f4 100644 --- a/src/components/pages/Quiz/Flashcards/Flashcards.tsx +++ b/src/components/pages/Quiz/Flashcards/Flashcards.tsx @@ -1,5 +1,5 @@ import { Toaster } from "react-hot-toast"; -import useQuizData from "@/hooks/useQuizData"; +import useQuizData from "@/hooks/quizes/useQuizData"; import Loading from "../../Status/Loading"; import NotFound from "../../Status/NotFound/NotFound"; import Error from "../../Status/Error"; diff --git a/src/components/pages/Quiz/Quiz.tsx b/src/components/pages/Quiz/Quiz.tsx index 2b82482..fbd6692 100644 --- a/src/components/pages/Quiz/Quiz.tsx +++ b/src/components/pages/Quiz/Quiz.tsx @@ -1,7 +1,7 @@ import Loading from "@/components/pages/Status/Loading"; import NotFound from "@/components/pages/Status/NotFound/NotFound"; import QuizView from "./QuizView"; -import useQuizData from "@/hooks/useQuizData"; +import useQuizData from "@/hooks/quizes/useQuizData"; export default function Quiz() { const { isLoading, isError, quiz } = useQuizData(); diff --git a/src/components/pages/QuizSearch/QuizSearch.tsx b/src/components/pages/QuizSearch/QuizSearch.tsx index 9360251..f568ede 100644 --- a/src/components/pages/QuizSearch/QuizSearch.tsx +++ b/src/components/pages/QuizSearch/QuizSearch.tsx @@ -1,7 +1,7 @@ import { QuizResponse } from "@/api/types/quiz"; -import { paramsAtom, quizesAtom, updateParamsAtom } from "@/atoms/quizSearch"; +import { quizesAtom, updateParamsAtom } from "@/atoms/quizSearch"; import { useAtom } from "jotai"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import QuizTile from "../Home/TileGrid/QuizTile"; import Loading from "../Status/Loading"; import NotFound from "../Status/NotFound/NotFound"; @@ -11,23 +11,25 @@ import PagingBar from "./PagingBar"; export default function QuizSearch() { const [{ isLoading, isError, data }] = useAtom(quizesAtom); const [, setParams] = useAtom(updateParamsAtom); - const [params] = useAtom(paramsAtom); - const [input, setInput] = useState( - params.searchTerm ? params.searchTerm : "" - ); + const [input, setInput] = useState(""); const resetFilters = () => { setInput(""); setParams({ pageNumber: 1, - pageSize: 9, - sortColumn: "createdAt", + pageSize: 12, + sortColumn: "name", sortOrder: "asc", searchTerm: "", + userName: "", }); }; + useEffect(() => { + resetFilters(); + }, []); + return ( <>
diff --git a/src/components/router/PersistLogin.tsx b/src/components/router/PersistLogin.tsx index be7f08e..039bf6c 100644 --- a/src/components/router/PersistLogin.tsx +++ b/src/components/router/PersistLogin.tsx @@ -2,7 +2,7 @@ import { useAtomValue } from "jotai"; import { useEffect, useState } from "react"; import { Outlet } from "react-router-dom"; import { accessTokenAtom } from "../../atoms/auth"; -import useRefreshToken from "../../hooks/useRefreshToken"; +import useRefreshToken from "../../hooks/auth/useRefreshToken"; import Loading from "../pages/Status/Loading"; export default function PersistLogin() { diff --git a/src/hooks/useApiPrivate.tsx b/src/hooks/auth/useApiPrivate.tsx similarity index 93% rename from src/hooks/useApiPrivate.tsx rename to src/hooks/auth/useApiPrivate.tsx index a0dce85..24975c3 100644 --- a/src/hooks/useApiPrivate.tsx +++ b/src/hooks/auth/useApiPrivate.tsx @@ -2,7 +2,7 @@ import { apiPrivate } from "@/api/axios"; import { AxiosError } from "axios"; import { useAtomValue } from "jotai"; import { useEffect } from "react"; -import { accessTokenAtom } from "../atoms/auth"; +import { accessTokenAtom } from "../../atoms/auth"; import useRefreshToken from "./useRefreshToken"; export default function useApiPrivate() { @@ -11,7 +11,7 @@ export default function useApiPrivate() { useEffect(() => { const requestIntercept = apiPrivate.interceptors.request.use( - (config) => { + config => { if (!config.headers["Authorization"]) { config.headers["Authorization"] = `Bearer ${accessToken}`; } @@ -22,7 +22,7 @@ export default function useApiPrivate() { ); const responseIntercept = apiPrivate.interceptors.response.use( - (response) => response, + response => response, async (error: AxiosError) => { const prevRequest = error.config; if (!prevRequest) return Promise.reject(error); diff --git a/src/hooks/useLogout.tsx b/src/hooks/auth/useLogout.tsx similarity index 89% rename from src/hooks/useLogout.tsx rename to src/hooks/auth/useLogout.tsx index 82aea7d..2b17728 100644 --- a/src/hooks/useLogout.tsx +++ b/src/hooks/auth/useLogout.tsx @@ -1,7 +1,7 @@ import { api } from "@/api/axios"; import { useMutation } from "@tanstack/react-query"; import { useAtomValue, useSetAtom } from "jotai"; -import { accessTokenAtom, isAuthenticatedAtom } from "../atoms/auth"; +import { accessTokenAtom, isAuthenticatedAtom } from "../../atoms/auth"; export default function useLogout() { const isAuthenticated = useAtomValue(isAuthenticatedAtom); diff --git a/src/hooks/useRefreshToken.tsx b/src/hooks/auth/useRefreshToken.tsx similarity index 100% rename from src/hooks/useRefreshToken.tsx rename to src/hooks/auth/useRefreshToken.tsx diff --git a/src/hooks/useQuizData.tsx b/src/hooks/quizes/useQuizData.tsx similarity index 100% rename from src/hooks/useQuizData.tsx rename to src/hooks/quizes/useQuizData.tsx diff --git a/src/hooks/useQuizesPaging.tsx b/src/hooks/quizes/useQuizesPaging.tsx similarity index 81% rename from src/hooks/useQuizesPaging.tsx rename to src/hooks/quizes/useQuizesPaging.tsx index 88835f7..a6140bd 100644 --- a/src/hooks/useQuizesPaging.tsx +++ b/src/hooks/quizes/useQuizesPaging.tsx @@ -4,7 +4,11 @@ import { useQuery } from "@tanstack/react-query"; export default function useQuizesPaging(params: GetQuizesQueryParams) { const { isLoading, isError, data } = useQuery({ - queryKey: ["quizes", Object.getOwnPropertyNames(params)], + queryKey: [ + "quizes", + Object.getOwnPropertyNames(params), + Object.values(params), + ], queryFn: () => api.get("/api/v1/Quiz", { params: params, diff --git a/src/hooks/useUserData.tsx b/src/hooks/quizes/useUserData.tsx similarity index 100% rename from src/hooks/useUserData.tsx rename to src/hooks/quizes/useUserData.tsx From 5102705d0f7dd5771b8d4f46c9aa4c96f8ac459d Mon Sep 17 00:00:00 2001 From: SzymonBudziak Date: Sat, 24 Feb 2024 13:08:37 +0100 Subject: [PATCH 02/26] quiz display without state --- src/atoms/quiz.ts | 59 ------------------- src/components/App.tsx | 6 -- src/components/layout/Header/QuizHeader.tsx | 8 --- .../pages/Quiz/Flashcards/Flashcard.tsx | 41 ++++++++----- .../pages/Quiz/Flashcards/Flashcards.tsx | 2 +- src/components/pages/Quiz/Quiz.tsx | 48 ++++++++++++++- src/components/pages/Quiz/QuizView.tsx | 48 --------------- src/hooks/quizes/useQuizData.tsx | 13 ++-- src/hooks/quizes/useUserData.tsx | 2 +- src/utils/intValue.ts | 6 ++ 10 files changed, 87 insertions(+), 146 deletions(-) delete mode 100644 src/atoms/quiz.ts delete mode 100644 src/components/pages/Quiz/QuizView.tsx create mode 100644 src/utils/intValue.ts diff --git a/src/atoms/quiz.ts b/src/atoms/quiz.ts deleted file mode 100644 index 3114170..0000000 --- a/src/atoms/quiz.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { api } from "@/api/axios"; -import { QuizResponse } from "@/api/types/quiz"; -import { atom } from "jotai"; -import { atomWithQuery } from "jotai-tanstack-query"; - -interface updateParamsAtom { - newName: string | undefined; - newSlug: string | undefined; -} - -interface updateCurrTermProps { - value: number; - length: number; -} - -export const userNameAtom = atom(""); -export const quizSlugAtom = atom(""); -export const currTermAtom = atom(0); - -export const quizNameAtom = atom( - get => get(quizAtom).data?.data.name ?? "Go Back" -); - -export const quizLengthAtom = atom( - get => get(quizAtom).data?.data.questions.length ?? 0 -); - -export const quizAtom = atomWithQuery(get => ({ - queryKey: ["quiz", get(userNameAtom), get(quizSlugAtom)], - queryFn: () => - api.get( - `/api/v1/Quiz/${get(userNameAtom)}/${get(quizSlugAtom)}` - ), -})); - -export const updateParamsAtom = atom( - null, - (get, set, { newName, newSlug }: updateParamsAtom) => { - if (newName !== get(userNameAtom) || newSlug !== get(quizSlugAtom)) { - set(userNameAtom, newName); - set(quizSlugAtom, newSlug); - set(currTermAtom, 0); - } - } -); - -export const updateCurrTermAtom = atom( - null, - (get, set, { value, length }: updateCurrTermProps) => { - const prev = get(currTermAtom); - value > 0 - ? prev === length - 1 - ? set(currTermAtom, 0) - : set(currTermAtom, prev + 1) - : prev === 0 - ? set(currTermAtom, length - 1) - : set(currTermAtom, prev - 1); - } -); diff --git a/src/components/App.tsx b/src/components/App.tsx index 8ff428b..49406a1 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -34,12 +34,6 @@ export default function App() { } /> - - {/* } /> */} - {/* } /> - } /> - } /> - } /> */} }> } /> diff --git a/src/components/layout/Header/QuizHeader.tsx b/src/components/layout/Header/QuizHeader.tsx index 3533d50..1806bbc 100644 --- a/src/components/layout/Header/QuizHeader.tsx +++ b/src/components/layout/Header/QuizHeader.tsx @@ -3,12 +3,9 @@ import { X } from "lucide-react"; import { Link, useNavigate } from "react-router-dom"; import DarkModeButton from "./DarkModeButton"; import Logo from "./Logo"; -import { useAtomValue } from "jotai"; -import { quizNameAtom } from "@/atoms/quiz"; export default function QuizHeader() { const navigate = useNavigate(); - const name = useAtomValue(quizNameAtom); return (