73 lines
2.7 KiB
JavaScript
73 lines
2.7 KiB
JavaScript
// Derives the Talent "credit score" dimensions and motivational metrics
|
||
// from a WorkerProfile. Keeps the UI honest by mapping to real fields only.
|
||
const clamp = (n, min = 0, max = 100) => Math.max(min, Math.min(max, Math.round(Number(n) || 0)));
|
||
|
||
export function getTalentScore(profile = {}) {
|
||
return clamp(profile.krow_score || 0);
|
||
}
|
||
|
||
// Career Score — FICO-style 300–850 scale, the number shown on the KROW ID.
|
||
export const toFICO = (s) => 300 + Math.round((clamp(s) / 100) * 550);
|
||
|
||
export function getStars(profile = {}) {
|
||
const s = getTalentScore(profile);
|
||
if (s >= 90) return 5;
|
||
if (s >= 75) return 4;
|
||
if (s >= 60) return 3;
|
||
if (s >= 40) return 2;
|
||
if (s > 0) return 1;
|
||
return 0;
|
||
}
|
||
|
||
// Market value uplift ($/hr) derived from Talent Score
|
||
export function getMarketValue(profile = {}) {
|
||
const s = getTalentScore(profile);
|
||
return Math.max(0, Math.round((s - 70) / 5));
|
||
}
|
||
|
||
// Approximate growth this month (motivational, derived from XP)
|
||
export function getGrowth(profile = {}) {
|
||
const xp = Number(profile.xp) || 0;
|
||
return clamp(Math.round(xp / 25), 0, 99);
|
||
}
|
||
|
||
export function getReputation(profile = {}) {
|
||
const s = profile || {};
|
||
const courses = s.completed_courses || [];
|
||
const learning = clamp(courses.length * 8 + (Number(s.xp) || 0) / 10);
|
||
return [
|
||
{ key: 'talent', label: 'Talent Score', value: getTalentScore(s), big: true },
|
||
{ key: 'reliability', label: 'Reliability', value: clamp(s.reliability_score) },
|
||
{ key: 'attendance', label: 'Attendance', value: clamp(s.attendance_score) },
|
||
{ key: 'communication', label: 'Communication', value: clamp(s.performance_score) },
|
||
{ key: 'leadership', label: 'Leadership', value: clamp(s.leadership_potential) },
|
||
{ key: 'learning', label: 'Learning', value: learning },
|
||
{ key: 'problem', label: 'Problem Solving', value: clamp(s.ai_interview_score) },
|
||
];
|
||
}
|
||
|
||
// Weight each reputation factor like a credit score (FICO-style, sums to 100)
|
||
export const FACTOR_WEIGHTS = {
|
||
reliability: 25,
|
||
attendance: 20,
|
||
communication: 15,
|
||
leadership: 15,
|
||
learning: 15,
|
||
problem: 10,
|
||
};
|
||
|
||
// Score band — the "credit rating" tier for the talent
|
||
export function getScoreBand(score = 0) {
|
||
if (score >= 90) return { label: 'Elite', color: '#0838E0' };
|
||
if (score >= 75) return { label: 'Excellent', color: '#16A34A' };
|
||
if (score >= 60) return { label: 'Solid', color: '#2563EB' };
|
||
if (score >= 40) return { label: 'Building', color: '#D97706' };
|
||
if (score > 0) return { label: 'New', color: '#9CA3AF' };
|
||
return { label: 'No score yet', color: '#D1D5DB' };
|
||
}
|
||
|
||
export function getFactors(profile = {}) {
|
||
return getReputation(profile)
|
||
.filter((d) => !d.big)
|
||
.map((d) => ({ ...d, weight: FACTOR_WEIGHTS[d.key] || 0 }));
|
||
} |