mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
fix: infinity scrolling of bank account transactions
This commit is contained in:
@@ -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 (
|
||||
<AppShellProvider
|
||||
mainProps={mainProps}
|
||||
asideProps={asideProps}
|
||||
topbarOffset={topbarOffset}
|
||||
hideAside={hideAside}
|
||||
hideMain={hideMain}
|
||||
>
|
||||
<Box {...restProps} className={styles.root} />
|
||||
</AppShellProvider>
|
||||
);
|
||||
}
|
||||
export const AppContentShell = forwardRef(
|
||||
(
|
||||
{
|
||||
asideProps,
|
||||
mainProps,
|
||||
topbarOffset = 0,
|
||||
hideAside = false,
|
||||
hideMain = false,
|
||||
...restProps
|
||||
}: AppContentShellProps,
|
||||
ref: Ref<HTMLDivElement>,
|
||||
) => {
|
||||
return (
|
||||
<AppShellProvider
|
||||
mainProps={mainProps}
|
||||
asideProps={asideProps}
|
||||
topbarOffset={topbarOffset}
|
||||
hideAside={hideAside}
|
||||
hideMain={hideMain}
|
||||
>
|
||||
<Box {...restProps} className={styles.root} ref={ref} />
|
||||
</AppShellProvider>
|
||||
);
|
||||
},
|
||||
);
|
||||
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<HTMLDivElement>) => {
|
||||
const { hideMain } = useAppShellContext();
|
||||
|
||||
if (hideMain === true) {
|
||||
return null;
|
||||
}
|
||||
return <Box {...props} className={styles.main} />;
|
||||
}
|
||||
if (hideMain === true) {
|
||||
return null;
|
||||
}
|
||||
return <Box {...props} className={styles.main} ref={ref} />;
|
||||
},
|
||||
);
|
||||
|
||||
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<HTMLDivElement>) => {
|
||||
const { hideAside } = useAppShellContext();
|
||||
|
||||
if (hideAside === true) {
|
||||
return null;
|
||||
}
|
||||
return <Box {...props} className={styles.aside} />;
|
||||
}
|
||||
if (hideAside === true) {
|
||||
return null;
|
||||
}
|
||||
return <Box {...props} className={styles.aside} ref={ref} />;
|
||||
},
|
||||
);
|
||||
AppContentShellAside.displayName = 'AppContentShellAside';
|
||||
|
||||
AppContentShell.Main = AppContentShellMain;
|
||||
AppContentShell.Aside = AppContentShellAside;
|
||||
|
||||
@@ -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 }) => <TableVirtualizedListRow {...args} key={key} />,
|
||||
@@ -40,7 +39,7 @@ export function TableVirtualizedListRows() {
|
||||
);
|
||||
|
||||
return (
|
||||
<WindowScroller scrollElement={dashboardContentPane}>
|
||||
<WindowScroller scrollElement={scrollElement}>
|
||||
{({ height, isScrolling, onChildScroll, scrollTop }) => (
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }) => (
|
||||
|
||||
@@ -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<HTMLDivElement>) => {
|
||||
const Element = 'div';
|
||||
|
||||
return <Element className={className} {...rest} />;
|
||||
}
|
||||
return <Element className={className} ref={ref} {...rest} />;
|
||||
},
|
||||
);
|
||||
Box.displayName = '@bigcapital/Box';
|
||||
|
||||
@@ -29,28 +29,41 @@ function AccountTransactionsListRoot({
|
||||
return (
|
||||
<AccountTransactionsProvider>
|
||||
<AppContentShell hideAside={!openMatchingTransactionAside}>
|
||||
<AppContentShell.Main>
|
||||
<AccountTransactionsActionsBar />
|
||||
<AccountTransactionsDetailsBar />
|
||||
<AccountTransactionsProgressBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<AccountTransactionsFilterTabs />
|
||||
|
||||
<Suspense fallback={<Spinner size={30} />}>
|
||||
<AccountTransactionsContent />
|
||||
</Suspense>
|
||||
</DashboardPageContent>
|
||||
</AppContentShell.Main>
|
||||
|
||||
<AppContentShell.Aside>
|
||||
<CategorizeTransactionAside />
|
||||
</AppContentShell.Aside>
|
||||
<AccountTransactionsMain />
|
||||
<AccountTransactionsAside />
|
||||
</AppContentShell>
|
||||
</AccountTransactionsProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountTransactionsMain() {
|
||||
const { setScrollableRef } = useAccountTransactionsContext();
|
||||
|
||||
return (
|
||||
<AppContentShell.Main ref={(e) => setScrollableRef(e)}>
|
||||
<AccountTransactionsActionsBar />
|
||||
<AccountTransactionsDetailsBar />
|
||||
<AccountTransactionsProgressBar />
|
||||
|
||||
<DashboardPageContent>
|
||||
<AccountTransactionsFilterTabs />
|
||||
|
||||
<Suspense fallback={<Spinner size={30} />}>
|
||||
<AccountTransactionsContent />
|
||||
</Suspense>
|
||||
</DashboardPageContent>
|
||||
</AppContentShell.Main>
|
||||
);
|
||||
}
|
||||
|
||||
function AccountTransactionsAside() {
|
||||
return (
|
||||
<AppContentShell.Aside>
|
||||
<CategorizeTransactionAside />
|
||||
</AppContentShell.Aside>
|
||||
);
|
||||
}
|
||||
|
||||
export default R.compose(
|
||||
withBanking(
|
||||
({ selectedUncategorizedTransactionId, openMatchingTransactionAside }) => ({
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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,
|
||||
}}
|
||||
|
||||
@@ -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={<RecognizedTransactionsTableNoResults />}
|
||||
className="table-constrant"
|
||||
payload={{
|
||||
|
||||
@@ -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,
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user