Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 1x 19x 19x 19x 133x 399x 190x 133x | "use client";
import { signIn, useSession } from "next-auth/react";
import { Shield, LogIn } from "lucide-react";
import { DEMO_PERSONAS, ROLE_LABELS } from "@/lib/auth";
const IS_STATIC = process.env.NEXT_PUBLIC_STATIC_EXPORT === "true";
/**
* Demo persona cards showing available users and their roles.
* Displayed on the start page so new users can quickly see which
* test accounts are available and sign in directly.
*/
export function DemoPersonaCards() {
const { data: session } = useSession();
// Hide persona cards if already signed in (unless static mode)
Iif (session && !IS_STATIC) return null;
return (
<div>
<h2
id="personas-title"
className="text-sm font-semibold text-[var(--text-secondary)] uppercase tracking-wider mb-3"
>
Demo Users & Roles
</h2>
<p className="text-xs text-[var(--text-secondary)] mb-3">
Sign in as any persona to explore role-specific views.
<span className="text-gray-500 dark:text-gray-400">
{" "}
Password = username ยท Keycloak realm: EDCV
</span>
</p>
<div
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3"
role="list"
aria-labelledby="personas-title"
>
{DEMO_PERSONAS.map((persona) => (
<button
key={persona.username}
role="listitem"
onClick={() => {
if (IS_STATIC) {
localStorage.setItem("demo-persona", persona.username);
window.location.href = `/graph?persona=${persona.personaId}`;
} else {
signIn("keycloak", {
callbackUrl: `/graph?persona=${persona.personaId}`,
});
}
}}
aria-label={`Sign in as ${persona.username}, ${persona.organisation}`}
className={`group text-left rounded-xl border p-4 bg-[var(--surface-2)]/40 hover:bg-[var(--surface-2)] transition-colors touch-target ${
persona.badge.split(" ").find((c) => c.startsWith("border-")) ??
"border-[var(--border)]"
}`}
>
<div className="flex items-center justify-between mb-1.5">
<div>
<span className="font-mono text-sm font-semibold text-[var(--text-primary)] group-hover:text-[var(--accent)] transition-colors">
{persona.username}
</span>
<span className="text-xs text-[var(--text-secondary)] ml-2">
{persona.organisation}
</span>
</div>
<LogIn
size={14}
className="text-[var(--text-secondary)] group-hover:text-[var(--accent)] transition-colors"
aria-hidden="true"
/>
</div>
<div className="flex flex-wrap gap-1 mb-1.5">
{[...persona.roles]
.filter(
(r) =>
r !== "EDC_USER_PARTICIPANT" || persona.roles.length === 1,
)
.map((role) => (
<span
key={role}
className={`inline-flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded font-medium ${persona.badge}`}
>
<Shield size={8} aria-hidden="true" />
{ROLE_LABELS[role] ?? role}
</span>
))}
</div>
<p className="text-xs text-[var(--text-secondary)] leading-tight">
{persona.description}
</p>
</button>
))}
</div>
</div>
);
}
|