kyd-shared-badge 0.3.27 → 0.3.29

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyd-shared-badge",
3
- "version": "0.3.27",
3
+ "version": "0.3.29",
4
4
  "private": false,
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -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';
@@ -178,6 +179,17 @@ const SharedBadgeDisplay = ({ badgeData, chatProps, headless }: { badgeData: Pub
178
179
  countries={(assessmentResult?.screening_sources?.ip_risk_analysis?.raw_data?.countries) || []}
179
180
  />
180
181
  </Reveal>
182
+ {/* Coaching / Evidence under header when present */}
183
+ {(() => {
184
+ const em = (assessmentResult as any)?.enterprise_match;
185
+ const coaching = em?.coaching;
186
+ if (!coaching || !(Array.isArray(coaching.items) && coaching.items.length)) return null;
187
+ return (
188
+ <Reveal headless={isHeadless}>
189
+ <EnterpriseCoaching roleName={em?.role?.name} matchLabel={em?.label} coaching={coaching} />
190
+ </Reveal>
191
+ );
192
+ })()}
181
193
  <div
182
194
  className={isHeadless ? 'p-6 sm:p-8 mt-2 border' : 'rounded-xl shadow-xl p-6 sm:p-8 mt-8 border'}
183
195
  style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}
@@ -51,6 +51,13 @@ export default function ChatWidget({ api = '/api/chat', title = 'KYD Bot', hintT
51
51
  } catch {}
52
52
  // eslint-disable-next-line react-hooks/exhaustive-deps
53
53
  }, [hasMounted, isMobile]);
54
+
55
+ useEffect(() => {
56
+ // when sidebar is closed, dismiss hint
57
+ if (open) return;
58
+ setShowHint(false);
59
+ }, [open]);
60
+
54
61
  // Sidebar width with bounds and persistence
55
62
  const [width, setWidth] = useState<number>(() => {
56
63
  try { const w = Number(localStorage.getItem('kydChatSidebarWidth')); return Number.isFinite(w) && w >= 320 ? Math.min(w, Math.floor(window.innerWidth * 0.9)) : 420; } catch { return 420; }
@@ -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
+
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,7 @@ export interface EnterpriseMatch {
161
173
  };
162
174
  label: string;
163
175
  description: string;
176
+ coaching?: EnterpriseCoaching;
164
177
  }
165
178
 
166
179