From 64c0732e5fe575af51a5757ff767071d3804d962 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Mon, 5 Aug 2024 20:57:13 +0200 Subject: [PATCH] fix: infinity scrolling of bank account transactions --- .../AppContentShell/AppContentShell.tsx | 99 ++++++++++++------- .../Datatable/TableVirtualizedRows.tsx | 11 +-- .../webapp/src/components/Layout/Box/Box.tsx | 13 ++- .../AccountTransactionsList.tsx | 47 +++++---- .../AccountTransactionsProvider.tsx | 7 +- .../ExcludedTransactionsTable.tsx | 4 + .../RecognizedTransactionsTable.tsx | 4 + .../AccountTransactionsUncategorizedTable.tsx | 4 + 8 files changed, 124 insertions(+), 65 deletions(-) diff --git a/packages/webapp/src/components/AppShell/AppContentShell/AppContentShell.tsx b/packages/webapp/src/components/AppShell/AppContentShell/AppContentShell.tsx index da442eb6e..83299110a 100644 --- a/packages/webapp/src/components/AppShell/AppContentShell/AppContentShell.tsx +++ b/packages/webapp/src/components/AppShell/AppContentShell/AppContentShell.tsx @@ -1,5 +1,9 @@ -import React from 'react'; -import { AppShellProvider, useAppShellContext } from './AppContentShellProvider'; +// @ts-nocheck +import React, { forwardRef, Ref } from 'react'; +import { + AppShellProvider, + useAppShellContext, +} from './AppContentShellProvider'; import { Box, BoxProps } from '../../Layout'; import styles from './AppContentShell.module.scss'; @@ -12,50 +16,73 @@ interface AppContentShellProps { hideMain?: boolean; } -export function AppContentShell({ - asideProps, - mainProps, - topbarOffset = 0, - hideAside = false, - hideMain = false, - ...restProps -}: AppContentShellProps) { - return ( - - - - ); -} +export const AppContentShell = forwardRef( + ( + { + asideProps, + mainProps, + topbarOffset = 0, + hideAside = false, + hideMain = false, + ...restProps + }: AppContentShellProps, + ref: Ref, + ) => { + return ( + + + + ); + }, +); +AppContentShell.displayName = 'AppContentShell'; interface AppContentShellMainProps extends BoxProps {} -function AppContentShellMain({ ...props }: AppContentShellMainProps) { - const { hideMain } = useAppShellContext(); +/** + * Main content of the app shell. + * @param {AppContentShellMainProps} props - + * @returns {React.ReactNode} + */ +const AppContentShellMain = forwardRef( + ({ ...props }: AppContentShellMainProps, ref: Ref) => { + const { hideMain } = useAppShellContext(); - if (hideMain === true) { - return null; - } - return ; -} + if (hideMain === true) { + return null; + } + return ; + }, +); + +AppContentShellMain.displayName = 'AppContentShellMain'; interface AppContentShellAsideProps extends BoxProps { children: React.ReactNode; } -function AppContentShellAside({ ...props }: AppContentShellAsideProps) { - const { hideAside } = useAppShellContext(); +/** + * Aside content of the app shell. + * @param {AppContentShellAsideProps} props + * @returns {React.ReactNode} + */ +const AppContentShellAside = forwardRef( + ({ ...props }: AppContentShellAsideProps, ref: Ref) => { + const { hideAside } = useAppShellContext(); - if (hideAside === true) { - return null; - } - return ; -} + if (hideAside === true) { + return null; + } + return ; + }, +); +AppContentShellAside.displayName = 'AppContentShellAside'; AppContentShell.Main = AppContentShellMain; AppContentShell.Aside = AppContentShellAside; diff --git a/packages/webapp/src/components/Datatable/TableVirtualizedRows.tsx b/packages/webapp/src/components/Datatable/TableVirtualizedRows.tsx index 563575b12..ab2bc35b3 100644 --- a/packages/webapp/src/components/Datatable/TableVirtualizedRows.tsx +++ b/packages/webapp/src/components/Datatable/TableVirtualizedRows.tsx @@ -25,14 +25,13 @@ function TableVirtualizedListRow({ index, isScrolling, isVisible, style }) { export function TableVirtualizedListRows() { const { table: { page }, - props: { vListrowHeight, vListOverscanRowCount }, + props: { vListrowHeight, vListOverscanRowCount, windowScrollerProps }, } = useContext(TableContext); // Dashboard content pane. - const dashboardContentPane = React.useMemo( - () => document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`), - [], - ); + const scrollElement = + windowScrollerProps?.scrollElement || + document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`); const rowRenderer = React.useCallback( ({ key, ...args }) => , @@ -40,7 +39,7 @@ export function TableVirtualizedListRows() { ); return ( - + {({ height, isScrolling, onChildScroll, scrollTop }) => ( {({ width }) => ( diff --git a/packages/webapp/src/components/Layout/Box/Box.tsx b/packages/webapp/src/components/Layout/Box/Box.tsx index 15acc305b..9d104cf58 100644 --- a/packages/webapp/src/components/Layout/Box/Box.tsx +++ b/packages/webapp/src/components/Layout/Box/Box.tsx @@ -1,12 +1,15 @@ -import React from 'react'; +import React, { forwardRef, Ref } from 'react'; import { HTMLDivProps, Props } from '@blueprintjs/core'; export interface BoxProps extends Props, HTMLDivProps { className?: string; } -export function Box({ className, ...rest }: BoxProps) { - const Element = 'div'; +export const Box = forwardRef( + ({ className, ...rest }: BoxProps, ref: Ref) => { + const Element = 'div'; - return ; -} + return ; + }, +); +Box.displayName = '@bigcapital/Box'; diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsList.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsList.tsx index 671747706..c5a8fed62 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsList.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsList.tsx @@ -29,28 +29,41 @@ function AccountTransactionsListRoot({ return ( - - - - - - - - - }> - - - - - - - - + + ); } +function AccountTransactionsMain() { + const { setScrollableRef } = useAccountTransactionsContext(); + + return ( + setScrollableRef(e)}> + + + + + + + + }> + + + + + ); +} + +function AccountTransactionsAside() { + return ( + + + + ); +} + export default R.compose( withBanking( ({ selectedUncategorizedTransactionId, openMatchingTransactionAside }) => ({ diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsProvider.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsProvider.tsx index ba4447c69..4266fae1c 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsProvider.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/AccountTransactionsProvider.tsx @@ -1,5 +1,5 @@ // @ts-nocheck -import React from 'react'; +import React, { useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; import { DashboardInsider } from '@/components'; import { useCashflowAccounts, useAccount } from '@/hooks/query'; @@ -41,6 +41,8 @@ function AccountTransactionsProvider({ query, ...props }) { isLoading: isBankAccountMetaSummaryLoading, } = useGetBankAccountSummaryMeta(accountId); + const [scrollableRef, setScrollableRef] = useState(); + // Provider payload. const provider = { accountId, @@ -56,6 +58,9 @@ function AccountTransactionsProvider({ query, ...props }) { filterTab, setFilterTab, + + scrollableRef, + setScrollableRef }; return ( diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/ExcludedTransactions/ExcludedTransactionsTable.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/ExcludedTransactions/ExcludedTransactionsTable.tsx index 90fa018f1..c84ec27aa 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/ExcludedTransactions/ExcludedTransactionsTable.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/ExcludedTransactions/ExcludedTransactionsTable.tsx @@ -16,6 +16,7 @@ import { TABLES } from '@/constants/tables'; import { useMemorizedColumnsWidths } from '@/hooks'; import { useExcludedTransactionsColumns } from './_utils'; import { useExcludedTransactionsBoot } from './ExcludedTransactionsTableBoot'; +import { useAccountTransactionsContext } from '../AccountTransactionsProvider'; import { ActionsMenu } from './_components'; import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules'; @@ -37,6 +38,8 @@ function ExcludedTransactionsTableRoot({ const { mutateAsync: unexcludeBankTransaction } = useUnexcludeUncategorizedTransaction(); + const { scrollableRef } = useAccountTransactionsContext(); + // Retrieve table columns. const columns = useExcludedTransactionsColumns(); @@ -97,6 +100,7 @@ function ExcludedTransactionsTableRoot({ className="table-constrant" selectionColumn={true} onSelectedRowsChange={handleSelectedRowsChange} + windowScrollerProps={{ scrollElement: scrollableRef }} payload={{ onRestore: handleRestoreClick, }} diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/RecognizedTransactions/RecognizedTransactionsTable.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/RecognizedTransactions/RecognizedTransactionsTable.tsx index a3732eb6e..bfdf90d2e 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/RecognizedTransactions/RecognizedTransactionsTable.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/RecognizedTransactions/RecognizedTransactionsTable.tsx @@ -20,6 +20,7 @@ import { useRecognizedTransactionsBoot } from './RecognizedTransactionsTableBoot import { ActionsMenu } from './_components'; import { compose } from '@/utils'; +import { useAccountTransactionsContext } from '../AccountTransactionsProvider'; import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules'; import { WithBankingActionsProps, @@ -49,6 +50,8 @@ function RecognizedTransactionsTableRoot({ const [initialColumnsWidths, , handleColumnResizing] = useMemorizedColumnsWidths(TABLES.UNCATEGORIZED_ACCOUNT_TRANSACTIONS); + const { scrollableRef } = useAccountTransactionsContext(); + // Handle cell click. const handleCellClick = (cell, event) => { setUncategorizedTransactionIdForMatching( @@ -102,6 +105,7 @@ function RecognizedTransactionsTableRoot({ vListOverscanRowCount={0} initialColumnsWidths={initialColumnsWidths} onColumnResizing={handleColumnResizing} + windowScrollerProps={{ scrollElement: scrollableRef }} noResults={} className="table-constrant" payload={{ diff --git a/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountTransactionsUncategorizedTable.tsx b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountTransactionsUncategorizedTable.tsx index f2bd264bd..bd586adb4 100644 --- a/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountTransactionsUncategorizedTable.tsx +++ b/packages/webapp/src/containers/CashFlow/AccountTransactions/UncategorizedTransactions/AccountTransactionsUncategorizedTable.tsx @@ -22,6 +22,7 @@ import { useMemorizedColumnsWidths } from '@/hooks'; import { useAccountUncategorizedTransactionsContext } from '../AllTransactionsUncategorizedBoot'; import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules'; import { useAccountUncategorizedTransactionsColumns } from './hooks'; +import { useAccountTransactionsContext } from '../AccountTransactionsProvider'; import { compose } from '@/utils'; import { withBanking } from '../../withBanking'; @@ -48,6 +49,8 @@ function AccountTransactionsDataTable({ // Retrieve table columns. const columns = useAccountUncategorizedTransactionsColumns(); + const { scrollableRef } = useAccountTransactionsContext(); + // Retrieve list context. const { uncategorizedTransactions, isUncategorizedTransactionsLoading } = useAccountUncategorizedTransactionsContext(); @@ -124,6 +127,7 @@ function AccountTransactionsDataTable({ onCategorize: handleCategorizeBtnClick, }} onSelectedRowsChange={handleSelectedRowsChange} + windowScrollerProps={{ scrollElement: scrollableRef }} className={clsx('table-constrant', styles.table, { [styles.showCategorizeColumn]: enableMultipleCategorization, })}