Files
Sankofa/portal/src/components/auth/PortalSignInCard.tsx
defiQUG 456cc613b7
Some checks failed
API CI / API Lint (push) Successful in 53s
API CI / API Type Check (push) Failing after 51s
API CI / API Test (push) Successful in 1m32s
API CI / API Build (push) Failing after 1m0s
API CI / Build Docker Image (push) Has been skipped
CD Pipeline / Deploy to Staging (push) Failing after 32s
CI Pipeline / Lint and Type Check (push) Failing after 33s
CI Pipeline / Build (push) Has been skipped
CI Pipeline / Test Backend (push) Failing after 2m1s
CI Pipeline / Test Frontend (push) Failing after 35s
CI Pipeline / Security Scan (push) Failing after 1m12s
Deploy to Staging / Deploy to Staging (push) Failing after 28s
Portal CI / Portal Lint (push) Failing after 19s
Portal CI / Portal Type Check (push) Failing after 18s
Portal CI / Portal Test (push) Failing after 19s
Portal CI / Portal Build (push) Failing after 18s
Test Suite / frontend-tests (push) Failing after 30s
Test Suite / api-tests (push) Failing after 44s
Test Suite / blockchain-tests (push) Failing after 27s
Type Check / type-check (map[directory:. name:root]) (push) Failing after 18s
Type Check / type-check (map[directory:api name:api]) (push) Failing after 19s
Type Check / type-check (map[directory:portal name:portal]) (push) Failing after 18s
CD Pipeline / Deploy to Production (push) Has been skipped
fix(portal): corporate landing SEO, favicon, and public home UX
Add sankofa.nexus marketing site with institutional grade scorecards,
server-side metadata/title, dynamic icons, favicon rewrite, and instant
landing render without session-loading flash; split authenticated AppShell
from unauthenticated corporate chrome.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-11 01:27:05 -07:00

62 lines
2.1 KiB
TypeScript

'use client';
import { signIn } from 'next-auth/react';
import { useCallback, useState, type ReactNode } from 'react';
import { CloudflareTurnstile } from '@/components/security/CloudflareTurnstile';
const TURNSTILE_SITE_KEY = process.env.NEXT_PUBLIC_CLOUDFLARE_TURNSTILE_SITE_KEY;
export interface PortalSignInCardProps {
badge?: string;
title: string;
subtitle: string;
callbackUrl?: string;
/** Extra hint under the sign-in button (e.g. dev IdP note) */
footer?: ReactNode;
}
export function PortalSignInCard({
badge = 'Sankofa Phoenix',
title,
subtitle,
callbackUrl = '/',
footer,
}: PortalSignInCardProps) {
const [turnstileToken, setTurnstileToken] = useState<string | null>(() =>
TURNSTILE_SITE_KEY ? null : ''
);
const onTurnstileToken = useCallback((token: string | null) => {
setTurnstileToken(token);
}, []);
const canSignIn = !TURNSTILE_SITE_KEY || Boolean(turnstileToken);
return (
<div className="w-full max-w-md rounded-2xl border border-gray-800 bg-gray-900/80 p-8 shadow-xl shadow-black/40 backdrop-blur-sm">
<p className="mb-1 text-center text-sm font-medium uppercase tracking-wide text-orange-400">{badge}</p>
<h1 className="mb-2 text-center text-2xl font-bold text-white">{title}</h1>
<p className="mb-8 text-center text-gray-400">{subtitle}</p>
{TURNSTILE_SITE_KEY ? (
<div className="mb-6">
<p className="mb-2 text-center text-sm text-gray-500">Verification</p>
<CloudflareTurnstile siteKey={TURNSTILE_SITE_KEY} onToken={onTurnstileToken} />
</div>
) : null}
<button
type="button"
disabled={!canSignIn}
onClick={() => signIn(undefined, { callbackUrl })}
className="w-full rounded-lg bg-gradient-to-r from-orange-500 to-amber-500 px-6 py-3 font-semibold text-gray-950 shadow-lg transition hover:from-orange-400 hover:to-amber-400 focus:outline-none focus:ring-2 focus:ring-orange-400 focus:ring-offset-2 focus:ring-offset-gray-900 disabled:cursor-not-allowed disabled:opacity-50"
>
Sign In
</button>
{footer}
</div>
);
}