fix: infinity scrolling of bank account transactions

This commit is contained in:
Ahmed Bouhuolia
2024-08-05 20:57:13 +02:00
parent 8e99a31455
commit 64c0732e5f
8 changed files with 124 additions and 65 deletions

View File

@@ -1,5 +1,9 @@
import React from 'react'; // @ts-nocheck
import { AppShellProvider, useAppShellContext } from './AppContentShellProvider'; import React, { forwardRef, Ref } from 'react';
import {
AppShellProvider,
useAppShellContext,
} from './AppContentShellProvider';
import { Box, BoxProps } from '../../Layout'; import { Box, BoxProps } from '../../Layout';
import styles from './AppContentShell.module.scss'; import styles from './AppContentShell.module.scss';
@@ -12,14 +16,18 @@ interface AppContentShellProps {
hideMain?: boolean; hideMain?: boolean;
} }
export function AppContentShell({ export const AppContentShell = forwardRef(
(
{
asideProps, asideProps,
mainProps, mainProps,
topbarOffset = 0, topbarOffset = 0,
hideAside = false, hideAside = false,
hideMain = false, hideMain = false,
...restProps ...restProps
}: AppContentShellProps) { }: AppContentShellProps,
ref: Ref<HTMLDivElement>,
) => {
return ( return (
<AppShellProvider <AppShellProvider
mainProps={mainProps} mainProps={mainProps}
@@ -28,34 +36,53 @@ export function AppContentShell({
hideAside={hideAside} hideAside={hideAside}
hideMain={hideMain} hideMain={hideMain}
> >
<Box {...restProps} className={styles.root} /> <Box {...restProps} className={styles.root} ref={ref} />
</AppShellProvider> </AppShellProvider>
); );
} },
);
AppContentShell.displayName = 'AppContentShell';
interface AppContentShellMainProps extends BoxProps {} interface AppContentShellMainProps extends BoxProps {}
function AppContentShellMain({ ...props }: AppContentShellMainProps) { /**
* Main content of the app shell.
* @param {AppContentShellMainProps} props -
* @returns {React.ReactNode}
*/
const AppContentShellMain = forwardRef(
({ ...props }: AppContentShellMainProps, ref: Ref<HTMLDivElement>) => {
const { hideMain } = useAppShellContext(); const { hideMain } = useAppShellContext();
if (hideMain === true) { if (hideMain === true) {
return null; return null;
} }
return <Box {...props} className={styles.main} />; return <Box {...props} className={styles.main} ref={ref} />;
} },
);
AppContentShellMain.displayName = 'AppContentShellMain';
interface AppContentShellAsideProps extends BoxProps { interface AppContentShellAsideProps extends BoxProps {
children: React.ReactNode; children: React.ReactNode;
} }
function AppContentShellAside({ ...props }: AppContentShellAsideProps) { /**
* Aside content of the app shell.
* @param {AppContentShellAsideProps} props
* @returns {React.ReactNode}
*/
const AppContentShellAside = forwardRef(
({ ...props }: AppContentShellAsideProps, ref: Ref<HTMLDivElement>) => {
const { hideAside } = useAppShellContext(); const { hideAside } = useAppShellContext();
if (hideAside === true) { if (hideAside === true) {
return null; return null;
} }
return <Box {...props} className={styles.aside} />; return <Box {...props} className={styles.aside} ref={ref} />;
} },
);
AppContentShellAside.displayName = 'AppContentShellAside';
AppContentShell.Main = AppContentShellMain; AppContentShell.Main = AppContentShellMain;
AppContentShell.Aside = AppContentShellAside; AppContentShell.Aside = AppContentShellAside;

View File

@@ -25,14 +25,13 @@ function TableVirtualizedListRow({ index, isScrolling, isVisible, style }) {
export function TableVirtualizedListRows() { export function TableVirtualizedListRows() {
const { const {
table: { page }, table: { page },
props: { vListrowHeight, vListOverscanRowCount }, props: { vListrowHeight, vListOverscanRowCount, windowScrollerProps },
} = useContext(TableContext); } = useContext(TableContext);
// Dashboard content pane. // Dashboard content pane.
const dashboardContentPane = React.useMemo( const scrollElement =
() => document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`), windowScrollerProps?.scrollElement ||
[], document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`);
);
const rowRenderer = React.useCallback( const rowRenderer = React.useCallback(
({ key, ...args }) => <TableVirtualizedListRow {...args} key={key} />, ({ key, ...args }) => <TableVirtualizedListRow {...args} key={key} />,
@@ -40,7 +39,7 @@ export function TableVirtualizedListRows() {
); );
return ( return (
<WindowScroller scrollElement={dashboardContentPane}> <WindowScroller scrollElement={scrollElement}>
{({ height, isScrolling, onChildScroll, scrollTop }) => ( {({ height, isScrolling, onChildScroll, scrollTop }) => (
<AutoSizer disableHeight> <AutoSizer disableHeight>
{({ width }) => ( {({ width }) => (

View File

@@ -1,12 +1,15 @@
import React from 'react'; import React, { forwardRef, Ref } from 'react';
import { HTMLDivProps, Props } from '@blueprintjs/core'; import { HTMLDivProps, Props } from '@blueprintjs/core';
export interface BoxProps extends Props, HTMLDivProps { export interface BoxProps extends Props, HTMLDivProps {
className?: string; className?: string;
} }
export function Box({ className, ...rest }: BoxProps) { export const Box = forwardRef(
({ className, ...rest }: BoxProps, ref: Ref<HTMLDivElement>) => {
const Element = 'div'; const Element = 'div';
return <Element className={className} {...rest} />; return <Element className={className} ref={ref} {...rest} />;
} },
);
Box.displayName = '@bigcapital/Box';

View File

@@ -29,7 +29,18 @@ function AccountTransactionsListRoot({
return ( return (
<AccountTransactionsProvider> <AccountTransactionsProvider>
<AppContentShell hideAside={!openMatchingTransactionAside}> <AppContentShell hideAside={!openMatchingTransactionAside}>
<AppContentShell.Main> <AccountTransactionsMain />
<AccountTransactionsAside />
</AppContentShell>
</AccountTransactionsProvider>
);
}
function AccountTransactionsMain() {
const { setScrollableRef } = useAccountTransactionsContext();
return (
<AppContentShell.Main ref={(e) => setScrollableRef(e)}>
<AccountTransactionsActionsBar /> <AccountTransactionsActionsBar />
<AccountTransactionsDetailsBar /> <AccountTransactionsDetailsBar />
<AccountTransactionsProgressBar /> <AccountTransactionsProgressBar />
@@ -42,12 +53,14 @@ function AccountTransactionsListRoot({
</Suspense> </Suspense>
</DashboardPageContent> </DashboardPageContent>
</AppContentShell.Main> </AppContentShell.Main>
);
}
function AccountTransactionsAside() {
return (
<AppContentShell.Aside> <AppContentShell.Aside>
<CategorizeTransactionAside /> <CategorizeTransactionAside />
</AppContentShell.Aside> </AppContentShell.Aside>
</AppContentShell>
</AccountTransactionsProvider>
); );
} }

View File

@@ -1,5 +1,5 @@
// @ts-nocheck // @ts-nocheck
import React from 'react'; import React, { useRef, useState } from 'react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { DashboardInsider } from '@/components'; import { DashboardInsider } from '@/components';
import { useCashflowAccounts, useAccount } from '@/hooks/query'; import { useCashflowAccounts, useAccount } from '@/hooks/query';
@@ -41,6 +41,8 @@ function AccountTransactionsProvider({ query, ...props }) {
isLoading: isBankAccountMetaSummaryLoading, isLoading: isBankAccountMetaSummaryLoading,
} = useGetBankAccountSummaryMeta(accountId); } = useGetBankAccountSummaryMeta(accountId);
const [scrollableRef, setScrollableRef] = useState();
// Provider payload. // Provider payload.
const provider = { const provider = {
accountId, accountId,
@@ -56,6 +58,9 @@ function AccountTransactionsProvider({ query, ...props }) {
filterTab, filterTab,
setFilterTab, setFilterTab,
scrollableRef,
setScrollableRef
}; };
return ( return (

View File

@@ -16,6 +16,7 @@ import { TABLES } from '@/constants/tables';
import { useMemorizedColumnsWidths } from '@/hooks'; import { useMemorizedColumnsWidths } from '@/hooks';
import { useExcludedTransactionsColumns } from './_utils'; import { useExcludedTransactionsColumns } from './_utils';
import { useExcludedTransactionsBoot } from './ExcludedTransactionsTableBoot'; import { useExcludedTransactionsBoot } from './ExcludedTransactionsTableBoot';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { ActionsMenu } from './_components'; import { ActionsMenu } from './_components';
import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules'; import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
@@ -37,6 +38,8 @@ function ExcludedTransactionsTableRoot({
const { mutateAsync: unexcludeBankTransaction } = const { mutateAsync: unexcludeBankTransaction } =
useUnexcludeUncategorizedTransaction(); useUnexcludeUncategorizedTransaction();
const { scrollableRef } = useAccountTransactionsContext();
// Retrieve table columns. // Retrieve table columns.
const columns = useExcludedTransactionsColumns(); const columns = useExcludedTransactionsColumns();
@@ -97,6 +100,7 @@ function ExcludedTransactionsTableRoot({
className="table-constrant" className="table-constrant"
selectionColumn={true} selectionColumn={true}
onSelectedRowsChange={handleSelectedRowsChange} onSelectedRowsChange={handleSelectedRowsChange}
windowScrollerProps={{ scrollElement: scrollableRef }}
payload={{ payload={{
onRestore: handleRestoreClick, onRestore: handleRestoreClick,
}} }}

View File

@@ -20,6 +20,7 @@ import { useRecognizedTransactionsBoot } from './RecognizedTransactionsTableBoot
import { ActionsMenu } from './_components'; import { ActionsMenu } from './_components';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules'; import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { import {
WithBankingActionsProps, WithBankingActionsProps,
@@ -49,6 +50,8 @@ function RecognizedTransactionsTableRoot({
const [initialColumnsWidths, , handleColumnResizing] = const [initialColumnsWidths, , handleColumnResizing] =
useMemorizedColumnsWidths(TABLES.UNCATEGORIZED_ACCOUNT_TRANSACTIONS); useMemorizedColumnsWidths(TABLES.UNCATEGORIZED_ACCOUNT_TRANSACTIONS);
const { scrollableRef } = useAccountTransactionsContext();
// Handle cell click. // Handle cell click.
const handleCellClick = (cell, event) => { const handleCellClick = (cell, event) => {
setUncategorizedTransactionIdForMatching( setUncategorizedTransactionIdForMatching(
@@ -102,6 +105,7 @@ function RecognizedTransactionsTableRoot({
vListOverscanRowCount={0} vListOverscanRowCount={0}
initialColumnsWidths={initialColumnsWidths} initialColumnsWidths={initialColumnsWidths}
onColumnResizing={handleColumnResizing} onColumnResizing={handleColumnResizing}
windowScrollerProps={{ scrollElement: scrollableRef }}
noResults={<RecognizedTransactionsTableNoResults />} noResults={<RecognizedTransactionsTableNoResults />}
className="table-constrant" className="table-constrant"
payload={{ payload={{

View File

@@ -22,6 +22,7 @@ import { useMemorizedColumnsWidths } from '@/hooks';
import { useAccountUncategorizedTransactionsContext } from '../AllTransactionsUncategorizedBoot'; import { useAccountUncategorizedTransactionsContext } from '../AllTransactionsUncategorizedBoot';
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules'; import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { useAccountUncategorizedTransactionsColumns } from './hooks'; import { useAccountUncategorizedTransactionsColumns } from './hooks';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { compose } from '@/utils'; import { compose } from '@/utils';
import { withBanking } from '../../withBanking'; import { withBanking } from '../../withBanking';
@@ -48,6 +49,8 @@ function AccountTransactionsDataTable({
// Retrieve table columns. // Retrieve table columns.
const columns = useAccountUncategorizedTransactionsColumns(); const columns = useAccountUncategorizedTransactionsColumns();
const { scrollableRef } = useAccountTransactionsContext();
// Retrieve list context. // Retrieve list context.
const { uncategorizedTransactions, isUncategorizedTransactionsLoading } = const { uncategorizedTransactions, isUncategorizedTransactionsLoading } =
useAccountUncategorizedTransactionsContext(); useAccountUncategorizedTransactionsContext();
@@ -124,6 +127,7 @@ function AccountTransactionsDataTable({
onCategorize: handleCategorizeBtnClick, onCategorize: handleCategorizeBtnClick,
}} }}
onSelectedRowsChange={handleSelectedRowsChange} onSelectedRowsChange={handleSelectedRowsChange}
windowScrollerProps={{ scrollElement: scrollableRef }}
className={clsx('table-constrant', styles.table, { className={clsx('table-constrant', styles.table, {
[styles.showCategorizeColumn]: enableMultipleCategorization, [styles.showCategorizeColumn]: enableMultipleCategorization,
})} })}