Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
MatanYadaev committed Feb 11, 2025
1 parent 481629c commit b67d197
Show file tree
Hide file tree
Showing 20 changed files with 340 additions and 352 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const useWebsiteMonitoringBusinessReportTab = ({
}: {
businessReport: TBusinessReport;
}) => {
const { tabs: tabsWithSummary, riskIndicators: originalRiskIndicators } = useReportTabs({
const { tabs: tabsWithSummary, sectionsSummary: originalSectionsSummary } = useReportTabs({
report: businessReport ?? {},
Link: RiskIndicatorLink,
});
Expand All @@ -29,10 +29,10 @@ export const useWebsiteMonitoringBusinessReportTab = ({
},
[],
);
const riskIndicators = originalRiskIndicators?.map(riskIndicator => ({
...riskIndicator,
const riskIndicators = originalSectionsSummary?.map(section => ({
...section,
search: getUpdatedSearchParamsWithActiveMonitoringTab({
tab: riskIndicator.search.split('=')[1] ?? '',
tab: section.search.split('=')[1] ?? '',
search,
}),
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,7 @@ export const columns = [
return (
<div className="flex items-center gap-2">
{riskLevel ? (
<Badge
className={ctw(
severityToClassName[
(riskLevel.toUpperCase() as keyof typeof severityToClassName) ?? 'DEFAULT'
],
'w-20 py-0.5 font-bold',
)}
>
<Badge className={ctw(severityToClassName[riskLevel], 'w-20 py-0.5 font-bold')}>
{titleCase(riskLevel)}
</Badge>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useCallback } from 'react';
import { Link, useLocation } from 'react-router-dom';

import { useLocale } from '@/common/hooks/useLocale/useLocale';
import { MERCHANT_REPORT_STATUSES_MAP } from '@/domains/business-reports/constants';
import { MERCHANT_REPORT_STATUSES_MAP } from '@ballerine/common';
import { TBusinessReports } from '@/domains/business-reports/fetchers';

export const useMerchantMonitoringTableLogic = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/consts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const MERCHANT_REPORT_RISK_LEVELS_MAP = Object.fromEntries(
MERCHANT_REPORT_RISK_LEVELS.map(level => [level, level]),
) as Record<MerchantReportRiskLevel, MerchantReportRiskLevel>;

export const RISK_INDICATOR_RISK_LEVELS = ['positive', 'moderate', 'high', 'critical'] as const;
export const RISK_INDICATOR_RISK_LEVELS = ['positive', 'moderate', 'critical'] as const;

export type RiskIndicatorRiskLevel = (typeof RISK_INDICATOR_RISK_LEVELS)[number];

Expand Down
17 changes: 9 additions & 8 deletions packages/common/src/schemas/report-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ export const FacebookPageSchema = z.object({
id: z.string(),
url: z.string(),
name: z.string(),
email: z.string().nullable(),
email: z.string().nullish(),
likes: z.number(),
address: z.string().nullable(),
categories: z.array(z.string()),
phoneNumber: z.string().nullable(),
address: z.string().nullish(),
categories: z.array(z.string()).nullish(),
phoneNumber: z.string().nullish(),
creationDate: z.string(),
screenshotUrl: z.string().url(),
});
Expand All @@ -23,15 +23,15 @@ export const InstagramPageSchema = z.object({
id: z.string(),
url: z.string(),
username: z.string(),
biography: z.string().nullable(),
biography: z.string().nullish(),
followers: z.number(),
categories: z.array(z.string()),
categories: z.array(z.string()).nullish(),
isVerified: z.boolean(),
screenshotUrl: z.string().url(),
isBusinessProfile: z.boolean(),
});

const RiskIndicatorSchema = z
export const RiskIndicatorSchema = z
.object({
id: z.string(),
name: z.string().nullish(),
Expand All @@ -42,12 +42,13 @@ const RiskIndicatorSchema = z
})
.nullish(),
explanation: z.string().nullish(),
reason: z.string().nullish(),
quoteFromSource: z.string().nullish(),
riskLevel: z.enum(RISK_INDICATOR_RISK_LEVELS).nullish(),
})
.passthrough();

const EcosystemRecordSchema = z.object({
export const EcosystemRecordSchema = z.object({
domain: z.string(),
relatedNode: z.string(),
relatedNodeType: z.string(),
Expand Down
27 changes: 10 additions & 17 deletions packages/ui/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import { SeverityType } from '@ballerine/common';
import { ComponentProps } from 'react';
import { Badge } from '@/components';
import { MERCHANT_REPORT_RISK_LEVELS_MAP, MerchantReportRiskLevel } from '@ballerine/common';

type SeverityToClassName = Record<
Uppercase<SeverityType> | 'DEFAULT',
ComponentProps<typeof Badge>['className']
>;
type SeverityToClassName = Record<MerchantReportRiskLevel, string>;

export const severityToTextClassName = {
HIGH: 'text-destructive',
MEDIUM: 'text-orange-300',
LOW: 'text-success',
CRITICAL: 'text-background',
DEFAULT: 'text-background',
[MERCHANT_REPORT_RISK_LEVELS_MAP.high]: 'text-destructive',
[MERCHANT_REPORT_RISK_LEVELS_MAP.medium]: 'text-orange-300',
[MERCHANT_REPORT_RISK_LEVELS_MAP.low]: 'text-success',
[MERCHANT_REPORT_RISK_LEVELS_MAP.critical]: 'text-background',
} as const satisfies SeverityToClassName;

export const severityToClassName = {
HIGH: `bg-destructive/20 ${severityToTextClassName.HIGH}`,
MEDIUM: `bg-orange-100 ${severityToTextClassName.MEDIUM}`,
LOW: `bg-success/20 ${severityToTextClassName.LOW}`,
CRITICAL: `bg-destructive ${severityToTextClassName.CRITICAL}`,
DEFAULT: `bg-foreground ${severityToTextClassName.DEFAULT}`,
[MERCHANT_REPORT_RISK_LEVELS_MAP.high]: `bg-destructive/20 ${severityToTextClassName.high}`,
[MERCHANT_REPORT_RISK_LEVELS_MAP.medium]: `bg-orange-100 ${severityToTextClassName.medium}`,
[MERCHANT_REPORT_RISK_LEVELS_MAP.low]: `bg-success/20 ${severityToTextClassName.low}`,
[MERCHANT_REPORT_RISK_LEVELS_MAP.critical]: `bg-destructive ${severityToTextClassName.critical}`,
} as const satisfies SeverityToClassName;
22 changes: 22 additions & 0 deletions packages/ui/src/common/utils/get-unique-risk-indicators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { RiskIndicatorSchema } from '@ballerine/common';
import { z } from 'zod';

type RiskIndicator = z.infer<typeof RiskIndicatorSchema>;

export const getUniqueRiskIndicators = (riskIndicators: RiskIndicator[]): RiskIndicator[] => {
if (!riskIndicators) {
return [];
}

const riskIndicatorsMap: Record<string, (typeof riskIndicators)[number]> = {};

for (const indicator of riskIndicators) {
if (indicator.id in riskIndicatorsMap) {
continue;
}

riskIndicatorsMap[indicator.id] = indicator;
}

return Object.values(riskIndicatorsMap);
};
1 change: 1 addition & 0 deletions packages/ui/src/common/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './check-is-date';
export * from './ctw';
export * from './format-date';
export * from './to-risk-indicators';
export * from './get-unique-risk-indicators';
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { CheckCircle } from '@/components/atoms/CheckCircle/CheckCircle';
import React, { FunctionComponent } from 'react';
import { isNonEmptyArray, Severity } from '@ballerine/common';
import {
isNonEmptyArray,
RISK_INDICATOR_RISK_LEVELS_MAP,
RiskIndicatorSchema,
} from '@ballerine/common';
import { ctw } from '@/common';
import { WarningFilledSvg } from '@/components/atoms/WarningFilledSvg/WarningFilledSvg';
import { z } from 'zod';

export const RiskIndicator = ({
title,
search,
violations,
riskIndicators,
Link,
}: {
title: string;
search: string | undefined;
violations: Array<{
label: string;
severity: string;
}> | null;
riskIndicators: z.infer<typeof RiskIndicatorSchema>[] | null;
Link: FunctionComponent<{
search: string;
}>;
Expand All @@ -27,21 +29,21 @@ export const RiskIndicator = ({
{search && <Link search={search} />}
</h3>
<ul className="list-inside list-disc">
{!!violations &&
isNonEmptyArray(violations) &&
violations.map(violation => (
<li key={violation.label} className="flex list-none items-center text-slate-500">
{violation.severity !== Severity.LOW && (
{!!riskIndicators &&
isNonEmptyArray(riskIndicators) &&
riskIndicators.map(riskIndicator => (
<li key={riskIndicator.name} className="flex list-none items-center text-slate-500">
{riskIndicator.riskLevel !== RISK_INDICATOR_RISK_LEVELS_MAP.positive && (
<WarningFilledSvg
className={ctw('me-3 mt-px', {
'[&>:not(:first-child)]:stroke-background text-slate-300':
violation.severity === Severity.MEDIUM,
riskIndicator.riskLevel === RISK_INDICATOR_RISK_LEVELS_MAP.moderate,
})}
width={'20'}
height={'20'}
/>
)}
{violation.severity === Severity.LOW && (
{riskIndicator.riskLevel === RISK_INDICATOR_RISK_LEVELS_MAP.positive && (
<CheckCircle
size={18}
className={`stroke-background`}
Expand All @@ -50,10 +52,10 @@ export const RiskIndicator = ({
}}
/>
)}
{violation.label}
{riskIndicator.name}
</li>
))}
{Array.isArray(violations) && !violations.length && (
{Array.isArray(riskIndicators) && !riskIndicators.length && (
<li className="flex list-none items-center text-slate-500">
<CheckCircle
size={18}
Expand All @@ -62,7 +64,7 @@ export const RiskIndicator = ({
className: 'me-3 bg-success mt-px',
}}
/>
No Violations Detected
No Risk Detected
</li>
)}
</ul>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import React, { FunctionComponent } from 'react';
import { ctw } from '@/common';
import { ctw, getUniqueRiskIndicators } from '@/common';
import { Card, CardContent, CardHeader } from '@/components/atoms';
import { CheckCircle } from '@/components/atoms/CheckCircle/CheckCircle';
import { WarningFilledSvg } from '@/components/atoms/WarningFilledSvg/WarningFilledSvg';
import { Severity } from '@ballerine/common';
import { RISK_INDICATOR_RISK_LEVELS_MAP, RiskIndicatorSchema } from '@ballerine/common';
import { z } from 'zod';

export const RiskIndicators: FunctionComponent<{
violations: Array<{
label: string;
severity: string;
}>;
}> = ({ violations }) => {
riskIndicators: Array<z.infer<typeof RiskIndicatorSchema>>;
}> = ({ riskIndicators }) => {
const uniqueRiskIndicators = getUniqueRiskIndicators(riskIndicators);

return (
<Card>
<CardHeader className={'pt-4 font-bold'}>Risk Indicators</CardHeader>
<CardContent>
<ul className="list-inside list-disc">
{!!violations?.length &&
violations.map(violation => (
<li key={violation.label} className="flex list-none items-center text-slate-500">
{violation.severity !== Severity.LOW && (
{!!uniqueRiskIndicators?.length &&
uniqueRiskIndicators.map(riskIndicator => (
<li key={riskIndicator.name} className="flex list-none items-center text-slate-500">
{riskIndicator.riskLevel !== RISK_INDICATOR_RISK_LEVELS_MAP.positive && (
<WarningFilledSvg
className={ctw('me-3 mt-px', {
'[&>:not(:first-child)]:stroke-background text-slate-300':
violation.severity === Severity.MEDIUM,
riskIndicator.riskLevel === RISK_INDICATOR_RISK_LEVELS_MAP.moderate,
})}
width={'20'}
height={'20'}
/>
)}
{violation.severity === Severity.LOW && (
{riskIndicator.riskLevel === RISK_INDICATOR_RISK_LEVELS_MAP.positive && (
<CheckCircle
size={18}
className={`stroke-background`}
Expand All @@ -38,10 +38,10 @@ export const RiskIndicators: FunctionComponent<{
}}
/>
)}
{violation.label}
{riskIndicator.name}
</li>
))}
{!violations?.length && (
{!uniqueRiskIndicators?.length && (
<li className="flex list-none items-center text-slate-500">
<CheckCircle
size={18}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
import React, { ComponentProps, FunctionComponent } from 'react';
import { RiskIndicator } from '@/components/molecules/RiskIndicator/RiskIndicator';
import { Card, CardContent, CardHeader } from '@/components/atoms';
import { RiskIndicatorSchema } from '@ballerine/common';
import { z } from 'zod';

export const RiskIndicatorsSummary: FunctionComponent<{
riskIndicators: Array<{
sections: ReadonlyArray<{
title: string;
search: string;
violations: Array<{
label: string;
severity: string;
}> | null;
riskIndicators: z.infer<typeof RiskIndicatorSchema>[] | null;
}>;
Link: ComponentProps<typeof RiskIndicator>['Link'];
}> = ({ riskIndicators, Link }) => {
}> = ({ sections, Link }) => {
return (
<Card className={'col-span-full'}>
<CardHeader className={'pt-4 font-bold'}>Risk Indicators</CardHeader>
<CardContent className={'grid grid-cols-2 gap-4 xl:grid-cols-3'}>
{!!riskIndicators?.length &&
riskIndicators?.map(riskIndicator => (
<RiskIndicator
key={riskIndicator.title}
title={riskIndicator.title}
search={riskIndicator.search}
violations={riskIndicator.violations}
Link={Link}
/>
))}
{!riskIndicators?.length && <p>No risk indicators detected.</p>}
{sections.map(section => (
<RiskIndicator
key={section.title}
title={section.title}
search={section.search}
riskIndicators={section.riskIndicators}
Link={Link}
/>
))}
</CardContent>
</Card>
);
Expand Down
Loading

0 comments on commit b67d197

Please sign in to comment.