diff --git a/packages/desktop-client/src/components/common/Block.tsx b/packages/desktop-client/src/components/common/Block.tsx index a1603aef0cf..7be0dd3590b 100644 --- a/packages/desktop-client/src/components/common/Block.tsx +++ b/packages/desktop-client/src/components/common/Block.tsx @@ -2,8 +2,11 @@ import { type HTMLProps, type Ref } from 'react'; import { css } from 'glamor'; +import { type CSSProperties } from '../../style'; + type BlockProps = HTMLProps & { innerRef?: Ref; + style?: CSSProperties; }; export function Block(props: BlockProps) { diff --git a/packages/desktop-client/src/components/reports/ChooseGraph.tsx b/packages/desktop-client/src/components/reports/ChooseGraph.tsx index c02c5d8890c..2019433b483 100644 --- a/packages/desktop-client/src/components/reports/ChooseGraph.tsx +++ b/packages/desktop-client/src/components/reports/ChooseGraph.tsx @@ -12,7 +12,6 @@ import { LineGraph } from './graphs/LineGraph'; import { StackedBarGraph } from './graphs/StackedBarGraph'; import { ReportTable } from './graphs/tableGraph/ReportTable'; import { ReportTableHeader } from './graphs/tableGraph/ReportTableHeader'; -import { ReportTableList } from './graphs/tableGraph/ReportTableList'; import { ReportTableTotals } from './graphs/tableGraph/ReportTableTotals'; import { ReportOptions } from './ReportOptions'; @@ -42,6 +41,12 @@ export function ChooseGraph({ viewLabels, }: ChooseGraphProps) { const balanceTypeOp = ReportOptions.balanceTypeMap.get(balanceType); + const groupByData = + groupBy === 'Category' + ? 'groupedData' + : ['Month', 'Year'].includes(groupBy) + ? 'monthData' + : 'data'; const saveScrollWidth = value => { setScrollWidth(!value ? 0 : value); @@ -128,16 +133,12 @@ export function ChooseGraph({ saveScrollWidth={saveScrollWidth} listScrollRef={listScrollRef} handleScroll={handleScroll} - > - - + balanceTypeOp={balanceTypeOp} + groupBy={groupBy} + data={data[groupByData]} + mode={mode} + monthsCount={months.length} + /> ; - monthData: Array; - groupedData: Array; + data: GroupedEntity[]; + monthData: GroupedEntity[]; + groupedData: GroupedEntity[]; legend: LegendEntity[]; startDate: string; endDate: string; @@ -31,7 +31,7 @@ export type MonthData = { totalTotals: number; }; -type GroupedEntity = { +export type GroupedEntity = { id: string; name: string; date?: string; diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx index a022eee4a00..d087bea38ad 100644 --- a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx @@ -1,29 +1,42 @@ // @ts-strict-ignore import React, { - type UIEventHandler, + useCallback, useLayoutEffect, useRef, - type ReactNode, + type UIEventHandler, } from 'react'; import { type RefProp } from 'react-spring'; import { type CSSProperties } from '../../../../style'; +import { Block } from '../../../common/Block'; import { View } from '../../../common/View'; +import { type GroupedEntity } from '../../entities'; + +import { ReportTableList } from './ReportTableList'; +import { ReportTableRow } from './ReportTableRow'; type ReportTableProps = { - saveScrollWidth?: (value: number) => void; - listScrollRef?: RefProp; + saveScrollWidth: (value: number) => void; + listScrollRef: RefProp; + handleScroll: UIEventHandler; style?: CSSProperties; - children?: ReactNode; - handleScroll?: UIEventHandler; + groupBy: string; + balanceTypeOp: 'totalDebts' | 'totalTotals' | 'totalAssets'; + data: GroupedEntity[]; + mode: string; + monthsCount: number; }; export function ReportTable({ saveScrollWidth, listScrollRef, - style, - children, handleScroll, + style, + groupBy, + balanceTypeOp, + data, + mode, + monthsCount, }: ReportTableProps) { const contentRef = useRef(null); @@ -33,25 +46,56 @@ export function ReportTable({ } }); + const renderItem = useCallback( + ({ item, groupByItem, mode, style, key, monthsCount }) => { + return ( + + ); + }, + [], + ); + return ( - -
{children}
-
+ + +
); } diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx index 7138c4ba908..5a16c916b38 100644 --- a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableHeader.tsx @@ -5,15 +5,15 @@ import { type RefProp } from 'react-spring'; import { styles, theme } from '../../../../style'; import { View } from '../../../common/View'; import { Row, Cell } from '../../../table'; -import { type MonthData } from '../../entities'; +import { type GroupedEntity } from '../../entities'; type ReportTableHeaderProps = { scrollWidth?: number; groupBy: string; - interval?: MonthData[]; + interval?: GroupedEntity[]; balanceType: string; headerScrollRef: RefProp; - handleScroll?: UIEventHandler; + handleScroll: UIEventHandler; }; export function ReportTableHeader({ diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx index 3034fb293ca..8d27ccfeb36 100644 --- a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableList.tsx @@ -1,244 +1,90 @@ // @ts-strict-ignore -import React, { memo } from 'react'; +import React from 'react'; -import { - amountToCurrency, - amountToInteger, - integerToCurrency, -} from 'loot-core/src/shared/util'; - -import { type CSSProperties, styles, theme } from '../../../../style'; +import { type CSSProperties, theme } from '../../../../style'; import { View } from '../../../common/View'; -import { Row, Cell } from '../../../table'; +import { Cell, Row } from '../../../table'; +import { type GroupedEntity } from '../../entities'; -type TableRowProps = { - item: { - date: string; - name: string; - monthData: []; - totalAssets: number; - totalDebts: number; - }; - balanceTypeOp?: string; - groupByItem: string; - mode: string; - monthsCount: number; - style?: CSSProperties; +type ReportTableListProps = { + data: GroupedEntity[]; + mode?: string; + monthsCount?: number; + groupBy: string; + renderItem; }; -const TableRow = memo( - ({ - item, - balanceTypeOp, - groupByItem, - mode, - monthsCount, - style, - }: TableRowProps) => { - const average = amountToInteger(item[balanceTypeOp]) / monthsCount; - return ( - - 12 && item[groupByItem]} - style={{ - width: 120, - flexShrink: 0, - ...styles.tnum, - }} - /> - {item.monthData && mode === 'time' - ? item.monthData.map(month => { - return ( - 100000 && - amountToCurrency(month[balanceTypeOp]) - } - width="flex" - privacyFilter - /> - ); - }) - : balanceTypeOp === 'totalTotals' && ( - <> - 100000 && - amountToCurrency(item.totalAssets) - } - width="flex" - style={{ - minWidth: 85, - ...styles.tnum, - }} - /> - 100000 && - amountToCurrency(item.totalDebts) - } - width="flex" - style={{ - minWidth: 85, - ...styles.tnum, - }} - /> - - )} - 100000 && - amountToCurrency(item[balanceTypeOp]) - } - style={{ - fontWeight: 600, - minWidth: 85, - ...styles.tnum, - }} - width="flex" - privacyFilter - /> - 100000 && - integerToCurrency(Math.round(average)) - } - style={{ - fontWeight: 600, - minWidth: 85, - ...styles.tnum, - }} - width="flex" - privacyFilter - /> - - ); - }, -); - -function GroupedTableRow({ - item, - balanceTypeOp, - groupByItem, - mode, - monthsCount, - empty, -}) { - return ( - <> - - - {item.categories - .filter(i => - !empty - ? balanceTypeOp === 'totalTotals' - ? i.totalAssets !== 0 || - i.totalDebts !== 0 || - i.totalTotals !== 0 - : i[balanceTypeOp] !== 0 - : true, - ) - .map(cat => { - return ( - - ); - })} - - - - ); -} - export function ReportTableList({ data, - empty, monthsCount, - balanceTypeOp, mode, groupBy, -}) { + renderItem, +}: ReportTableListProps) { const groupByItem = ['Month', 'Year'].includes(groupBy) ? 'date' : 'name'; - const groupByData = - groupBy === 'Category' - ? 'groupedData' - : ['Month', 'Year'].includes(groupBy) - ? 'monthData' - : 'data'; + + type RenderRowProps = { + key: string; + index: number; + parent_index?: number; + style?: CSSProperties; + }; + function RenderRow({ index, parent_index, style, key }: RenderRowProps) { + const item = parent_index + ? data[parent_index].categories[index] + : data[index]; + + return renderItem({ + item, + groupByItem, + mode, + style, + key, + monthsCount, + }); + } return ( - {data[groupByData] - .filter(i => - !empty - ? balanceTypeOp === 'totalTotals' - ? i.totalAssets !== 0 || i.totalDebts !== 0 || i.totalTotals !== 0 - : i[balanceTypeOp] !== 0 - : true, - ) - .map(item => { - if (groupBy === 'Category') { - return ( - - ); - } else { - return ( - - ); - } - })} + {data.map((item, index) => { + return ( + + {data ? ( + <> + + {item.categories && ( + <> + + {item.categories.map((category, i) => { + return ( + + ); + })} + + + + )} + + ) : ( + + )} + + ); + })} ); } diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableRow.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableRow.tsx new file mode 100644 index 00000000000..63c275a6e29 --- /dev/null +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableRow.tsx @@ -0,0 +1,135 @@ +import React, { memo } from 'react'; + +import { + amountToCurrency, + amountToInteger, + integerToCurrency, +} from 'loot-core/src/shared/util'; + +import { type CSSProperties, styles, theme } from '../../../../style'; +import { Row, Cell } from '../../../table'; +import { type GroupedEntity } from '../../entities'; + +type ReportTableRowProps = { + item: GroupedEntity; + balanceTypeOp: 'totalAssets' | 'totalDebts' | 'totalTotals'; + groupByItem: 'id' | 'name'; + mode: string; + style?: CSSProperties; + monthsCount: number; +}; + +export const ReportTableRow = memo( + ({ + item, + balanceTypeOp, + groupByItem, + mode, + style, + monthsCount, + }: ReportTableRowProps) => { + const average = amountToInteger(item[balanceTypeOp]) / monthsCount; + return ( + + 12 ? item[groupByItem] : undefined} + style={{ + width: 120, + flexShrink: 0, + ...styles.tnum, + }} + /> + {item.monthData && mode === 'time' + ? item.monthData.map(month => { + return ( + 100000 + ? amountToCurrency(month[balanceTypeOp]) + : undefined + } + width="flex" + privacyFilter + /> + ); + }) + : balanceTypeOp === 'totalTotals' && ( + <> + 100000 + ? amountToCurrency(item.totalAssets) + : undefined + } + width="flex" + privacyFilter + style={{ + minWidth: 85, + ...styles.tnum, + }} + /> + 100000 + ? amountToCurrency(item.totalDebts) + : undefined + } + width="flex" + privacyFilter + style={{ + minWidth: 85, + ...styles.tnum, + }} + /> + + )} + 100000 + ? amountToCurrency(item[balanceTypeOp]) + : undefined + } + style={{ + fontWeight: 600, + minWidth: 85, + ...styles.tnum, + }} + width="flex" + privacyFilter + /> + 100000 + ? integerToCurrency(Math.round(average)) + : undefined + } + style={{ + fontWeight: 600, + minWidth: 85, + ...styles.tnum, + }} + width="flex" + privacyFilter + /> + + ); + }, +); diff --git a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx index 4b708a985fa..5b396202518 100644 --- a/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx +++ b/packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx @@ -110,6 +110,7 @@ export function ReportTableTotals({ amountToCurrency(data.totalAssets) } width="flex" + privacyFilter /> )} diff --git a/upcoming-release-notes/2192.md b/upcoming-release-notes/2192.md new file mode 100644 index 00000000000..ff341b26d62 --- /dev/null +++ b/upcoming-release-notes/2192.md @@ -0,0 +1,6 @@ +--- +category: Maintenance +authors: [carkom] +--- + +Fix table graph rendering issue for custom reports.