kyd-shared-badge 0.3.28 → 0.3.30
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
|
@@ -4,6 +4,7 @@ import { FiAlertTriangle } from 'react-icons/fi';
|
|
|
4
4
|
import { PublicBadgeData, GraphInsightsPayload, ScoringSummary, BusinessRule, TopBusinessRule } from './types';
|
|
5
5
|
// import ShareButton from './components/ShareButton';
|
|
6
6
|
import ReportHeader from './components/ReportHeader';
|
|
7
|
+
import EnterpriseCoaching from './components/EnterpriseCoaching';
|
|
7
8
|
import AppendixTables from './components/AppendixTables';
|
|
8
9
|
import BusinessRuleLink from './components/BusinessRuleLink';
|
|
9
10
|
import IpRiskAnalysisDisplay from './components/IpRiskAnalysisDisplay';
|
|
@@ -23,6 +24,7 @@ import { BusinessRulesProvider } from './components/BusinessRulesContext';
|
|
|
23
24
|
import Reveal from './components/Reveal';
|
|
24
25
|
import { formatLocalDateTime } from './utils/date';
|
|
25
26
|
import ChatWidget from './chat/ChatWidget';
|
|
27
|
+
import UseCases from './components/UseCases';
|
|
26
28
|
type ChatWidgetProps = Partial<{
|
|
27
29
|
api: string;
|
|
28
30
|
title: string;
|
|
@@ -178,6 +180,17 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
178
180
|
countries={(assessmentResult?.screening_sources?.ip_risk_analysis?.raw_data?.countries) || []}
|
|
179
181
|
/>
|
|
180
182
|
</Reveal>
|
|
183
|
+
{/* Coaching / Evidence under header when present */}
|
|
184
|
+
{(() => {
|
|
185
|
+
const em = assessmentResult.enterprise_match;
|
|
186
|
+
const coaching = em?.coaching;
|
|
187
|
+
if (!coaching || !(Array.isArray(coaching.items) && coaching.items.length)) return null;
|
|
188
|
+
return (
|
|
189
|
+
<Reveal headless={isHeadless}>
|
|
190
|
+
<EnterpriseCoaching roleName={em?.role?.name} matchLabel={em?.label} coaching={coaching} />
|
|
191
|
+
</Reveal>
|
|
192
|
+
);
|
|
193
|
+
})()}
|
|
181
194
|
<div
|
|
182
195
|
className={isHeadless ? 'p-6 sm:p-8 mt-2 border' : 'rounded-xl shadow-xl p-6 sm:p-8 mt-8 border'}
|
|
183
196
|
style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}
|
|
@@ -248,6 +261,11 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
|
|
|
248
261
|
</Reveal>
|
|
249
262
|
</div>
|
|
250
263
|
|
|
264
|
+
{/* Enterprise Use Cases (directly under the three summary cards) */}
|
|
265
|
+
{assessmentResult?.enterprise_use_cases?.items && assessmentResult.enterprise_use_cases.items.length > 0 && (
|
|
266
|
+
<UseCases useCases={assessmentResult.enterprise_use_cases} headless={isHeadless} />
|
|
267
|
+
)}
|
|
268
|
+
|
|
251
269
|
{/* Technical Scores */}
|
|
252
270
|
<div className="mt-8" >
|
|
253
271
|
<div key={'Technical'} className='pt-8 space-y-8 kyd-avoid-break' style={{ borderColor: 'var(--icon-button-secondary)'}}>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { FiThumbsUp, FiTrendingUp, FiInfo } from 'react-icons/fi';
|
|
4
|
+
|
|
5
|
+
type CoachingItem = {
|
|
6
|
+
headline: string;
|
|
7
|
+
rationale: string;
|
|
8
|
+
action?: string;
|
|
9
|
+
type?: 'support' | 'coaching';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function EnterpriseCoaching({
|
|
13
|
+
roleName,
|
|
14
|
+
matchLabel,
|
|
15
|
+
coaching,
|
|
16
|
+
}: {
|
|
17
|
+
roleName?: string;
|
|
18
|
+
matchLabel?: string;
|
|
19
|
+
coaching?: { items?: CoachingItem[]; summary?: string } | null;
|
|
20
|
+
}) {
|
|
21
|
+
if (!coaching || !Array.isArray(coaching.items) || coaching.items.length === 0) return null;
|
|
22
|
+
|
|
23
|
+
const toneTint = (label?: string) => {
|
|
24
|
+
const l = (label || '').toLowerCase();
|
|
25
|
+
if (l.includes('optimal') || l.includes('strong')) return 'rgba(2,163,137,0.10)';
|
|
26
|
+
if (l.includes('moderate')) return 'rgba(255,187,84,0.10)';
|
|
27
|
+
return 'rgba(236,102,98,0.10)';
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className={'mt-4 p-4 rounded-lg border'} style={{ background: toneTint(matchLabel), borderColor: 'var(--icon-button-secondary)' }}>
|
|
32
|
+
<div className="flex items-center justify-between mb-2">
|
|
33
|
+
<div className="flex items-center gap-2">
|
|
34
|
+
<span className={'px-2 py-1 rounded text-xs font-semibold'} style={{ backgroundColor: 'var(--content-card-background)', border: '1px solid var(--icon-button-secondary)', color: 'var(--text-main)' }}>
|
|
35
|
+
{matchLabel || 'Role Match'}
|
|
36
|
+
</span>
|
|
37
|
+
<div className={'text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>
|
|
38
|
+
{roleName ? `Role Alignment — ${roleName}` : 'Role Alignment'}
|
|
39
|
+
</div>
|
|
40
|
+
<span className={'relative inline-flex items-center group'} style={{ color: 'var(--text-secondary)' }}>
|
|
41
|
+
<FiInfo size={14} />
|
|
42
|
+
<div className="hidden group-hover:block absolute z-30 left-1/2 -translate-x-1/2 top-full mt-2 w-80">
|
|
43
|
+
<div style={{ background: 'var(--content-card-background)', border: '1px solid var(--icon-button-secondary)', color: 'var(--text-main)', padding: 10, borderRadius: 6 }}>
|
|
44
|
+
<div style={{ fontWeight: 600 }}>AI-generated</div>
|
|
45
|
+
<div style={{ marginTop: 6, fontSize: 12, color: 'var(--text-secondary)' }}>These items reflect alignment evidence and coaching opportunities based on the role requirements.</div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</span>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<ul className={'space-y-3'}>
|
|
52
|
+
{coaching.items.slice(0, 4).map((it, idx) => {
|
|
53
|
+
const isSupport = (it.type || '').toLowerCase() === 'support';
|
|
54
|
+
return (
|
|
55
|
+
<li key={idx} className={'flex items-start gap-3'} style={{ color: 'var(--text-secondary)' }}>
|
|
56
|
+
<div className={'mt-0.5'} style={{ color: isSupport ? 'var(--text-main)' : 'var(--text-secondary)' }}>
|
|
57
|
+
{isSupport ? <FiThumbsUp size={16} /> : <FiTrendingUp size={16} />}
|
|
58
|
+
</div>
|
|
59
|
+
<div>
|
|
60
|
+
<div className={'text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>{it.headline}</div>
|
|
61
|
+
<div className={'text-sm'}>{it.rationale}</div>
|
|
62
|
+
{it.action ? (
|
|
63
|
+
<div className={'text-sm'}>
|
|
64
|
+
<span className={'font-semibold'} style={{ color: 'var(--text-main)' }}>Action:</span> {it.action}
|
|
65
|
+
</div>
|
|
66
|
+
) : null}
|
|
67
|
+
</div>
|
|
68
|
+
</li>
|
|
69
|
+
);
|
|
70
|
+
})}
|
|
71
|
+
</ul>
|
|
72
|
+
{coaching.summary ? (
|
|
73
|
+
<div className={'mt-3 text-sm'} style={{ color: 'var(--text-secondary)' }}>{coaching.summary}</div>
|
|
74
|
+
) : null}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Reveal from './Reveal';
|
|
4
|
+
import { EnterpriseUseCases, UseCaseItem } from '../types';
|
|
5
|
+
|
|
6
|
+
export default function UseCases({ useCases, headless }: { useCases?: EnterpriseUseCases | null; headless?: boolean }) {
|
|
7
|
+
if (!useCases || !Array.isArray(useCases.items) || useCases.items.length === 0) return null;
|
|
8
|
+
|
|
9
|
+
const items: UseCaseItem[] = useCases.items.slice(0, 4);
|
|
10
|
+
const note = (useCases.note || '').trim();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Reveal headless={!!headless}>
|
|
14
|
+
<div className={'pt-8 kyd-avoid-break'}>
|
|
15
|
+
<h3 className={'text-2xl font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Potential Use Cases</h3>
|
|
16
|
+
<div className={'grid grid-cols-1 md:grid-cols-2 gap-4'}>
|
|
17
|
+
{items.map((uc, idx) => (
|
|
18
|
+
<div key={idx} className={'rounded-md p-5 border'} style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}>
|
|
19
|
+
<div className={'font-semibold'} style={{ color: 'var(--text-main)' }}>{uc.title}</div>
|
|
20
|
+
{uc.potential_impact ? (
|
|
21
|
+
<div className={'text-sm mt-2'} style={{ color: 'var(--text-secondary)' }}>
|
|
22
|
+
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>Potential Impact: </span>
|
|
23
|
+
{uc.potential_impact}
|
|
24
|
+
</div>
|
|
25
|
+
) : null}
|
|
26
|
+
{uc.demonstrated_capability ? (
|
|
27
|
+
<div className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>
|
|
28
|
+
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>Demonstrated Capability: </span>
|
|
29
|
+
{uc.demonstrated_capability}
|
|
30
|
+
</div>
|
|
31
|
+
) : null}
|
|
32
|
+
{uc.justification ? (
|
|
33
|
+
<div className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>
|
|
34
|
+
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>Justification: </span>
|
|
35
|
+
{uc.justification}
|
|
36
|
+
</div>
|
|
37
|
+
) : null}
|
|
38
|
+
</div>
|
|
39
|
+
))}
|
|
40
|
+
</div>
|
|
41
|
+
{note ? (
|
|
42
|
+
<div className={'text-xs mt-3'} style={{ color: 'var(--text-secondary)' }}>{note}</div>
|
|
43
|
+
) : null}
|
|
44
|
+
</div>
|
|
45
|
+
</Reveal>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
package/src/types.ts
CHANGED
|
@@ -154,6 +154,18 @@ export interface FBIWantedMatch {
|
|
|
154
154
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
155
155
|
raw_result: any;
|
|
156
156
|
}
|
|
157
|
+
export interface EnterpriseCoachingItem {
|
|
158
|
+
headline: string;
|
|
159
|
+
rationale: string;
|
|
160
|
+
action?: string;
|
|
161
|
+
type: 'support' | 'coaching';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface EnterpriseCoaching {
|
|
165
|
+
items: EnterpriseCoachingItem[];
|
|
166
|
+
summary?: string;
|
|
167
|
+
}
|
|
168
|
+
|
|
157
169
|
export interface EnterpriseMatch {
|
|
158
170
|
role: {
|
|
159
171
|
name: string;
|
|
@@ -161,6 +173,19 @@ export interface EnterpriseMatch {
|
|
|
161
173
|
};
|
|
162
174
|
label: string;
|
|
163
175
|
description: string;
|
|
176
|
+
coaching?: EnterpriseCoaching;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface UseCaseItem {
|
|
180
|
+
title: string;
|
|
181
|
+
potential_impact: string;
|
|
182
|
+
demonstrated_capability: string;
|
|
183
|
+
justification: string;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface EnterpriseUseCases {
|
|
187
|
+
items: UseCaseItem[];
|
|
188
|
+
note?: string;
|
|
164
189
|
}
|
|
165
190
|
|
|
166
191
|
|
|
@@ -235,6 +260,7 @@ export interface AssessmentResult {
|
|
|
235
260
|
skills_all?: SkillsAll;
|
|
236
261
|
graph_insights?: GraphInsightsPayload;
|
|
237
262
|
enterprise_match?: EnterpriseMatch;
|
|
263
|
+
enterprise_use_cases?: EnterpriseUseCases;
|
|
238
264
|
}
|
|
239
265
|
export interface ClientMetadata {
|
|
240
266
|
ipAddress: string;
|