mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 23:30:32 +00:00
feat(webapp): bank rule form
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import React, { createContext } from 'react';
|
import React, { createContext } from 'react';
|
||||||
import { DialogContent } from '@/components';
|
import { DialogContent } from '@/components';
|
||||||
|
import { useBankRule } from '@/hooks/query/bank-rules';
|
||||||
|
import { useAccounts } from '@/hooks/query';
|
||||||
|
|
||||||
interface RuleFormBootValues {
|
interface RuleFormBootValues {
|
||||||
bankRule?: null;
|
bankRule?: null;
|
||||||
@@ -17,10 +19,25 @@ interface RuleFormBootProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function RuleFormBoot({ bankRuleId, ...props }: RuleFormBootProps) {
|
function RuleFormBoot({ bankRuleId, ...props }: RuleFormBootProps) {
|
||||||
const provider = {} as RuleFormBootValues;
|
const { data: bankRule, isLoading: isBankRuleLoading } = useBankRule(
|
||||||
|
bankRuleId as number,
|
||||||
|
{
|
||||||
|
enabled: !!bankRuleId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const { data: accounts, isLoading: isAccountsLoading } = useAccounts({}, {});
|
||||||
|
|
||||||
|
const provider = {
|
||||||
|
bankRule,
|
||||||
|
accounts,
|
||||||
|
isBankRuleLoading,
|
||||||
|
isAccountsLoading,
|
||||||
|
} as RuleFormBootValues;
|
||||||
|
|
||||||
|
const isLoading = isBankRuleLoading || isAccountsLoading;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContent isLoading={false}>
|
<DialogContent isLoading={isLoading}>
|
||||||
<RuleFormBootContext.Provider value={provider} {...props} />
|
<RuleFormBootContext.Provider value={provider} {...props} />
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,10 +11,8 @@ export default function RuleFormContent({
|
|||||||
bankRuleId,
|
bankRuleId,
|
||||||
}: RuleFormContentProps) {
|
}: RuleFormContentProps) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<RuleFormBoot bankRuleId={bankRuleId}>
|
||||||
<RuleFormBoot bankRuleId={bankRuleId}>
|
<RuleFormContentForm />
|
||||||
<RuleFormContentForm />
|
</RuleFormBoot>
|
||||||
</RuleFormBoot>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { Form, Formik, useFormikContext } from 'formik';
|
// @ts-nocheck
|
||||||
|
import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
|
||||||
import { Button, Classes, Intent, Radio } from '@blueprintjs/core';
|
import { Button, Classes, Intent, Radio } from '@blueprintjs/core';
|
||||||
|
import * as R from 'ramda';
|
||||||
import { CreateRuleFormSchema } from './RuleFormContentForm.schema';
|
import { CreateRuleFormSchema } from './RuleFormContentForm.schema';
|
||||||
import {
|
import {
|
||||||
|
AccountsSelect,
|
||||||
|
AppToaster,
|
||||||
Box,
|
Box,
|
||||||
FFormGroup,
|
FFormGroup,
|
||||||
FInputGroup,
|
FInputGroup,
|
||||||
@@ -9,42 +13,57 @@ import {
|
|||||||
FSelect,
|
FSelect,
|
||||||
Group,
|
Group,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
|
import { useCreateBankRule } from '@/hooks/query/bank-rules';
|
||||||
|
import {
|
||||||
|
AssignTransactionTypeOptions,
|
||||||
|
FieldCondition,
|
||||||
|
Fields,
|
||||||
|
RuleFormValues,
|
||||||
|
TransactionTypeOptions,
|
||||||
|
initialValues,
|
||||||
|
} from './_utils';
|
||||||
|
import { useRuleFormDialogBoot } from './RuleFormBoot';
|
||||||
|
import { transfromToSnakeCase } from '@/utils';
|
||||||
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
|
||||||
const initialValues = {
|
function RuleFormContentFormRoot({
|
||||||
name: '',
|
// #withDialogActions
|
||||||
order: 0,
|
openDialog,
|
||||||
applyIfAccountId: '',
|
closeDialog,
|
||||||
applyIfTransactionType: '',
|
}) {
|
||||||
conditionsType: '',
|
const { accounts } = useRuleFormDialogBoot();
|
||||||
conditions: [
|
const { mutateAsync: createBankRule } = useCreateBankRule();
|
||||||
{
|
|
||||||
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 validationSchema = CreateRuleFormSchema;
|
||||||
const handleSubmit = () => {};
|
|
||||||
|
// Handles the form submitting.
|
||||||
|
const handleSubmit = (
|
||||||
|
values: RuleFormValues,
|
||||||
|
{ setSubmitting }: FormikHelpers<RuleFormValues>,
|
||||||
|
) => {
|
||||||
|
const _value = transfromToSnakeCase(values);
|
||||||
|
|
||||||
|
setSubmitting(true);
|
||||||
|
createBankRule(_value)
|
||||||
|
.then(() => {
|
||||||
|
setSubmitting(false);
|
||||||
|
closeDialog(DialogsName.BankRuleForm);
|
||||||
|
|
||||||
|
AppToaster.show({
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
message: 'The bank rule has been created successfully.',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setSubmitting(false);
|
||||||
|
|
||||||
|
AppToaster.show({
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
message: 'Something went wrong!',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Formik<RuleFormValues>
|
<Formik<RuleFormValues>
|
||||||
@@ -57,8 +76,21 @@ export function RuleFormContentForm() {
|
|||||||
<FInputGroup name={'name'} />
|
<FInputGroup name={'name'} />
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup name={'conditionsType'} label={'Apply to transactions are'}>
|
<FFormGroup
|
||||||
<FSelect name={'conditionsType'} items={[]} />
|
name={'applyIfAccountId'}
|
||||||
|
label={'Apply the rule to account'}
|
||||||
|
>
|
||||||
|
<AccountsSelect name={'applyIfAccountId'} items={accounts} />
|
||||||
|
</FFormGroup>
|
||||||
|
|
||||||
|
<FFormGroup
|
||||||
|
name={'applyIfTransactionType'}
|
||||||
|
label={'Apply to transactions are'}
|
||||||
|
>
|
||||||
|
<FSelect
|
||||||
|
name={'applyIfTransactionType'}
|
||||||
|
items={TransactionTypeOptions}
|
||||||
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
@@ -78,11 +110,14 @@ export function RuleFormContentForm() {
|
|||||||
<h3>Then Assign</h3>
|
<h3>Then Assign</h3>
|
||||||
|
|
||||||
<FFormGroup name={'assignCategory'} label={'Transaction type'}>
|
<FFormGroup name={'assignCategory'} label={'Transaction type'}>
|
||||||
<FSelect name={'assignCategory'} items={[]} />
|
<FSelect
|
||||||
|
name={'assignCategory'}
|
||||||
|
items={AssignTransactionTypeOptions}
|
||||||
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup name={'assignAccountId'} label={'Account category'}>
|
<FFormGroup name={'assignAccountId'} label={'Account category'}>
|
||||||
<FSelect name={'assignAccountId'} items={[]} />
|
<AccountsSelect name={'assignAccountId'} items={accounts} />
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup name={'assignRef'} label={'Reference'}>
|
<FFormGroup name={'assignRef'} label={'Reference'}>
|
||||||
@@ -95,15 +130,19 @@ export function RuleFormContentForm() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const RuleFormContentForm = R.compose(withDialogActions)(
|
||||||
|
RuleFormContentFormRoot,
|
||||||
|
);
|
||||||
|
|
||||||
function RuleFormConditions() {
|
function RuleFormConditions() {
|
||||||
const { values } = useFormikContext<RuleFormValues>();
|
const { values, setFieldValue } = useFormikContext<RuleFormValues>();
|
||||||
|
|
||||||
const handleAddConditionBtnClick = () => {
|
const handleAddConditionBtnClick = () => {
|
||||||
values.conditions.push({
|
const _conditions = [
|
||||||
field: '',
|
...values.conditions,
|
||||||
comparator: '',
|
{ field: '', comparator: '', value: '' },
|
||||||
value: '',
|
];
|
||||||
});
|
setFieldValue('conditions', _conditions);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -111,20 +150,20 @@ function RuleFormConditions() {
|
|||||||
{values?.conditions?.map((condition, index) => (
|
{values?.conditions?.map((condition, index) => (
|
||||||
<Group>
|
<Group>
|
||||||
<FFormGroup name={`conditions[${index}].field`} label={'Field'}>
|
<FFormGroup name={`conditions[${index}].field`} label={'Field'}>
|
||||||
<FSelect name={`conditions[${index}].field`} items={[]} />
|
<FSelect name={`conditions[${index}].field`} items={Fields} />
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup
|
<FFormGroup
|
||||||
name={`conditions[${index}].comparator`}
|
name={`conditions[${index}].comparator`}
|
||||||
label={'Condition'}
|
label={'Condition'}
|
||||||
>
|
>
|
||||||
<FSelect name={`conditions[${index}].comparator`} items={[]} />
|
<FSelect
|
||||||
|
name={`conditions[${index}].comparator`}
|
||||||
|
items={FieldCondition}
|
||||||
|
/>
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
|
|
||||||
<FFormGroup
|
<FFormGroup name={`conditions[${index}].value`} label={'Condition'}>
|
||||||
name={`conditions[${index}].condition`}
|
|
||||||
label={'Condition'}
|
|
||||||
>
|
|
||||||
<FInputGroup name={`conditions[${index}].value`} />
|
<FInputGroup name={`conditions[${index}].value`} />
|
||||||
</FFormGroup>
|
</FFormGroup>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
export const initialValues = {
|
||||||
|
name: '',
|
||||||
|
order: 0,
|
||||||
|
applyIfAccountId: '',
|
||||||
|
applyIfTransactionType: '',
|
||||||
|
conditionsType: '',
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
field: 'description',
|
||||||
|
comparator: 'contains',
|
||||||
|
value: 'payment',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
assignCategory: '',
|
||||||
|
assignAccountId: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
export 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 const TransactionTypeOptions = [
|
||||||
|
{ value: 'deposit', text: 'Deposit' },
|
||||||
|
{ value: 'withdrawal', text: 'Withdrawal' },
|
||||||
|
];
|
||||||
|
export const Fields = [
|
||||||
|
{ value: 'description', text: 'Description' },
|
||||||
|
{ value: 'amount', text: 'Amount' },
|
||||||
|
{ value: 'payee', text: 'Payee' },
|
||||||
|
];
|
||||||
|
export const FieldCondition = [
|
||||||
|
{ value: 'contains', text: 'Contains' },
|
||||||
|
{ value: 'equals', text: 'equals' },
|
||||||
|
{ value: 'not_contains', text: 'Not Contains' },
|
||||||
|
];
|
||||||
|
export const AssignTransactionTypeOptions = [
|
||||||
|
{ value: 'expense', text: 'Expense' },
|
||||||
|
];
|
||||||
@@ -13,7 +13,9 @@ export function RulesList() {
|
|||||||
<RulesListActionsBar />
|
<RulesListActionsBar />
|
||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<BankRulesTable />
|
<RulesListBoot>
|
||||||
|
<BankRulesTable />
|
||||||
|
</RulesListBoot>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</RulesListBoot>
|
</RulesListBoot>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React, { createContext } from 'react';
|
import React, { createContext } from 'react';
|
||||||
import { DialogContent } from '@/components';
|
import { DialogContent } from '@/components';
|
||||||
|
import { useBankRules } from '@/hooks/query/bank-rules';
|
||||||
|
|
||||||
interface RulesListBootValues {
|
interface RulesListBootValues {
|
||||||
rules: any;
|
bankRules: any;
|
||||||
isRulesLoading: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const RulesListBootContext = createContext<RulesListBootValues>(
|
const RulesListBootContext = createContext<RulesListBootValues>(
|
||||||
@@ -15,7 +15,9 @@ interface RulesListBootProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function RulesListBoot({ ...props }: RulesListBootProps) {
|
function RulesListBoot({ ...props }: RulesListBootProps) {
|
||||||
const provider = {} as RulesListBootValues;
|
const { data: bankRules, isLoading: isBankRulesLoading } = useBankRules();
|
||||||
|
|
||||||
|
const provider = { bankRules, isBankRulesLoading } as RulesListBootValues;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DialogContent isLoading={false}>
|
<DialogContent isLoading={false}>
|
||||||
|
|||||||
71
packages/webapp/src/hooks/query/bank-rules.ts
Normal file
71
packages/webapp/src/hooks/query/bank-rules.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||||
|
import useApiRequest from '../useRequest';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function useCreateBankRule(props) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useMutation((values) => apiRequest.post(`/banking/rules`, values), {
|
||||||
|
onSuccess: (res, id) => {
|
||||||
|
// Invalidate queries.
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useEditBankRule(props) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useMutation((id: number) => apiRequest.post(`/bank-rules/${id}`), {
|
||||||
|
onSuccess: (res, id) => {
|
||||||
|
// Invalidate queries.
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDeleteBankRule(props) {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useMutation((id: number) => apiRequest.delete(`/bank-rules/${id}`), {
|
||||||
|
onSuccess: (res, id) => {
|
||||||
|
// Invalidate queries.
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function useBankRules() {
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useQuery(['BANK_RULEs'], () =>
|
||||||
|
apiRequest.get('/banking/rules').then((res) => res.data.bank_rules),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function useBankRule(bankRuleId: number, props) {
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
|
return useQuery(
|
||||||
|
['BANK_RULEs', bankRuleId],
|
||||||
|
() =>
|
||||||
|
apiRequest
|
||||||
|
.get(`/banking/rules/${bankRuleId}`)
|
||||||
|
.then((res) => res.data.bank_rule),
|
||||||
|
props,
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user