Compare commits
1 Commits
patch-3
...
reconcile-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45ad4aa1f1 |
@@ -21,4 +21,5 @@
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
background-color: #fff;
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -1,13 +1,16 @@
|
||||
import { Button, Classes } from '@blueprintjs/core';
|
||||
import { Box, Group } from '../Layout';
|
||||
import clsx from 'classnames';
|
||||
import { Box, BoxProps, Group } from '../Layout';
|
||||
import { Icon } from '../Icon';
|
||||
import styles from './Aside.module.scss';
|
||||
|
||||
interface AsideProps {
|
||||
interface AsideProps extends BoxProps {
|
||||
title?: string;
|
||||
onClose?: () => void;
|
||||
children?: React.ReactNode;
|
||||
hideCloseButton?: boolean;
|
||||
classNames?: Record<string, string>;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Aside({
|
||||
@@ -15,13 +18,15 @@ export function Aside({
|
||||
onClose,
|
||||
children,
|
||||
hideCloseButton,
|
||||
classNames,
|
||||
className
|
||||
}: AsideProps) {
|
||||
const handleClose = () => {
|
||||
onClose && onClose();
|
||||
};
|
||||
return (
|
||||
<Box className={styles.root}>
|
||||
<Group position="apart" className={styles.title}>
|
||||
<Box className={clsx(styles.root, className, classNames?.root)}>
|
||||
<Group position="apart" className={clsx(styles.title, classNames?.title)}>
|
||||
{title}
|
||||
|
||||
{hideCloseButton !== true && (
|
||||
@@ -34,7 +39,23 @@ export function Aside({
|
||||
/>
|
||||
)}
|
||||
</Group>
|
||||
<Box className={styles.content}>{children}</Box>
|
||||
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface AsideContentProps extends BoxProps {}
|
||||
|
||||
function AsideContent({ ...props }: AsideContentProps) {
|
||||
return <Box {...props} className={clsx(styles.content, props?.className)} />;
|
||||
}
|
||||
|
||||
interface AsideFooterProps extends BoxProps {}
|
||||
|
||||
function AsideFooter({ ...props }: AsideFooterProps) {
|
||||
return <Box {...props} />;
|
||||
}
|
||||
|
||||
Aside.Body = AsideContent;
|
||||
Aside.Footer = AsideFooter;
|
||||
|
||||
@@ -19,6 +19,12 @@ const ContentTabItemRoot = styled.button<ContentTabItemRootProps>`
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
|
||||
${(props) =>
|
||||
props.small &&
|
||||
`
|
||||
padding: 8px 10px;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
props.active &&
|
||||
`
|
||||
@@ -55,6 +61,8 @@ interface ContentTabsItemProps {
|
||||
title?: React.ReactNode;
|
||||
description?: React.ReactNode;
|
||||
active?: boolean;
|
||||
className?: string;
|
||||
small?: booean;
|
||||
}
|
||||
|
||||
const ContentTabsItem = ({
|
||||
@@ -62,11 +70,18 @@ const ContentTabsItem = ({
|
||||
description,
|
||||
active,
|
||||
onClick,
|
||||
small,
|
||||
className,
|
||||
}: ContentTabsItemProps) => {
|
||||
return (
|
||||
<ContentTabItemRoot active={active} onClick={onClick}>
|
||||
<ContentTabItemRoot
|
||||
active={active}
|
||||
onClick={onClick}
|
||||
className={className}
|
||||
small={small}
|
||||
>
|
||||
<ContentTabTitle>{title}</ContentTabTitle>
|
||||
<ContentTabDesc>{description}</ContentTabDesc>
|
||||
{description && <ContentTabDesc>{description}</ContentTabDesc>}
|
||||
</ContentTabItemRoot>
|
||||
);
|
||||
};
|
||||
@@ -77,6 +92,7 @@ interface ContentTabsProps {
|
||||
onChange?: (value: string) => void;
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
small?: boolean;
|
||||
}
|
||||
|
||||
export function ContentTabs({
|
||||
@@ -85,6 +101,7 @@ export function ContentTabs({
|
||||
onChange,
|
||||
children,
|
||||
className,
|
||||
small,
|
||||
}: ContentTabsProps) {
|
||||
const [localValue, handleItemChange] = useUncontrolled<string>({
|
||||
initialValue,
|
||||
@@ -102,6 +119,7 @@ export function ContentTabs({
|
||||
{...tab.props}
|
||||
active={localValue === tab.props.id}
|
||||
onClick={() => handleItemChange(tab.props?.id)}
|
||||
small={small}
|
||||
/>
|
||||
))}
|
||||
</ContentTabsRoot>
|
||||
|
||||
@@ -28,11 +28,13 @@ function CategorizeTransactionAsideRoot({
|
||||
}
|
||||
return (
|
||||
<Aside title={'Categorize Bank Transaction'} onClose={handleClose}>
|
||||
<CategorizeTransactionTabsBoot
|
||||
uncategorizedTransactionId={uncategorizedTransactionId}
|
||||
>
|
||||
<CategorizeTransactionTabs />
|
||||
</CategorizeTransactionTabsBoot>
|
||||
<Aside.Body>
|
||||
<CategorizeTransactionTabsBoot
|
||||
uncategorizedTransactionId={uncategorizedTransactionId}
|
||||
>
|
||||
<CategorizeTransactionTabs />
|
||||
</CategorizeTransactionTabsBoot>
|
||||
</Aside.Body>
|
||||
</Aside>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useAccounts, useBranches } from '@/hooks/query';
|
||||
import { Spinner } from '@blueprintjs/core';
|
||||
import React from 'react';
|
||||
|
||||
interface MatchingReconcileTransactionBootProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
interface MatchingReconcileTransactionBootValue {}
|
||||
|
||||
const MatchingReconcileTransactionBootContext =
|
||||
React.createContext<MatchingReconcileTransactionBootValue>(
|
||||
{} as MatchingReconcileTransactionBootValue,
|
||||
);
|
||||
|
||||
export function MatchingReconcileTransactionBoot({
|
||||
children,
|
||||
}: MatchingReconcileTransactionBootProps) {
|
||||
const { data: accounts, isLoading: isAccountsLoading } = useAccounts({}, {});
|
||||
const { data: branches, isLoading: isBranchesLoading } = useBranches({}, {});
|
||||
|
||||
const provider = {
|
||||
accounts,
|
||||
branches,
|
||||
isAccountsLoading,
|
||||
isBranchesLoading,
|
||||
};
|
||||
const isLoading = isAccountsLoading || isBranchesLoading;
|
||||
|
||||
if (isLoading) {
|
||||
return <Spinner size={20} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<MatchingReconcileTransactionBootContext.Provider value={provider}>
|
||||
{children}
|
||||
</MatchingReconcileTransactionBootContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useMatchingReconcileTransactionBoot = () =>
|
||||
React.useContext<MatchingReconcileTransactionBootValue>(
|
||||
MatchingReconcileTransactionBootContext,
|
||||
);
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
.content{
|
||||
padding: 18px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 11px 20px;
|
||||
border-top: 1px solid #ced4db;
|
||||
}
|
||||
|
||||
.form{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 0;
|
||||
|
||||
:global .bp4-form-group{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
:global .bp4-input {
|
||||
line-height: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.asideContent{
|
||||
background: #F6F7F9;
|
||||
height: 335px;
|
||||
}
|
||||
|
||||
.asideRoot {
|
||||
flex: 1 1 0;
|
||||
box-shadow: 0 0 0 1px rgba(17,20,24,.1),0 1px 1px rgba(17,20,24,.2),0 2px 6px rgba(17,20,24,.2);
|
||||
}
|
||||
|
||||
.asideFooter {
|
||||
background: #F6F7F9;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import * as Yup from 'yup';
|
||||
|
||||
export const MatchingReconcileFormSchema = Yup.object().shape({
|
||||
type: Yup.string().required().label('Type'),
|
||||
date: Yup.string().required().label('Date'),
|
||||
amount: Yup.string().required().label('Amount'),
|
||||
memo: Yup.string().required().label('Memo'),
|
||||
referenceNo: Yup.string().label('Refernece #'),
|
||||
category: Yup.string().required().label('Categogry'),
|
||||
});
|
||||
@@ -0,0 +1,199 @@
|
||||
// @ts-nocheck
|
||||
import * as R from 'ramda';
|
||||
import { Button, Intent, Position, Tag } from '@blueprintjs/core';
|
||||
import { Form, Formik, FormikValues, useFormikContext } from 'formik';
|
||||
import {
|
||||
AccountsSelect,
|
||||
AppToaster,
|
||||
Box,
|
||||
BranchSelect,
|
||||
FDateInput,
|
||||
FFormGroup,
|
||||
FInputGroup,
|
||||
FMoneyInputGroup,
|
||||
Group,
|
||||
} from '@/components';
|
||||
import { Aside } from '@/components/Aside/Aside';
|
||||
import { momentFormatter } from '@/utils';
|
||||
import styles from './MatchingReconcileTransactionForm.module.scss';
|
||||
import { ContentTabs } from '@/components/ContentTabs';
|
||||
import { withBankingActions } from '../../withBankingActions';
|
||||
import {
|
||||
MatchingReconcileTransactionBoot,
|
||||
useMatchingReconcileTransactionBoot,
|
||||
} from './MatchingReconcileTransactionBoot';
|
||||
import { useCreateCashflowTransaction } from '@/hooks/query';
|
||||
import { useAccountTransactionsContext } from '../../AccountTransactions/AccountTransactionsProvider';
|
||||
import { MatchingReconcileFormSchema } from './MatchingReconcileTransactionForm.schema';
|
||||
import { initialValues } from './_utils';
|
||||
|
||||
function MatchingReconcileTransactionFormRoot({
|
||||
closeReconcileMatchingTransaction,
|
||||
}) {
|
||||
// Mutation create cashflow transaction.
|
||||
const { mutateAsync: createCashflowTransactionMutate } =
|
||||
useCreateCashflowTransaction();
|
||||
|
||||
const { accountId } = useAccountTransactionsContext();
|
||||
|
||||
const handleAsideClose = () => {
|
||||
closeReconcileMatchingTransaction();
|
||||
};
|
||||
const handleSubmit = (
|
||||
values: MatchingReconcileTransactionValues,
|
||||
{ setSubmitting }: FormikValues<MatchingReconcileTransactionValues>,
|
||||
) => {
|
||||
setSubmitting(true);
|
||||
const _values = transformToReq(values, accountId);
|
||||
|
||||
createCashflowTransactionMutate(_values)
|
||||
.then(() => {
|
||||
setSubmitting(false);
|
||||
|
||||
AppToaster.show({
|
||||
message: 'The transaction has been created.',
|
||||
intent: Intent.SUCCESS,
|
||||
});
|
||||
closeReconcileMatchingTransaction();
|
||||
})
|
||||
.catch((error) => {
|
||||
setSubmitting(false);
|
||||
|
||||
AppToaster.show({
|
||||
message: 'Something went wrong.',
|
||||
intent: Intent.DANGER,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Aside
|
||||
title={'Create Reconcile Transactions'}
|
||||
className={styles.asideRoot}
|
||||
onClose={handleAsideClose}
|
||||
>
|
||||
<MatchingReconcileTransactionBoot>
|
||||
<Formik
|
||||
onSubmit={handleSubmit}
|
||||
initialValues={initialValues}
|
||||
validationSchema={MatchingReconcileFormSchema}
|
||||
>
|
||||
<Form className={styles.form}>
|
||||
<Aside.Body className={styles.asideContent}>
|
||||
<CreateReconcileTransactionContent />
|
||||
</Aside.Body>
|
||||
|
||||
<Aside.Footer className={styles.asideFooter}>
|
||||
<MatchingReconcileTransactionFooter />
|
||||
</Aside.Footer>
|
||||
</Form>
|
||||
</Formik>
|
||||
</MatchingReconcileTransactionBoot>
|
||||
</Aside>
|
||||
);
|
||||
}
|
||||
|
||||
export const MatchingReconcileTransactionForm = R.compose(withBankingActions)(
|
||||
MatchingReconcileTransactionFormRoot,
|
||||
);
|
||||
|
||||
export function MatchingReconcileTransactionFooter() {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<Box className={styles.footer}>
|
||||
<Group>
|
||||
<Button
|
||||
fill
|
||||
type={'submit'}
|
||||
intent={Intent.PRIMARY}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Group>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function ReconcileMatchingType() {
|
||||
const { setFieldValue, values } =
|
||||
useFormikContext<MatchingReconcileFormValues>();
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
setFieldValue('type', value);
|
||||
};
|
||||
return (
|
||||
<ContentTabs
|
||||
value={values?.type || 'deposit'}
|
||||
onChange={handleChange}
|
||||
small
|
||||
>
|
||||
<ContentTabs.Tab id={'deposit'} title={'Deposit'} />
|
||||
<ContentTabs.Tab id={'withdrawal'} title={'Withdrawal'} />
|
||||
</ContentTabs>
|
||||
);
|
||||
}
|
||||
|
||||
export function CreateReconcileTransactionContent() {
|
||||
const { accounts, branches } = useMatchingReconcileTransactionBoot();
|
||||
|
||||
return (
|
||||
<Box className={styles.content}>
|
||||
<ReconcileMatchingType />
|
||||
|
||||
<FFormGroup label={'Date'} name={'date'}>
|
||||
<FDateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
name={'date'}
|
||||
formatDate={(date) => date.toLocaleString()}
|
||||
popoverProps={{
|
||||
position: Position.LEFT,
|
||||
}}
|
||||
inputProps={{ fill: true }}
|
||||
fill
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
label={'Amount'}
|
||||
name={'amount'}
|
||||
labelInfo={<Tag minimal>Required</Tag>}
|
||||
>
|
||||
<FMoneyInputGroup name={'amount'} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
label={'Category'}
|
||||
name={'category'}
|
||||
labelInfo={<Tag minimal>Required</Tag>}
|
||||
>
|
||||
<AccountsSelect
|
||||
name={'category'}
|
||||
items={accounts}
|
||||
popoverProps={{ minimal: false, position: Position.LEFT }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup
|
||||
label={'Memo'}
|
||||
name={'memo'}
|
||||
labelInfo={<Tag minimal>Required</Tag>}
|
||||
>
|
||||
<FInputGroup name={'memo'} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup label={'Reference No.'} name={'reference_no'}>
|
||||
<FInputGroup name={'reference_no'} />
|
||||
</FFormGroup>
|
||||
|
||||
<FFormGroup name={'branchId'} label={'Branch'}>
|
||||
<BranchSelect
|
||||
name={'branchId'}
|
||||
branches={branches}
|
||||
popoverProps={{ minimal: true }}
|
||||
/>
|
||||
</FFormGroup>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface MatchingReconcileTransactionValues {
|
||||
type: string;
|
||||
date: string;
|
||||
amount: string;
|
||||
memo: string;
|
||||
referenceNo: string;
|
||||
category: string;
|
||||
branchId: string;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { MatchingReconcileTransactionValues } from './_types';
|
||||
|
||||
export const transformToReq = (
|
||||
values: MatchingReconcileTransactionValues,
|
||||
bankAccountId: number,
|
||||
) => {
|
||||
return {
|
||||
date: values.date,
|
||||
reference_no: values.referenceNo,
|
||||
transaction_type:
|
||||
values.type === 'deposit' ? 'other_income' : 'other_expense',
|
||||
description: values.memo,
|
||||
amount: values.amount,
|
||||
credit_account_id: values.category,
|
||||
cashflow_account_id: bankAccountId,
|
||||
branch_id: values.branchId,
|
||||
publish: true,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const initialValues = {
|
||||
type: 'deposit',
|
||||
date: '',
|
||||
amount: '',
|
||||
memo: '',
|
||||
referenceNo: '',
|
||||
category: '',
|
||||
branchId: '',
|
||||
};
|
||||
@@ -25,6 +25,8 @@ import {
|
||||
withBankingActions,
|
||||
} from '../withBankingActions';
|
||||
import styles from './CategorizeTransactionAside.module.scss';
|
||||
import { MatchingReconcileTransactionForm } from './MatchingReconcileTransactionAside/MatchingReconcileTransactionForm';
|
||||
import { withBanking } from '../withBanking';
|
||||
|
||||
const initialValues = {
|
||||
matched: {},
|
||||
@@ -37,6 +39,9 @@ const initialValues = {
|
||||
function MatchingBankTransactionRoot({
|
||||
// #withBankingActions
|
||||
closeMatchingTransactionAside,
|
||||
|
||||
// #withBanking
|
||||
openReconcileMatchingTransaction,
|
||||
}) {
|
||||
const { uncategorizedTransactionId } = useCategorizeTransactionTabsBoot();
|
||||
const { mutateAsync: matchTransaction } = useMatchUncategorizedTransaction();
|
||||
@@ -81,16 +86,23 @@ function MatchingBankTransactionRoot({
|
||||
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
|
||||
<>
|
||||
<MatchingBankTransactionContent />
|
||||
<MatchTransactionFooter />
|
||||
|
||||
{openReconcileMatchingTransaction && (
|
||||
<MatchingReconcileTransactionForm />
|
||||
)}
|
||||
{!openReconcileMatchingTransaction && <MatchTransactionFooter />}
|
||||
</>
|
||||
</Formik>
|
||||
</MatchingTransactionBoot>
|
||||
);
|
||||
}
|
||||
|
||||
export const MatchingBankTransaction = R.compose(withBankingActions)(
|
||||
MatchingBankTransactionRoot,
|
||||
);
|
||||
export const MatchingBankTransaction = R.compose(
|
||||
withBankingActions,
|
||||
withBanking(({ openReconcileMatchingTransaction }) => ({
|
||||
openReconcileMatchingTransaction,
|
||||
})),
|
||||
)(MatchingBankTransactionRoot);
|
||||
|
||||
function MatchingBankTransactionContent() {
|
||||
return (
|
||||
@@ -212,7 +224,10 @@ interface MatchTransctionFooterProps extends WithBankingActionsProps {}
|
||||
* @returns {React.ReactNode}
|
||||
*/
|
||||
const MatchTransactionFooter = R.compose(withBankingActions)(
|
||||
({ closeMatchingTransactionAside }: MatchTransctionFooterProps) => {
|
||||
({
|
||||
closeMatchingTransactionAside,
|
||||
openReconcileMatchingTransaction,
|
||||
}: MatchTransctionFooterProps) => {
|
||||
const { submitForm, isSubmitting } = useFormikContext();
|
||||
const totalPending = useGetPendingAmountMatched();
|
||||
const showReconcileLink = useIsShowReconcileTransactionLink();
|
||||
@@ -224,13 +239,21 @@ const MatchTransactionFooter = R.compose(withBankingActions)(
|
||||
const handleSubmitBtnClick = () => {
|
||||
submitForm();
|
||||
};
|
||||
const handleReconcileTransaction = () => {
|
||||
openReconcileMatchingTransaction();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box className={styles.footer}>
|
||||
<Box className={styles.footerTotal}>
|
||||
<Group position={'apart'}>
|
||||
{showReconcileLink && (
|
||||
<AnchorButton small minimal intent={Intent.PRIMARY}>
|
||||
<AnchorButton
|
||||
small
|
||||
minimal
|
||||
intent={Intent.PRIMARY}
|
||||
onClick={handleReconcileTransaction}
|
||||
>
|
||||
Add Reconcile Transaction +
|
||||
</AnchorButton>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,8 @@ export const withBanking = (mapState) => {
|
||||
openMatchingTransactionAside: state.plaid.openMatchingTransactionAside,
|
||||
selectedUncategorizedTransactionId:
|
||||
state.plaid.uncategorizedTransactionIdForMatching,
|
||||
openReconcileMatchingTransaction:
|
||||
state.plaid.openReconcileMatchingTransaction,
|
||||
};
|
||||
return mapState ? mapState(mapped, state, props) : mapped;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,8 @@ import { connect } from 'react-redux';
|
||||
import {
|
||||
closeMatchingTransactionAside,
|
||||
setUncategorizedTransactionIdForMatching,
|
||||
openReconcileMatchingTransaction,
|
||||
closeReconcileMatchingTransaction,
|
||||
} from '@/store/banking/banking.reducer';
|
||||
|
||||
export interface WithBankingActionsProps {
|
||||
@@ -9,6 +11,8 @@ export interface WithBankingActionsProps {
|
||||
setUncategorizedTransactionIdForMatching: (
|
||||
uncategorizedTransactionId: number,
|
||||
) => void;
|
||||
openReconcileMatchingTransaction: () => void;
|
||||
closeReconcileMatchingTransaction: () => void;
|
||||
}
|
||||
|
||||
const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
|
||||
@@ -20,6 +24,10 @@ const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
|
||||
dispatch(
|
||||
setUncategorizedTransactionIdForMatching(uncategorizedTransactionId),
|
||||
),
|
||||
openReconcileMatchingTransaction: () =>
|
||||
dispatch(openReconcileMatchingTransaction()),
|
||||
closeReconcileMatchingTransaction: () =>
|
||||
dispatch(closeReconcileMatchingTransaction()),
|
||||
});
|
||||
|
||||
export const withBankingActions = connect<
|
||||
|
||||
@@ -4,6 +4,7 @@ interface StorePlaidState {
|
||||
plaidToken: string;
|
||||
openMatchingTransactionAside: boolean;
|
||||
uncategorizedTransactionIdForMatching: number | null;
|
||||
openReconcileMatchingTransaction: boolean;
|
||||
}
|
||||
|
||||
export const PlaidSlice = createSlice({
|
||||
@@ -12,6 +13,7 @@ export const PlaidSlice = createSlice({
|
||||
plaidToken: '',
|
||||
openMatchingTransactionAside: false,
|
||||
uncategorizedTransactionIdForMatching: null,
|
||||
openReconcileMatchingTransaction: false,
|
||||
} as StorePlaidState,
|
||||
reducers: {
|
||||
setPlaidId: (state: StorePlaidState, action: PayloadAction<string>) => {
|
||||
@@ -34,6 +36,14 @@ export const PlaidSlice = createSlice({
|
||||
state.openMatchingTransactionAside = false;
|
||||
state.uncategorizedTransactionIdForMatching = null;
|
||||
},
|
||||
|
||||
openReconcileMatchingTransaction: (state: StorePlaidState) => {
|
||||
state.openReconcileMatchingTransaction = true;
|
||||
},
|
||||
|
||||
closeReconcileMatchingTransaction: (state: StorePlaidState) => {
|
||||
state.openReconcileMatchingTransaction = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -42,6 +52,8 @@ export const {
|
||||
resetPlaidId,
|
||||
setUncategorizedTransactionIdForMatching,
|
||||
closeMatchingTransactionAside,
|
||||
openReconcileMatchingTransaction,
|
||||
closeReconcileMatchingTransaction,
|
||||
} = PlaidSlice.actions;
|
||||
|
||||
export const getPlaidToken = (state: any) => state.plaid.plaidToken;
|
||||
|
||||
Reference in New Issue
Block a user