diff --git a/package-lock.json b/package-lock.json index ccdfc4b..8b88beb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "server-only": "^0.0.1", "superjson": "^2.2.1", "svix": "^1.15.0", - "zod": "^3.22.4" + "zod": "^3.22.4", + "zustand": "^4.4.7" }, "devDependencies": { "@next/eslint-plugin-next": "^14.0.3", @@ -1254,7 +1255,7 @@ "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "dev": true + "devOptional": true }, "node_modules/@types/qs": { "version": "6.9.10", @@ -1270,7 +1271,7 @@ "version": "18.2.41", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.41.tgz", "integrity": "sha512-CwOGr/PiLiNBxEBqpJ7fO3kocP/2SSuC9fpH5K7tusrg4xPSRT/193rzolYwQnTN02We/ATXKnb6GqA5w4fRxw==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1290,7 +1291,7 @@ "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "dev": true + "devOptional": true }, "node_modules/@types/semver": { "version": "7.5.6", @@ -2006,7 +2007,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true + "devOptional": true }, "node_modules/d": { "version": "1.0.1", @@ -5104,6 +5105,33 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zustand": { + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.7.tgz", + "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 8185801..5f08143 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,8 @@ "server-only": "^0.0.1", "superjson": "^2.2.1", "svix": "^1.15.0", - "zod": "^3.22.4" + "zod": "^3.22.4", + "zustand": "^4.4.7" }, "devDependencies": { "@next/eslint-plugin-next": "^14.0.3", diff --git a/src/app/_hooks/useLessonStore.ts b/src/app/_hooks/useLessonStore.ts new file mode 100644 index 0000000..a1085ce --- /dev/null +++ b/src/app/_hooks/useLessonStore.ts @@ -0,0 +1,29 @@ +import { create } from "zustand"; +import type { SelectExercises } from "~/server/db/schema-types"; + +interface State { + id: Id | undefined; + exercises: SelectExercises[]; +} + +interface Actions { + setId: (id?: Id) => void; + reset: () => void; +} + +interface Id { + courseId: number; + topicId: number; + lessonId: number; +} + +const initialState: State = { + id: undefined, + exercises: [], +}; + +export const useLessonStore = create()((set) => ({ + ...initialState, + setId: (id) => set(() => ({ id })), + reset: () => set(initialState), +})); diff --git a/src/app/_hooks/useResetLesson.ts b/src/app/_hooks/useResetLesson.ts new file mode 100644 index 0000000..1386300 --- /dev/null +++ b/src/app/_hooks/useResetLesson.ts @@ -0,0 +1,20 @@ +import { useEffect, useRef } from "react"; +import { usePathname } from "next/navigation"; +import { useLessonStore } from "~/app/_hooks/useLessonStore"; + +/** + * This resets the lesson store any time a user leaves + * the lessons page + */ +export default function useResetLesson() { + const lastRoute = useRef("/"); + + const id = useLessonStore((state) => state.id); + const reset = useLessonStore((state) => state.reset); + + const pathname = usePathname(); + useEffect(() => { + if (lastRoute.current === "/lesson" && id) reset(); + lastRoute.current = pathname; + }, [pathname]); +} diff --git a/src/app/client-providers.tsx b/src/app/client-providers.tsx index 097e973..6950351 100644 --- a/src/app/client-providers.tsx +++ b/src/app/client-providers.tsx @@ -1,11 +1,14 @@ "use client"; import type { PropsWithChildren } from "react"; +import useResetLesson from "~/app/_hooks/useResetLesson"; + /** * Client-side provider components that need to wrap * the entire app should be defined here to avoid * turning the entire app into a client component */ export default function ClientProviders({ children }: PropsWithChildren) { + useResetLesson(); return <>{children}; }