kyd-shared-badge 0.2.23 → 0.2.25
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/SharedBadgeDisplay.tsx +196 -284
package/package.json
CHANGED
|
@@ -57,315 +57,227 @@ const getAiIconSrc = (descriptor?: string): string => {
|
|
|
57
57
|
return '/badge/aired.png';
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
interface ScoreCardProps {
|
|
61
|
-
title: React.ReactNode;
|
|
62
|
-
score: number;
|
|
63
|
-
description: string;
|
|
64
|
-
descriptor?: string;
|
|
65
|
-
scoreType: 'number' | 'risk' | 'descriptor';
|
|
66
|
-
iconImageSrc: string;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const ScoreCard = ({ title, score, description, descriptor, scoreType, iconImageSrc }: ScoreCardProps) => {
|
|
70
|
-
const isDescriptor = scoreType === 'descriptor';
|
|
71
|
-
const scoreHex = getScoreColor(score);
|
|
72
|
-
const overlay = scoreHex ? hexToRgba(scoreHex, 0.08) : 'transparent';
|
|
73
|
-
let displayScore;
|
|
74
|
-
|
|
75
|
-
if (scoreType === 'risk') {
|
|
76
|
-
displayScore = getRiskText(score);
|
|
77
|
-
} else if (scoreType === 'descriptor') {
|
|
78
|
-
displayScore = descriptor;
|
|
79
|
-
} else {
|
|
80
|
-
displayScore = `${score}/100`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<div
|
|
85
|
-
className={
|
|
86
|
-
'p-6 rounded-xl flex flex-col items-center justify-start text-center shadow h-full border'
|
|
87
|
-
}
|
|
88
|
-
style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)', backgroundImage: `linear-gradient(${overlay}, ${overlay})` }}
|
|
89
|
-
>
|
|
90
|
-
<div className={`text-3xl mb-4`} style={scoreHex ? { color: scoreHex } : undefined}>
|
|
91
|
-
<Image src={iconImageSrc} alt="icon" width={32} height={32} className="h-8 w-8 object-contain" />
|
|
92
|
-
</div>
|
|
93
|
-
<h3 className={`font-semibold text-xl ${isDescriptor ? 'text-neutral-400' : ''}`} style={{ color: 'var(--text-main)' }}>{title}</h3>
|
|
94
|
-
<p className={`text-4xl font-bold`} style={scoreHex ? { color: scoreHex } : undefined}>{displayScore}</p>
|
|
95
|
-
<p className={'text-sm text-neutral-600 dark:text-neutral-400 mt-4'} style={{ color: 'var(--text-secondary)' }}>{description}</p>
|
|
96
|
-
</div>
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
|
-
|
|
100
60
|
const SharedBadgeDisplay = ({ badgeData }: { badgeData: PublicBadgeData }) => {
|
|
101
61
|
const { badgeId, developerName, assessmentResult, updatedAt, connectedAccounts } = badgeData;
|
|
102
|
-
const { summary_scores, report_summary, developer_trust_explanation, key_skills, screening_sources, industry_considerations
|
|
62
|
+
const { summary_scores, report_summary, developer_trust_explanation, key_skills, screening_sources, industry_considerations } = assessmentResult;
|
|
103
63
|
|
|
104
|
-
const devTrustScore = summary_scores
|
|
105
|
-
const riskScore = summary_scores
|
|
106
|
-
const aiUsageScore = summary_scores
|
|
64
|
+
// const devTrustScore = summary_scores.developer_trust;
|
|
65
|
+
// const riskScore = summary_scores.risk_score;
|
|
66
|
+
// const aiUsageScore = summary_scores.ai_usage;
|
|
107
67
|
|
|
108
68
|
const wrapperMaxWidth = 'max-w-5xl';
|
|
109
69
|
|
|
110
70
|
return (
|
|
111
71
|
<div className={`${wrapperMaxWidth} mx-auto`}>
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{summary_scores && (
|
|
126
|
-
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12">
|
|
127
|
-
<ScoreCard
|
|
128
|
-
title="KYD Technical™"
|
|
129
|
-
score={devTrustScore?.score || 0}
|
|
130
|
-
description={devTrustScore?.description || ''}
|
|
131
|
-
scoreType='number'
|
|
132
|
-
iconImageSrc={getTechnicalIconSrc(devTrustScore?.score || 0)}
|
|
133
|
-
/>
|
|
134
|
-
<ScoreCard
|
|
135
|
-
title="KYD Risk™"
|
|
136
|
-
score={riskScore?.score || 0}
|
|
137
|
-
description={riskScore?.description || ''}
|
|
138
|
-
scoreType='risk'
|
|
139
|
-
iconImageSrc={getRiskIconSrc(riskScore?.score || 0)}
|
|
140
|
-
/>
|
|
141
|
-
<ScoreCard
|
|
142
|
-
title={<span>KYD AI™ <span className="text-xs font-semibold bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-2 py-1 rounded-full align-middle">Beta</span></span>}
|
|
143
|
-
score={aiUsageScore?.score || 0}
|
|
144
|
-
description={aiUsageScore?.description || ''}
|
|
145
|
-
descriptor={aiUsageScore?.descriptor}
|
|
146
|
-
scoreType='descriptor'
|
|
147
|
-
iconImageSrc={getAiIconSrc(aiUsageScore?.descriptor)}
|
|
148
|
-
/>
|
|
149
|
-
</div>
|
|
150
|
-
)}
|
|
72
|
+
{/* Share controls removed; app-level pages render their own actions */}
|
|
73
|
+
<ReportHeader
|
|
74
|
+
badgeId={badgeId}
|
|
75
|
+
developerName={badgeData.developerName}
|
|
76
|
+
updatedAt={updatedAt}
|
|
77
|
+
score={summary_scores.kyd_self_check.score}
|
|
78
|
+
isPublic={true}
|
|
79
|
+
badgeImageUrl={badgeData.badgeImageUrl || ''}
|
|
80
|
+
/>
|
|
81
|
+
<div
|
|
82
|
+
className={'rounded-xl shadow-xl p-6 sm:p-8 mt-8 border'}
|
|
83
|
+
style={{ backgroundColor: 'var(--content-card-background)', borderColor: 'var(--icon-button-secondary)' }}
|
|
84
|
+
>
|
|
151
85
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
86
|
+
<div className={'space-y-12 divide-y'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
|
|
87
|
+
<div className="pt-8 first:pt-0">
|
|
88
|
+
<h3 className={'text-2xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>1. Summary Findings</h3>
|
|
89
|
+
<div className={'prose prose-sm max-w-none'} style={{ color: 'var(--text-secondary)' }}>
|
|
90
|
+
<p>{report_summary}</p>
|
|
91
|
+
</div>
|
|
92
|
+
{/* {key_skills && key_skills.length > 0 && (
|
|
159
93
|
<div className="mt-6">
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
94
|
+
<h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>Key Skills Observed</h4>
|
|
95
|
+
<div className="flex flex-wrap gap-2">
|
|
96
|
+
{key_skills.map((skill: string, index: number) => (
|
|
97
|
+
<span key={index} className={'text-xs font-medium px-2.5 py-1 rounded-full'} style={{ backgroundColor: 'var(--icon-button-secondary)', color: 'var(--text-main)' }}>
|
|
98
|
+
{skill}
|
|
99
|
+
</span>
|
|
100
|
+
))}
|
|
101
|
+
</div>
|
|
166
102
|
</div>
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
103
|
+
)} */}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div className="pt-8">
|
|
107
|
+
<h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>2. KYD Technical™ Signals</h3>
|
|
108
|
+
<div className={'prose prose-sm max-w-none mb-6'} style={{ color: 'var(--text-secondary)' }}>
|
|
109
|
+
<p>{developer_trust_explanation}</p>
|
|
110
|
+
</div>
|
|
111
|
+
<ProviderInsights
|
|
112
|
+
platforms={connectedAccounts || []}
|
|
113
|
+
insights={assessmentResult.provider_insights}
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div className="pt-8">
|
|
118
|
+
<h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>3. KYD Risk™ Signals</h3>
|
|
119
|
+
{badgeData.optOutScreening ? (
|
|
120
|
+
<div className={'mb-4 p-4 rounded-lg border'} style={{ backgroundColor: 'var(--icon-button-secondary)', borderColor: 'var(--icon-button-secondary)' }}>
|
|
121
|
+
<div className="flex items-start">
|
|
122
|
+
<span className="h-5 w-5 mr-3 mt-0.5 flex-shrink-0" style={{ color: yellow }}>
|
|
123
|
+
<FiAlertTriangle size={20} />
|
|
124
|
+
</span>
|
|
125
|
+
<div>
|
|
126
|
+
<h4 className={'font-bold'} style={{ color: 'var(--text-main)' }}>User Opted Out of Screening</h4>
|
|
127
|
+
<p className={'text-sm mt-1'} style={{ color: 'var(--text-secondary)' }}>
|
|
128
|
+
The user chose not to participate in the automated sanctions and risk screening process. The risk score reflects this decision and is for informational purposes only.
|
|
129
|
+
</p>
|
|
130
|
+
</div>
|
|
177
131
|
</div>
|
|
178
132
|
</div>
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
<h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>3. KYD Risk™ Signals</h3>
|
|
195
|
-
{badgeData.optOutScreening ? (
|
|
196
|
-
<div className={'mb-4 p-4 rounded-lg border'} style={{ backgroundColor: 'var(--icon-button-secondary)', borderColor: 'var(--icon-button-secondary)' }}>
|
|
197
|
-
<div className="flex items-start">
|
|
198
|
-
<span className="h-5 w-5 mr-3 mt-0.5 flex-shrink-0" style={{ color: yellow }}>
|
|
199
|
-
<FiAlertTriangle size={20} />
|
|
200
|
-
</span>
|
|
133
|
+
) : (
|
|
134
|
+
<>
|
|
135
|
+
{(() => {
|
|
136
|
+
const ss = assessmentResult?.screening_sources;
|
|
137
|
+
const ofacMatches = ss?.ofac_screen?.matches && (ss.ofac_screen.matches.length > 0);
|
|
138
|
+
const cslDetails = ss?.csl_details && (Array.isArray(ss.csl_details) ? ss.csl_details.length > 0 : Object.keys(ss.csl_details).length > 0);
|
|
139
|
+
const fbiMatches = ss?.fbi_matches && (ss.fbi_matches.length > 0);
|
|
140
|
+
if (!(ofacMatches || cslDetails || fbiMatches)) return null;
|
|
141
|
+
return (
|
|
142
|
+
<div className={'mb-8 rounded-lg border p-4'} style={{ borderColor: 'var(--icon-button-secondary)', backgroundColor: 'var(--content-card-background)' }}>
|
|
143
|
+
<h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>3A. Sanctions Matches</h4>
|
|
144
|
+
{/* OFAC matches */}
|
|
145
|
+
{ofacMatches && (
|
|
146
|
+
<div className={'mb-4'}>
|
|
147
|
+
<h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>OFAC API Matches</h5>
|
|
201
148
|
<div>
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
) : (
|
|
210
|
-
<>
|
|
211
|
-
{riskScore?.description && (
|
|
212
|
-
<div className={'prose prose-sm max-w-none space-y-4 mb-6'} style={{ color: 'var(--text-secondary)' }}>
|
|
213
|
-
<p>{riskScore.description}</p>
|
|
214
|
-
</div>
|
|
215
|
-
)}
|
|
216
|
-
{(() => {
|
|
217
|
-
const ss = assessmentResult?.screening_sources;
|
|
218
|
-
const ofacMatches = ss?.ofac_screen?.matches && (ss.ofac_screen.matches.length > 0);
|
|
219
|
-
const cslDetails = ss?.csl_details && (Array.isArray(ss.csl_details) ? ss.csl_details.length > 0 : Object.keys(ss.csl_details).length > 0);
|
|
220
|
-
const fbiMatches = ss?.fbi_matches && (ss.fbi_matches.length > 0);
|
|
221
|
-
if (!(ofacMatches || cslDetails || fbiMatches)) return null;
|
|
222
|
-
return (
|
|
223
|
-
<div className={'mb-8 rounded-lg border p-4'} style={{ borderColor: 'var(--icon-button-secondary)', backgroundColor: 'var(--content-card-background)' }}>
|
|
224
|
-
<h4 className={'text-lg font-semibold mb-3'} style={{ color: 'var(--text-main)' }}>3A. Sanctions Matches</h4>
|
|
225
|
-
{/* OFAC matches */}
|
|
226
|
-
{ofacMatches && (
|
|
227
|
-
<div className={'mb-4'}>
|
|
228
|
-
<h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>OFAC API Matches</h5>
|
|
229
|
-
<div>
|
|
230
|
-
{ss!.ofac_screen!.matches!.map((m: any, i: number) => {
|
|
231
|
-
const s = m?.sanction || {};
|
|
232
|
-
const title = s.name || 'Unknown';
|
|
233
|
-
const programs = (s.programs && s.programs.length) ? ` — Programs: ${s.programs.join(', ')}` : '';
|
|
234
|
-
return (
|
|
235
|
-
<div key={i} style={{ display: 'grid', gridTemplateColumns: '12px 1fr', columnGap: 8, alignItems: 'start', marginBottom: 6 }}>
|
|
236
|
-
<div aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', marginTop: 6, backgroundColor: 'var(--text-secondary)' }} />
|
|
237
|
-
<div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
|
|
238
|
-
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{title}</span>
|
|
239
|
-
<span>{programs}</span>
|
|
240
|
-
{s.entityLink ? (
|
|
241
|
-
<>
|
|
242
|
-
{' '}— <a href={s.entityLink} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a>
|
|
243
|
-
</>
|
|
244
|
-
) : null}
|
|
245
|
-
</div>
|
|
246
|
-
</div>
|
|
247
|
-
);
|
|
248
|
-
})}
|
|
249
|
-
</div>
|
|
250
|
-
<details className={'mt-2'}>
|
|
251
|
-
<summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View OFAC Raw JSON</summary>
|
|
252
|
-
<pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.ofac_screen!.raw, null, 2)}</pre>
|
|
253
|
-
</details>
|
|
254
|
-
</div>
|
|
255
|
-
)}
|
|
256
|
-
{/* CSL details */}
|
|
257
|
-
{cslDetails && (
|
|
258
|
-
<div className={'mb-4'}>
|
|
259
|
-
<h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>U.S. CSL Details</h5>
|
|
260
|
-
<details>
|
|
261
|
-
<summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View CSL Raw JSON</summary>
|
|
262
|
-
<pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.csl_details, null, 2)}</pre>
|
|
263
|
-
</details>
|
|
264
|
-
</div>
|
|
265
|
-
)}
|
|
266
|
-
{/* FBI matches */}
|
|
267
|
-
{fbiMatches && (
|
|
268
|
-
<div className={'mb-2'}>
|
|
269
|
-
<h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>FBI Wanted List Matches</h5>
|
|
270
|
-
<div>
|
|
271
|
-
{ss!.fbi_matches!.map((f: any, i: number) => (
|
|
149
|
+
{ss!.ofac_screen!.matches!.map((m: any, i: number) => {
|
|
150
|
+
const s = m?.sanction || {};
|
|
151
|
+
const title = s.name || 'Unknown';
|
|
152
|
+
const programs = (s.programs && s.programs.length) ? ` — Programs: ${s.programs.join(', ')}` : '';
|
|
153
|
+
return (
|
|
272
154
|
<div key={i} style={{ display: 'grid', gridTemplateColumns: '12px 1fr', columnGap: 8, alignItems: 'start', marginBottom: 6 }}>
|
|
273
155
|
<div aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', marginTop: 6, backgroundColor: 'var(--text-secondary)' }} />
|
|
274
156
|
<div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
|
|
275
|
-
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{
|
|
276
|
-
|
|
157
|
+
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{title}</span>
|
|
158
|
+
<span>{programs}</span>
|
|
159
|
+
{s.entityLink ? (
|
|
160
|
+
<>
|
|
161
|
+
{' '}— <a href={s.entityLink} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a>
|
|
162
|
+
</>
|
|
163
|
+
) : null}
|
|
277
164
|
</div>
|
|
278
165
|
</div>
|
|
279
|
-
)
|
|
280
|
-
|
|
166
|
+
);
|
|
167
|
+
})}
|
|
168
|
+
</div>
|
|
169
|
+
<details className={'mt-2'}>
|
|
170
|
+
<summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View OFAC Raw JSON</summary>
|
|
171
|
+
<pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.ofac_screen!.raw, null, 2)}</pre>
|
|
172
|
+
</details>
|
|
173
|
+
</div>
|
|
174
|
+
)}
|
|
175
|
+
{/* CSL details */}
|
|
176
|
+
{cslDetails && (
|
|
177
|
+
<div className={'mb-4'}>
|
|
178
|
+
<h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>U.S. CSL Details</h5>
|
|
179
|
+
<details>
|
|
180
|
+
<summary className={'cursor-pointer text-sm font-semibold'} style={{ color: 'var(--text-main)' }}>View CSL Raw JSON</summary>
|
|
181
|
+
<pre className={'mt-2 overflow-auto text-xs p-3 rounded'} style={{ background: 'rgba(0,0,0,0.04)', color: 'var(--text-main)' }}>{JSON.stringify(ss!.csl_details, null, 2)}</pre>
|
|
182
|
+
</details>
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
185
|
+
{/* FBI matches */}
|
|
186
|
+
{fbiMatches && (
|
|
187
|
+
<div className={'mb-2'}>
|
|
188
|
+
<h5 className={'font-semibold mb-2'} style={{ color: 'var(--text-main)' }}>FBI Wanted List Matches</h5>
|
|
189
|
+
<div>
|
|
190
|
+
{ss!.fbi_matches!.map((f: any, i: number) => (
|
|
191
|
+
<div key={i} style={{ display: 'grid', gridTemplateColumns: '12px 1fr', columnGap: 8, alignItems: 'start', marginBottom: 6 }}>
|
|
192
|
+
<div aria-hidden="true" style={{ width: 6, height: 6, borderRadius: '50%', marginTop: 6, backgroundColor: 'var(--text-secondary)' }} />
|
|
193
|
+
<div className={'text-sm'} style={{ color: 'var(--text-secondary)' }}>
|
|
194
|
+
<span className={'font-medium'} style={{ color: 'var(--text-main)' }}>{f.title || 'Match'}</span>
|
|
195
|
+
{f.url ? <> — <a href={f.url} target='_blank' rel='noopener noreferrer' className={'underline'} style={{ color: 'var(--icon-accent)' }}>Details</a></> : null}
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
))}
|
|
281
199
|
</div>
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
200
|
+
</div>
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
})()}
|
|
205
|
+
<IpRiskAnalysisDisplay ipRiskAnalysis={screening_sources?.ip_risk_analysis} />
|
|
206
|
+
</>
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div className="pt-8">
|
|
211
|
+
<h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>4. KYD AI™ Signals <span className="text-sm font-semibold bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200 px-2 py-1 rounded-full align-middle">Beta</span></h3>
|
|
212
|
+
<div className={'prose prose-sm max-w-none mb-6 space-y-4'} style={{ color: 'var(--text-secondary)' }}>
|
|
213
|
+
<p>{assessmentResult.ai_usage_summary?.explanation}</p>
|
|
214
|
+
{assessmentResult.ai_usage_summary?.key_findings && (
|
|
215
|
+
<ul className="list-disc list-inside">
|
|
216
|
+
{assessmentResult.ai_usage_summary.key_findings.map((finding, index) => (
|
|
217
|
+
<li key={index}>{finding}</li>
|
|
218
|
+
))}
|
|
219
|
+
</ul>
|
|
288
220
|
)}
|
|
289
221
|
</div>
|
|
222
|
+
</div>
|
|
290
223
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
224
|
+
{!badgeData.optOutScreening && screening_sources && (
|
|
225
|
+
<div className="pt-8">
|
|
226
|
+
<h3 className={'text-2xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>6. Appendix: Data Sources</h3>
|
|
227
|
+
<div className="space-y-8">
|
|
228
|
+
<div>
|
|
229
|
+
<h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Sanctions & Watchlists</h4>
|
|
230
|
+
{(() => {
|
|
231
|
+
const ofacProvided = screening_sources.ofac_screen?.sources || [];
|
|
232
|
+
const lists = [...(screening_sources.ofac_lists || []), ...ofacProvided];
|
|
233
|
+
const seen: { [k: string]: boolean } = {};
|
|
234
|
+
const dedup: string[] = [];
|
|
235
|
+
for (let i = 0; i < lists.length; i++) {
|
|
236
|
+
const val = lists[i];
|
|
237
|
+
if (!seen[val]) { seen[val] = true; dedup.push(val); }
|
|
238
|
+
}
|
|
239
|
+
const detailed = screening_sources.sanctions_sources_detailed || [];
|
|
240
|
+
const useDetailed = detailed && detailed.length > 0;
|
|
241
|
+
return (
|
|
242
|
+
<AppendixTables
|
|
243
|
+
type="sanctions"
|
|
244
|
+
sources={useDetailed ? detailed : dedup}
|
|
245
|
+
searchedAt={updatedAt}
|
|
246
|
+
developerName={developerName || 'this developer'}
|
|
247
|
+
/>
|
|
248
|
+
);
|
|
249
|
+
})()}
|
|
250
|
+
</div>
|
|
251
|
+
<div>
|
|
252
|
+
<h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Country-specific Entity Affiliations</h4>
|
|
253
|
+
<AppendixTables
|
|
254
|
+
type="domains"
|
|
255
|
+
sources={screening_sources.risk_profile_domains || []}
|
|
256
|
+
searchedAt={updatedAt}
|
|
257
|
+
developerName={developerName || 'this developer'}
|
|
258
|
+
/>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
302
261
|
</div>
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
<div className="pt-8">
|
|
306
|
-
<h3 className={'text-xl font-bold mb-3'} style={{ color: 'var(--text-main)' }}>5. Industry Considerations</h3>
|
|
307
|
-
<div className={'prose prose-sm max-w-none'} style={{ color: 'var(--text-secondary)' }}>
|
|
308
|
-
<p>{industry_considerations}</p>
|
|
309
|
-
</div>
|
|
310
|
-
</div>
|
|
262
|
+
)}
|
|
311
263
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
return (
|
|
330
|
-
<AppendixTables
|
|
331
|
-
type="sanctions"
|
|
332
|
-
sources={useDetailed ? detailed : dedup}
|
|
333
|
-
searchedAt={updatedAt}
|
|
334
|
-
developerName={developerName || 'this developer'}
|
|
335
|
-
/>
|
|
336
|
-
);
|
|
337
|
-
})()}
|
|
338
|
-
</div>
|
|
339
|
-
<div>
|
|
340
|
-
<h4 className={'text-xl font-bold mb-4'} style={{ color: 'var(--text-main)' }}>Country-specific Entity Affiliations</h4>
|
|
341
|
-
<AppendixTables
|
|
342
|
-
type="domains"
|
|
343
|
-
sources={screening_sources.risk_profile_domains || []}
|
|
344
|
-
searchedAt={updatedAt}
|
|
345
|
-
developerName={developerName || 'this developer'}
|
|
346
|
-
/>
|
|
347
|
-
</div>
|
|
348
|
-
</div>
|
|
349
|
-
</div>
|
|
350
|
-
)}
|
|
351
|
-
|
|
352
|
-
<div className={'pt-8 text-sm text-center'} style={{ color: 'var(--text-secondary)' }}>
|
|
353
|
-
Report Completed: {new Date(updatedAt).toLocaleString(undefined, {
|
|
354
|
-
year: 'numeric',
|
|
355
|
-
month: 'long',
|
|
356
|
-
day: 'numeric',
|
|
357
|
-
hour: 'numeric',
|
|
358
|
-
minute: '2-digit',
|
|
359
|
-
timeZoneName: 'short',
|
|
360
|
-
})}
|
|
361
|
-
</div>
|
|
362
|
-
</div>
|
|
363
|
-
</div>
|
|
364
|
-
<footer className={'mt-12 pt-6 border-t'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
|
|
365
|
-
<p className={'text-center text-xs max-w-4xl mx-auto'} style={{ color: 'var(--text-secondary)' }}>
|
|
366
|
-
© 2025 Know Your Developer, LLC. All rights reserved. KYD Self-Check™, and associated marks are trademarks of Know Your Developer, LLC. This document is confidential, proprietary, and intended solely for the individual or entity to whom it is addressed. Unauthorized use, disclosure, copying, or distribution of this document or any of its contents is strictly prohibited and may be unlawful. Know Your Developer, LLC assumes no responsibility or liability for any errors or omissions contained herein. Report validity subject to the terms and conditions stated on the official Know Your Developer website located at https://knowyourdeveloper.ai.
|
|
367
|
-
</p>
|
|
368
|
-
</footer>
|
|
264
|
+
<div className={'pt-8 text-sm text-center'} style={{ color: 'var(--text-secondary)' }}>
|
|
265
|
+
Report Completed: {new Date(updatedAt).toLocaleString(undefined, {
|
|
266
|
+
year: 'numeric',
|
|
267
|
+
month: 'long',
|
|
268
|
+
day: 'numeric',
|
|
269
|
+
hour: 'numeric',
|
|
270
|
+
minute: '2-digit',
|
|
271
|
+
timeZoneName: 'short',
|
|
272
|
+
})}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
<footer className={'mt-12 pt-6 border-t'} style={{ borderColor: 'var(--icon-button-secondary)' }}>
|
|
277
|
+
<p className={'text-center text-xs max-w-4xl mx-auto'} style={{ color: 'var(--text-secondary)' }}>
|
|
278
|
+
© 2025 Know Your Developer, LLC. All rights reserved. KYD Self-Check™, and associated marks are trademarks of Know Your Developer, LLC. This document is confidential, proprietary, and intended solely for the individual or entity to whom it is addressed. Unauthorized use, disclosure, copying, or distribution of this document or any of its contents is strictly prohibited and may be unlawful. Know Your Developer, LLC assumes no responsibility or liability for any errors or omissions contained herein. Report validity subject to the terms and conditions stated on the official Know Your Developer website located at https://knowyourdeveloper.ai.
|
|
279
|
+
</p>
|
|
280
|
+
</footer>
|
|
369
281
|
</div>
|
|
370
282
|
);
|
|
371
283
|
};
|