Skip to content

Commit

Permalink
fix(backoffice-v2): counter party name empty state now works - now tr…
Browse files Browse the repository at this point in the history
…imming name
  • Loading branch information
Omri-Levy committed Feb 18, 2024
2 parents b7cf677 + 07a0d88 commit 911b31c
Show file tree
Hide file tree
Showing 22 changed files with 439 additions and 90 deletions.
12 changes: 12 additions & 0 deletions apps/backoffice-v2/public/locales/en/toast.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,17 @@
"unassign_alerts": {
"success": "The alerts have been unassigned successfully.",
"error": "Error occurred while unassigning the alerts."
},
"reject_alerts": {
"success": "The alerts have been rejected successfully.",
"error": "Error occurred while rejecting the alerts."
},
"not_suspicious_alerts": {
"success": "The alerts have been marked as not suspicious successfully.",
"error": "Error occurred while marking the alerts as not suspicious."
},
"revert_decision_alerts": {
"success": "The alerts decision have been reverted successfully.",
"error": "Error occurred while reverting the alerts decision."
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FunctionComponent, ReactNode, useCallback, useState } from 'react';
import { ReactNode, useCallback, useState } from 'react';
import {
Badge,
Button,
Expand All @@ -17,17 +17,37 @@ import {
import { CheckIcon, PlusCircledIcon } from '@radix-ui/react-icons';
import { Separator } from '@/common/components/atoms/Separator/Separator';

export const MultiSelect: FunctionComponent<{
interface IMultiSelectProps<
TOption extends {
label: string;
value: unknown;
icon?: ReactNode;
},
> {
title: string;
selectedValues: string[];
onSelect: (value: string) => void;
selectedValues: Array<TOption['value']>;
onSelect: (value: Array<TOption['value']>) => void;
onClearSelect: () => void;
options: Array<{ label: string; value: string; icon?: ReactNode }>;
}> = ({ title, selectedValues, onSelect, onClearSelect, options }) => {
options: TOption[];
}

export const MultiSelect = <
TOption extends {
label: string;
value: unknown;
icon?: ReactNode;
},
>({
title,
selectedValues,
onSelect,
onClearSelect,
options,
}: IMultiSelectProps<TOption>) => {
const [selected, setSelected] = useState(selectedValues);

const onSelectChange = useCallback(
(value: string) => {
(value: TOption['value']) => {
const isSelected = selected.some(selectedValue => selectedValue === value);
const nextSelected = isSelected
? selected.filter(selectedValue => selectedValue !== value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const useFilter = () => {

const onFilter = useCallback(
(accessor: string) => {
return (values: string[]) => {
return (values: Array<string | null>) => {
setSearchParams({
filter: {
...filter,
Expand Down
12 changes: 12 additions & 0 deletions apps/backoffice-v2/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
PropsWithChildren,
} from 'react';
import { Action, Method, Resource, State } from './enums';
import translations from '../../public/locales/en/toast.json';

export type WithRequired<TObject, TKey extends keyof TObject> = TObject & {
[TProperty in TKey]-?: TObject[TProperty];
Expand Down Expand Up @@ -54,6 +55,17 @@ export type TypesafeOmit<TObj extends Record<PropertyKey, unknown>, TProps exten

export type UnknownRecord = Record<PropertyKey, unknown>;

export type NoInfer<T> = [T][T extends any ? 0 : never];

export type TToastKeyWithSuccessAndError = {
[TKey in keyof typeof translations]: (typeof translations)[TKey] extends {
success: string;
error: string;
}
? TKey
: never;
}[keyof typeof translations];

// Polymorphic component props

// A more precise version of just ComponentPropsWithoutRef on its own
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { isString } from '@/common/utils/is-string/is-string';
import { snakeCase, toUpperCase } from 'string-ts';

export const toScreamingSnakeCase = <TString extends string>(string_: TString) => {
if (!isString(string_)) return string_;

return toUpperCase(snakeCase(string_));
};
68 changes: 67 additions & 1 deletion apps/backoffice-v2/src/domains/alerts/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,52 @@ export const AlertTypes = [
AlertType.UNUSUAL_PATTERN,
] as const satisfies ReadonlyArray<TObjectValues<typeof AlertType>>;

export const AlertState = {
TRIGGERED: 'Triggered',
UNDER_REVIEW: 'UnderReview',
ESCALATED: 'Escalated',
RESOLVED: 'Resolved',
ACKNOWLEDGED: 'Acknowledged',
DISMISSED: 'Dismissed',
REJECTED: 'Rejected',
NOT_SUSPICIOUS: 'NotSuspicious',
} as const;

export const AlertStates = [
AlertState.TRIGGERED,
AlertState.UNDER_REVIEW,
AlertState.ESCALATED,
AlertState.RESOLVED,
AlertState.ACKNOWLEDGED,
AlertState.DISMISSED,
AlertState.REJECTED,
AlertState.NOT_SUSPICIOUS,
] as const satisfies ReadonlyArray<TObjectValues<typeof AlertState>>;

export const alertStateToDecision = {
REJECTED: 'Reject',
NOT_SUSPICIOUS: 'Not Suspicious',
REVERT_DECISION: 'Revert Decision',
} as const satisfies Partial<Record<keyof typeof AlertState | (string & {}), string>>;

export const alertDecisionToState = {
REJECT: 'Rejected',
NOT_SUSPICIOUS: 'NotSuspicious',
REVERT_DECISION: 'Triggered',
} as const satisfies Partial<Record<keyof typeof AlertState | (string & {}), string>>;

export type TAlertSeverity = (typeof AlertSeverities)[number];

export type TAlertSeverities = typeof AlertSeverities;

export type TAlertType = (typeof AlertTypes)[number];

export type TAlertTypes = typeof AlertTypes;

export type TAlertState = (typeof AlertStates)[number];

export type TAlertStates = typeof AlertStates;

export const AlertsListSchema = z.array(
ObjectWithIdSchema.extend({
dataTimestamp: z.string().datetime(),
Expand All @@ -61,7 +107,7 @@ export const AlertsListSchema = z.array(
.nullable()
.default(null),
status: z.enum(AlertStatuses),
// decision: z.string(),
decision: z.enum(AlertStates).nullable().default(null),
}),
);

Expand Down Expand Up @@ -105,3 +151,23 @@ export const assignAlertsByIds = async ({

return handleZodError(error, alerts);
};

export const updateAlertsDecisionByIds = async ({
decision,
alertIds,
}: {
decision: TAlertState;
alertIds: string[];
}) => {
const [alerts, error] = await apiClient({
url: `${getOriginUrl(env.VITE_API_URL)}/api/v1/external/alerts/decision`,
method: Method.PATCH,
body: {
decision,
alertIds,
},
schema: z.any(),
});

return handleZodError(error, alerts);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import toast from 'react-hot-toast';
import { t } from 'i18next';
import { AlertState, TAlertState, updateAlertsDecisionByIds } from '@/domains/alerts/fetchers';
import { TToastKeyWithSuccessAndError } from '@/common/types';

const getToastAction = (decision: TAlertState): TToastKeyWithSuccessAndError => {
if (decision === AlertState.REJECTED) {
return 'reject_alerts' as const;
}

if (decision === AlertState.NOT_SUSPICIOUS) {
return 'not_suspicious_alerts' as const;
}

if (decision === AlertState.TRIGGERED) {
return 'revert_decision_alerts' as const;
}

throw new Error(`Invalid decision: "${decision}"`);
};

export const useAlertsDecisionByIdsMutation = ({
onSuccess,
}: {
onSuccess?: <TData>(data: TData, { decision }: { decision: TAlertState }) => void;
} = {}) => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: ({ decision, alertIds }: { decision: TAlertState; alertIds: string[] }) =>
updateAlertsDecisionByIds({
decision,
alertIds,
}),
onSuccess: (data, { decision }) => {
void queryClient.invalidateQueries();

const action = getToastAction(decision);

toast.success(t(`toast:${action}.success`));
onSuccess?.(data, { decision });
},
onError: (error, { decision }) => {
const action = getToastAction(decision);

toast.error(t(`toast:${action}.error`));
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useUsersQuery } from '@/domains/users/hooks/queries/useUsersQuery/useUs
import toast from 'react-hot-toast';
import { t } from 'i18next';
import { assignAlertsByIds } from '@/domains/alerts/fetchers';
import { TToastKeyWithSuccessAndError } from '@/common/types';

const getToastActionAndContext = ({
assigneeId,
Expand All @@ -12,7 +13,10 @@ const getToastActionAndContext = ({
assigneeId: string | null;
assigneeName: string | null;
isAssignedToMe: boolean;
}) => {
}): {
action: TToastKeyWithSuccessAndError;
context: Record<string, string>;
} => {
const action = assigneeId ? 'assign_alerts' : 'unassign_alerts';
const context = assigneeId
? {
Expand Down
3 changes: 2 additions & 1 deletion apps/backoffice-v2/src/domains/transactions/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ export const TransactionsListSchema = z.array(
}).transform(({ business, counterpartyOriginator, ...data }) => ({
...data,
business: business?.companyName,
counterpartyOriginatorName: noNullish`${counterpartyOriginator?.endUser?.firstName} ${counterpartyOriginator?.endUser?.lastName}`,
counterpartyOriginatorName:
noNullish`${counterpartyOriginator?.endUser?.firstName} ${counterpartyOriginator?.endUser?.lastName}`.trim(),
})),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import toast from 'react-hot-toast';
import { t } from 'i18next';
import { updateWorkflowSetAssignById } from '../../../fetchers';
import { useUsersQuery } from '../../../../users/hooks/queries/useUsersQuery/useUsersQuery';
import { TToastKeyWithSuccessAndError } from '@/common/types';

const getToastActionAndContext = ({
assigneeId,
Expand All @@ -12,7 +13,10 @@ const getToastActionAndContext = ({
assigneeId: string | null;
assigneeName: string | null;
isAssignedToMe: boolean;
}) => {
}): {
action: TToastKeyWithSuccessAndError;
context: Record<string, string>;
} => {
const action = assigneeId ? 'assign_case' : 'unassign_case';
const context = assigneeId
? {
Expand Down
Loading

0 comments on commit 911b31c

Please sign in to comment.