kyd-shared-badge 0.3.108 → 0.3.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/PrintableBadgeDisplay.tsx +1 -0
- package/src/SharedBadgeDisplay.tsx +16 -13
- package/src/components/GaugeCard.tsx +29 -15
- package/src/components/ReportHeader.tsx +28 -11
- package/src/components/RiskCard.tsx +2 -2
- package/src/components/RoleOverviewCard.tsx +3 -5
- package/src/components/SkillsBubble.tsx +2 -3
package/package.json
CHANGED
|
@@ -139,6 +139,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
139
139
|
countries={(assessmentResult?.screening_sources?.ip_risk_analysis?.raw_data?.countries) || []}
|
|
140
140
|
accountAuthenticity={assessmentResult?.account_authenticity}
|
|
141
141
|
companyName={badgeData.companyName}
|
|
142
|
+
rightBadgeLayout={!assessmentResult?.enterprise_match}
|
|
142
143
|
/>
|
|
143
144
|
</Reveal>
|
|
144
145
|
{/* Coaching / Evidence under header when present */}
|
|
@@ -52,7 +52,7 @@ type ChatWidgetProps = Partial<{
|
|
|
52
52
|
// return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
53
53
|
// };
|
|
54
54
|
|
|
55
|
-
const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: PublicBadgeData, chatProps?: ChatWidgetProps, headless?: boolean }) => {
|
|
55
|
+
const SharedBadgeDisplay = ({ badgeData, chatProps, headless, selfCheck = false }: { badgeData: PublicBadgeData, chatProps?: ChatWidgetProps, headless?: boolean, selfCheck?: boolean }) => {
|
|
56
56
|
const {
|
|
57
57
|
badgeId,
|
|
58
58
|
developerName,
|
|
@@ -91,18 +91,18 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
91
91
|
}
|
|
92
92
|
})();
|
|
93
93
|
|
|
94
|
-
const topBusinessForGenre = (genre: string) => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const skillsMatrix = assessmentResult?.skills_matrix || { skills: [] };
|
|
94
|
+
// const topBusinessForGenre = (genre: string) => {
|
|
95
|
+
// const cats: string[] = (genreMapping)?.[genre] || [];
|
|
96
|
+
// const items = [];
|
|
97
|
+
// for (const c of cats) {
|
|
98
|
+
// const arr = (categoryTopByGraph)?.[c] || [];
|
|
99
|
+
// for (const it of arr) items.push(it);
|
|
100
|
+
// }
|
|
101
|
+
// items.sort((a, b) => Number(b?.weight || 0) - Number(a?.weight || 0));
|
|
102
|
+
// return items.slice(0, 3) as TopBusinessRule[];
|
|
103
|
+
// };
|
|
104
|
+
|
|
105
|
+
// const skillsMatrix = assessmentResult?.skills_matrix || { skills: [] };
|
|
106
106
|
const skillsAll = assessmentResult?.skills_all || { skills: [] };
|
|
107
107
|
const connected = badgeData?.connectedAccounts || [];
|
|
108
108
|
|
|
@@ -225,6 +225,8 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
225
225
|
accountAuthenticity={assessmentResult?.account_authenticity}
|
|
226
226
|
companyName={badgeData.companyName}
|
|
227
227
|
sourcesProviders={(badgeData?.connectedAccounts || []).map(a => (a?.name || '').toLowerCase())}
|
|
228
|
+
selfCheck={selfCheck}
|
|
229
|
+
rightBadgeLayout={!hasEnterpriseMatch}
|
|
228
230
|
/>
|
|
229
231
|
</div>
|
|
230
232
|
{/* Top-right: Role match section */}
|
|
@@ -258,6 +260,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
258
260
|
percent={techPct}
|
|
259
261
|
label={techLabel}
|
|
260
262
|
topMovers={[]}
|
|
263
|
+
selfCheck={selfCheck}
|
|
261
264
|
/>
|
|
262
265
|
);
|
|
263
266
|
})()}
|
|
@@ -4,7 +4,7 @@ import React, { useMemo } from 'react';
|
|
|
4
4
|
import GaugeComponent from '@knowyourdeveloper/react-gauge-component';
|
|
5
5
|
import BusinessRuleLink from './BusinessRuleLink';
|
|
6
6
|
import { FiInfo } from 'react-icons/fi';
|
|
7
|
-
import { hexToRgba, scoreToColorHex, clampPercent, red, yellow, green } from '../colors';
|
|
7
|
+
import { hexToRgba, scoreToColorHex, clampPercent, red, yellow, green, green1, green2, green3, green4, green5 } from '../colors';
|
|
8
8
|
|
|
9
9
|
type TopMover = { label?: string; uid?: string };
|
|
10
10
|
|
|
@@ -18,6 +18,7 @@ export default function GaugeCard({
|
|
|
18
18
|
topMovers,
|
|
19
19
|
topMoversTitle,
|
|
20
20
|
tooltipText,
|
|
21
|
+
selfCheck,
|
|
21
22
|
}: {
|
|
22
23
|
title: string;
|
|
23
24
|
description?: string;
|
|
@@ -26,10 +27,18 @@ export default function GaugeCard({
|
|
|
26
27
|
topMovers?: TopMover[];
|
|
27
28
|
topMoversTitle?: string;
|
|
28
29
|
tooltipText?: string;
|
|
30
|
+
selfCheck?: boolean;
|
|
29
31
|
}) {
|
|
30
32
|
const pct = clampPercent(percent);
|
|
31
33
|
const displayLabel = label || '';
|
|
32
|
-
const
|
|
34
|
+
const shadeFor = (p: number) => {
|
|
35
|
+
if (p < 20) return green5;
|
|
36
|
+
if (p < 40) return green4;
|
|
37
|
+
if (p < 60) return green3;
|
|
38
|
+
if (p < 80) return green2;
|
|
39
|
+
return green1;
|
|
40
|
+
};
|
|
41
|
+
const headerTint = hexToRgba(selfCheck ? shadeFor(pct) : scoreToColorHex(pct), 0.06);
|
|
33
42
|
|
|
34
43
|
// Technical evidence tiers from backend thresholds
|
|
35
44
|
const tickLabels = useMemo(() => ({
|
|
@@ -65,10 +74,8 @@ export default function GaugeCard({
|
|
|
65
74
|
>
|
|
66
75
|
<div className="mb-3 flex items-start justify-between gap-2 pt-5 px-5">
|
|
67
76
|
<div>
|
|
68
|
-
<div className={'font-semibold'} style={{ color: 'var(--text-main)' }}>{title}</div>
|
|
69
|
-
{
|
|
70
|
-
<div className={'text-xs mt-1'} style={{ color: 'var(--text-secondary)' }}>{description}</div>
|
|
71
|
-
) : null}
|
|
77
|
+
<div className={'font-semibold text-xl'} style={{ color: 'var(--text-main)' }}>{title}</div>
|
|
78
|
+
<div className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>{description}</div>
|
|
72
79
|
</div>
|
|
73
80
|
{(tooltipText || description) && (
|
|
74
81
|
<span className={'relative inline-flex items-center group cursor-help'} style={{ color: 'var(--text-secondary)' }}>
|
|
@@ -103,15 +110,22 @@ export default function GaugeCard({
|
|
|
103
110
|
},
|
|
104
111
|
tickLabels: tickLabels,
|
|
105
112
|
}}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
arc={{
|
|
114
|
+
padding: 0.02,
|
|
115
|
+
subArcs: selfCheck
|
|
116
|
+
? [
|
|
117
|
+
{ limit: 20, color: green5 },
|
|
118
|
+
{ limit: 40, color: green4 },
|
|
119
|
+
{ limit: 60, color: green3 },
|
|
120
|
+
{ limit: 80, color: green2 },
|
|
121
|
+
{ limit: 100, color: green1 },
|
|
122
|
+
]
|
|
123
|
+
: [
|
|
124
|
+
{ limit: 33, color: red },
|
|
125
|
+
{ limit: 66, color: yellow },
|
|
126
|
+
{ limit: 100, color: green },
|
|
127
|
+
],
|
|
128
|
+
}}
|
|
115
129
|
pointer={{ type: 'blob', elastic: true, animationDelay: 0 }}
|
|
116
130
|
/>
|
|
117
131
|
{(tooltipText || description) && (
|
|
@@ -6,6 +6,7 @@ import countriesLib from 'i18n-iso-countries';
|
|
|
6
6
|
import enLocale from 'i18n-iso-countries/langs/en.json';
|
|
7
7
|
import { FiInfo, FiAlertTriangle } from 'react-icons/fi';
|
|
8
8
|
import { ProviderIcon } from '../utils/provider';
|
|
9
|
+
import { green1, green2, green3, green4, green5 } from '../colors';
|
|
9
10
|
|
|
10
11
|
// Register English locale once at module import time
|
|
11
12
|
countriesLib.registerLocale(enLocale);
|
|
@@ -24,7 +25,14 @@ const hexToRgba = (hex: string, alpha: number) => {
|
|
|
24
25
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
const pickTint = (score: number) => {
|
|
28
|
+
const pickTint = (score: number, selfCheck?: boolean) => {
|
|
29
|
+
if (selfCheck) {
|
|
30
|
+
if (score < 20) return green5;
|
|
31
|
+
if (score < 40) return green4;
|
|
32
|
+
if (score < 60) return green3;
|
|
33
|
+
if (score < 80) return green2;
|
|
34
|
+
return green1;
|
|
35
|
+
}
|
|
28
36
|
if (score >= 75) return '#02a389';
|
|
29
37
|
if (score >= 50) return '#ffbb54';
|
|
30
38
|
return '#EC6662';
|
|
@@ -43,12 +51,14 @@ interface ReportHeaderProps {
|
|
|
43
51
|
accountAuthenticity?: { label?: string; description?: string };
|
|
44
52
|
companyName?: string;
|
|
45
53
|
sourcesProviders?: string[];
|
|
54
|
+
selfCheck?: boolean;
|
|
55
|
+
rightBadgeLayout?: boolean;
|
|
46
56
|
}
|
|
47
57
|
|
|
48
|
-
const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImageUrl, summary, enterpriseMatch, countries = [], accountAuthenticity, companyName, sourcesProviders = [] }: ReportHeaderProps) => {
|
|
58
|
+
const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImageUrl, summary, enterpriseMatch, countries = [], accountAuthenticity, companyName, sourcesProviders = [], selfCheck, rightBadgeLayout }: ReportHeaderProps) => {
|
|
49
59
|
// Use the dynamic image if available, otherwise fall back to the score-based one.
|
|
50
60
|
const finalBadgeImageUrl = badgeImageUrl || getBadgeImageUrl(score || 0);
|
|
51
|
-
const tint = hexToRgba(pickTint(score || 0), 0.06);
|
|
61
|
+
const tint = hexToRgba(pickTint(score || 0, selfCheck), 0.06);
|
|
52
62
|
const matchLabel = enterpriseMatch?.label;
|
|
53
63
|
const sources = (() => {
|
|
54
64
|
const primary = Array.isArray(sourcesProviders) ? sourcesProviders : [];
|
|
@@ -67,7 +77,7 @@ const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImage
|
|
|
67
77
|
|
|
68
78
|
return (
|
|
69
79
|
<div
|
|
70
|
-
className={'p-6 rounded-md
|
|
80
|
+
className={'p-6 rounded-md border'}
|
|
71
81
|
style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)', backgroundImage: `linear-gradient(${tint}, ${tint})` }}
|
|
72
82
|
>
|
|
73
83
|
{(() => {
|
|
@@ -89,9 +99,9 @@ const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImage
|
|
|
89
99
|
</div>
|
|
90
100
|
);
|
|
91
101
|
})()}
|
|
92
|
-
<div className=
|
|
102
|
+
<div className={`flex gap-3 ${rightBadgeLayout ? 'flex-col md:flex-row items-center justify-between' : 'flex-col'}`}>
|
|
93
103
|
{/* Info section: Title, Candidate, Details and Summary */}
|
|
94
|
-
<div className=
|
|
104
|
+
<div className={`w-full ${rightBadgeLayout ? 'md:flex-1' : ''}`}>
|
|
95
105
|
<div className='space-y-2'>
|
|
96
106
|
<span className='flex gap-2 w-full items-end text-start justify-start'>
|
|
97
107
|
<h2 className={'text-xl font-light'} style={{ color: 'var(--text-main)' }}>KYD Candidate:</h2>
|
|
@@ -179,11 +189,18 @@ const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImage
|
|
|
179
189
|
</div>
|
|
180
190
|
|
|
181
191
|
{/* Badge Image with robust centered overlay */}
|
|
182
|
-
<div className=
|
|
183
|
-
<div className=
|
|
184
|
-
<Image
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
<div className={`flex items-center ${rightBadgeLayout ? 'md:justify-end h-20' : 'justify-center w-full mt-4'} `}>
|
|
193
|
+
<div className={`relative w-full ${rightBadgeLayout ? 'max-w-[85px]' : 'px-20'} select-none`}>
|
|
194
|
+
<Image
|
|
195
|
+
src={finalBadgeImageUrl}
|
|
196
|
+
alt="KYD Badge"
|
|
197
|
+
width={rightBadgeLayout ? 25 : 100}
|
|
198
|
+
height={rightBadgeLayout ? 25 : 100}
|
|
199
|
+
priority
|
|
200
|
+
className='w-full h-auto pointer-events-none'
|
|
201
|
+
/>
|
|
202
|
+
<div className={`pointer-events-none absolute left-1/2 -translate-x-1/2 -translate-y-1/2 ${rightBadgeLayout ? 'top-[72%]' : 'top-[69%]'}`}>
|
|
203
|
+
<div className={`font-extrabold text-black ${rightBadgeLayout ? 'text-xs' : 'text-3xl'}`}>
|
|
187
204
|
{Math.round(score || 0)}%
|
|
188
205
|
</div>
|
|
189
206
|
</div>
|
|
@@ -58,9 +58,9 @@ export default function RiskCard({
|
|
|
58
58
|
>
|
|
59
59
|
<div className="mb-3 flex items-start justify-between gap-2">
|
|
60
60
|
<div>
|
|
61
|
-
<div className={'font-semibold'} style={{ color: 'var(--text-main)' }}>{title}</div>
|
|
61
|
+
<div className={'font-semibold text-xl'} style={{ color: 'var(--text-main)' }}>{title}</div>
|
|
62
62
|
{description ? (
|
|
63
|
-
<div className={'text-
|
|
63
|
+
<div className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>{description}</div>
|
|
64
64
|
) : null}
|
|
65
65
|
</div>
|
|
66
66
|
{(tooltipText || description) && (
|
|
@@ -31,7 +31,7 @@ export default function RoleOverviewCard({
|
|
|
31
31
|
|
|
32
32
|
const tickLabels = useMemo(() => ({
|
|
33
33
|
type: 'outer' as const,
|
|
34
|
-
hideMinMax:
|
|
34
|
+
hideMinMax: true,
|
|
35
35
|
defaultTickLineConfig: {
|
|
36
36
|
length: 7,
|
|
37
37
|
width: 1,
|
|
@@ -45,11 +45,9 @@ export default function RoleOverviewCard({
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
ticks: [
|
|
48
|
-
{ value:
|
|
49
|
-
{ value: 25, valueConfig: { formatTextValue: () => 'Weak' } },
|
|
48
|
+
{ value: 16, valueConfig: { formatTextValue: () => 'Weak' } },
|
|
50
49
|
{ value: 50, valueConfig: { formatTextValue: () => 'Partial' } },
|
|
51
|
-
{ value:
|
|
52
|
-
{ value: 100, valueConfig: { formatTextValue: () => 'Optimal' } },
|
|
50
|
+
{ value: 83, valueConfig: { formatTextValue: () => 'Strong' } },
|
|
53
51
|
]
|
|
54
52
|
}), []);
|
|
55
53
|
|
|
@@ -262,7 +262,6 @@ export default function SkillsBubble({ skillsCategoryRadar, skillsByCategory, sk
|
|
|
262
262
|
{entry.label}
|
|
263
263
|
{/* Evidence count bullet */}
|
|
264
264
|
{(() => {
|
|
265
|
-
console.log('entry', entry);
|
|
266
265
|
const meta = skillsMeta?.[entry.label];
|
|
267
266
|
const count = Number((meta as any)?.evidenceCount || 0);
|
|
268
267
|
return count > 0 ? (
|
|
@@ -410,11 +409,11 @@ export default function SkillsBubble({ skillsCategoryRadar, skillsByCategory, sk
|
|
|
410
409
|
}}
|
|
411
410
|
>
|
|
412
411
|
<div className="flex items-center gap-2">
|
|
413
|
-
<span className="inline-block h-3 w-3 rounded-full" style={{ background:
|
|
412
|
+
<span className="inline-block h-3 w-3 rounded-full" style={{ background: green5 }} />
|
|
414
413
|
<span>Size = evidence count per category</span>
|
|
415
414
|
</div>
|
|
416
415
|
<div className="flex items-center gap-2 mt-1">
|
|
417
|
-
<span className="inline-block h-3 w-3 rounded-full" style={{ background:
|
|
416
|
+
<span className="inline-block h-3 w-3 rounded-full border border-[var(--text-secondary)]" style={{ background: green1 }} />
|
|
418
417
|
<span>Color = experience (darker = more)</span>
|
|
419
418
|
</div>
|
|
420
419
|
</div>
|