Improve fresh install flow and auth page routing

- Move /setup out of protected (pages) route group so it's accessible
  without auth (fixes fresh install redirect loop)
- Redirect /login → /register when zero users exist
- Add "Get Started" button on landing page for fresh installs
- Hide register button/link when registration is closed
- Add auth redirects: logged-in users on /login or /register → /dashboard
- Convert register page to server component with server-side checks
- Fix animation snap on auth form buttons (transition-all → scoped)
- Update proxy middleware with /login and /register routes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 13:58:15 -05:00
co-authored by Claude Opus 4.6
parent 6cfe3a0439
commit 3511a76508
7 changed files with 126 additions and 90 deletions
+29 -27
View File
@@ -12,6 +12,7 @@ export interface AuthConfig {
oidcEnabled: boolean;
oidcProviderName: string | null;
passwordLoginDisabled: boolean;
registrationOpen?: boolean;
}
const fieldVariants = {
@@ -122,7 +123,7 @@ export function AuthForm({
disabled={oidcLoading}
variants={fieldVariants}
whileTap={{ scale: 0.98 }}
className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg border border-border/50 bg-background/50 text-sm font-medium transition-all hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
className="inline-flex h-11 w-full items-center justify-center gap-2 rounded-lg border border-border/50 bg-background/50 text-sm font-medium transition-colors hover:bg-accent hover:text-foreground disabled:pointer-events-none disabled:opacity-50"
>
<IconKey className="size-4" />
{oidcLoading
@@ -213,7 +214,7 @@ export function AuthForm({
disabled={loading}
variants={fieldVariants}
whileTap={{ scale: 0.98 }}
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-primary font-medium text-primary-foreground transition-all hover:shadow-lg hover:shadow-primary/20 disabled:pointer-events-none disabled:opacity-50"
className="inline-flex h-11 w-full items-center justify-center rounded-lg bg-primary font-medium text-primary-foreground transition-shadow hover:shadow-lg hover:shadow-primary/20 disabled:pointer-events-none disabled:opacity-50"
>
{loading
? "Loading..."
@@ -237,31 +238,32 @@ export function AuthForm({
)}
</AnimatePresence>
{showPasswordForm && (
<p className="text-center text-sm text-muted-foreground">
{isRegister ? (
<>
Already have an account?{" "}
<Link
href="/login"
className="font-medium text-primary transition-colors hover:text-primary/80"
>
Sign in
</Link>
</>
) : (
<>
Don&apos;t have an account?{" "}
<Link
href="/register"
className="font-medium text-primary transition-colors hover:text-primary/80"
>
Register
</Link>
</>
)}
</p>
)}
{showPasswordForm &&
(isRegister || authConfig?.registrationOpen !== false) && (
<p className="text-center text-sm text-muted-foreground">
{isRegister ? (
<>
Already have an account?{" "}
<Link
href="/login"
className="font-medium text-primary transition-colors hover:text-primary/80"
>
Sign in
</Link>
</>
) : (
<>
Don&apos;t have an account?{" "}
<Link
href="/register"
className="font-medium text-primary transition-colors hover:text-primary/80"
>
Register
</Link>
</>
)}
</p>
)}
</motion.div>
</div>
);
+36 -14
View File
@@ -40,7 +40,15 @@ const posterLayout = [
{ x: "78%", y: "66%", rotate: 5, delay: 0.23 },
];
export function LandingPage({ posterUrls }: { posterUrls: string[] }) {
export function LandingPage({
posterUrls,
freshInstall,
registrationOpen,
}: {
posterUrls: string[];
freshInstall: boolean;
registrationOpen: boolean;
}) {
const { data: session, isPending } = useSession();
const router = useRouter();
@@ -169,19 +177,33 @@ export function LandingPage({ posterUrls }: { posterUrls: string[] }) {
delay: 0.35,
}}
>
<Link
href="/login"
className="group relative inline-flex h-12 items-center justify-center overflow-hidden rounded-lg bg-primary px-8 font-medium text-primary-foreground transition-all hover:shadow-lg hover:shadow-primary/20"
>
<span className="relative z-10">Sign In</span>
<div className="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent opacity-0 transition-opacity group-hover:opacity-100" />
</Link>
<Link
href="/register"
className="inline-flex h-12 items-center justify-center rounded-lg border border-border px-8 font-medium transition-all hover:border-primary/40 hover:bg-primary/5"
>
Register
</Link>
{freshInstall ? (
<Link
href="/register"
className="group relative inline-flex h-12 items-center justify-center overflow-hidden rounded-lg bg-primary px-8 font-medium text-primary-foreground transition-all hover:shadow-lg hover:shadow-primary/20"
>
<span className="relative z-10">Get Started</span>
<div className="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent opacity-0 transition-opacity group-hover:opacity-100" />
</Link>
) : (
<>
<Link
href="/login"
className="group relative inline-flex h-12 items-center justify-center overflow-hidden rounded-lg bg-primary px-8 font-medium text-primary-foreground transition-all hover:shadow-lg hover:shadow-primary/20"
>
<span className="relative z-10">Sign In</span>
<div className="absolute inset-0 bg-gradient-to-t from-black/10 to-transparent opacity-0 transition-opacity group-hover:opacity-100" />
</Link>
{registrationOpen && (
<Link
href="/register"
className="inline-flex h-12 items-center justify-center rounded-lg border border-border px-8 font-medium transition-all hover:border-primary/40 hover:bg-primary/5"
>
Register
</Link>
)}
</>
)}
</motion.div>
</main>