Skip to content

Commit

Permalink
feat(dm): adding nuveri and axs changes
Browse files Browse the repository at this point in the history
  • Loading branch information
alonp99 committed Sep 2, 2024
2 parents 896efff + 040e685 commit 9051dbe
Show file tree
Hide file tree
Showing 43 changed files with 494 additions and 116 deletions.
9 changes: 9 additions & 0 deletions apps/backoffice-v2/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# @ballerine/backoffice-v2

## 0.7.36

### Patch Changes

- Updated dependencies
- @ballerine/common@0.9.26
- @ballerine/workflow-browser-sdk@0.6.37
- @ballerine/workflow-node-sdk@0.6.37

## 0.7.35

### Patch Changes
Expand Down
8 changes: 4 additions & 4 deletions apps/backoffice-v2/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ballerine/backoffice-v2",
"version": "0.7.35",
"version": "0.7.36",
"description": "Ballerine - Backoffice",
"homepage": "https://github.com/ballerine-io/ballerine",
"repository": {
Expand Down Expand Up @@ -51,11 +51,11 @@
},
"dependencies": {
"@ballerine/blocks": "0.2.12",
"@ballerine/common": "0.9.25",
"@ballerine/common": "0.9.26",
"@ballerine/react-pdf-toolkit": "^1.2.20",
"@ballerine/ui": "^0.5.20",
"@ballerine/workflow-browser-sdk": "0.6.36",
"@ballerine/workflow-node-sdk": "0.6.36",
"@ballerine/workflow-browser-sdk": "0.6.37",
"@ballerine/workflow-node-sdk": "0.6.37",
"@fontsource/inter": "^4.5.15",
"@formkit/auto-animate": "1.0.0-beta.5",
"@hookform/resolvers": "^3.1.0",
Expand Down
6 changes: 6 additions & 0 deletions apps/backoffice-v2/public/locales/en/toast.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,11 @@
"success": "Merchant check created successfully.",
"error": "Error occurred while creating a merchant check.",
"is_example": "Please contact Ballerine at oss@ballerine.com for access to this feature."
},
"batch_business_report_creation": {
"no_file": "No file selected.",
"success": "Merchant checks created successfully.",
"error": "Error occurred while creating merchant checks.",
"is_example": "Please contact Ballerine at oss@ballerine.com for access to this feature."
}
}
6 changes: 6 additions & 0 deletions apps/backoffice-v2/src/Router/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { MerchantMonitoringBusinessReport } from '@/pages/MerchantMonitoringBusi
import { MerchantMonitoringLayout } from '@/domains/business-reports/components/MerchantMonitoringLayout/MerchantMonitoringLayout';
import { NotFoundRedirectWithProviders } from '@/pages/NotFound/NotFoundRedirectWithProviders';
import { RouteErrorWithProviders } from '@/common/components/atoms/RouteError/RouteErrorWithProviders';
import { MerchantMonitoringUploadMultiplePage } from '@/pages/MerchantMonitoringUploadMultiple/MerchantMonitoringUploadMultiple.page';

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -94,6 +95,11 @@ const router = createBrowserRouter([
element: <MerchantMonitoringCreateCheckPage />,
errorElement: <RouteError />,
},
{
path: '/:locale/merchant-monitoring/upload-multiple-merchants',
element: <MerchantMonitoringUploadMultiplePage />,
errorElement: <RouteError />,
},
],
},
{
Expand Down
2 changes: 2 additions & 0 deletions apps/backoffice-v2/src/common/api-client/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface IApiClient {
timeout?: number;
schema: TZodSchema;
isBlob?: boolean;
isFormData?: boolean;
}): Promise<[z.infer<TZodSchema>, undefined] | [undefined, Error]>;

<TBody extends AnyRecord, TZodSchema extends ZodSchema>(params: {
Expand All @@ -24,6 +25,7 @@ export interface IApiClient {
timeout?: number;
schema: TZodSchema;
isBlob?: boolean;
isFormData?: boolean;
}): Promise<[z.infer<TZodSchema>, undefined] | [undefined, Error]>;

<TZodSchema extends ZodSchema>(params: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@ export interface ButtonProps
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : 'button';

return (
<Comp className={ctw(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
);
},
);

Button.displayName = 'Button';
8 changes: 6 additions & 2 deletions apps/backoffice-v2/src/common/utils/fetcher/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { handlePromise } from '../handle-promise/handle-promise';
import { isZodError } from '../is-zod-error/is-zod-error';
import { IFetcher } from './interfaces';

const handleBody = ({ body, isFormData }: { body: unknown; isFormData: boolean }) =>
isFormData ? body : JSON.stringify(body);

export const fetcher: IFetcher = async ({
url,
method,
Expand All @@ -15,6 +18,7 @@ export const fetcher: IFetcher = async ({
timeout = 10000,
schema,
isBlob = false,
isFormData = false,
}) => {
const controller = new AbortController();
const { signal } = controller;
Expand All @@ -26,8 +30,8 @@ export const fetcher: IFetcher = async ({
...options,
method,
signal,
body: method !== 'GET' && body ? JSON.stringify(body) : undefined,
headers,
body: method !== 'GET' && body ? handleBody({ body, isFormData }) : undefined,
headers: isFormData ? undefined : headers,
}),
);
clearTimeout(timeoutRef);
Expand Down
29 changes: 29 additions & 0 deletions apps/backoffice-v2/src/domains/business-reports/fetchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,32 @@ export const createBusinessReport = async ({

return handleZodError(error, businessReport);
};

export const createBusinessReportBatch = async ({
merchantSheet,
isExample,
reportType,
}: {
merchantSheet: File;
isExample: boolean;
reportType: TBusinessReportType;
}) => {
if (isExample) {
toast.info(t('toast:batch_business_report_creation.is_example'));

return;
}

const formData = new FormData();
formData.append('file', merchantSheet);

const [batchId, error] = await apiClient({
endpoint: `business-reports/upload-batch/${reportType}`,
method: Method.POST,
schema: z.object({ batchId: z.string() }),
body: formData,
isFormData: true,
});

return handleZodError(error, batchId);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { t } from 'i18next';
import { toast } from 'sonner';
import { useMutation, useQueryClient } from '@tanstack/react-query';

import { HttpError } from '@/common/errors/http-error';
import { TBusinessReportType } from '@/domains/business-reports/types';
import { createBusinessReportBatch } from '@/domains/business-reports/fetchers';
import { useCustomerQuery } from '@/domains/customer/hook/queries/useCustomerQuery/useCustomerQuery';
import { isObject } from '@ballerine/common';

export const useCreateBusinessReportBatchMutation = ({
reportType,
onSuccess,
}: {
reportType: TBusinessReportType;
onSuccess?: <TData>(data: TData) => void;
}) => {
const queryClient = useQueryClient();

const { data: customer } = useCustomerQuery();

return useMutation({
mutationFn: (merchantSheet: File) =>
createBusinessReportBatch({
reportType,
merchantSheet,
isExample: customer?.config?.isExample ?? false,
}),
onSuccess: data => {
void queryClient.invalidateQueries();

toast.success(t(`toast:batch_business_report_creation.success`));

onSuccess?.(data);
},
onError: (error: unknown) => {
if (error instanceof HttpError && error.code === 400) {
toast.error(error.message);

return;
}

toast.error(
t(`toast:batch_business_report_creation.error`, {
errorMessage: isObject(error) && 'message' in error ? error.message : error,
}),
);
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { createBusinessReport } from '@/domains/business-reports/fetchers';
import { TBusinessReportType } from '@/domains/business-reports/types';
import { useCustomerQuery } from '@/domains/customer/hook/queries/useCustomerQuery/useCustomerQuery';
import { HttpError } from '@/common/errors/http-error';
import { isObject } from '@ballerine/common';

export const useCreateBusinessReportMutation = ({
reportType,
Expand Down Expand Up @@ -39,7 +40,7 @@ export const useCreateBusinessReportMutation = ({
companyName,
businessCorrelationId,
reportType,
isExample: customer?.config?.isExample,
isExample: customer?.config?.isExample ?? false,
}),
onSuccess: data => {
if (customer?.config?.isExample) {
Expand All @@ -51,14 +52,18 @@ export const useCreateBusinessReportMutation = ({
toast.success(t(`toast:business_report_creation.success`));
onSuccess?.(data);
},
onError: error => {
onError: (error: unknown) => {
if (error instanceof HttpError && error.code === 400) {
toast.error(error.message);

return;
}

toast.error(t(`toast:business_report_creation.error`, { errorMessage: error.message }));
toast.error(
t(`toast:business_report_creation.error`, {
errorMessage: isObject(error) && 'message' in error ? error.message : error,
}),
);
},
});
};
9 changes: 4 additions & 5 deletions apps/backoffice-v2/src/pages/Home/Home.page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { FunctionComponent } from 'react';
import { Outlet } from 'react-router-dom';
import { UserAvatar } from '@/common/components/atoms/UserAvatar/UserAvatar';
import { DateRangePicker } from '@/common/components/molecules/DateRangePicker/DateRangePicker';
import { useHomeLogic } from '@/common/hooks/useHomeLogic/useHomeLogic';
import { t } from 'i18next';
import { FullScreenLoader } from '@/common/components/molecules/FullScreenLoader/FullScreenLoader';
Expand Down Expand Up @@ -41,10 +40,10 @@ export const Home: FunctionComponent = () => {
{firstName && ` ${firstName}`}
</h3>
</div>
<DateRangePicker
onChange={onDateRangeChange}
value={{ from: from ? new Date(from) : undefined, to: to ? new Date(to) : undefined }}
/>
{/*<DateRangePicker*/}
{/* onChange={onDateRangeChange}*/}
{/* value={{ from: from ? new Date(from) : undefined, to: to ? new Date(to) : undefined }}*/}
{/*/>*/}
</div>
<div>
{/*<Tabs defaultValue={defaultTabValue} key={defaultTabValue}>*/}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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 } from 'lucide-react';
import { Plus, Table2 } from 'lucide-react';
import { Link } from 'react-router-dom';
import { Search } from '@/common/components/molecules/Search';
import { Skeleton } from '@ballerine/ui';
Expand All @@ -32,16 +32,28 @@ export const MerchantMonitoring: FunctionComponent = () => {
<div className={`flex justify-between`}>
<h1 className="pb-5 text-2xl font-bold">Merchant Monitoring</h1>
{!hideCreateMerchantMonitoringButton && (
<Link
className={buttonVariants({
variant: 'outline',
className: 'flex items-center justify-start gap-2 font-semibold',
})}
to={`/${locale}/merchant-monitoring/create-check`}
>
<Plus />
<span>Create Merchant Check</span>
</Link>
<div className={`flex space-x-3`}>
<Link
className={buttonVariants({
variant: 'outline',
className: 'flex items-center justify-start gap-2 font-semibold',
})}
to={`/${locale}/merchant-monitoring/upload-multiple-merchants`}
>
<Table2 />
<span>Upload Multiple Merchants</span>
</Link>
<Link
className={buttonVariants({
variant: 'outline',
className: 'flex items-center justify-start gap-2 font-semibold',
})}
to={`/${locale}/merchant-monitoring/create-check`}
>
<Plus />
<span>Create Merchant Check</span>
</Link>
</div>
)}
</div>
<div className={`flex`}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Input } from '@ballerine/ui';
import { Link } from 'react-router-dom';
import { ChevronLeft, Download } from 'lucide-react';
import React, { FunctionComponent } from 'react';

import { Card } from '@/common/components/atoms/Card/Card';
import { Form } from '@/common/components/organisms/Form/Form';
import { FormItem } from '@/common/components/organisms/Form/Form.Item';
import { FormField } from '@/common/components/organisms/Form/Form.Field';
import { FormLabel } from '@/common/components/organisms/Form/Form.Label';
import { CardContent } from '@/common/components/atoms/Card/Card.Content';
import { FormControl } from '@/common/components/organisms/Form/Form.Control';
import { Button, buttonVariants } from '@/common/components/atoms/Button/Button';
import { FormDescription } from '@/common/components/organisms/Form/Form.Description';
import { useMerchantMonitoringUploadMultiplePageLogic } from '@/pages/MerchantMonitoringUploadMultiple/hooks/useMerchantMonitoringUploadMultiplePageLogic/useMerchantMonitoringUploadMultiplePageLogic';

export const MerchantMonitoringUploadMultiplePage: FunctionComponent = () => {
const { form, onSubmit, onChange, locale, csvTemplateUrl } =
useMerchantMonitoringUploadMultiplePageLogic();

return (
<section className="flex h-full flex-col px-6 pb-6 pt-10">
<div>
<Link
to={`/${locale}/merchant-monitoring`}
className={buttonVariants({
variant: 'ghost',
className: 'mb-6 flex items-center space-x-[1px] pe-3 ps-1 font-semibold',
})}
>
<ChevronLeft size={18} /> <span>Back to Reports</span>
</Link>
</div>
<h1 className="pb-5 text-2xl font-bold">Upload Multiple Merchants</h1>
<Card>
<CardContent className={`px-10 pt-8`}>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="merchantSheet"
render={() => (
<FormItem className={`max-w-[250px]`}>
<FormLabel>Upload Merchants Sheet</FormLabel>
<FormControl>
<Input
type="file"
accept=".csv"
onChange={onChange}
id={`merchantSheet`}
name={`merchantSheet`}
className="flex items-center"
/>
</FormControl>
<FormDescription>File should follow the CSV template</FormDescription>
</FormItem>
)}
/>
<div className={`flex space-x-[54px]`}>
<Button type="submit" size={`wide`}>
Start Analyzing
</Button>
<a
href={csvTemplateUrl}
download="batch-report-template.csv"
className={'flex items-center space-x-2 text-[#007AFF] hover:underline'}
>
<Download className={`d-6`} />
<span className={`text-sm font-medium leading-5`}>Download CSV template</span>
</a>
</div>
</form>
</Form>
</CardContent>
</Card>
</section>
);
};
Loading

0 comments on commit 9051dbe

Please sign in to comment.