Compare commits
1 Commits
darkmode-u
...
BIG-213
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
882fc20ac1 |
@@ -3,7 +3,15 @@ import React from 'react';
|
||||
import clsx from 'classnames';
|
||||
import { Navbar } from '@blueprintjs/core';
|
||||
|
||||
export function DashboardActionsBar({ className, children, name }) {
|
||||
interface DashboardActionsBarProps {
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export function DashboardActionsBar({
|
||||
className,
|
||||
children,
|
||||
name,
|
||||
}: DashboardActionsBarProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
||||
@@ -20,8 +20,9 @@ export const AbilitySubject = {
|
||||
SubscriptionBilling: 'SubscriptionBilling',
|
||||
CreditNote: 'CreditNote',
|
||||
VendorCredit: 'VendorCredit',
|
||||
Project:'Project',
|
||||
Project: 'Project',
|
||||
TaxRate: 'TaxRate',
|
||||
BankRule: 'BankRule',
|
||||
};
|
||||
|
||||
export const ItemAction = {
|
||||
@@ -188,10 +189,16 @@ export const SubscriptionBillingAbility = {
|
||||
Payment: 'payment',
|
||||
};
|
||||
|
||||
|
||||
export const TaxRateAction = {
|
||||
View: 'View',
|
||||
Create: 'Create',
|
||||
Edit: 'Edit',
|
||||
Delete: 'Delete',
|
||||
};
|
||||
|
||||
export const BankRuleAction = {
|
||||
View: 'View',
|
||||
Create: 'Create',
|
||||
Edit: 'Edit',
|
||||
Delete: 'Delete',
|
||||
};
|
||||
|
||||
@@ -458,6 +458,11 @@ export const SidebarMenu = [
|
||||
ability: CashflowAction.View,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Rules',
|
||||
href: '/bank-rules',
|
||||
type: ISidebarMenuItemType.Link,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { DialogContent } from '@/components';
|
||||
|
||||
interface RuleFormBootValues {
|
||||
bankRule?: null;
|
||||
bankRuleId?: null;
|
||||
isBankRuleLoading: boolean;
|
||||
}
|
||||
|
||||
const RuleFormBootContext = createContext<RuleFormBootValues>(
|
||||
{} as RuleFormBootValues,
|
||||
);
|
||||
|
||||
interface RuleFormBootProps {
|
||||
bankRuleId?: number;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function RuleFormBoot({ bankRuleId, ...props }: RuleFormBootProps) {
|
||||
const provider = {} as RuleFormBootValues;
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={false}>
|
||||
<RuleFormBootContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useRuleFormDialogBoot = () =>
|
||||
React.useContext<RuleFormBootValues>(RuleFormBootContext);
|
||||
|
||||
export { RuleFormBoot, useRuleFormDialogBoot };
|
||||
@@ -0,0 +1,19 @@
|
||||
import { RuleFormBoot } from "./RuleFormBoot";
|
||||
|
||||
|
||||
interface RuleFormContentProps {
|
||||
dialogName: string;
|
||||
bankRuleId?: number;
|
||||
}
|
||||
export function RuleFormContent({
|
||||
dialogName,
|
||||
bankRuleId,
|
||||
}: RuleFormContentProps) {
|
||||
return (
|
||||
<RuleFormBoot
|
||||
bankRuleId={bankRuleId}
|
||||
>
|
||||
|
||||
</RuleFormBoot>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// @ts-nocheck
|
||||
import * as Yup from 'yup';
|
||||
|
||||
const Schema = Yup.object().shape({
|
||||
name: Yup.string().required().label('Rule name'),
|
||||
applyIfAccountId: Yup.number().required().label(''),
|
||||
applyIfTransactionType: Yup.string().required().label(''),
|
||||
conditionsType: Yup.string().required(),
|
||||
assignCategory: Yup.string().required(),
|
||||
assignAccountId: Yup.string().required(),
|
||||
});
|
||||
|
||||
export const CreateRuleFormSchema = Schema;
|
||||
@@ -0,0 +1,134 @@
|
||||
import { Form, Formik, useFormikContext } from 'formik';
|
||||
import { Button, Radio } from '@blueprintjs/core';
|
||||
import { CreateRuleFormSchema } from './RuleFormContentForm.schema';
|
||||
import {
|
||||
Box,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FRadioGroup,
|
||||
FSelect,
|
||||
Group,
|
||||
} from '@/components';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
order: 0,
|
||||
applyIfAccountId: '',
|
||||
applyIfTransactionType: '',
|
||||
conditionsType: '',
|
||||
conditions: [
|
||||
{
|
||||
field: 'description',
|
||||
comparator: 'contains',
|
||||
value: 'payment',
|
||||
},
|
||||
],
|
||||
assignCategory: '',
|
||||
assignAccountId: '',
|
||||
};
|
||||
|
||||
interface RuleFormValues {
|
||||
name: string;
|
||||
order: number;
|
||||
applyIfAccountId: string;
|
||||
applyIfTransactionType: string;
|
||||
conditionsType: string;
|
||||
conditions: Array<{
|
||||
field: string;
|
||||
comparator: string;
|
||||
value: string;
|
||||
}>;
|
||||
assignCategory: string;
|
||||
assignAccountId: string;
|
||||
}
|
||||
|
||||
export function RuleFormContentForm() {
|
||||
const validationSchema = CreateRuleFormSchema;
|
||||
const handleSubmit = () => {};
|
||||
|
||||
return (
|
||||
<Formik<RuleFormValues>
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<Form>
|
||||
<FFormGroup name={'name'} label={'Rule Name'}>
|
||||
<FInputGroup name={'name'} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'conditionsType'} label={'Apply to transactions are'}>
|
||||
<FSelect name={'conditionsType'} items={[]} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={''} label={'Categorize the transactions when'}>
|
||||
<FRadioGroup name={'conditionsType'}>
|
||||
<Radio value={'and'} label={'All the following criteria matches'} />
|
||||
<Radio
|
||||
value={'or'}
|
||||
label={'Any one of the following criteria matches'}
|
||||
/>
|
||||
</FRadioGroup>
|
||||
</FFormGroup>
|
||||
|
||||
<RuleFormConditions />
|
||||
|
||||
<h3>Then Assign</h3>
|
||||
|
||||
<FFormGroup name={'assignCategory'} label={'Transaction type'}>
|
||||
<FSelect name={'assignCategory'} items={[]} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'assignAccountId'} label={'Account category'}>
|
||||
<FSelect name={'assignAccountId'} items={[]} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'assignRef'} label={'Reference'}>
|
||||
<FInputGroup name={'assignRef'} />
|
||||
</FFormGroup>
|
||||
</Form>
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
||||
function RuleFormConditions() {
|
||||
const { values } = useFormikContext<RuleFormValues>();
|
||||
|
||||
const handleAddConditionBtnClick = () => {
|
||||
values.conditions.push({
|
||||
field: '',
|
||||
comparator: '',
|
||||
value: '',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{values?.conditions?.map((condition, index) => (
|
||||
<Group>
|
||||
<FFormGroup name={`conditions[${index}].field`} label={'Field'}>
|
||||
<FSelect name={`conditions[${index}].field`} items={[]} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={`conditions[${index}].comparator`}
|
||||
label={'Condition'}
|
||||
>
|
||||
<FSelect name={`conditions[${index}].comparator`} items={[]} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
name={`conditions[${index}].condition`}
|
||||
label={'Condition'}
|
||||
>
|
||||
<FInputGroup name={`conditions[${index}].value`} />
|
||||
</FFormGroup>
|
||||
</Group>
|
||||
))}
|
||||
|
||||
<Button type={'button'} onClick={handleAddConditionBtnClick}>
|
||||
Add Condition
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Dialog, DialogSuspense } from '@/components';
|
||||
import withDialogRedux from '@/components/DialogReduxConnect';
|
||||
import { compose } from '@/utils';
|
||||
|
||||
const RuleFormContent = React.lazy(() => import('./RuleFormContent'));
|
||||
|
||||
/**
|
||||
* Payment mail dialog.
|
||||
*/
|
||||
function RuleFormDialog({
|
||||
dialogName,
|
||||
payload: { bankRuleId = null },
|
||||
isOpen,
|
||||
}) {
|
||||
return (
|
||||
<Dialog
|
||||
name={dialogName}
|
||||
title={'New Bank Rule'}
|
||||
isOpen={isOpen}
|
||||
canEscapeJeyClose={true}
|
||||
autoFocus={true}
|
||||
style={{ width: 600 }}
|
||||
>
|
||||
<DialogSuspense>
|
||||
<RuleFormContent dialogName={dialogName} bankRuleId={bankRuleId} />
|
||||
</DialogSuspense>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(withDialogRedux())(RuleFormDialog);
|
||||
@@ -0,0 +1,39 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import { Button, Intent } from '@blueprintjs/core';
|
||||
import { EmptyStatus, Can, FormattedMessage as T } from '@/components';
|
||||
import { AbilitySubject, BankRuleAction } from '@/constants/abilityOption';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
|
||||
function BankRulesLandingEmptyStateRoot({
|
||||
// #withDialogAction
|
||||
openDialog,
|
||||
}) {
|
||||
return (
|
||||
<EmptyStatus
|
||||
title={"The organization doesn't have taxes, yet!"}
|
||||
description={
|
||||
<p>
|
||||
Setup the organization taxes to start tracking taxes on sales
|
||||
transactions.
|
||||
</p>
|
||||
}
|
||||
action={
|
||||
<>
|
||||
<Can I={BankRuleAction.Create} a={AbilitySubject.BankRule}>
|
||||
<Button intent={Intent.PRIMARY} large={true} onClick={() => {}}>
|
||||
New tax rate
|
||||
</Button>
|
||||
<Button intent={Intent.NONE} large={true}>
|
||||
<T id={'learn_more'} />
|
||||
</Button>
|
||||
</Can>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const BankRulesLandingEmptyState = R.compose(withDialogActions)(
|
||||
BankRulesLandingEmptyStateRoot,
|
||||
);
|
||||
@@ -0,0 +1,20 @@
|
||||
// @ts-nocheck
|
||||
import { DashboardPageContent } from '@/components';
|
||||
import { RulesListBoot } from './RulesListBoot';
|
||||
import { RulesListActionsBar } from './RulesListActionsBar';
|
||||
import { BankRulesTable } from './RulesTable';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export function RulesList() {
|
||||
return (
|
||||
<RulesListBoot>
|
||||
<RulesListActionsBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<BankRulesTable />
|
||||
</DashboardPageContent>
|
||||
</RulesListBoot>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { DashboardActionsBar } from '@/components';
|
||||
import { NavbarGroup } from '@blueprintjs/core';
|
||||
|
||||
export function RulesListActionsBar() {
|
||||
return (
|
||||
<DashboardActionsBar>
|
||||
<NavbarGroup></NavbarGroup>
|
||||
</DashboardActionsBar>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import React, { createContext } from 'react';
|
||||
import { DialogContent } from '@/components';
|
||||
|
||||
interface RulesListBootValues {
|
||||
rules: any;
|
||||
isRulesLoading: boolean;
|
||||
}
|
||||
|
||||
const RulesListBootContext = createContext<RulesListBootValues>(
|
||||
{} as RulesListBootValues,
|
||||
);
|
||||
|
||||
interface RulesListBootProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function RulesListBoot({ ...props }: RulesListBootProps) {
|
||||
const provider = {} as RulesListBootValues;
|
||||
|
||||
return (
|
||||
<DialogContent isLoading={false}>
|
||||
<RulesListBootContext.Provider value={provider} {...props} />
|
||||
</DialogContent>
|
||||
);
|
||||
}
|
||||
|
||||
const useRulesListBoot = () =>
|
||||
React.useContext<RulesListBootValues>(RulesListBootContext);
|
||||
|
||||
export { RulesListBoot, useRulesListBoot };
|
||||
@@ -0,0 +1,81 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import {
|
||||
DataTable,
|
||||
DashboardContentTable,
|
||||
TableSkeletonHeader,
|
||||
TableSkeletonRows,
|
||||
} from '@/components';
|
||||
|
||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||
import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
|
||||
|
||||
import { useBankRulesTableColumns } from './hooks';
|
||||
import { BankRulesTableActionsMenu } from './_components';
|
||||
import { BankRulesLandingEmptyState } from './BankRulesLandingEmptyState';
|
||||
|
||||
/**
|
||||
* Invoices datatable.
|
||||
*/
|
||||
function RulesTable({
|
||||
// #withAlertsActions
|
||||
openAlert,
|
||||
|
||||
// #withDrawerActions
|
||||
openDrawer,
|
||||
|
||||
// #withDialogAction
|
||||
openDialog,
|
||||
}) {
|
||||
// Invoices table columns.
|
||||
const columns = useBankRulesTableColumns();
|
||||
|
||||
// Handle edit bank rule.
|
||||
const handleDeleteBankRule = ({ id }) => {};
|
||||
|
||||
// Handle delete bank rule.
|
||||
const handleEditBankRule = () => {};
|
||||
|
||||
// Display invoice empty status instead of the table.
|
||||
if (isEmptyStatus) {
|
||||
return <BankRulesLandingEmptyState />;
|
||||
}
|
||||
|
||||
return (
|
||||
<DashboardContentTable>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={[]}
|
||||
loading={false}
|
||||
headerLoading={false}
|
||||
progressBarLoading={false}
|
||||
manualSortBy={false}
|
||||
selectionColumn={false}
|
||||
noInitialFetch={true}
|
||||
sticky={true}
|
||||
pagination={false}
|
||||
manualPagination={false}
|
||||
autoResetSortBy={false}
|
||||
autoResetPage={false}
|
||||
TableLoadingRenderer={TableSkeletonRows}
|
||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||
ContextMenu={BankRulesTableActionsMenu}
|
||||
onCellClick={handleCellClick}
|
||||
size={'medium'}
|
||||
payload={{
|
||||
onDelete: handleDeleteTaxRate,
|
||||
onEdit: handleEditTaxRate,
|
||||
}}
|
||||
/>
|
||||
</DashboardContentTable>
|
||||
);
|
||||
}
|
||||
|
||||
export const BankRulesTable = R.compose(
|
||||
withDashboardActions,
|
||||
withAlertsActions,
|
||||
withDrawerActions,
|
||||
withDialogActions,
|
||||
)(RulesTable);
|
||||
@@ -0,0 +1,38 @@
|
||||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
import { Intent, Menu, MenuDivider, MenuItem } from '@blueprintjs/core';
|
||||
import { Can, Icon } from '@/components';
|
||||
import { AbilitySubject, BankRuleAction } from '@/constants/abilityOption';
|
||||
import { safeCallback } from '@/utils';
|
||||
|
||||
/**
|
||||
* Tax rates table actions menu.
|
||||
* @returns {JSX.Element}
|
||||
*/
|
||||
export function BankRulesTableActionsMenu({
|
||||
payload: { onEdit, onDelete },
|
||||
row: { original },
|
||||
}) {
|
||||
return (
|
||||
<Menu>
|
||||
<Can I={BankRuleAction.Edit} a={AbilitySubject.BankRule}>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
icon={<Icon icon="pen-18" />}
|
||||
text={'Edit Rule'}
|
||||
onClick={safeCallback(onEdit, original)}
|
||||
/>
|
||||
</Can>
|
||||
<MenuDivider />
|
||||
<Can I={BankRuleAction.Delete} a={AbilitySubject.BankRule}>
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
text={'Delete Rule'}
|
||||
intent={Intent.DANGER}
|
||||
onClick={safeCallback(onDelete, original)}
|
||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||
/>
|
||||
</Can>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export const useBankRulesTableColumns = () => {
|
||||
return [];
|
||||
};
|
||||
@@ -1221,6 +1221,14 @@ export const getDashboardRoutes = () => [
|
||||
pageTitle: 'Tax Rates',
|
||||
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
|
||||
},
|
||||
// Bank Rules
|
||||
{
|
||||
path: '/bank-rules',
|
||||
component: lazy(
|
||||
() => import('@/containers/Banking/Rules/RulesList/RulesList'),
|
||||
),
|
||||
pageTitle: 'Bank Rules',
|
||||
},
|
||||
// Homepage
|
||||
{
|
||||
path: `/`,
|
||||
|
||||
Reference in New Issue
Block a user