import React, { useRef, useState } from 'react'; import html2canvas from 'html2canvas'; import { Wallet, Smartphone, Image as ImageIcon, ShieldCheck, Briefcase, Sparkles, QrCode, Download, Check, Info, RefreshCw } from 'lucide-react'; import { toast } from 'react-hot-toast'; import { Image } from '@/components/ui/image'; import { getTalentScore, getScoreBand, getGrowth } from '@/lib/talentHome'; const clamp = (n, min = 0, max = 100) => Math.max(min, Math.min(max, Math.round(Number(n) || 0))); // Employee Satisfaction — composite of attendance, performance, client & supervisor ratings export function getESAT(profile = {}) { const att = clamp(profile.attendance_score ?? 100); const perf = clamp(profile.performance_score); const client = ((Number(profile.client_rating) || 0) / 5) * 100; const sup = ((Number(profile.supervisor_rating) || 0) / 5) * 100; const hasRatings = client > 0 || sup > 0; if (!hasRatings) return clamp(att * 0.6 + perf * 0.4); return clamp(att * 0.3 + perf * 0.25 + client * 0.225 + sup * 0.225); } // Display the career score on a FICO-style 300–850 scale ("like checking your credit score") const toFICO = (s) => 300 + Math.round((clamp(s) / 100) * 550); function buildVCard(profile) { const name = profile.full_name || 'KROW Talent'; const [first, ...rest] = name.split(' '); const last = rest.join(' '); const lines = [ 'BEGIN:VCARD', 'VERSION:3.0', `N:${last};${first};;;`, `FN:${name}`, profile.current_position ? `TITLE:${profile.current_position}` : '', profile.phone ? `TEL;TYPE=CELL:${profile.phone}` : '', profile.email ? `EMAIL:${profile.email}` : '', profile.address ? `ADR:;;${profile.address};;;;` : '', `URL:https://krow.app/me`, `NOTE:KROW ID ${(profile.id || '').slice(-6).toUpperCase()} · Talent Score ${profile.krow_score || 0}`, 'END:VCARD', ].filter(Boolean); return lines.join('\n'); } function download(filename, content, type) { const blob = new Blob([content], { type }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } const BLUE = '#0055FF'; const TRACK = '#E1E5E9'; const ARC_R = 64; const CX = 80; const CY = 80; function arcPoint(p) { const ang = Math.PI - p * Math.PI; return { x: CX + ARC_R * Math.cos(ang), y: CY - ARC_R * Math.sin(ang) }; } function arcPath(startP, endP) { const a = arcPoint(startP); const b = arcPoint(endP); const large = endP - startP > 0.5 ? 1 : 0; return `M ${a.x} ${a.y} A ${ARC_R} ${ARC_R} 0 ${large} 1 ${b.x} ${b.y}`; } function Gauge({ fico }) { const pct = Math.max(0, Math.min(1, (fico - 300) / 550)); const gap = 0.02; const filledEnd = Math.max(gap, Math.min(1 - gap, pct)); const marker = arcPoint(filledEnd); return (
{pct > gap && ( )}
Career Score {fico} 300-850
); } function FactorPill({ label, value }) { return ( {label} {value} ); } function ReportRow({ icon: Icon, label, value, tone }) { const valColor = tone === 'verified' ? 'text-[#10B981]' : tone === 'amber' ? 'text-[#D97706]' : 'text-[#0F172A]'; return (
{label}
{tone === 'verified' && }{value}
); } export default function IdentityCareerCard({ profile }) { const stackRef = useRef(null); const [busy, setBusy] = useState(false); const score = getTalentScore(profile); const band = getScoreBand(score); const growth = getGrowth(profile); const esat = getESAT(profile); const fico = toFICO(score); const shortId = (profile.id || '').slice(-6).toUpperCase(); const name = profile.full_name || 'KROW Talent'; const title = profile.current_position || profile.desired_position || 'Open to work'; const initials = name.split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase(); const experience = profile.experience || []; const identityOk = !!profile.selfie_url; const vcard = buildVCard(profile); const qrSrc = `https://api.qrserver.com/v1/create-qr-code/?margin=0&size=160x160&data=${encodeURIComponent(vcard)}`; const updated = new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); const addToContacts = () => { download(`${name.replace(/\s+/g, '_')}.vcf`, vcard, 'text/vcard'); toast.success('Contact file downloaded — open it to add to your phone.'); }; const saveReport = async () => { if (!stackRef.current) return; setBusy(true); try { const canvas = await html2canvas(stackRef.current, { backgroundColor: null, scale: 2 }); canvas.toBlob((blob) => { if (!blob) return; const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${name.replace(/\s+/g, '_')}_KROW_ID.png`; a.click(); URL.revokeObjectURL(url); toast.success('Holographic ID saved to your downloads.'); }); } catch { toast.error('Could not generate ID image.'); } finally { setBusy(false); } }; const walletNotice = () => toast('Wallet passes need Apple/Google pass certificates. Use Add to Contacts for now.', { icon: 'ℹ️' }); return (
{/* Stacked depth layers (behind) */}
{/* Front holographic pass */}
{/* holographic sheen */}
{/* Identity header */}
{profile.selfie_url ? ( {name} ) : ( {initials} )}

KROW ID · {shortId}

{name}

{title}

Career Credit Report · {updated}
{/* Career Score gauge */}
{band.label}
Next update in 31 days
{/* Score factors */}

Score factors

{/* Report rows */}
= 75 ? 'verified' : esat >= 40 ? 'amber' : 'neutral'} />
{/* Job history detail */} {experience.length > 0 && (
{experience.map((job, i) => (

{job.role || 'Role'}

{job.company || 'Company'}

{job.years ? `${job.years} yr${job.years === 1 ? '' : 's'}` : '—'}
))}
)} {/* Take your KROW ID */}

Take your KROW ID

KROW Identity QR

Scan to share your verified KROW Identity

); }