diff --git a/package.json b/package.json
index 68e488d..3984f82 100644
--- a/package.json
+++ b/package.json
@@ -61,7 +61,8 @@
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.4",
- "zod": "^3.23.8"
+ "zod": "^3.23.8",
+ "zustand": "^5.0.0-rc.2"
},
"devDependencies": {
"@types/eslint": "^8.56.10",
diff --git a/public/logo.svg b/public/logo.svg
new file mode 100644
index 0000000..e6fe743
--- /dev/null
+++ b/public/logo.svg
@@ -0,0 +1,9 @@
+
diff --git a/src/app/problems/_components/mobile-dropdown.tsx b/src/app/problems/_components/mobile-dropdown.tsx
new file mode 100644
index 0000000..45b42df
--- /dev/null
+++ b/src/app/problems/_components/mobile-dropdown.tsx
@@ -0,0 +1,34 @@
+"use client";
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "~/components/ui/dropdown-menu";
+import { MenuIcon } from "lucide-react";
+import { Button } from "~/components/ui/button";
+import { DropdownMenuSeparator } from "~/components/ui/dropdown-menu";
+import { useAuthStore } from "~/providers/auth-store-provider";
+
+export function MobileDropdown() {
+ const session = useAuthStore((state) => state.session);
+ return (
+
+
+
+
+
+ Profile
+ Multiplayer
+ {session && (
+ <>
+
+ Sign Out
+ >
+ )}
+
+
+ );
+}
diff --git a/src/app/problems/_components/navbar.tsx b/src/app/problems/_components/navbar.tsx
new file mode 100644
index 0000000..1670788
--- /dev/null
+++ b/src/app/problems/_components/navbar.tsx
@@ -0,0 +1,17 @@
+import Link from "next/link";
+import { MobileDropdown } from "./mobile-dropdown";
+import { Button } from "~/components/ui/button";
+
+export function Navbar() {
+ return (
+
+ );
+}
diff --git a/src/app/problems/page.tsx b/src/app/problems/page.tsx
new file mode 100644
index 0000000..418f46b
--- /dev/null
+++ b/src/app/problems/page.tsx
@@ -0,0 +1,13 @@
+import { AuthStoreProvider } from "~/providers/auth-store-provider";
+import { Navbar } from "./_components/navbar";
+import { validateRequest } from "~/lib/auth/validate-request";
+
+export default async function Problems() {
+ const auth = await validateRequest();
+ return (
+
+
+ Problems
+
+ );
+}
diff --git a/src/providers/auth-store-provider.tsx b/src/providers/auth-store-provider.tsx
new file mode 100644
index 0000000..87f42fb
--- /dev/null
+++ b/src/providers/auth-store-provider.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import { createContext, useContext, useRef } from "react";
+import { type validateRequest } from "~/lib/auth/validate-request";
+import { type AuthStore, createAuthStore } from "~/stores/auth-store";
+import { useStore } from "zustand";
+
+export type AuthStoreApi = ReturnType;
+
+export const AuthStoreContext = createContext(
+ undefined,
+);
+
+export function AuthStoreProvider({
+ children,
+ auth,
+}: {
+ children: React.ReactNode;
+ auth: Awaited>;
+}) {
+ const storeRef = useRef();
+ if (!storeRef.current) {
+ storeRef.current = createAuthStore(auth);
+ }
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function useAuthStore(selector: (state: AuthStore) => T): T {
+ const authStore = useContext(AuthStoreContext);
+ if (!authStore) {
+ throw new Error("useAuthStore must be used within an AuthStoreProvider");
+ }
+ return useStore(authStore, selector);
+}
diff --git a/src/stores/auth-store.ts b/src/stores/auth-store.ts
new file mode 100644
index 0000000..a84fbac
--- /dev/null
+++ b/src/stores/auth-store.ts
@@ -0,0 +1,19 @@
+import { createStore } from "zustand/vanilla";
+import { type validateRequest } from "~/lib/auth/validate-request";
+
+export type AuthState = Awaited>;
+
+export type AuthStore = AuthState;
+
+export const defaultAuthState: AuthState = {
+ user: null,
+ session: null,
+};
+
+export const createAuthStore = (
+ initialAuthState: AuthState = defaultAuthState,
+) => {
+ return createStore()(() => ({
+ ...initialAuthState,
+ }));
+};