import { MERCHANT_REPORT_TYPES_MAP } from '@ballerine/common'; import { Badge, CheckCircle, ContentTooltip, severityToClassName, TextWithNAFallback, WarningFilledSvg, } from '@ballerine/ui'; import { createColumnHelper, RowData } from '@tanstack/react-table'; import dayjs from 'dayjs'; import timezone from 'dayjs/plugin/timezone'; import utc from 'dayjs/plugin/utc'; import { Minus } from 'lucide-react'; import { useMemo } from 'react'; import { titleCase } from 'string-ts'; import { CopyToClipboardButton } from '@/common/components/atoms/CopyToClipboardButton/CopyToClipboardButton'; import { IndicatorCircle } from '@/common/components/atoms/IndicatorCircle/IndicatorCircle'; import { NO_VIOLATION_DETECTED_RISK_INDICATOR_ID, POSITIVE_RISK_LEVEL_ID, } from '@/common/constants'; import { useEllipsesWithTitle } from '@/common/hooks/useEllipsesWithTitle/useEllipsesWithTitle'; import { ctw } from '@/common/utils/ctw/ctw'; import { TBusinessReport } from '@/domains/business-reports/fetchers'; import { MerchantMonitoringReportStatus } from '@/pages/MerchantMonitoring/components/MerchantMonitoringReportStatus/MerchantMonitoringReportStatus'; import { statusToData } from '@/pages/MerchantMonitoring/components/MerchantMonitoringReportStatus/MerchantMonitoringStatusBadge'; import { uniqBy } from 'lodash-es'; dayjs.extend(utc); dayjs.extend(timezone); // https://tanstack.com/table/v8/docs/api/core/column-def#meta declare module '@tanstack/react-table' { interface ColumnMeta { conditional?: true; showColumn?: boolean; } } const columnHelper = createColumnHelper(); const SCAN_TYPES = { ONBOARDING: 'Onboarding', MONITORING: 'Monitoring', } as const; const REPORT_TYPE_TO_SCAN_TYPE = { [MERCHANT_REPORT_TYPES_MAP.MERCHANT_REPORT_T1]: SCAN_TYPES.ONBOARDING, [MERCHANT_REPORT_TYPES_MAP.ONGOING_MERCHANT_REPORT_T1]: SCAN_TYPES.MONITORING, } as const; export const useColumns = ({ isDemoAccount = false }) => { return useMemo(() => { const columns = [ columnHelper.accessor('companyName', { cell: info => { const companyName = info.getValue(); const isExample = info.row.original.isExample; return (
{companyName} {isExample && ( example )}
); }, header: 'Company Name', }), columnHelper.accessor('website', { cell: ({ getValue }) => { const website = getValue() .replace(/(^\w+:|^)\/\//, '') .replace(/\/$/, ''); return ( {website} ); }, header: 'Website', }), columnHelper.accessor('riskLevel', { cell: info => { const riskLevel = info.getValue(); return (
{riskLevel ? ( {titleCase(riskLevel)} ) : ( )}
); }, header: () =>

Risk Level

, }), columnHelper.accessor('data.allViolations', { cell: ({ row }) => { let violations = (row.original.data?.allViolations ?? []) .filter( violation => violation.id !== NO_VIOLATION_DETECTED_RISK_INDICATOR_ID && violation.name && violation.riskLevel && violation.riskLevel !== POSITIVE_RISK_LEVEL_ID, ) .sort((a, b) => { return a.riskLevel === b.riskLevel ? (a.name ?? '').localeCompare(b.name ?? '') : (a.riskLevel ?? '').localeCompare(b.riskLevel ?? ''); }); violations = uniqBy(violations, 'id'); if (!violations?.length) { return null; } return (

Findings

{violations.slice(0, 4).map((violation, index) => (
{violation.name}
))} {violations.length > 4 && (
+ {violations.length - 4} additional finding {violations.length - 4 > 1 ? 's' : ''}
)} } props={{ tooltipTrigger: { className: 'mx-auto pr-0' }, tooltipContent: { align: 'center', side: 'top', className: 'bg-background text-primary', }, }} >
v.riskLevel === 'critical'), 'bg-slate-500/20 text-slate-500': !violations.some( v => v.riskLevel === 'critical', ), }, )} > {violations.length}
); }, header: 'Findings', }), columnHelper.accessor('reportType', { cell: info => { const scanType = REPORT_TYPE_TO_SCAN_TYPE[info.getValue()]; return {scanType}; }, header: 'Scan Type', }), columnHelper.accessor('monitoringStatus', { cell: ({ getValue }) => { const value = getValue(); return ( This merchant is {!value && 'not '}subscribed to recurring ongoing monitoring

} props={{ tooltipTrigger: { className: 'flex w-full justify-start' }, tooltipContent: { align: 'center', side: 'top' }, }} >
{value ? ( ) : ( )}
); }, header: () => ( Indicates whether the merchant is subscribed to ongoing monitoring

} props={{ tooltipTrigger: { className: 'mx-auto' }, tooltipContent: { align: 'center', side: 'top' }, }} > Monitored
), }), columnHelper.accessor('isAlert', { cell: ({ getValue }) => { return getValue() ? ( ) : ( ); }, header: () =>

Alert

, meta: { conditional: true, showColumn: !isDemoAccount, }, }), columnHelper.accessor('displayDate', { cell: info => { const displayDate = info.getValue(); // Convert UTC time to local browser time const localDateTime = dayjs.utc(displayDate).local(); const date = localDateTime.format('MMM DD, YYYY'); const time = localDateTime.format('HH:mm'); return (
{date} {time}
); }, header: 'Created At', }), columnHelper.accessor('id', { cell: info => { // eslint-disable-next-line react-hooks/rules-of-hooks -- ESLint doesn't like `cell` not being `Cell`. const { ref, styles } = useEllipsesWithTitle(); const id = info.getValue(); return (
{id}
); }, header: 'Report ID', }), columnHelper.accessor('business.correlationId', { cell: info => { // eslint-disable-next-line react-hooks/rules-of-hooks -- ESLint doesn't like `cell` not being `Cell`. const { ref, styles } = useEllipsesWithTitle(); const merchantId = info.getValue() ?? info.row.original.business?.id; return (
{merchantId}
); }, header: 'Merchant ID', }), columnHelper.accessor('status', { meta: { useWrapper: true, }, cell: info => { const status = info.getValue() as keyof typeof statusToData; return ( ); }, header: 'Status', }), ]; return columns.filter(column => { const meta = column.meta; if (meta?.conditional) { return meta.showColumn; } return true; }); }, [isDemoAccount]); };