Skip to content

Commit a7d6189

Browse files
Merge pull request #117 from ARYPROGRAMMER/dashboard-fixtures
fix: added proper state management and route verification of dashboard
2 parents 31b7f1b + b281843 commit a7d6189

File tree

6 files changed

+158
-24
lines changed

6 files changed

+158
-24
lines changed

app/auth/register/page.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
import { Suspense } from "react";
12
import SignupForm from "@/components/AuthComponent/SignupForm";
3+
import SearchParamsWrapper from "@/components/AuthComponent/SearchParamsWrapper";
4+
25

36
export default function SignupPage() {
47
return (
58
<div className="">
6-
<SignupForm />
9+
<Suspense fallback={<div>Loading...</div>}>
10+
<SearchParamsWrapper>
11+
<SignupForm />
12+
</SearchParamsWrapper>
13+
</Suspense>
714
</div>
815
);
9-
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use client";
2+
3+
import { useSearchParams } from "next/navigation";
4+
import React from "react";
5+
6+
interface ChildProps {
7+
searchParams?: ReturnType<typeof useSearchParams>;
8+
}
9+
10+
export default function SearchParamsWrapper({
11+
children
12+
}: {
13+
children: React.ReactNode
14+
}) {
15+
const searchParams = useSearchParams();
16+
17+
return (
18+
<>
19+
{React.Children.map(children, child => {
20+
if (React.isValidElement<ChildProps>(child)) {
21+
return React.cloneElement(child, { searchParams });
22+
}
23+
return child;
24+
})}
25+
</>
26+
);
27+
}

components/AuthComponent/SignupForm.tsx

+28-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"use client";
22

33
import React, { useState } from "react";
4-
import { useRouter } from "next/navigation";
54
import { zodResolver } from "@hookform/resolvers/zod";
65
import { useForm } from "react-hook-form";
76
import * as z from "zod";
@@ -32,17 +31,27 @@ import {
3231
CardTitle,
3332
} from "@/components/ui/card";
3433
import { Alert, AlertDescription } from "@/components/ui/alert";
35-
import { useAuthStore } from "@/store/AuthStore/useAuthStore";
3634
import AuthBottom from "./AuthBottom";
3735
import LoadingButton from "./LoadingButton";
3836
import { signupSchema } from "@/validations/validation";
37+
import { useEffect } from "react"
38+
import { useRouter, useSearchParams } from "next/navigation"
39+
import { useAuthStore } from "@/store/AuthStore/useAuthStore"
40+
import { useAuth } from "@/hooks/useAuth";
3941

4042
type SignupFormValues = z.infer<typeof signupSchema>;
4143

42-
export default function SignupForm() {
44+
interface SignupFormProps {
45+
searchParams?: URLSearchParams;
46+
}
47+
48+
export default function SignupForm({searchParams}: SignupFormProps) {
4349
const { isSigningUp, signup, signupError } = useAuthStore();
4450
const router = useRouter();
4551
const [showPassword, setShowPassword] = useState(false);
52+
const { isSigningIn, signin, signinError } = useAuthStore()
53+
const { user, loading } = useAuth()
54+
4655

4756
const form = useForm<SignupFormValues>({
4857
resolver: zodResolver(signupSchema),
@@ -55,9 +64,22 @@ export default function SignupForm() {
5564
},
5665
});
5766

58-
const onSubmit = (data: SignupFormValues) => {
59-
signup(data, router);
60-
};
67+
useEffect(() => {
68+
// If user is already authenticated, redirect to the intended URL or dashboard
69+
if (user && !loading) {
70+
const redirectTo = searchParams?.get('redirect') || '/dashboard'
71+
router.push(redirectTo)
72+
}
73+
}, [user, loading, router, searchParams])
74+
75+
const onSubmit = async (data: SignupFormValues) => {
76+
try {
77+
signup(data, router);
78+
// The redirect will be handled by the useEffect above when the user state updates
79+
} catch (error) {
80+
console.error('Sign in error:', error)
81+
}
82+
}
6183

6284
return (
6385
<main className="flex min-h-screen items-center justify-center md:p-0 p-2">

components/DashboardV2/V2Navbar.tsx

+49-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22
import { ChevronsDown, Github, Menu } from "lucide-react";
3-
import React from "react";
3+
import React , { Suspense } from "react";
44
import {
55
Sheet,
66
SheetContent,
@@ -23,6 +23,9 @@ import Link from "next/link";
2323
import Image from "next/image";
2424
import { ToggleTheme } from "./ToggleTheme";
2525
import { Avatar, AvatarFallback, AvatarImage } from "../ui/avatar";
26+
import { useAuth } from "@/hooks/useAuth";
27+
import { signout } from "@/app/actions/action";
28+
import { useRouter } from "next/navigation";
2629

2730
interface RouteProps {
2831
href: string;
@@ -70,8 +73,41 @@ const featureList: FeatureProps[] = [
7073
},
7174
];
7275

73-
export const V2Navbar = () => {
76+
export const NavigationContent = () => {
7477
const [isOpen, setIsOpen] = React.useState(false);
78+
const { user, loading } = useAuth();
79+
const router = useRouter();
80+
const [authState, setAuthState] = React.useState({ user, loading });
81+
82+
React.useEffect(() => {
83+
setAuthState({ user, loading });
84+
}, [user, loading]);
85+
86+
const handleSignOut = async () => {
87+
await signout();
88+
router.push("/auth/signin");
89+
};
90+
91+
const renderAuthButtons = () => {
92+
if (authState.loading) return null;
93+
94+
return authState.user ? (
95+
<Button onClick={handleSignOut} className="rounded-2xl">
96+
Sign Out
97+
</Button>
98+
) : (
99+
<>
100+
<Link href="/auth/register">
101+
<Button className="rounded-2xl">Register</Button>
102+
</Link>
103+
<Link href="/auth/signin">
104+
<Button className="rounded-2xl">Login</Button>
105+
</Link>
106+
</>
107+
);
108+
};
109+
110+
75111
return (
76112
<header className="shadow-inner w-[90%] md:w-[70%] lg:w-[75%] lg:max-w-screen-xl top-5 mx-auto sticky border border-secondary z-40 rounded-2xl flex justify-between items-center p-2 bg-secondary/30 backdrop-blur-md">
77113
<Link href="/" className="flex items-center font-semibold">
@@ -127,6 +163,8 @@ export const V2Navbar = () => {
127163
<Separator className="mb-2" />
128164

129165
<ToggleTheme />
166+
<Separator className="mb-2" />
167+
{renderAuthButtons()}
130168
</SheetFooter>
131169
</SheetContent>
132170
</Sheet>
@@ -181,14 +219,16 @@ export const V2Navbar = () => {
181219

182220
<div className="hidden lg:flex gap-2">
183221
<ToggleTheme />
184-
185-
<Link href="/auth/register">
186-
<Button className="rounded-2xl">Register</Button>
187-
</Link>
188-
<Link href="/auth/signin">
189-
<Button className="rounded-2xl">Login</Button>
190-
</Link>
222+
{renderAuthButtons()}
191223
</div>
192224
</header>
193225
);
194226
};
227+
228+
export const V2Navbar = () => {
229+
return (
230+
<Suspense fallback={<div>Loading...</div>}>
231+
<NavigationContent />
232+
</Suspense>
233+
);
234+
};

hooks/useAuth.ts

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { useEffect, useState } from 'react';
2+
import { createClient } from '@/utils/supabase/client';
3+
4+
import { User } from '@supabase/supabase-js';
5+
6+
export function useAuth() {
7+
const [user, setUser] = useState<User | null>(null);
8+
const [loading, setLoading] = useState(true);
9+
const supabase = createClient();
10+
11+
useEffect(() => {
12+
// Check active sessions and sets the user
13+
const getUser = async () => {
14+
const { data: { user }, error } = await supabase.auth.getUser();
15+
setUser(user);
16+
setLoading(false);
17+
};
18+
19+
getUser();
20+
21+
// Listen for changes on auth state (login, logout, etc)
22+
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
23+
setUser(session?.user ?? null);
24+
setLoading(false);
25+
});
26+
27+
return () => {
28+
subscription.unsubscribe();
29+
};
30+
}, []);
31+
32+
return { user, loading };
33+
}

store/AuthStore/useAuthStore.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@ interface authStore {
1515
isSigningIn: boolean;
1616
signinError: string | null;
1717
signin: (signinMetaData: { email: string, password: string },router: any) => void;
18-
logout: () => void;
19-
18+
logout: (router: any) => void;
2019
signupError: string | null;
2120
isSigningUp: boolean;
2221
signup: (signupMetaData: User,router: any) => void;
2322
user: User | null;
24-
2523
authUserLoading: boolean;
2624
fetchAuthUser: () => void;
2725
authUser: User | null;
@@ -32,7 +30,7 @@ export const useAuthStore = create<authStore>((set) => ({
3230
isSigningIn: false,
3331
signin: async (signinMetaData,router) => {
3432
const supabase = createClient()
35-
set({ isSigningIn: true })
33+
set({ isSigningIn: true, signinError: null })
3634
try {
3735
const { data, error: loginError } =
3836
await supabase.auth.signInWithPassword(signinMetaData);
@@ -44,7 +42,8 @@ export const useAuthStore = create<authStore>((set) => ({
4442
}
4543

4644
if (data.session) {
47-
router.push("/dashboard");
45+
// Ensure we have a session before redirecting
46+
await router.push('/dashboard');
4847
} else {
4948
throw new Error("Unable to retrieve session after login.");
5049
}
@@ -56,8 +55,14 @@ export const useAuthStore = create<authStore>((set) => ({
5655
}
5756
},
5857

59-
logout: () => {
60-
console.log('logout');
58+
logout: async (router) => {
59+
const supabase = createClient()
60+
try {
61+
await supabase.auth.signOut();
62+
router.push('/auth/signin');
63+
} catch (error) {
64+
console.error('Logout error:', error);
65+
}
6166
},
6267

6368
signupError: null,

0 commit comments

Comments
 (0)