Skip to content

Commit bff3001

Browse files
dcl10claude
andauthored
Feature/sign in page (#46)
* Wire Sign in buttons directly to Keycloak, remove /sign-in placeholder Sign in buttons in LandingTopBar and the landing page hero now call signIn("keycloak") directly, bypassing the redundant /sign-in page. The /sign-in route is removed; hero CTAs are extracted to a client component so the server-side session check in page.tsx is preserved. Closes #43 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix sign-in buttons breaking after back navigation from Keycloak signIn() from next-auth/react uses window.location.href to redirect, which bypasses Next.js's router. On back navigation the router is left in a stale navigating state, silently swallowing subsequent onClick calls. Switching to a server action invoked via native form submission issues the OAuth redirect as an HTTP response, keeping the router untouched so the page remains fully interactive after pressing back. Also replaces the TopBar Sign up router.push with a Link for the same reason. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2f38761 commit bff3001

5 files changed

Lines changed: 68 additions & 49 deletions

File tree

frontend/app/_LandingCTA.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Link from "next/link";
2+
3+
import { signInWithKeycloak } from "./actions";
4+
5+
/**
6+
* Hero call-to-action buttons for the landing page.
7+
* Sign in uses a server action so the OAuth redirect is issued as an HTTP
8+
* response, avoiding client-side router state corruption on back navigation.
9+
*/
10+
export function LandingCTA() {
11+
return (
12+
<div className="flex items-center gap-3">
13+
<form action={signInWithKeycloak}>
14+
<button
15+
type="submit"
16+
className="inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm px-[16px] py-[9px] text-[14px] bg-paper text-ink border border-[var(--border-strong)] hover:bg-portland-stone transition-colors duration-[120ms] cursor-pointer"
17+
>
18+
Sign in
19+
</button>
20+
</form>
21+
<Link
22+
href="/sign-up"
23+
className="inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm px-[16px] py-[9px] text-[14px] bg-nottingham-blue text-paper border border-nottingham-blue hover:bg-[var(--color-primary-deep)] transition-colors duration-[120ms]"
24+
>
25+
Sign up
26+
</Link>
27+
</div>
28+
);
29+
}

frontend/app/actions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"use server";
2+
3+
import { signIn } from "@/auth";
4+
5+
/**
6+
* Initiates the Keycloak OAuth flow via a server action.
7+
* Using a server action (rather than signIn from next-auth/react) ensures
8+
* the redirect to Keycloak is issued as an HTTP response, keeping the
9+
* Next.js router state intact so the back button works correctly.
10+
*/
11+
export async function signInWithKeycloak() {
12+
await signIn("keycloak", { redirectTo: "/dashboard" });
13+
}

frontend/app/page.tsx

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import Link from "next/link";
21
import { redirect } from "next/navigation";
32

43
import { LandingTopBar } from "@/components/shared";
54
import { getSession } from "@/lib/auth";
65

6+
import { LandingCTA } from "./_LandingCTA";
7+
78
export default async function HomePage() {
89
const session = await getSession();
910
if (session) redirect("/dashboard");
@@ -19,20 +20,7 @@ export default async function HomePage() {
1920
The Digital Research Service skills-matching platform. Connect
2021
researchers with the expertise your project needs.
2122
</p>
22-
<div className="flex items-center gap-3">
23-
<Link
24-
href="/sign-in"
25-
className="inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm px-[16px] py-[9px] text-[14px] bg-paper text-ink border border-[var(--border-strong)] hover:bg-portland-stone transition-colors duration-[120ms]"
26-
>
27-
Sign in
28-
</Link>
29-
<Link
30-
href="/sign-up"
31-
className="inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm px-[16px] py-[9px] text-[14px] bg-nottingham-blue text-paper border border-nottingham-blue hover:bg-[var(--color-primary-deep)] transition-colors duration-[120ms]"
32-
>
33-
Sign up
34-
</Link>
35-
</div>
23+
<LandingCTA />
3624
</main>
3725
</>
3826
);

frontend/app/sign-in/page.tsx

Lines changed: 0 additions & 20 deletions
This file was deleted.

frontend/components/shared/LandingTopBar.tsx

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
"use client";
22

3-
import { useRouter } from "next/navigation";
3+
import Link from "next/link";
44

5+
import { signInWithKeycloak } from "@/app/actions";
56
import { Button } from "@/components/core";
67
import { useViewport } from "@/lib/hooks/useViewport";
8+
import { cn } from "@/lib/utils";
79

810
/**
911
* Sticky navigation bar for unauthenticated visitors.
1012
* Shows the UoN logo and Matchboard branding with Sign in / Sign up buttons.
1113
* Excludes search, notifications, and user-specific controls.
1214
*/
1315
export function LandingTopBar() {
14-
const router = useRouter();
1516
const { isMobile } = useViewport();
1617

1718
return (
@@ -57,20 +58,28 @@ export function LandingTopBar() {
5758
<div className="flex-1" />
5859

5960
<div className="flex items-center gap-2">
60-
<Button
61-
variant="secondary"
62-
size={isMobile ? "sm" : "md"}
63-
onClick={() => router.push("/sign-in")}
64-
>
65-
Sign in
66-
</Button>
67-
<Button
68-
variant="primary"
69-
size={isMobile ? "sm" : "md"}
70-
onClick={() => router.push("/sign-up")}
61+
<form action={signInWithKeycloak}>
62+
<Button
63+
variant="secondary"
64+
size={isMobile ? "sm" : "md"}
65+
type="submit"
66+
>
67+
Sign in
68+
</Button>
69+
</form>
70+
<Link
71+
href="/sign-up"
72+
className={cn(
73+
"inline-flex items-center gap-2 font-sans font-medium tracking-[-0.005em] rounded-sm",
74+
"transition-[background-color,transform,border-color] duration-[120ms] ease-[cubic-bezier(0.2,0,0,1)]",
75+
"bg-nottingham-blue text-paper border border-nottingham-blue hover:bg-[var(--color-primary-deep)]",
76+
isMobile
77+
? "px-[10px] py-[5px] text-[12px]"
78+
: "px-[16px] py-[9px] text-[14px]",
79+
)}
7180
>
7281
Sign up
73-
</Button>
82+
</Link>
7483
</div>
7584
</header>
7685
);

0 commit comments

Comments
 (0)