All files / src/components DemoPersonaCards.tsx

61.53% Statements 8/13
50% Branches 6/12
83.33% Functions 5/6
66.66% Lines 8/12

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 &amp; 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>
  );
}