Initial commit

This commit is contained in:
2026-08-07 23:53:15 +05:30
commit 90f14a73b2
222 changed files with 35000 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
import React from 'react';
import { Shield, Star, TrendingUp } from 'lucide-react';
import { getScoreBand } from '@/lib/talentHome';
import ReferencesEndorsements from '@/components/krow/ReferencesEndorsements';
const R = 44;
const STROKE = 8;
const CIRC = 2 * Math.PI * R;
const FICO_MIN = 300;
const FICO_MAX = 850;
function careerScoreFromApp(app) {
const s = Math.max(0, Math.min(100, Math.round(app?.ai_score || 0)));
return 300 + Math.round((s / 100) * 550);
}
function marketRangeFromApp(app) {
const s = Math.max(0, Math.min(100, Math.round(app?.ai_score || 0)));
const uplift = Math.max(0, Math.round((s - 70) / 5));
const low = 20 + uplift;
return `$${low}-$${low + 4}/hr`;
}
function nextTierFromApp(app) {
const s = Math.round(app?.ai_score || 0);
const yrs = app?.years_experience || 0;
if (s >= 85 || yrs >= 8) return 'Skilled';
if (s >= 60 || yrs >= 3) return 'Cross-Trained';
return 'Beginner';
}
function CareerScoreMini({ application }) {
const score = careerScoreFromApp(application);
const pct = Math.max(0, Math.min(1, (score - FICO_MIN) / (FICO_MAX - FICO_MIN)));
const dash = pct * CIRC;
const band = getScoreBand(Math.round(application?.ai_score || 0));
return (
<div className="flex items-center gap-5 bg-white/70 rounded-xl border border-[#E5E7EB] px-4 py-3">
<div className="flex flex-col items-center shrink-0">
<div className="relative" style={{ width: R * 2 + STROKE, height: R * 2 + STROKE }}>
<svg width={R * 2 + STROKE} height={R * 2 + STROKE} className="-rotate-90">
<circle cx={R + STROKE / 2} cy={R + STROKE / 2} r={R} fill="none" stroke="#EFF6FF" strokeWidth={STROKE} />
<circle
cx={R + STROKE / 2}
cy={R + STROKE / 2}
r={R}
fill="none"
stroke="#0A39DF"
strokeWidth={STROKE}
strokeLinecap="round"
strokeDasharray={`${dash} ${CIRC}`}
/>
</svg>
<div className="absolute inset-0 flex flex-col items-center justify-center">
<span className="text-[8px] uppercase tracking-wide text-[#94A3B8] font-medium">Career Score</span>
<span className="text-[22px] font-bold text-[#0A39DF] leading-none">{score}</span>
<span className="text-[8px] text-[#94A3B8] font-medium">300-850</span>
</div>
</div>
<span
className="mt-2 inline-flex items-center justify-center text-[11px] font-bold text-white px-3 py-1 rounded-full w-full"
style={{ backgroundColor: band.color }}
>
{band.label}
</span>
</div>
<div className="flex-1 space-y-3">
<div>
<p className="text-[10px] uppercase tracking-wide text-[#9CA3AF] font-medium">Potential Market Value</p>
<p className="text-[16px] font-bold text-[#111827]">{marketRangeFromApp(application)}</p>
</div>
<div>
<p className="text-[10px] uppercase tracking-wide text-[#9CA3AF] font-medium">Next Promotion</p>
<p className="text-[14px] font-semibold text-[#0F172A]">{nextTierFromApp(application)}</p>
</div>
</div>
</div>
);
}
const COMM_LABELS = [
{ min: 85, label: 'Excellent' },
{ min: 70, label: 'Good' },
{ min: 55, label: 'Average' },
{ min: 0, label: 'Needs Work' },
];
const commLabel = (score) => {
const v = score || 0;
return (COMM_LABELS.find((c) => v >= c.min) || COMM_LABELS[COMM_LABELS.length - 1]).label;
};
const COMPANY_COLORS = [
'bg-[#0A39DF]',
'bg-[#333F48]',
'bg-[#082EB4]',
];
const colorFor = (name) => {
let hash = 0;
for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);
return COMPANY_COLORS[Math.abs(hash) % COMPANY_COLORS.length];
};
const initialsFor = (name) => {
const parts = name.trim().split(/\s+/);
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
return (parts[0][0] + parts[1][0]).toUpperCase();
};
function StatTile({ label, value, suffix, accent }) {
const text = value != null && value !== '' ? value : '—';
return (
<div className="flex flex-col items-center justify-center gap-1 px-2 py-3 rounded-xl bg-white/70 border border-[#E5E7EB]">
<div className="text-[18px] font-bold leading-none" style={{ color: accent }}>
{text}
{suffix && <span className="text-[12px] font-semibold ml-0.5">{suffix}</span>}
</div>
<div className="text-[10px] text-[#6B7280] tracking-wide font-medium">{label}</div>
</div>
);
}
export default function WorkforceReputation({ application }) {
const breakdown = application?.score_breakdown || {};
const companies = application?.companies_worked || [];
const clientRating = application?.client_rating || 0;
const reliability = breakdown.reliability;
const attendance = breakdown.attendance_expectations;
const leadership = breakdown.leadership_expectations;
const communication = breakdown.communication_style;
const commText = communication != null ? commLabel(communication) : null;
const hasScores = [reliability, attendance, leadership, communication].some((v) => v != null);
const hasData = hasScores || companies.length > 0 || clientRating > 0 || (application?.ai_score || 0) > 0;
if (!hasData) return null;
return (
<div className="rounded-2xl border border-[#E5E7EB] bg-[#F8FAFC] p-4">
<div className="flex items-center gap-2 mb-3">
<div className="w-7 h-7 rounded-lg bg-[#0A39DF] flex items-center justify-center">
<Shield className="w-4 h-4 text-white" strokeWidth={2.5} />
</div>
<h4 className="text-[12px] font-bold text-[#111827] tracking-wide flex items-center gap-1.5">
WORKFORCE REPUTATION
<TrendingUp className="w-3.5 h-3.5 text-[#0A39DF]" />
</h4>
</div>
<CareerScoreMini application={application} />
<div className="grid grid-cols-2 sm:grid-cols-5 gap-2">
<StatTile label="Reliability" value={reliability != null ? reliability : null} suffix="%" accent="#0A39DF" />
<StatTile label="Attendance" value={attendance != null ? attendance : null} suffix="%" accent="#059669" />
<StatTile label="Leadership" value={leadership != null ? leadership : null} suffix="%" accent="#0A39DF" />
<StatTile label="Communication" value={commText} accent="#F59E0B" />
<div className="flex flex-col items-center justify-center gap-1 px-2 py-3 rounded-xl bg-white/70 border border-[#E5E7EB]">
<div className="flex items-center gap-0.5">
<Star className="w-3.5 h-3.5 text-[#F9E547] fill-[#F9E547]" />
<span className="text-[18px] font-bold leading-none text-[#111827]">
{clientRating > 0 ? clientRating.toFixed(1) : '—'}
</span>
</div>
<div className="text-[10px] text-[#6B7280] tracking-wide font-medium">Client Rating</div>
</div>
</div>
{companies.length > 0 && (
<div className="mt-3 pt-3 border-t border-[#E5E7EB]/80">
<p className="text-[10px] font-bold text-[#9CA3AF] tracking-wider mb-2">WORKED</p>
<div className="flex flex-wrap items-center gap-2.5">
{companies.map((c, i) => (
<div key={i} className="flex items-center gap-2">
<div className={`w-7 h-7 rounded-lg ${colorFor(c)} flex items-center justify-center text-white text-[11px] font-bold shadow-sm`}>
{initialsFor(c)}
</div>
<span className="text-[12px] font-semibold text-[#374151]">{c}</span>
</div>
))}
</div>
</div>
)}
<ReferencesEndorsements application={application} />
</div>
);
}