feat: toggle banking matching aside

This commit is contained in:
Ahmed Bouhuolia
2024-06-26 19:33:01 +02:00
parent 7a9c7209bc
commit d305c7ad32
14 changed files with 215 additions and 44 deletions

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { AppShellProvider } from './AppShellProvider';
import { AppShellProvider, useAppShellContext } from './AppShellProvider';
import { Box } from '../Layout';
import styles from './AppShell.module.scss';
@@ -8,16 +8,26 @@ interface AppShellProps {
mainProps: any;
asideProps: any;
children: React.ReactNode;
hideAside?: boolean;
hideMain?: boolean;
}
export function AppShell({
asideProps,
mainProps,
topbarOffset = 0,
hideAside = false,
hideMain = false,
...restProps
}: AppShellProps) {
return (
<AppShellProvider mainProps={mainProps} asideProps={asideProps} topbarOffset={topbarOffset}>
<AppShellProvider
mainProps={mainProps}
asideProps={asideProps}
topbarOffset={topbarOffset}
hideAside={hideAside}
hideMain={hideMain}
>
<Box {...restProps} className={styles.root} />
</AppShellProvider>
);
@@ -27,6 +37,12 @@ AppShell.Main = AppShellMain;
AppShell.Aside = AppShellAside;
function AppShellMain({ ...props }) {
const { hideMain } = useAppShellContext();
if (hideMain === true) {
return null;
}
return <Box {...props} className={styles.main} />;
}
@@ -35,5 +51,11 @@ interface AppShellAsideProps {
}
function AppShellAside({ ...props }: AppShellAsideProps) {
const { hideAside } = useAppShellContext();
console.log(hideAside, 'hideAsidehideAsidehideAsidehideAside');
if (hideAside === true) {
return null;
}
return <Box {...props} className={styles.aside} />;
}

View File

@@ -1,22 +1,37 @@
// @ts-nocheck
import React, { createContext } from 'react';
interface AppShellContextValue {
topbarOffset: number
interface ContentShellCommonValue {
mainProps: any;
asideProps: any;
topbarOffset: number;
hideAside: boolean;
hideMain: boolean;
}
interface AppShellContextValue extends ContentShellCommonValue {
topbarOffset: number;
}
const AppShellContext = createContext<AppShellContextValue>(
{} as AppShellContextValue,
);
interface AppShellProviderProps {
interface AppShellProviderProps extends ContentShellCommonValue {
children: React.ReactNode;
mainProps: any;
asideProps: any;
topbarOffset: number;
}
export function AppShellProvider({ topbarOffset, ...props }: AppShellProviderProps) {
const provider = { topbarOffset } as AppShellContextValue;
export function AppShellProvider({
topbarOffset,
hideAside,
hideMain,
...props
}: AppShellProviderProps) {
const provider = {
topbarOffset,
hideAside,
hideMain,
} as AppShellContextValue;
return <AppShellContext.Provider value={provider} {...props} />;
}

View File

@@ -1,5 +1,6 @@
// @ts-nocheck
import React, { Suspense } from 'react';
import * as R from 'ramda';
import { Spinner } from '@blueprintjs/core';
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
@@ -16,14 +17,18 @@ import { AccountTransactionsProgressBar } from './components';
import { AccountTransactionsFilterTabs } from './AccountTransactionsFilterTabs';
import { AppShell } from '@/components/AppShell/AppShell';
import { CategorizeTransactionAside } from '../CategorizeTransactionAside/CategorizeTransactionAside';
import { withBanking } from '../withBanking';
/**
* Account transactions list.
*/
function AccountTransactionsList() {
function AccountTransactionsListRoot({
// #withBanking
openMatchingTransactionAside,
}) {
return (
<AccountTransactionsProvider>
<AppShell>
<AppShell hideAside={!openMatchingTransactionAside}>
<AppShell.Main>
<AccountTransactionsActionsBar />
<AccountTransactionsDetailsBar />
@@ -46,7 +51,14 @@ function AccountTransactionsList() {
);
}
export default AccountTransactionsList;
export default R.compose(
withBanking(
({ selectedUncategorizedTransactionId, openMatchingTransactionAside }) => ({
selectedUncategorizedTransactionId,
openMatchingTransactionAside,
}),
),
)(AccountTransactionsListRoot);
const AccountsTransactionsAll = React.lazy(
() => import('./AccountsTransactionsAll'),

View File

@@ -15,6 +15,7 @@ import { TABLES } from '@/constants/tables';
import withSettings from '@/containers/Settings/withSettings';
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { withBankingActions } from '../withBankingActions';
import { useMemorizedColumnsWidths } from '@/hooks';
import {
@@ -24,7 +25,6 @@ import {
import { useAccountUncategorizedTransactionsContext } from './AllTransactionsUncategorizedBoot';
import { compose } from '@/utils';
import { DRAWERS } from '@/constants/drawers';
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { Intent } from '@blueprintjs/core';
@@ -35,6 +35,9 @@ function AccountTransactionsDataTable({
// #withSettings
cashflowTansactionsTableSize,
// #withBankingActions
setUncategorizedTransactionIdForMatching,
// #withDrawerActions
openDrawer,
}) {
@@ -53,10 +56,8 @@ function AccountTransactionsDataTable({
useMemorizedColumnsWidths(TABLES.UNCATEGORIZED_CASHFLOW_TRANSACTION);
// Handle cell click.
const handleCellClick = (cell, event) => {
openDrawer(DRAWERS.CATEGORIZE_TRANSACTION, {
uncategorizedTransactionId: cell.row.original.id,
});
const handleCellClick = (cell) => {
setUncategorizedTransactionIdForMatching(cell.row.original.id);
};
// Handle exclude transaction.
const handleExcludeTransaction = (transaction) => {
@@ -111,6 +112,7 @@ export default compose(
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
})),
withDrawerActions,
withBankingActions,
)(AccountTransactionsDataTable);
const DashboardConstrantTable = styled(DataTable)`

View File

@@ -1,10 +1,16 @@
// @ts-nocheck
import styled from 'styled-components';
import * as R from 'ramda';
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
import AccountTransactionsUncategorizedTable from './AccountTransactionsUncategorizedTable';
import { AccountUncategorizedTransactionsBoot } from './AllTransactionsUncategorizedBoot';
import {
WithBankingActionsProps,
withBankingActions,
} from '../withBankingActions';
import { useEffect } from 'react';
const Box = styled.div`
margin: 30px 15px;
@@ -18,7 +24,18 @@ const CashflowTransactionsTableCard = styled.div`
flex: 0 1;
`;
export default function AllTransactionsUncategorized() {
interface AllTransactionsUncategorizedProps extends WithBankingActionsProps {}
function AllTransactionsUncategorizedRoot({
// #withBankingActions
closeMatchingTransactionAside,
}: AllTransactionsUncategorizedProps) {
useEffect(
() => () => {
closeMatchingTransactionAside();
},
[closeMatchingTransactionAside],
);
return (
<AccountUncategorizedTransactionsBoot>
<Box>
@@ -29,3 +46,5 @@ export default function AllTransactionsUncategorized() {
</AccountUncategorizedTransactionsBoot>
);
}
export default R.compose(withBankingActions)(AllTransactionsUncategorizedRoot);

View File

@@ -1,8 +1,7 @@
// @ts-nocheck
import React, { useMemo } from 'react';
import { first } from 'lodash';
import { DrawerHeaderContent, DrawerLoading } from '@/components';
import { DRAWERS } from '@/constants/drawers';
import { DrawerLoading } from '@/components';
import {
useAccounts,
useBranches,
@@ -56,10 +55,6 @@ function CategorizeTransactionBoot({ uncategorizedTransactionId, ...props }) {
return (
<DrawerLoading loading={isLoading}>
<DrawerHeaderContent
name={DRAWERS.CATEGORIZE_TRANSACTION}
title={'Categorize Transaction'}
/>
<CategorizeTransactionBootContext.Provider value={provider} {...props} />
</DrawerLoading>
);

View File

@@ -4,9 +4,9 @@ import { DrawerBody } from '@/components';
import { CategorizeTransactionBoot } from './CategorizeTransactionBoot';
import { CategorizeTransactionForm } from './CategorizeTransactionForm';
export default function CategorizeTransactionContent({
uncategorizedTransactionId,
}) {
export function CategorizeTransactionContent({}) {
const uncategorizedTransactionId = 4;
return (
<CategorizeTransactionBoot
uncategorizedTransactionId={uncategorizedTransactionId}
@@ -18,7 +18,7 @@ export default function CategorizeTransactionContent({
);
}
export const CategorizeTransactionDrawerBody = styled(DrawerBody)`
const CategorizeTransactionDrawerBody = styled(DrawerBody)`
padding: 20px;
background-color: #fff;
`;

View File

@@ -48,9 +48,9 @@ export const CategorizeTransactionFormFooter = R.compose(withDrawerActions)(
);
const Root = styled.div`
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #fff;
// position: absolute;
// bottom: 0;
// left: 0;
// right: 0;
// background: #fff;
`;

View File

@@ -1,10 +1,28 @@
import * as R from 'ramda';
import { Aside } from '@/components/Aside/Aside';
import { CategorizeTransactionTabs } from './CategorizeTransactionTabs';
import {
WithBankingActionsProps,
withBankingActions,
} from '../withBankingActions';
interface CategorizeTransactionAsideProps extends WithBankingActionsProps {}
function CategorizeTransactionAsideRoot({
// #withBankingActions
closeMatchingTransactionAside,
}: CategorizeTransactionAsideProps) {
const handleClose = () => {
closeMatchingTransactionAside();
};
export function CategorizeTransactionAside() {
return (
<Aside title={'Categorize Bank Transaction'}>
<Aside title={'Categorize Bank Transaction'} onClose={handleClose}>
<CategorizeTransactionTabs />
</Aside>
);
}
export const CategorizeTransactionAside = R.compose(withBankingActions)(
CategorizeTransactionAsideRoot,
);

View File

@@ -1,9 +1,7 @@
import { Tab, Tabs } from '@blueprintjs/core';
import {
CategorizeBankTransactionContent,
MatchingBankTransaction,
} from './MatchingTransaction';
import { MatchingBankTransaction } from './MatchingTransaction';
import styles from './CategorizeTransactionTabs.module.scss';
import { CategorizeTransactionContent } from '../CategorizeTransaction/drawers/CategorizeTransactionDrawer/CategorizeTransactionContent';
export function CategorizeTransactionTabs() {
return (
@@ -11,7 +9,7 @@ export function CategorizeTransactionTabs() {
<Tab
id="categorize"
title="Categorize Transaction"
panel={<CategorizeBankTransactionContent />}
panel={<CategorizeTransactionContent />}
/>
<Tab
id="matching"

View File

@@ -0,0 +1,15 @@
// @ts-nocheck
import { connect } from 'react-redux';
export const withBanking = (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
openMatchingTransactionAside: state.plaid.openMatchingTransactionAside,
selectedUncategorizedTransactionId:
state.plaid.uncategorizedTransactionIdForMatching,
};
return mapState ? mapState(mapped, state, props) : mapped;
};
return connect(mapStateToProps);
};

View File

@@ -0,0 +1,30 @@
import { connect } from 'react-redux';
import {
closeMatchingTransactionAside,
setUncategorizedTransactionIdForMatching,
} from '@/store/banking/banking.reducer';
export interface WithBankingActionsProps {
closeMatchingTransactionAside: () => void;
setUncategorizedTransactionIdForMatching: (
uncategorizedTransactionId: number,
) => void;
}
const mapDipatchToProps = (dispatch: any): WithBankingActionsProps => ({
closeMatchingTransactionAside: () =>
dispatch(closeMatchingTransactionAside()),
setUncategorizedTransactionIdForMatching: (
uncategorizedTransactionId: number,
) =>
dispatch(
setUncategorizedTransactionIdForMatching(uncategorizedTransactionId),
),
});
export const withBankingActions = connect<
null,
WithBankingActionsProps,
{},
any
>(null, mapDipatchToProps);

View File

@@ -0,0 +1,21 @@
// @ts-nocheck
import t from '@/store/types';
/**
* Sets global table state of the table.
* @param {object} queries
*/
export const setUncategorizedTransactionIdForMatching = (
uncategorizedTransactionId: number,
) => {
return {
type: 'setUncategorizedTransactionIdForMatching',
payload: uncategorizedTransactionId,
};
};
export const closeMatchingTransactionAside = () => {
return {
type: 'closeMatchingTransactionAside',
};
};

View File

@@ -2,22 +2,46 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit';
interface StorePlaidState {
plaidToken: string;
openMatchingTransactionAside: boolean;
uncategorizedTransactionIdForMatching: number | null;
}
export const PlaidSlice = createSlice({
name: 'plaid',
initialState: {
plaidToken: '',
openMatchingTransactionAside: false,
uncategorizedTransactionIdForMatching: null,
} as StorePlaidState,
reducers: {
setPlaidId: (state: StorePlaidState, action: PayloadAction<string>) => {
state.plaidToken = action.payload;
},
resetPlaidId: (state: StorePlaidState) => {
state.plaidToken = '';
}
},
setUncategorizedTransactionIdForMatching: (
state: StorePlaidState,
action: PayloadAction<number>,
) => {
state.openMatchingTransactionAside = true;
state.uncategorizedTransactionIdForMatching = action.payload;
},
closeMatchingTransactionAside: (state: StorePlaidState) => {
state.openMatchingTransactionAside = false;
state.uncategorizedTransactionIdForMatching = null;
},
},
});
export const { setPlaidId, resetPlaidId } = PlaidSlice.actions;
export const getPlaidToken = (state: any) => state.plaid.plaidToken;
export const {
setPlaidId,
resetPlaidId,
setUncategorizedTransactionIdForMatching,
closeMatchingTransactionAside,
} = PlaidSlice.actions;
export const getPlaidToken = (state: any) => state.plaid.plaidToken;