114 lines
5.5 KiB
JavaScript
114 lines
5.5 KiB
JavaScript
import React from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { motion } from 'framer-motion';
|
|
import {
|
|
Fingerprint, GraduationCap, Mic, BadgeCheck, Handshake, Briefcase,
|
|
LineChart, Star, TrendingUp, Crown, Presentation, Repeat, ArrowRight,
|
|
} from 'lucide-react';
|
|
|
|
// The Credit Bureau for Human Talent — the career flywheel.
|
|
const STEPS = [
|
|
{ key: 'identity', label: 'Create Identity', to: '/identity', icon: Fingerprint },
|
|
{ key: 'learn', label: 'Learn', to: '/university', icon: GraduationCap },
|
|
{ key: 'interview', label: 'Interview', to: '/owliver', icon: Mic },
|
|
{ key: 'verify', label: 'Verify Skills', to: '/identity', icon: BadgeCheck },
|
|
{ key: 'hired', label: 'Get Hired', to: '/apply', icon: Handshake },
|
|
{ key: 'work', label: 'Work', to: '/me', icon: Briefcase },
|
|
{ key: 'track', label: 'Track Performance', to: '/me', icon: LineChart },
|
|
{ key: 'reputation', label: 'Earn Reputation', to: '/me', icon: Star },
|
|
{ key: 'promoted', label: 'Get Promoted', to: '/university', icon: TrendingUp },
|
|
{ key: 'leader', label: 'Become Leader', to: '/university', icon: Crown },
|
|
{ key: 'train', label: 'Train Others', to: '/university', icon: Presentation },
|
|
{ key: 'repeat', label: 'Repeat', to: '/university', icon: Repeat, loop: true },
|
|
];
|
|
|
|
export function stepStatus(profile, apps = []) {
|
|
const hired = apps.some(a => a.status === 'hired');
|
|
const worked = (profile.experience || []).length > 0 || hired;
|
|
const isDone = {
|
|
identity: !!profile.selfie_url && (profile.skills || []).length > 0,
|
|
learn: (profile.completed_courses || []).length > 0,
|
|
interview: (profile.ai_interview_score || 0) > 0 || !!(profile.personality || profile.strengths?.length),
|
|
verify: (profile.certifications || []).length > 0 || (profile.earned_badges || []).length > 0,
|
|
hired,
|
|
work: worked,
|
|
track: (profile.performance_score || 0) > 0 || (profile.attendance_score || 0) > 0 && worked,
|
|
reputation: (profile.client_rating || 0) > 0 || (profile.supervisor_rating || 0) > 0 || (profile.krow_score || 0) >= 50,
|
|
promoted: (profile.leadership_potential || 0) >= 40,
|
|
leader: (profile.leadership_potential || 0) >= 70,
|
|
train: (profile.leadership_potential || 0) >= 85 && (profile.completed_courses || []).length >= 3,
|
|
repeat: false,
|
|
};
|
|
return isDone;
|
|
}
|
|
|
|
export default function TalentLoop({ profile, applications = [] }) {
|
|
const done = stepStatus(profile, applications);
|
|
const reached = STEPS.filter(s => done[s.key]).length;
|
|
const current = STEPS.find(s => !done[s.key]) || STEPS[STEPS.length - 1];
|
|
const progress = Math.round((reached / (STEPS.length - 1)) * 100);
|
|
|
|
return (
|
|
<section className="glass-card border border-white/60 rounded-2xl p-6 sm:p-8 shadow-sm">
|
|
<div className="flex items-end justify-between flex-wrap gap-3 mb-1">
|
|
<div>
|
|
<span className="text-[11px] font-medium uppercase tracking-[0.18em] text-[#0A39DF]">The Talent Loop</span>
|
|
<h2 className="text-[22px] font-heading font-bold text-[#0F172A] mt-1 tracking-tight">Build your reputation. Not just your resume.</h2>
|
|
</div>
|
|
<span className="text-[12px] text-[#64748B]">{reached}/{STEPS.length - 1} stages</span>
|
|
</div>
|
|
|
|
<div className="h-1.5 bg-[#EEF2F7] rounded-full overflow-hidden mt-4 mb-7">
|
|
<motion.div
|
|
initial={{ width: 0 }}
|
|
animate={{ width: `${progress}%` }}
|
|
transition={{ duration: 0.8, ease: 'easeOut' }}
|
|
className="h-full bg-[#0A39DF] rounded-full"
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3">
|
|
{STEPS.map((s, i) => {
|
|
const isDone = done[s.key];
|
|
const isCurrent = s.key === current.key && !s.loop;
|
|
const Icon = s.icon;
|
|
return (
|
|
<Link
|
|
key={s.key}
|
|
to={s.to}
|
|
className={`group relative flex flex-col items-start gap-2 rounded-xl border p-3 transition-all ${
|
|
isDone
|
|
? 'bg-[#0A39DF] border-[#0A39DF] text-white'
|
|
: isCurrent
|
|
? 'bg-white border-[#0A39DF] ring-2 ring-[#0A39DF]/20'
|
|
: 'bg-white border-[#E5E7EB] hover:border-[#0A39DF]/50'
|
|
}`}
|
|
>
|
|
<div className="flex items-center justify-between w-full">
|
|
<span className={`text-[10px] font-semibold ${isDone ? 'text-white/70' : 'text-[#94A3B8]'}`}>{String(i + 1).padStart(2, '0')}</span>
|
|
{s.loop && <Repeat className={`w-3.5 h-3.5 ${isDone ? 'text-white/70' : 'text-[#94A3B8]'}`} />}
|
|
</div>
|
|
<Icon className={`w-5 h-5 ${isDone ? 'text-white' : isCurrent ? 'text-[#0A39DF]' : 'text-[#64748B]'}`} />
|
|
<span className={`text-[12px] font-medium leading-tight ${isDone ? 'text-white' : isCurrent ? 'text-[#0A39DF]' : 'text-[#334155]'}`}>
|
|
{s.label}
|
|
</span>
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between gap-3 mt-6 pt-5 border-t border-[#EEF2F7] flex-wrap">
|
|
<div>
|
|
<p className="text-[11px] text-[#94A3B8] font-medium">UP NEXT</p>
|
|
<p className="text-[15px] font-semibold text-[#0F172A]">{current.label}</p>
|
|
</div>
|
|
<Link
|
|
to={current.to}
|
|
className="inline-flex items-center gap-1.5 text-[13px] font-semibold text-[#0A39DF] hover:gap-2.5 transition-all"
|
|
>
|
|
Continue <ArrowRight className="w-4 h-4" />
|
|
</Link>
|
|
</div>
|
|
</section>
|
|
);
|
|
} |