generated from muhtadeetaron/nextjs-template
fix(nav): improve navigation for authorization routes
This commit is contained in:
@ -29,7 +29,7 @@ const LoginPage = () => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
await login(form, setToken);
|
||||
router.push("/home");
|
||||
router.replace("/home");
|
||||
} catch (err: unknown) {
|
||||
console.error(err);
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ export default function RegisterPage() {
|
||||
|
||||
try {
|
||||
await register(form, setToken);
|
||||
router.push("/login");
|
||||
router.replace("/login");
|
||||
} catch (err: unknown) {
|
||||
setError(formatError(err));
|
||||
console.error("User creation error: ", err);
|
||||
|
||||
@ -73,7 +73,10 @@ export default function MockScreen() {
|
||||
<Header displayTabTitle="Mocks" />
|
||||
<div className="overflow-y-auto">
|
||||
<div className="mt-5 px-5">
|
||||
<DestructibleAlert text={errorMsg} />
|
||||
<h1 className="text-2xl font-semibold my-5">
|
||||
{user?.preparation_unit}
|
||||
</h1>
|
||||
<DestructibleAlert text={errorMsg} variant="error" />
|
||||
</div>
|
||||
<div className="flex justify-center mt-4">
|
||||
<button
|
||||
|
||||
@ -68,7 +68,10 @@ export default function PaperScreen() {
|
||||
<Header displayTabTitle="Subjects" />
|
||||
<div className="overflow-y-auto">
|
||||
<div className="mt-5 px-5">
|
||||
<DestructibleAlert text={errorMsg} />
|
||||
<h1 className="text-2xl font-semibold my-5">
|
||||
{user?.preparation_unit}
|
||||
</h1>
|
||||
<DestructibleAlert text={errorMsg} variant="error" />
|
||||
</div>
|
||||
<div className="flex justify-center mt-4">
|
||||
<button
|
||||
|
||||
@ -72,7 +72,10 @@ export default function TopicScreen() {
|
||||
<Header displayTabTitle="Subjects" />
|
||||
<div className="overflow-y-auto">
|
||||
<div className="mt-5 px-5">
|
||||
<DestructibleAlert text={errorMsg} />
|
||||
<h1 className="text-2xl font-semibold my-5">
|
||||
{user?.preparation_unit}
|
||||
</h1>
|
||||
<DestructibleAlert text={errorMsg} variant="error" />
|
||||
</div>
|
||||
<div className="flex justify-center mt-4">
|
||||
<button
|
||||
|
||||
@ -9,32 +9,41 @@ export default function AuthInitializer({
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { initializeAuth, isLoading, token } = useAuthStore();
|
||||
const { initializeAuth, token, hydrated } = useAuthStore();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
// 1️⃣ Run initialization once
|
||||
useEffect(() => {
|
||||
const run = async () => {
|
||||
await initializeAuth();
|
||||
initializeAuth();
|
||||
}, [initializeAuth]);
|
||||
|
||||
// Routing logic based on auth state
|
||||
const publicPages = ["/", "/login", "/register"];
|
||||
// 2️⃣ Run routing logic only after hydration
|
||||
useEffect(() => {
|
||||
if (!hydrated) return;
|
||||
|
||||
if (token) {
|
||||
if (publicPages.includes(pathname)) {
|
||||
router.replace("/home");
|
||||
}
|
||||
} else {
|
||||
if (!publicPages.includes(pathname)) {
|
||||
router.replace("/");
|
||||
}
|
||||
const publicPages = ["/", "/login", "/register"];
|
||||
|
||||
if (token) {
|
||||
if (publicPages.includes(pathname)) {
|
||||
router.replace("/home");
|
||||
}
|
||||
};
|
||||
} else {
|
||||
if (!publicPages.includes(pathname)) {
|
||||
router.replace("/login");
|
||||
}
|
||||
}
|
||||
}, [pathname, token, hydrated, router]);
|
||||
|
||||
run();
|
||||
}, [pathname, token, initializeAuth, router]);
|
||||
|
||||
if (isLoading) return <p>Loading...</p>;
|
||||
// 3️⃣ Show loading until hydrated
|
||||
if (!hydrated) {
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col justify-center items-center gap-3">
|
||||
<div className="animate-spin rounded-full h-20 w-20 border-b-2 border-blue-500"></div>
|
||||
<p className="text-2xl font-semibold tracking-tighter">Loading...</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@ -46,9 +46,9 @@ const Header = ({
|
||||
const seconds = timeRemaining % 60;
|
||||
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<header className="bg-[#113768] h-[100px] w-full pt-7 px-6 flex items-center justify-between sticky top-0 z-50">
|
||||
{displayUser && (
|
||||
<div className={styles.profile}>
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar className="bg-gray-200 w-10 h-10">
|
||||
<AvatarFallback className="flex items-center justify-center h-10 text-lg">
|
||||
{user?.username ? (
|
||||
@ -58,24 +58,26 @@ const Header = ({
|
||||
)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className={styles.text}>
|
||||
<span className="text-md font-bold text-white">
|
||||
Hello, {user?.username ? user.username.split(" ")[0] : "User"}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{displayTabTitle && (
|
||||
<div className={styles.profile}>
|
||||
<button onClick={handleBackClick} className={styles.iconButton}>
|
||||
<div className="flex items-center gap-3">
|
||||
<button onClick={handleBackClick} className="bg-none border-none p-1">
|
||||
<ChevronLeft size={24} color="white" />
|
||||
</button>
|
||||
<span className={styles.text}>{displayTabTitle}</span>
|
||||
<span className="text-md font-bold text-white">
|
||||
{displayTabTitle}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{displaySubject && (
|
||||
<div className={styles.profile}>
|
||||
<span className={styles.text}>{displaySubject}</span>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-md font-bold text-white">{displaySubject}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -127,32 +127,4 @@ export const getLinkedViews = (): GalleryViews[] => [
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: (
|
||||
<Link
|
||||
href="https://www.facebook.com/share/g/15jdqESvWV/?mibextid=wwXIfr"
|
||||
className="lock "
|
||||
>
|
||||
<div className="w-full h-full p-6 flex text-black bg-blue-50 rounded-3xl border-[0.5px] border-[#113768]/30">
|
||||
<div className="">
|
||||
<h3 className="text-2xl text-[#113768] font-black">
|
||||
Meet, Share, and Learn!
|
||||
</h3>
|
||||
<p className="font-bold text-sm text-[#113768] ">
|
||||
Join Facebook Community
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-center items-center shrink-0">
|
||||
<Image
|
||||
src="/images/static/facebook-logo.png"
|
||||
alt="Facebook Logo"
|
||||
width={150}
|
||||
height={150}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
@ -35,6 +35,7 @@ const setCookie = (
|
||||
interface AuthState {
|
||||
token: string | null;
|
||||
isLoading: boolean;
|
||||
hydrated: boolean;
|
||||
user: UserData | null;
|
||||
|
||||
setToken: (token: string | null) => void;
|
||||
@ -46,6 +47,7 @@ interface AuthState {
|
||||
export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
token: null,
|
||||
isLoading: true,
|
||||
hydrated: false,
|
||||
user: null,
|
||||
|
||||
setToken: (newToken) => {
|
||||
@ -59,9 +61,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/me/profile/`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error("Failed to fetch user info");
|
||||
@ -85,6 +85,6 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
||||
set({ token: storedToken });
|
||||
await get().fetchUser();
|
||||
}
|
||||
set({ isLoading: false });
|
||||
set({ isLoading: false, hydrated: true });
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user