kyd-shared-badge 0.3.107 → 0.3.109
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
CHANGED
|
@@ -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,7 @@ 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}
|
|
228
229
|
/>
|
|
229
230
|
</div>
|
|
230
231
|
{/* Top-right: Role match section */}
|
|
@@ -258,6 +259,7 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
258
259
|
percent={techPct}
|
|
259
260
|
label={techLabel}
|
|
260
261
|
topMovers={[]}
|
|
262
|
+
selfCheck={selfCheck}
|
|
261
263
|
/>
|
|
262
264
|
);
|
|
263
265
|
})()}
|
|
@@ -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(() => ({
|
|
@@ -103,15 +112,22 @@ export default function GaugeCard({
|
|
|
103
112
|
},
|
|
104
113
|
tickLabels: tickLabels,
|
|
105
114
|
}}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
arc={{
|
|
116
|
+
padding: 0.02,
|
|
117
|
+
subArcs: selfCheck
|
|
118
|
+
? [
|
|
119
|
+
{ limit: 20, color: green5 },
|
|
120
|
+
{ limit: 40, color: green4 },
|
|
121
|
+
{ limit: 60, color: green3 },
|
|
122
|
+
{ limit: 80, color: green2 },
|
|
123
|
+
{ limit: 100, color: green1 },
|
|
124
|
+
]
|
|
125
|
+
: [
|
|
126
|
+
{ limit: 33, color: red },
|
|
127
|
+
{ limit: 66, color: yellow },
|
|
128
|
+
{ limit: 100, color: green },
|
|
129
|
+
],
|
|
130
|
+
}}
|
|
115
131
|
pointer={{ type: 'blob', elastic: true, animationDelay: 0 }}
|
|
116
132
|
/>
|
|
117
133
|
{(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,13 @@ interface ReportHeaderProps {
|
|
|
43
51
|
accountAuthenticity?: { label?: string; description?: string };
|
|
44
52
|
companyName?: string;
|
|
45
53
|
sourcesProviders?: string[];
|
|
54
|
+
selfCheck?: boolean;
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImageUrl, summary, enterpriseMatch, countries = [], accountAuthenticity, companyName, sourcesProviders = [] }: ReportHeaderProps) => {
|
|
57
|
+
const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImageUrl, summary, enterpriseMatch, countries = [], accountAuthenticity, companyName, sourcesProviders = [], selfCheck }: ReportHeaderProps) => {
|
|
49
58
|
// Use the dynamic image if available, otherwise fall back to the score-based one.
|
|
50
59
|
const finalBadgeImageUrl = badgeImageUrl || getBadgeImageUrl(score || 0);
|
|
51
|
-
const tint = hexToRgba(pickTint(score || 0), 0.06);
|
|
60
|
+
const tint = hexToRgba(pickTint(score || 0, selfCheck), 0.06);
|
|
52
61
|
const matchLabel = enterpriseMatch?.label;
|
|
53
62
|
const sources = (() => {
|
|
54
63
|
const primary = Array.isArray(sourcesProviders) ? sourcesProviders : [];
|
|
@@ -67,7 +76,7 @@ const ReportHeader = ({ badgeId, developerName, updatedAt, score = 0, badgeImage
|
|
|
67
76
|
|
|
68
77
|
return (
|
|
69
78
|
<div
|
|
70
|
-
className={'p-6 rounded-md
|
|
79
|
+
className={'p-6 rounded-md border'}
|
|
71
80
|
style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)', backgroundImage: `linear-gradient(${tint}, ${tint})` }}
|
|
72
81
|
>
|
|
73
82
|
{(() => {
|
|
@@ -251,7 +251,7 @@ export default function SkillsBubble({ skillsCategoryRadar, skillsByCategory, sk
|
|
|
251
251
|
|
|
252
252
|
const columnComponent = (entry: { label: string; years?: number; presence?: string; presenceTypes?: Array<'certified' | 'observed' | 'self-reported'>; sources?: string[] } | '', idx: number, isLeft: boolean) => {
|
|
253
253
|
return (
|
|
254
|
-
<div key={idx} className="flex
|
|
254
|
+
<div key={idx} className="flex justify-between gap-3 min-w-0">
|
|
255
255
|
<div className="flex flex-row w-1/2 items-start gap-8">
|
|
256
256
|
{entry ? <span className="shrink-0 opacity-70 text-base items-center flex h-full">{idx + (isLeft ? 1 : 6)}.</span> : <span className="opacity-0 whitespace-nowrap">\u00A0</span>}
|
|
257
257
|
|
|
@@ -262,14 +262,13 @@ 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 ? (
|
|
269
268
|
<>
|
|
270
269
|
{' '}<span className="opacity-60">•</span>{' '}
|
|
271
270
|
<span
|
|
272
|
-
className="
|
|
271
|
+
className="cursor-help opacity-80"
|
|
273
272
|
onMouseEnter={(e) =>
|
|
274
273
|
showLegendTooltipAt(
|
|
275
274
|
e.currentTarget,
|
|
@@ -339,52 +338,55 @@ export default function SkillsBubble({ skillsCategoryRadar, skillsByCategory, sk
|
|
|
339
338
|
</span>
|
|
340
339
|
</div>
|
|
341
340
|
</div>
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
>
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
341
|
+
<div
|
|
342
|
+
className="flex flex-col items-end leading-tight h-full justify-start text-base"
|
|
343
|
+
>
|
|
344
|
+
<div className="pb-1">
|
|
345
|
+
{entry && typeof entry !== 'string' && entry.years ? (
|
|
346
|
+
<span
|
|
347
|
+
className="whitespace-nowrap text-[var(--text-secondary)] cursor-help"
|
|
348
|
+
onMouseEnter={(e) => {
|
|
349
|
+
const copy = experienceLegendTooltip();
|
|
350
|
+
showLegendTooltipAt(e.currentTarget, copy.title, copy.body);
|
|
351
|
+
}}
|
|
352
|
+
onMouseLeave={hideLegendTooltip}
|
|
353
|
+
>
|
|
354
|
+
{`${entry.years} Years`}
|
|
355
|
+
</span>
|
|
356
|
+
) : (
|
|
357
|
+
<span className="opacity-0 whitespace-nowrap text-[var(--text-secondary)]">0 Years</span>
|
|
358
|
+
)}
|
|
359
|
+
</div>
|
|
360
|
+
<div
|
|
361
|
+
onMouseEnter={(e) => {
|
|
362
|
+
if (entry && typeof entry !== 'string') {
|
|
364
363
|
const copy = presenceLegendTooltip();
|
|
365
364
|
showLegendTooltipAt(e.currentTarget, undefined, copy.body);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
365
|
+
}
|
|
366
|
+
}}
|
|
367
|
+
onMouseLeave={(e) => {
|
|
368
|
+
if (entry && typeof entry !== 'string') hideLegendTooltip();
|
|
369
|
+
}}
|
|
370
|
+
className="pt-1"
|
|
371
|
+
>
|
|
372
|
+
{(() => {
|
|
373
|
+
if (entry && typeof entry !== 'string') {
|
|
374
|
+
const types = Array.isArray(entry.presenceTypes) ? entry.presenceTypes : (entry.presence ? [String(entry.presence) as any] : []);
|
|
375
|
+
const hasAny = types.length > 0;
|
|
376
|
+
return hasAny ? (
|
|
377
|
+
<div
|
|
378
|
+
className="flex items-center gap-1"
|
|
379
|
+
>
|
|
380
|
+
{types.map((t) => (
|
|
381
|
+
<span key={t} className="inline-block h-2 w-2 rounded-full" style={{ background: presenceColor(t) }} />
|
|
382
|
+
))}
|
|
383
|
+
</div>
|
|
384
|
+
) : <span className="opacity-0 whitespace-nowrap">.</span>;
|
|
385
|
+
}
|
|
386
|
+
return <span className="opacity-0 whitespace-nowrap">.</span>;
|
|
383
387
|
})()}
|
|
384
|
-
|
|
385
|
-
</div>
|
|
386
388
|
</div>
|
|
387
|
-
|
|
389
|
+
</div>
|
|
388
390
|
</div>
|
|
389
391
|
)
|
|
390
392
|
}
|
|
@@ -407,11 +409,11 @@ export default function SkillsBubble({ skillsCategoryRadar, skillsByCategory, sk
|
|
|
407
409
|
}}
|
|
408
410
|
>
|
|
409
411
|
<div className="flex items-center gap-2">
|
|
410
|
-
<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 }} />
|
|
411
413
|
<span>Size = evidence count per category</span>
|
|
412
414
|
</div>
|
|
413
415
|
<div className="flex items-center gap-2 mt-1">
|
|
414
|
-
<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 }} />
|
|
415
417
|
<span>Color = experience (darker = more)</span>
|
|
416
418
|
</div>
|
|
417
419
|
</div>
|