From d82d4b140d0078c831743c7e1ffb98425064da1c Mon Sep 17 00:00:00 2001 From: mewdev Date: Thu, 9 Jan 2025 10:11:05 +0100 Subject: [PATCH] wip: questionsPage (/xyz) refactor within /abc route, context test, browserTab title test --- apps/web/app/abc/components/counter.tsx | 22 +++++++++ apps/web/app/abc/counter/page.tsx | 11 +++++ apps/web/app/abc/layout.tsx | 21 ++++++++ apps/web/app/abc/page.tsx | 48 +++++++++++++++++++ .../abc/providers/counterStoreProvider.tsx | 43 +++++++++++++++++ apps/web/app/abc/store.ts | 26 ++++++++++ apps/web/app/abc/utils/urlUpdater.tsx | 19 ++++++++ 7 files changed, 190 insertions(+) create mode 100644 apps/web/app/abc/components/counter.tsx create mode 100644 apps/web/app/abc/counter/page.tsx create mode 100644 apps/web/app/abc/layout.tsx create mode 100644 apps/web/app/abc/page.tsx create mode 100644 apps/web/app/abc/providers/counterStoreProvider.tsx create mode 100644 apps/web/app/abc/store.ts create mode 100644 apps/web/app/abc/utils/urlUpdater.tsx diff --git a/apps/web/app/abc/components/counter.tsx b/apps/web/app/abc/components/counter.tsx new file mode 100644 index 00000000..1369e1fd --- /dev/null +++ b/apps/web/app/abc/components/counter.tsx @@ -0,0 +1,22 @@ +"use client"; + +import { useCounterStore } from "../providers/counterStoreProvider"; + +export default function Counter() { + const { count, incrementCount, decrementCount } = useCounterStore( + (state) => state, + ); + + return ( +
+ Count: {count} +
+ + +
+ ); +} diff --git a/apps/web/app/abc/counter/page.tsx b/apps/web/app/abc/counter/page.tsx new file mode 100644 index 00000000..fcc0c028 --- /dev/null +++ b/apps/web/app/abc/counter/page.tsx @@ -0,0 +1,11 @@ +"use client"; + +import Counter from "../components/counter"; + +export default function Page() { + return ( +
+ +
+ ); +} diff --git a/apps/web/app/abc/layout.tsx b/apps/web/app/abc/layout.tsx new file mode 100644 index 00000000..c496ddf4 --- /dev/null +++ b/apps/web/app/abc/layout.tsx @@ -0,0 +1,21 @@ +import "../globals.css"; +import "@repo/design-system/styles"; +import "@repo/design-system/themes/theme-default"; +import { CounterStoreProvider } from "./providers/counterStoreProvider"; +import UrlUpdater from "./utils/urlUpdater"; + +export default async function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + {children} + + + + ); +} diff --git a/apps/web/app/abc/page.tsx b/apps/web/app/abc/page.tsx new file mode 100644 index 00000000..71bf3677 --- /dev/null +++ b/apps/web/app/abc/page.tsx @@ -0,0 +1,48 @@ +"use client"; + +import { useEffect, useState } from "react"; + +type Question = { + id: string; + title: string; + statement: string; + detail: string; + tags: string[]; +}; + +export default function Page() { + const [isLoading, setIsLoading] = useState(true); + const [questions, setQuestions] = useState([]); + + useEffect(() => { + // make a generic fn + async function fetchQuestions() { + const res = await fetch( + "https://www.volebnikalkulacka.cz/data/instance/volebnikalkulacka.cz/krajske-2024/10-jihomoravsky/questions.json", + ); + const data = await res.json(); + setQuestions(data); + setIsLoading(false); + } + fetchQuestions(); + }, []); + + // loading ui + if (isLoading) { + return

Data is Loading

; + } + // loaded ui + return ( +
+
+ {questions?.map((question: Question) => { + return ( +
+ {question.statement} +
+ ); + })} +
+
+ ); +} diff --git a/apps/web/app/abc/providers/counterStoreProvider.tsx b/apps/web/app/abc/providers/counterStoreProvider.tsx new file mode 100644 index 00000000..948f2dcc --- /dev/null +++ b/apps/web/app/abc/providers/counterStoreProvider.tsx @@ -0,0 +1,43 @@ +"use client"; + +import { type ReactNode, createContext, useRef, useContext } from "react"; +import { useStore } from "zustand"; + +import { type CounterStore, createCounterStore } from "../store"; + +export type CounterStoreApi = ReturnType; + +export const CounterStoreContext = createContext( + undefined, +); + +export interface CounterStoreProviderProps { + children: ReactNode; +} + +export const CounterStoreProvider = ({ + children, +}: CounterStoreProviderProps) => { + const storeRef = useRef(); + if (!storeRef.current) { + storeRef.current = createCounterStore(); + } + + return ( + + {children} + + ); +}; + +export const useCounterStore = ( + selector: (store: CounterStore) => T, +): T => { + const counterStoreContext = useContext(CounterStoreContext); + + if (!counterStoreContext) { + throw new Error(`useCounterStore must be used within CounterStoreProvider`); + } + + return useStore(counterStoreContext, selector); +}; diff --git a/apps/web/app/abc/store.ts b/apps/web/app/abc/store.ts new file mode 100644 index 00000000..cc001872 --- /dev/null +++ b/apps/web/app/abc/store.ts @@ -0,0 +1,26 @@ +import { createStore } from "zustand/vanilla"; + +export type CounterState = { + count: number; +}; + +export type CounterActions = { + decrementCount: () => void; + incrementCount: () => void; +}; + +export type CounterStore = CounterState & CounterActions; + +export const defaultInitState: CounterState = { + count: 0, +}; + +export const createCounterStore = ( + initState: CounterState = defaultInitState, +) => { + return createStore()((set) => ({ + ...initState, + decrementCount: () => set((state) => ({ count: state.count - 1 })), + incrementCount: () => set((state) => ({ count: state.count + 1 })), + })); +}; diff --git a/apps/web/app/abc/utils/urlUpdater.tsx b/apps/web/app/abc/utils/urlUpdater.tsx new file mode 100644 index 00000000..1f9f4407 --- /dev/null +++ b/apps/web/app/abc/utils/urlUpdater.tsx @@ -0,0 +1,19 @@ +"use client"; +import { useEffect } from "react"; +import { useCounterStore } from "../providers/counterStoreProvider"; + +type Props = { + children: React.ReactNode; +}; + +export default function UrlUpdater({ children }: Props) { + const count = useCounterStore((state) => state.count); + + useEffect(() => { + function changeTitle() { + document.title = `Hello World: ${count}`; + } + changeTitle(); + }, [count]); + return children; +}