Skip to content

Commit

Permalink
Custom Reports optimization (#1988)
Browse files Browse the repository at this point in the history
* Range fix and payee fix

* bug fixes and UI tweaks

* range options, hover UI

* Select - UnSelect All Buttons

* fix hidden group bug

* YAxis PrivacyFilter

* notes

* more privacyFilter graphs

* overflowY fix

* Loading Indicator

* Fix Filter button hover

* data revamp

* review fixes

* LoadingIndicator fixes

* remove a loop

* filterbuttontype

* lint fixes

* review fixes

* filtersbutton

* updates

* Split out functions to separate files

* uncategorized optimization

* rename ambiguous variables

* notes

* remove indexStack

* renaming variables

* Improve scrolling of tableGraph

* revert renaming variables

* code fixes

* lint fixes

* review fixes

* fix

* review fixes

* variable name changes

* const eslint fixes

* remove indexStack
  • Loading branch information
carkom authored Dec 6, 2023
1 parent cde4551 commit 2741422
Show file tree
Hide file tree
Showing 23 changed files with 882 additions and 716 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useRef } from 'react';

import View from '../common/View';

Expand All @@ -15,8 +15,6 @@ import ReportTableList from './ReportTableList';
import ReportTableTotals from './ReportTableTotals';

export function ChooseGraph({
start,
end,
data,
mode,
graphType,
Expand All @@ -27,18 +25,23 @@ export function ChooseGraph({
setScrollWidth,
months,
}) {
function saveScrollWidth(parent, child) {
const width = parent > 0 && child > 0 && parent - child;
const saveScrollWidth = value => {
setScrollWidth(!value ? 0 : value);
};

setScrollWidth(!width ? 0 : width);
}
const headerScrollRef = useRef<HTMLDivElement>(null);
const listScrollRef = useRef<HTMLDivElement>(null);
const totalScrollRef = useRef<HTMLDivElement>(null);

const handleScrollTotals = scroll => {
headerScrollRef.current.scrollLeft = scroll.target.scrollLeft;
listScrollRef.current.scrollLeft = scroll.target.scrollLeft;
};

if (graphType === 'AreaGraph') {
return (
<AreaGraph
style={{ flexGrow: 1 }}
start={start}
end={end}
data={data}
balanceTypeOp={ReportOptions.balanceTypeMap.get(balanceType)}
/>
Expand All @@ -48,8 +51,6 @@ export function ChooseGraph({
return (
<BarGraph
style={{ flexGrow: 1 }}
start={start}
end={end}
data={data}
groupBy={groupBy}
empty={empty}
Expand All @@ -58,21 +59,12 @@ export function ChooseGraph({
);
}
if (graphType === 'BarLineGraph') {
return (
<BarLineGraph
style={{ flexGrow: 1 }}
start={start}
end={end}
graphData={data.graphData}
/>
);
return <BarLineGraph style={{ flexGrow: 1 }} graphData={data.graphData} />;
}
if (graphType === 'DonutGraph') {
return (
<DonutGraph
style={{ flexGrow: 1 }}
start={start}
end={end}
data={data}
groupBy={groupBy}
empty={empty}
Expand All @@ -81,40 +73,25 @@ export function ChooseGraph({
);
}
if (graphType === 'LineGraph') {
return (
<LineGraph
style={{ flexGrow: 1 }}
start={start}
end={end}
graphData={data.graphData}
/>
);
return <LineGraph style={{ flexGrow: 1 }} graphData={data.graphData} />;
}
if (graphType === 'StackedBarGraph') {
return (
<StackedBarGraph
style={{ flexGrow: 1 }}
start={start}
end={end}
data={data}
balanceTypeOp={ReportOptions.balanceTypeMap.get(balanceType)}
/>
);
return <StackedBarGraph style={{ flexGrow: 1 }} data={data} />;
}
if (graphType === 'TableGraph') {
return (
<View
style={{
overflow: 'auto',
}}
>
<View>
<ReportTableHeader
headerScrollRef={headerScrollRef}
interval={mode === 'time' && months}
scrollWidth={scrollWidth}
groupBy={groupBy}
balanceType={balanceType}
/>
<ReportTable saveScrollWidth={saveScrollWidth}>
<ReportTable
saveScrollWidth={saveScrollWidth}
listScrollRef={listScrollRef}
>
<ReportTableList
data={data}
empty={empty}
Expand All @@ -123,15 +100,16 @@ export function ChooseGraph({
mode={mode}
groupBy={groupBy}
/>
<ReportTableTotals
scrollWidth={scrollWidth}
data={data}
mode={mode}
balanceTypeOp={ReportOptions.balanceTypeMap.get(balanceType)}
monthsCount={months.length}
balanceType={balanceType}
/>
</ReportTable>
<ReportTableTotals
totalScrollRef={totalScrollRef}
handleScrollTotals={handleScrollTotals}
scrollWidth={scrollWidth}
data={data}
mode={mode}
balanceTypeOp={ReportOptions.balanceTypeMap.get(balanceType)}
monthsCount={months.length}
/>
</View>
);
}
Expand Down
132 changes: 132 additions & 0 deletions packages/desktop-client/src/components/reports/ReportOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import {
type AccountEntity,
type CategoryEntity,
type CategoryGroupEntity,
type PayeeEntity,
} from 'loot-core/src/types/models';

const balanceTypeOptions = [
{ description: 'Expense', format: 'totalDebts' },
{ description: 'Income', format: 'totalAssets' },
Expand Down Expand Up @@ -44,3 +51,128 @@ const intervalOptions = [
{ value: 5, description: 'Yearly', name: 5,
];
*/
export type QueryDataEntity = {
date: string;
category: string;
categoryGroup: string;
account: string;
accountOffBudget: boolean;
payee: string;
transferAccount: string;
amount: number;
};

export type UncategorizedEntity = CategoryEntity & {
/*
When looking at uncategorized and hidden transactions we
need a way to group them. To do this we give them a unique
uncategorized_id. We also need a way to filter the
transctions from our query. For this we use the 3 variables
below.
*/
uncategorized_id: string;
is_off_budget: boolean;
is_transfer: boolean;
has_category: boolean;
};

const uncategorizedCategory: UncategorizedEntity = {
name: 'Uncategorized',
id: null,
uncategorized_id: '1',
hidden: false,
is_off_budget: false,
is_transfer: false,
has_category: false,
};
const transferCategory: UncategorizedEntity = {
name: 'Transfers',
id: null,
uncategorized_id: '2',
hidden: false,
is_off_budget: false,
is_transfer: true,
has_category: false,
};
const offBudgetCategory: UncategorizedEntity = {
name: 'Off Budget',
id: null,
uncategorized_id: '3',
hidden: false,
is_off_budget: true,
is_transfer: false,
has_category: true,
};

type UncategorizedGroupEntity = CategoryGroupEntity & {
categories?: UncategorizedEntity[];
};

const uncategouncatGrouprizedGroup: UncategorizedGroupEntity = {
name: 'Uncategorized & Off Budget',
id: null,
hidden: false,
categories: [uncategorizedCategory, transferCategory, offBudgetCategory],
};

export const categoryLists = (
showOffBudgetHidden: boolean,
showUncategorized: boolean,
categories: { list: CategoryEntity[]; grouped: CategoryGroupEntity[] },
) => {
const categoryList = showUncategorized
? [
...categories.list,
uncategorizedCategory,
transferCategory,
offBudgetCategory,
]
: categories.list;
const categoryGroup = showUncategorized
? [
...categories.grouped.filter(f => showOffBudgetHidden || !f.hidden),
uncategouncatGrouprizedGroup,
]
: categories.grouped;
return [categoryList, categoryGroup] as const;
};

export const groupBySelections = (
groupBy: string,
categoryList: CategoryEntity[],
categoryGroup: CategoryGroupEntity[],
payees: PayeeEntity[],
accounts: AccountEntity[],
) => {
let groupByList;
let groupByLabel;
switch (groupBy) {
case 'Category':
groupByList = categoryList;
groupByLabel = 'category';
break;
case 'Group':
groupByList = categoryGroup;
groupByLabel = 'categoryGroup';
break;
case 'Payee':
groupByList = payees;
groupByLabel = 'payee';
break;
case 'Account':
groupByList = accounts;
groupByLabel = 'account';
break;
case 'Month':
groupByList = categoryList;
groupByLabel = 'category';
break;
case 'Year':
groupByList = categoryList;
groupByLabel = 'category';
break;
default:
throw new Error('Error loading data into the spreadsheet.');
}
return [groupByList, groupByLabel];
};
31 changes: 22 additions & 9 deletions packages/desktop-client/src/components/reports/ReportTable.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
import React, { useLayoutEffect, useRef } from 'react';
import React, { useLayoutEffect, useRef, type ReactNode } from 'react';
import { type RefProp } from 'react-spring';

import { type CSSProperties } from '../../style';
import View from '../common/View';

export default function ReportTable({ saveScrollWidth, style, children }) {
const contentRef = useRef<HTMLDivElement>();
type ReportTableProps = {
saveScrollWidth?: (value: number) => void;
listScrollRef?: RefProp<HTMLDivElement>;
style?: CSSProperties;
children?: ReactNode;
};

export default function ReportTable({
saveScrollWidth,
listScrollRef,
style,
children,
}: ReportTableProps) {
const contentRef = useRef<HTMLDivElement>(null);

useLayoutEffect(() => {
if (contentRef.current && saveScrollWidth) {
saveScrollWidth(
contentRef.current.offsetParent
? contentRef.current.parentElement.offsetWidth
: 0,
contentRef.current ? contentRef.current.offsetWidth : 0,
);
saveScrollWidth(contentRef.current ? contentRef.current.offsetWidth : 0);
}
});

return (
<View
innerRef={listScrollRef}
style={{
overflowY: 'auto',
scrollbarWidth: 'none',
'::-webkit-scrollbar': { display: 'none' },
flex: 1,
outline: 'none',
'& .animated .animated-row': { transition: '.25s transform' },
Expand Down
Loading

0 comments on commit 2741422

Please sign in to comment.