diff --git a/frontend/package.json b/frontend/package.json
index ac87fd2..f40abbb 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -6,7 +6,7 @@
"dev": "next dev --turbopack",
"build": "next build --turbopack",
"start": "next start",
- "lint": "eslint"
+ "lint": "next lint"
},
"dependencies": {
"@hookform/resolvers": "^5.2.2",
diff --git a/frontend/src/app/(app)/layout.tsx b/frontend/src/app/(app)/layout.tsx
index b2afcc9..319c8ad 100644
--- a/frontend/src/app/(app)/layout.tsx
+++ b/frontend/src/app/(app)/layout.tsx
@@ -1,8 +1,30 @@
'use client';
import type { ReactElement, ReactNode } from 'react';
+import { useEffect } from 'react';
import { AppShell } from '@/components/layout/app-shell';
+import { useAuth } from '@/providers/auth-context';
+import { useRouter } from 'next/navigation';
+import { Loader2 } from 'lucide-react';
export default function ProtectedLayout({ children }: { children: ReactNode }): ReactElement {
+ const { isAuthenticated } = useAuth();
+ const router = useRouter();
+
+ useEffect(() => {
+ if (!isAuthenticated) {
+ router.push('/');
+ }
+ }, [isAuthenticated, router]);
+
+ if (!isAuthenticated) {
+ return (
+
+ );
+ }
+
return {children};
}
diff --git a/frontend/src/components/layout/app-header.tsx b/frontend/src/components/layout/app-header.tsx
index 3a4ae49..edfa98c 100644
--- a/frontend/src/components/layout/app-header.tsx
+++ b/frontend/src/components/layout/app-header.tsx
@@ -141,7 +141,7 @@ export function AppHeader({ onMobileMenuToggle }: AppHeaderProps = {}): ReactEle
variant="ghost"
size="md"
onClick={() => {
- void signOut();
+ signOut();
}}
leftIcon={}
className={cn('border border-transparent text-slate-300 hover:border-rose-500/50 hover:bg-rose-500/10 hover:text-rose-200', isLoading && 'pointer-events-none opacity-60')}
diff --git a/frontend/src/providers/auth-context.tsx b/frontend/src/providers/auth-context.tsx
index 3b2bdf4..d58b6b1 100644
--- a/frontend/src/providers/auth-context.tsx
+++ b/frontend/src/providers/auth-context.tsx
@@ -5,6 +5,7 @@ import type { BackendUser } from '@/types/api';
import { useCallback, useMemo } from 'react';
import { useActiveAccount, useActiveWallet } from 'thirdweb/react';
import { client } from '@/lib/thirdweb';
+import { useRouter } from 'next/navigation';
export type AuthContextValue = {
user: BackendUser | null;
@@ -28,6 +29,7 @@ export function useAuth(): AuthContextValue {
// Always call hooks first, then handle the conditional logic
const account = useActiveAccount();
const wallet = useActiveWallet();
+ const router = useRouter();
const address = account?.address ?? null;
@@ -46,11 +48,15 @@ export function useAuth(): AuthContextValue {
const signOut = useCallback(async () => {
try {
- await wallet?.disconnect?.();
- } catch {
- // ignore
+ if (wallet) {
+ await wallet.disconnect?.();
+ }
+ await new Promise(resolve => setTimeout(resolve, 100));
+ router.push('/');
+ } catch (error) {
+ router.push('/');
}
- }, [wallet]);
+ }, [wallet, router]);
const refreshProfile = useCallback(async (): Promise => {
return user;
@@ -58,13 +64,11 @@ export function useAuth(): AuthContextValue {
const signInWithEmail = useCallback(async (_email: string): Promise => {
// TODO: Implement email authentication when backend is ready
- console.log('Email sign-in attempted:', _email);
return false;
}, []);
const resendVerification = useCallback(async (_email: string): Promise => {
// TODO: Implement email verification when backend is ready
- console.log('Email verification requested:', _email);
return false;
}, []);
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index c133409..ee38357 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -5,7 +5,7 @@
"allowJs": true,
"skipLibCheck": true,
"strict": true,
- "noEmit": true,
+ "noEmit": false,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
diff --git a/frontend/vercel.json b/frontend/vercel.json
new file mode 100644
index 0000000..63c6810
--- /dev/null
+++ b/frontend/vercel.json
@@ -0,0 +1,9 @@
+{
+ "buildCommand": "pnpm build",
+ "outputDirectory": ".next",
+ "framework": "nextjs",
+ "installCommand": "pnpm install",
+ "env": {
+ "NODE_ENV": "production"
+ }
+}