'use client'; import Image from 'next/image'; import { formatLocalDate } from '../utils/date'; import countriesLib from 'i18n-iso-countries'; import enLocale from 'i18n-iso-countries/langs/en.json'; import { FiInfo } from 'react-icons/fi'; import { ProviderIcon } from '../utils/provider'; import type { ConnectedAccount } from '../types'; import { green1, green2, green3, green4, green5 } from '../colors'; // Register English locale once at module import time countriesLib.registerLocale(enLocale); export const getBadgeImageUrl = (score: number, bland: boolean = false, selfCheck?: boolean) => { if (selfCheck) { // self-check badges are always green return bland ? 'badgegreensimple.png' : '/badgegreen2.png'; }; if (score >= 75) return bland ? 'badgegreensimple.png' : '/badgegreen2.png'; if (score >= 50) return bland ? 'badgeyellowsimple.png' : '/badgeyellow2.png'; return bland ? 'badgeredsimple.png' : '/badgered2.png'; }; const hexToRgba = (hex: string, alpha: number) => { const clean = hex.replace('#', ''); const r = parseInt(clean.substring(0, 2), 16); const g = parseInt(clean.substring(2, 4), 16); const b = parseInt(clean.substring(4, 6), 16); return `rgba(${r}, ${g}, ${b}, ${alpha})`; }; const pickTint = (score: number, selfCheck?: boolean) => { if (selfCheck) { if (score < 20) return green5; if (score < 40) return green4; if (score < 60) return green3; if (score < 80) return green2; return green1; } if (score >= 75) return '#02a389'; if (score >= 50) return '#ffbb54'; return '#EC6662'; }; interface ReportHeaderProps { badgeId: string | undefined; developerName: string | undefined; updatedAt: string | undefined; score?: number | undefined; isPublic: boolean; badgeImageUrl: string; summary?: string; enterpriseMatch?: { label?: string; description?: string; roleName?: string } | null; countries?: string[]; accountAuthenticity?: { label?: string; description?: string }; companyName?: string; sourcesProviders?: string[]; connectedAccounts?: ConnectedAccount[]; selfCheck?: boolean; rightBadgeLayout?: boolean; } const normalizeProvider = (value?: string) => (value || '').toLowerCase().trim(); const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImageUrl, summary, enterpriseMatch, countries = [], accountAuthenticity, companyName, sourcesProviders = [], connectedAccounts = [], selfCheck, rightBadgeLayout, isPublic }: ReportHeaderProps) => { // Use the dynamic image if available, otherwise fall back to the score-based one. const finalBadgeImageUrl = badgeImageUrl || getBadgeImageUrl(score || 0, false, selfCheck); const tint = hexToRgba(pickTint(score || 0, selfCheck), 0.06); const matchLabel = enterpriseMatch?.label; const sources = (() => { const primary = Array.isArray(sourcesProviders) ? sourcesProviders : []; // Fallback to authenticity oauth list if no explicit sources provided const fallback = (accountAuthenticity as any)?.oauth_connected as string[] | undefined; const combined = (primary && primary.length ? primary : (fallback || [])).filter(Boolean); // Deduplicate while preserving order const seen: Record = {}; return combined.filter((n) => { const key = (n || '').toLowerCase(); if (seen[key]) return false; seen[key] = true; return true; }); })(); const sourceAccounts = (() => { const map: Record = {}; (Array.isArray(connectedAccounts) ? connectedAccounts : []).forEach((account) => { const normalized = normalizeProvider(account?.name); if (normalized && !map[normalized]) map[normalized] = account; const underscored = normalized.replace(/\s+/g, '_'); if (underscored && !map[underscored]) map[underscored] = account; const spaced = normalized.replace(/_/g, ' '); if (spaced && !map[spaced]) map[spaced] = account; }); return map; })(); const resolveSourceLink = (provider: string) => { if (!provider) return null; if (!isPublic) { return { href: '#appendix-connected', external: false }; } const normalized = normalizeProvider(provider); const account = sourceAccounts[normalized] || sourceAccounts[normalized.replace(/\s+/g, '_')] || sourceAccounts[normalized.replace(/_/g, ' ')]; if (account?.url) { return { href: account.url, external: true, providerName: account?.name || provider }; } return null; }; const SourceIcon = ({ provider }: { provider: string }) => ( ); return (
{/* Authenticity notice moved to top-level display */}
{/* Info section: Title, Candidate, Details and Summary */}

KYD Candidate:

{developerName || 'N/A'}

Date:

{formatLocalDate(updatedAt)}
{(() => { const countryNames = countries .map(code => countriesLib.getName((code || '').toUpperCase(), 'en') || code) .filter(Boolean); return (
{countryNames.length > 1 ? 'Countries:' : 'Country:'} {countryNames.length > 0 ? ( {countryNames.join(', ')} ) : ( N/A )}
Countries
Derived from linked sources and activity; shows where they’re most affiliated.
); })()} {sources.length > 0 && ( isPublic ? (
Sources Shared: {sources.map((provider, idx) => { const link = resolveSourceLink(provider); const icon = ; if (link) { return ( {icon} ); } return ( {icon} ); })}
) : (

Sources Shared: {sources.map((provider, idx) => ( ))}

) )} {(enterpriseMatch?.description || matchLabel) ? (

Role Alignment{enterpriseMatch?.roleName ? ` — ${enterpriseMatch.roleName}` : ''}

AI-generated
Role match label and description are AI-generated.
{matchLabel && ( {matchLabel} )}
{enterpriseMatch?.description && (

{enterpriseMatch.description}

)}
) : summary && (

Summary:

{summary}

)}
{/* Badge Image with robust centered overlay */}
KYD Badge
{Math.round(score || 0)}%
); }; export default ReportHeader;