-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
225 additions
and
9 deletions.
There are no files selected for viewing
218 changes: 218 additions & 0 deletions
218
packages/ui/src/components/templates/report/adapters/report-adapter/report-adapter.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
import { adsProviderAdapter } from '@/components'; | ||
import { AdsProviders, severityToDisplaySeverity } from '@/components/templates/report/constants'; | ||
import { TAdsProvider } from '@/components/templates/report/types'; | ||
import { SeverityType } from '@ballerine/common'; | ||
import dayjs from 'dayjs'; | ||
import { capitalize } from 'string-ts'; | ||
|
||
const getLabel = ({ label, provider }: { label: string; provider: string }) => { | ||
if (label === 'page') { | ||
return `${provider} Page`; | ||
} | ||
|
||
return label; | ||
}; | ||
|
||
export const toRiskLabels = (riskIndicators: Array<{ name: string; riskLevel: string }>) => { | ||
if (!Array.isArray(riskIndicators) || !riskIndicators.length) { | ||
return []; | ||
} | ||
|
||
return riskIndicators.map(({ name, riskLevel, ...rest }) => ({ | ||
label: name, | ||
severity: | ||
severityToDisplaySeverity[riskLevel as keyof typeof severityToDisplaySeverity] ?? riskLevel, | ||
})); | ||
}; | ||
|
||
const normalizeRiskLevel = (riskTypeLevels: Record<string, SeverityType>) => { | ||
return Object.entries(riskTypeLevels).reduce((acc, [riskType, riskLevel]) => { | ||
acc[riskType] = | ||
severityToDisplaySeverity[riskLevel as keyof typeof severityToDisplaySeverity] ?? riskLevel; | ||
|
||
return acc; | ||
}, {} as Record<string, SeverityType>); | ||
}; | ||
|
||
const normalizeHyphenedDataString = (str: string) => { | ||
const parts = str.split(' - '); | ||
|
||
return { | ||
label: capitalize(parts.length > 1 ? parts.slice(0, -1).join(' - ') : parts.at(0) ?? 'Unknown'), | ||
value: parts.at(-1), | ||
}; | ||
}; | ||
|
||
export const reportAdapter = { | ||
DEFAULT: (report: Record<string, any>) => { | ||
return { | ||
websitesCompanyAnalysis: toRiskLabels( | ||
report?.summary?.riskIndicatorsByDomain?.companyNameViolations, | ||
), | ||
adsAndSocialMediaAnalysis: toRiskLabels( | ||
report?.summary?.riskIndicatorsByDomain?.adsAndSocialViolations, | ||
), | ||
adsAndSocialMediaPresence: [ | ||
...Object.entries({ facebook: report?.socialMedia?.facebookData ?? {} }), | ||
...Object.entries({ instagram: report?.socialMedia?.instagramData ?? {} }), | ||
] | ||
.map(([provider, data]) => { | ||
if (!AdsProviders.includes(provider.toUpperCase() as TAdsProvider)) { | ||
return; | ||
} | ||
|
||
const adapter = adsProviderAdapter[provider as keyof typeof adsProviderAdapter]; | ||
const adaptedData = adapter(data); | ||
|
||
return { | ||
label: provider, | ||
items: Object.entries(adaptedData).map(([label, value]) => ({ | ||
label: getLabel({ | ||
label, | ||
provider, | ||
}), | ||
value, | ||
})), | ||
}; | ||
}) | ||
?.filter((value): value is NonNullable<typeof value> => Boolean(value)), | ||
websiteLineOfBusinessAnalysis: | ||
report?.summary?.riskIndicatorsByDomain?.lineOfBusinessViolations?.map( | ||
({ | ||
name, | ||
riskLevel, | ||
sourceUrl, | ||
screenshot, | ||
explanation, | ||
}: { | ||
name: string; | ||
riskLevel: string; | ||
sourceUrl: string; | ||
screenshot: { | ||
screenshotUrl: string; | ||
}; | ||
explanation: string; | ||
}) => ({ | ||
label: name, | ||
severity: | ||
severityToDisplaySeverity[riskLevel as keyof typeof severityToDisplaySeverity] ?? | ||
riskLevel, | ||
screenshotUrl: screenshot?.screenshotUrl, | ||
sourceUrl, | ||
explanation, | ||
}), | ||
), | ||
ecosystemAnalysis: toRiskLabels(report?.summary?.riskIndicatorsByDomain?.ecosystemViolations), | ||
ecosystemMatches: report?.ecosystem?.domains?.map( | ||
({ | ||
domain, | ||
relatedNode, | ||
relatedNodeType, | ||
indicator, | ||
}: { | ||
domain: string; | ||
relatedNode: string; | ||
relatedNodeType: string; | ||
indicator: Record< | ||
string, | ||
{ | ||
name: string; | ||
riskLevel: string; | ||
} | ||
>; | ||
}) => ({ | ||
matchedName: domain, | ||
relatedNode, | ||
relatedNodeType: relatedNodeType, | ||
indicators: { | ||
label: indicator?.name, | ||
severity: | ||
severityToDisplaySeverity[ | ||
indicator?.riskLevel as unknown as keyof typeof severityToDisplaySeverity | ||
] ?? indicator?.riskLevel, | ||
}, | ||
}), | ||
), | ||
websiteCredibilityAnalysis: toRiskLabels( | ||
report?.summary?.riskIndicatorsByDomain?.tldViolations, | ||
), | ||
adsImages: [ | ||
...Object.entries({ facebook: report?.socialMedia?.facebookData ?? {} }), | ||
...Object.entries({ instagram: report?.socialMedia?.instagramData ?? {} }), | ||
] | ||
.map(([provider, data]) => ({ | ||
provider, | ||
src: data?.screenshotUrl, | ||
link: data?.pageUrl, | ||
})) | ||
.filter(({ src }: { src: string }) => !!src), | ||
relatedAdsImages: report?.socialMedia?.pickedAds | ||
?.map((data: { screenshotUrl: string; link: string }) => ({ | ||
src: data?.screenshotUrl, | ||
link: data?.link, | ||
})) | ||
.filter(({ src }: { src: string }) => !!src), | ||
onlineReputationAnalysis: report?.transactionLaundering?.scamOrFraud?.indicators | ||
?.filter(({ violation }: { violation: string }) => !!violation) | ||
?.map(({ violation, sourceUrl }: { violation: string; sourceUrl: string }) => ({ | ||
label: violation, | ||
url: sourceUrl, | ||
})), | ||
summary: report?.summary?.summary, | ||
ongoingMonitoringSummary: report?.summary?.ongoingMonitoringSummary, | ||
riskScore: report?.summary?.riskScore, | ||
riskLevels: normalizeRiskLevel(report?.summary?.riskLevels ?? {}), | ||
companyReputationAnalysis: report?.websiteCompanyAnalysis?.scamOrFraud?.indicators | ||
?.filter(({ violation }: { violation: string }) => !!violation) | ||
?.map(({ violation, sourceUrl }: { violation: string; sourceUrl: string }) => ({ | ||
label: violation, | ||
url: sourceUrl, | ||
})), | ||
lineOfBusinessDescription: report?.lineOfBusiness?.lobDescription, | ||
relatedAdsSummary: report?.socialMedia?.relatedAds?.summary, | ||
pricingAnalysis: report?.transactionLaundering?.pricingAnalysis?.indicators, | ||
websiteStructureAndContentEvaluation: | ||
report?.transactionLaundering?.websiteStructureEvaluation?.indicators, | ||
// Example data: | ||
// { | ||
// "trafficSources": [ | ||
// "search / organic - 46.31%", | ||
// "direct - 42.68%" | ||
// ], | ||
// "engagements": [ | ||
// "Time on site - 117.09 seconds", | ||
// "Page per visit - 2.71", | ||
// "Bounce rate - 44.76%" | ||
// ], | ||
// "montlyVisitsIndicators": [ | ||
// "May 2024 - 1987263", | ||
// "June 2024 - 3500503", | ||
// "July 2024 - 1671071", | ||
// "August 2024 - 1793033", | ||
// "September 2024 - 2520118", | ||
// "October 2024 - 3384101" | ||
// ] | ||
// } | ||
trafficAnalysis: { | ||
montlyVisitsIndicators: ( | ||
report?.transactionLaundering?.trafficAnalysis?.montlyVisitsIndicators ?? [] | ||
).map((item: string) => { | ||
const normalized = normalizeHyphenedDataString(item); | ||
|
||
return { | ||
label: dayjs(normalized.label, 'MMMM YYYY').format('MMM YYYY'), | ||
value: normalized.value, | ||
}; | ||
}), | ||
trafficSources: (report?.transactionLaundering?.trafficAnalysis?.trafficSources ?? []).map( | ||
normalizeHyphenedDataString, | ||
), | ||
engagements: (report?.transactionLaundering?.trafficAnalysis?.engagements ?? []).map( | ||
normalizeHyphenedDataString, | ||
), | ||
}, | ||
homepageScreenshotUrl: report?.homepageScreenshot, | ||
formattedMcc: report?.lineOfBusiness?.formattedMcc, | ||
}; | ||
}, | ||
} as const; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters