Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BAL 3197 - add merchant monitoring filters to UI #2901

Merged
merged 5 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,18 @@ export const MultiSelect = <
},
>({
title,
selectedValues,
selectedValues: selected,
onSelect,
onClearSelect,
options,
}: IMultiSelectProps<TOption>) => {
const [selected, setSelected] = useState(selectedValues);

const onSelectChange = useCallback(
(value: TOption['value']) => {
const isSelected = selected.some(selectedValue => selectedValue === value);
const nextSelected = isSelected
? selected.filter(selectedValue => selectedValue !== value)
: [...selected, value];

setSelected(nextSelected);
onSelect(nextSelected);
},
[onSelect, selected],
Expand Down Expand Up @@ -125,13 +122,7 @@ export const MultiSelect = <
<>
<CommandSeparator />
<CommandGroup>
<CommandItem
onSelect={() => {
onClearSelect();
setSelected([]);
}}
className="justify-center text-center"
>
<CommandItem onSelect={onClearSelect} className="justify-center text-center">
Clear filters
</CommandItem>
</CommandGroup>
Expand Down
14 changes: 12 additions & 2 deletions apps/backoffice-v2/src/domains/business-reports/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import {
MerchantReportVersion,
} from '@/domains/business-reports/constants';
import { UnknownRecord } from 'type-fest';
import {
RISK_LEVELS,
STATUS_OPTIONS,
} from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const BusinessReportSchema = z
.object({
Expand Down Expand Up @@ -86,9 +90,13 @@ export const fetchLatestBusinessReport = async ({

export const fetchBusinessReports = async ({
reportType,
riskLevel,
status,
...params
}: {
reportType: MerchantReportType;
reportType: MerchantReportType | 'All';
riskLevel: Array<(typeof RISK_LEVELS)[number]>;
status: Array<(typeof STATUS_OPTIONS)[number]>;
page: {
number: number;
size: number;
Expand All @@ -98,7 +106,9 @@ export const fetchBusinessReports = async ({
const queryParams = qs.stringify(
{
...params,
type: reportType,
...(reportType !== 'All' && { type: reportType }),
riskLevel,
status,
},
{ encode: false },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { useQuery } from '@tanstack/react-query';
import { businessReportsQueryKey } from '@/domains/business-reports/query-keys';
import { isString } from '@/common/utils/is-string/is-string';
import { MerchantReportType } from '@/domains/business-reports/constants';
import {
RISK_LEVELS,
STATUS_OPTIONS,
} from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const useBusinessReportsQuery = ({
reportType,
Expand All @@ -11,18 +15,31 @@ export const useBusinessReportsQuery = ({
pageSize,
sortBy,
sortDir,
riskLevel,
status,
}: {
reportType: MerchantReportType;
reportType: MerchantReportType | 'All';
search: string;
page: number;
pageSize: number;
sortBy: string;
sortDir: string;
riskLevel: Array<(typeof RISK_LEVELS)[number]>;
status: Array<(typeof STATUS_OPTIONS)[number]>;
}) => {
const isAuthenticated = useIsAuthenticated();

return useQuery({
...businessReportsQueryKey.list({ reportType, search, page, pageSize, sortBy, sortDir }),
...businessReportsQueryKey.list({
reportType,
search,
page,
pageSize,
sortBy,
sortDir,
riskLevel,
status,
}),
enabled:
isAuthenticated &&
isString(reportType) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import {
fetchLatestBusinessReport,
} from '@/domains/business-reports/fetchers';
import { MerchantReportType } from '@/domains/business-reports/constants';
import {
RISK_LEVELS,
STATUS_OPTIONS,
} from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const businessReportsQueryKey = createQueryKeys('business-reports', {
list: ({
Expand All @@ -15,12 +19,14 @@ export const businessReportsQueryKey = createQueryKeys('business-reports', {
sortDir,
...params
}: {
reportType: MerchantReportType;
reportType: MerchantReportType | 'All';
search: string;
page: number;
pageSize: number;
sortBy: string;
sortDir: string;
riskLevel: Array<(typeof RISK_LEVELS)[number]>;
status: Array<(typeof STATUS_OPTIONS)[number]>;
}) => ({
queryKey: [{ page, pageSize, sortBy, sortDir, ...params }],
queryFn: () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ import { useMerchantMonitoringLogic } from '@/pages/MerchantMonitoring/hooks/use
import { NoBusinessReports } from '@/pages/MerchantMonitoring/components/NoBusinessReports/NoBusinessReports';
import { MerchantMonitoringTable } from '@/pages/MerchantMonitoring/components/MerchantMonitoringTable/MerchantMonitoringTable';
import { buttonVariants } from '@/common/components/atoms/Button/Button';
import { Plus, Table2 } from 'lucide-react';
import { Plus, SlidersHorizontal, Table2 } from 'lucide-react';
import { Link } from 'react-router-dom';
import { Search } from '@/common/components/molecules/Search';
import { Skeleton } from '@ballerine/ui';
import {
Button,
DropdownMenuTrigger,
DropdownMenu,
Skeleton,
DropdownMenuContent,
DropdownMenuCheckboxItem,
} from '@ballerine/ui';
import { TooltipProvider } from '@/common/components/atoms/Tooltip/Tooltip.Provider';
import { Tooltip } from '@/common/components/atoms/Tooltip/Tooltip';
import { TooltipTrigger } from '@/common/components/atoms/Tooltip/Tooltip.Trigger';
import { TooltipContent } from '@/common/components/atoms/Tooltip/Tooltip.Content';
import { t } from 'i18next';
import { MultiSelect } from '@/common/components/atoms/MultiSelect/MultiSelect';

export const MerchantMonitoring: FunctionComponent = () => {
const {
Expand All @@ -31,6 +39,15 @@ export const MerchantMonitoring: FunctionComponent = () => {
locale,
createBusinessReport,
createBusinessReportBatch,
reportType,
onReportTypeChange,
REPORT_TYPE_TO_DISPLAY_TEXT,
RISK_LEVEL_FILTERS,
STATUS_LEVEL_FILTERS,
handleFilterChange,
handleFilterClear,
riskLevel,
status,
} = useMerchantMonitoringLogic();

return (
Expand Down Expand Up @@ -90,8 +107,49 @@ export const MerchantMonitoring: FunctionComponent = () => {
</TooltipProvider>
</div>
</div>
<div className={`flex`}>
<div className={`flex gap-2`}>
<Search value={search} onChange={onSearch} />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">
<SlidersHorizontal size={18} className="mr-2" /> Type
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{Object.entries(REPORT_TYPE_TO_DISPLAY_TEXT).map(([type, displayText]) => (
<DropdownMenuCheckboxItem
key={displayText}
checked={reportType === displayText}
onCheckedChange={() =>
onReportTypeChange(type as keyof typeof REPORT_TYPE_TO_DISPLAY_TEXT)
}
>
{displayText}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuContent>
</DropdownMenu>

{RISK_LEVEL_FILTERS.map(({ title, accessor, options }) => (
<MultiSelect
key={title}
title={title}
selectedValues={riskLevel ?? []}
onSelect={handleFilterChange(accessor)}
onClearSelect={handleFilterClear(accessor)}
options={options}
/>
))}
{STATUS_LEVEL_FILTERS.map(({ title, accessor, options }) => (
<MultiSelect
key={title}
title={title}
selectedValues={status ?? []}
onSelect={handleFilterChange(accessor)}
onClearSelect={handleFilterClear(accessor)}
options={options}
/>
))}
</div>
<div className="flex flex-1 flex-col gap-6 overflow-auto">
{isNonEmptyArray(businessReports) && <MerchantMonitoringTable data={businessReports} />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { BaseSearchSchema } from '@/common/hooks/useSearchParamsByEntity/validat
import { z } from 'zod';
import { TBusinessReport } from '@/domains/business-reports/fetchers';
import { BooleanishRecordSchema } from '@ballerine/ui';
import {
REPORT_TYPE_TO_DISPLAY_TEXT,
RISK_LEVELS,
STATUS_OPTIONS,
} from './hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const getMerchantMonitoringSearchSchema = () =>
BaseSearchSchema.extend({
Expand All @@ -14,15 +19,44 @@ export const getMerchantMonitoringSearchSchema = () =>
'business.country',
'riskScore',
'status',
'reportType',
] as const satisfies ReadonlyArray<
| Extract<
keyof NonNullable<TBusinessReport>,
'createdAt' | 'updatedAt' | 'riskScore' | 'status'
'createdAt' | 'updatedAt' | 'riskScore' | 'status' | 'reportType'
>
| 'business.website'
| 'business.companyName'
| 'business.country'
>)
.catch('createdAt'),
reportType: z
.enum([
...(Object.values(REPORT_TYPE_TO_DISPLAY_TEXT) as [
(typeof REPORT_TYPE_TO_DISPLAY_TEXT)['All'],
...Array<(typeof REPORT_TYPE_TO_DISPLAY_TEXT)[keyof typeof REPORT_TYPE_TO_DISPLAY_TEXT]>,
]),
])
.catch('All'),
selected: BooleanishRecordSchema.optional(),
riskLevel: z
.array(
z.enum(
RISK_LEVELS.map(riskLevel => riskLevel.toLowerCase()) as [
(typeof RISK_LEVELS)[number],
...Array<(typeof RISK_LEVELS)[number]>,
],
),
)
.catch([]),
status: z
.array(
z.enum(
STATUS_OPTIONS.map(status => status.toLowerCase()) as [
(typeof STATUS_OPTIONS)[number],
...Array<(typeof STATUS_OPTIONS)[number]>,
],
),
)
.catch([]),
});
Loading
Loading