Skip to content

Commit

Permalink
feat(MerchantMonitoring): add status filters to reports
Browse files Browse the repository at this point in the history
- Refactor MultiSelect components to include status filters
- Update handling functions for new status parameter

(your code is now as organized as a folder full of junk drawers)
  • Loading branch information
shanegrouber committed Dec 19, 2024
1 parent 0d282c4 commit 1ab4ea5
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 43 deletions.
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
10 changes: 8 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,7 +14,10 @@ import {
MerchantReportVersion,
} from '@/domains/business-reports/constants';
import { UnknownRecord } from 'type-fest';
import { RISK_LEVELS } from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';
import {
RISK_LEVELS,
STATUS_OPTIONS,
} from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const BusinessReportSchema = z
.object({
Expand Down Expand Up @@ -88,10 +91,12 @@ export const fetchLatestBusinessReport = async ({
export const fetchBusinessReports = async ({
reportType,
riskLevel,
status,
...params
}: {
reportType: MerchantReportType | 'All';
riskLevel: Array<(typeof RISK_LEVELS)[number]>;
status: Array<(typeof STATUS_OPTIONS)[number]>;
page: {
number: number;
size: number;
Expand All @@ -102,7 +107,8 @@ export const fetchBusinessReports = async ({
{
...params,
...(reportType !== 'All' && { type: reportType }),
riskLevel: riskLevel,
riskLevel,
status,
},
{ encode: false },
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +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 } from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';
import {
RISK_LEVELS,
STATUS_OPTIONS,
} from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const useBusinessReportsQuery = ({
reportType,
Expand All @@ -13,6 +16,7 @@ export const useBusinessReportsQuery = ({
sortBy,
sortDir,
riskLevel,
status,
}: {
reportType: MerchantReportType | 'All';
search: string;
Expand All @@ -21,6 +25,7 @@ export const useBusinessReportsQuery = ({
sortBy: string;
sortDir: string;
riskLevel: Array<(typeof RISK_LEVELS)[number]>;
status: Array<(typeof STATUS_OPTIONS)[number]>;
}) => {
const isAuthenticated = useIsAuthenticated();

Expand All @@ -33,6 +38,7 @@ export const useBusinessReportsQuery = ({
sortBy,
sortDir,
riskLevel,
status,
}),
enabled:
isAuthenticated &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
fetchLatestBusinessReport,
} from '@/domains/business-reports/fetchers';
import { MerchantReportType } from '@/domains/business-reports/constants';
import { RISK_LEVELS } from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';
import {
RISK_LEVELS,
STATUS_OPTIONS,
} from '@/pages/MerchantMonitoring/hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const businessReportsQueryKey = createQueryKeys('business-reports', {
list: ({
Expand All @@ -23,6 +26,7 @@ export const businessReportsQueryKey = createQueryKeys('business-reports', {
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 @@ -43,8 +43,11 @@ export const MerchantMonitoring: FunctionComponent = () => {
onReportTypeChange,
REPORT_TYPE_TO_DISPLAY_TEXT,
RISK_LEVEL_FILTERS,
onRiskLevelChange,
onClearSelect,
STATUS_LEVEL_FILTERS,
handleFilterChange,
handleFilterClear,
riskLevel,
status,
} = useMerchantMonitoringLogic();

return (
Expand Down Expand Up @@ -127,18 +130,26 @@ export const MerchantMonitoring: FunctionComponent = () => {
</DropdownMenuContent>
</DropdownMenu>

<div className={`flex gap-2`}>
{RISK_LEVEL_FILTERS.map(({ title, options }) => (
<MultiSelect
key={title}
title={title}
selectedValues={[]}
onSelect={onRiskLevelChange}
onClearSelect={onClearSelect}
options={options}
/>
))}
</div>
{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 @@ -5,6 +5,7 @@ import { BooleanishRecordSchema } from '@ballerine/ui';
import {
REPORT_TYPE_TO_DISPLAY_TEXT,
RISK_LEVELS,
STATUS_OPTIONS,
} from './hooks/useMerchantMonitoringLogic/useMerchantMonitoringLogic';

export const getMerchantMonitoringSearchSchema = () =>
Expand Down Expand Up @@ -47,5 +48,15 @@ export const getMerchantMonitoringSearchSchema = () =>
],
),
)
.optional(),
.catch([]),
status: z
.array(
z.enum(
STATUS_OPTIONS.map(status => status.toLowerCase()) as [
(typeof STATUS_OPTIONS)[number],
...Array<(typeof STATUS_OPTIONS)[number]>,
],
),
)
.catch([]),
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,35 @@ export const RISK_LEVELS = ['Critical', 'High', 'Medium', 'Low'] as const;
const RISK_LEVEL_FILTERS = [
{
title: 'Risk Level',
accessor: 'riskLevel',
options: RISK_LEVELS.map(riskLevel => ({
label: riskLevel,
value: riskLevel.toLowerCase(),
})),
},
];

export const STATUS_OPTIONS = ['In Progress', 'Quality Control', 'Manual Review'] as const;

const STATUS_LEVEL_FILTERS = [
{
title: 'Status',
accessor: 'status',
options: STATUS_OPTIONS.map(status => ({
label: status,
value: status.toLowerCase(),
})),
},
];

export const useMerchantMonitoringLogic = () => {
const locale = useLocale();
const { data: customer } = useCustomerQuery();

const MerchantMonitoringSearchSchema = getMerchantMonitoringSearchSchema();

const [
{ page, pageSize, sortBy, sortDir, search: searchParamValue, reportType, riskLevel },
{ page, pageSize, sortBy, sortDir, search: searchParamValue, reportType, riskLevel, status },
setSearchParams,
] = useZodSearchParams(MerchantMonitoringSearchSchema);

Expand All @@ -59,26 +73,32 @@ export const useMerchantMonitoringLogic = () => {
sortBy,
sortDir,
riskLevel: riskLevel ?? [],
status: status ?? [],
});

const onReportTypeChange = (reportType: keyof typeof REPORT_TYPE_TO_DISPLAY_TEXT) => {
setSearchParams({ reportType: REPORT_TYPE_TO_DISPLAY_TEXT[reportType] });
};

const onRiskLevelChange = useCallback(
(selected: unknown[]) => {
const selectedRiskLevels = selected as Array<(typeof RISK_LEVELS)[number]>;

const handleFilterChange = useCallback(
(filterKey: string) => (selected: unknown) => {
setSearchParams({
riskLevel: selectedRiskLevels,
[filterKey]: Array.isArray(selected) ? selected : [selected],
page: '1',
});
},
[setSearchParams],
);

const onClearSelect = useCallback(() => {
setSearchParams({ riskLevel: [] });
}, [setSearchParams]);
const handleFilterClear = useCallback(
(filterKey: string) => () => {
setSearchParams({
[filterKey]: [],
page: '1',
});
},
[setSearchParams],
);

const { onPaginate, onPrevPage, onNextPage, onLastPage, isLastPage } = usePagination({
totalPages: data?.totalPages ?? 0,
Expand All @@ -104,7 +124,10 @@ export const useMerchantMonitoringLogic = () => {
onReportTypeChange,
REPORT_TYPE_TO_DISPLAY_TEXT,
RISK_LEVEL_FILTERS,
onRiskLevelChange,
onClearSelect,
STATUS_LEVEL_FILTERS,
handleFilterChange,
handleFilterClear,
riskLevel,
status,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { MultiSelect } from '@/common/components/atoms/MultiSelect/MultiSelect';
import { useFilter } from '@/common/hooks/useFilter/useFilter';
import { AlertStatuses } from '@/domains/alerts/fetchers';
import { titleCase } from 'string-ts';
import { keyFactory } from '@/common/utils/key-factory/key-factory';

export const AlertsFilters: FunctionComponent<{
assignees: TUsers;
Expand Down Expand Up @@ -79,7 +78,7 @@ export const AlertsFilters: FunctionComponent<{
<div className={`flex gap-x-2`}>
{filters.map(({ title, accessor, options }) => (
<MultiSelect
key={keyFactory(title, filter?.[accessor])}
key={title}
title={title}
selectedValues={filter?.[accessor] ?? []}
onSelect={onFilter(accessor)}
Expand Down

0 comments on commit 1ab4ea5

Please sign in to comment.