Pending course, rest ready for launch

This commit is contained in:
Marcelo
2026-03-15 13:52:11 +00:00
parent be4ca2ed78
commit 62b3cfe467
77 changed files with 6450 additions and 868 deletions

View File

@@ -1,7 +1,7 @@
"use client";
import { createBrowserClient } from "@supabase/ssr";
import { FormEvent, useState } from "react";
import { FormEvent, useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
@@ -9,17 +9,24 @@ type LoginFormProps = {
redirectTo: string;
role?: string;
showForgot?: boolean;
skipAuthedRedirect?: boolean;
};
// Helper to prevent open redirect vulnerabilities
const normalizeRedirect = (redirectTo: string) => {
if (redirectTo.startsWith("/") && !redirectTo.startsWith("//")) {
return redirectTo;
if (!redirectTo.startsWith("/") || redirectTo.startsWith("//")) {
return "/courses";
}
return "/home"; // Default fallback
// Never redirect back into auth routes after successful login.
if (redirectTo.startsWith("/auth/")) {
return "/courses";
}
return redirectTo;
};
export default function LoginForm({ redirectTo, role, showForgot }: LoginFormProps) {
export default function LoginForm({ redirectTo, role, showForgot, skipAuthedRedirect }: LoginFormProps) {
const router = useRouter();
const safeRedirect = normalizeRedirect(redirectTo);
const isTeacher = role === "teacher";
@@ -30,6 +37,23 @@ export default function LoginForm({ redirectTo, role, showForgot }: LoginFormPro
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (skipAuthedRedirect) {
return;
}
const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
);
supabase.auth.getUser().then(({ data }) => {
if (data.user) {
router.replace(safeRedirect);
}
});
}, [router, safeRedirect, skipAuthedRedirect]);
// Construct the "Forgot Password" link to preserve context
const forgotHref = `/auth/login?redirectTo=${encodeURIComponent(safeRedirect)}${isTeacher ? "&role=teacher" : ""
}&forgot=1`;
@@ -62,8 +86,9 @@ export default function LoginForm({ redirectTo, role, showForgot }: LoginFormPro
// so they see the new cookie immediately.
router.refresh();
// 4. Navigate to the protected page
router.push(safeRedirect);
// 4. Navigate to the protected page and release button state.
setLoading(false);
router.replace(safeRedirect);
};
return (
@@ -149,4 +174,4 @@ export default function LoginForm({ redirectTo, role, showForgot }: LoginFormPro
</div>
</div>
);
}
}