Skip to content

Commit

Permalink
Custom Reports Bug Fixes (#1930)
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

* review fixes

* LoadingIndicator fixes

* remove a loop

* filterbuttontype

* review fixes

* filtersbutton

* updates
  • Loading branch information
carkom authored Nov 26, 2023
1 parent 1ed8405 commit e48f36c
Show file tree
Hide file tree
Showing 34 changed files with 531 additions and 248 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

import { Filter } from '../../icons/v1';
import Button from '../common/Button';

type CompactFiltersButtonProps = {
onClick: (newValue) => void;
};

function CompactFiltersButton({ onClick }: CompactFiltersButtonProps) {
return (
<Button type="bare" onClick={onClick}>
<Filter width={15} height={15} />
</Button>
);
}

export default CompactFiltersButton;
21 changes: 21 additions & 0 deletions packages/desktop-client/src/components/filters/FiltersButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';

import { SettingsSliderAlternate } from '../../icons/v2';
import Button from '../common/Button';

type FiltersButtonProps = {
onClick: (newValue) => void;
};

function FiltersButton({ onClick }: FiltersButtonProps) {
return (
<Button type="bare" onClick={onClick} title={'Filters'}>
<SettingsSliderAlternate
style={{ width: 16, height: 16, marginRight: 5 }}
/>{' '}
Filter
</Button>
);
}

export default FiltersButton;
55 changes: 30 additions & 25 deletions packages/desktop-client/src/components/filters/FiltersMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ import {
import { titleFirst } from 'loot-core/src/shared/util';

import DeleteIcon from '../../icons/v0/Delete';
import Filter from '../../icons/v1/Filter';
import SettingsSliderAlternate from '../../icons/v2/SettingsSliderAlternate';
import { theme } from '../../style';
import Button from '../common/Button';
import HoverTarget from '../common/HoverTarget';
import Menu from '../common/Menu';
import Select from '../common/Select';
import Stack from '../common/Stack';
Expand All @@ -37,6 +36,8 @@ import Value from '../rules/Value';
import { Tooltip } from '../tooltips';
import GenericInput from '../util/GenericInput';

import CompactFiltersButton from './CompactFiltersButton';
import FiltersButton from './FiltersButton';
import { CondOpMenu } from './SavedFilters';

let filterFields = [
Expand Down Expand Up @@ -336,28 +337,7 @@ function ConfigureField({
);
}

function ButtonType({ type, dispatch }) {
return (
<Button
type="bare"
onClick={() => dispatch({ type: 'select-field' })}
title={type && 'Filters'}
>
{type === 'reports' ? (
<Filter width={15} height={15} />
) : (
<>
<SettingsSliderAlternate
style={{ width: 16, height: 16, marginRight: 5 }}
/>{' '}
Filter
</>
)}
</Button>
);
}

export function FilterButton({ onApply, type }) {
export function FilterButton({ onApply, compact, hover }) {
let filters = useFilters();

let { dateFormat } = useSelector(state => {
Expand Down Expand Up @@ -440,7 +420,32 @@ export function FilterButton({ onApply, type }) {

return (
<View>
<ButtonType type={type} dispatch={dispatch} />
<HoverTarget
style={{ flexShrink: 0 }}
renderContent={() =>
hover && (
<Tooltip
position="bottom-left"
style={{
lineHeight: 1.5,
padding: '6px 10px',
backgroundColor: theme.menuAutoCompleteBackground,
color: theme.menuAutoCompleteText,
}}
>
<Text>Filters</Text>
</Tooltip>
)
}
>
{compact ? (
<CompactFiltersButton
onClick={() => dispatch({ type: 'select-field' })}
/>
) : (
<FiltersButton onClick={() => dispatch({ type: 'select-field' })} />
)}
</HoverTarget>
{state.fieldsOpen && (
<Tooltip
position="bottom-left"
Expand Down
85 changes: 67 additions & 18 deletions packages/desktop-client/src/components/reports/CategorySelector.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,95 @@
import React, { Fragment, useState } from 'react';
import React, { Fragment, useMemo, useState } from 'react';

import {
type CategoryEntity,
type CategoryGroupEntity,
} from 'loot-core/src/types/models';

import { CheckAll, UncheckAll } from '../../icons/v2';
import ViewHide from '../../icons/v2/ViewHide';
import ViewShow from '../../icons/v2/ViewShow';
import { type CategoryListProps } from '../autocomplete/CategoryAutocomplete';
import Button from '../common/Button';
import Text from '../common/Text';
import View from '../common/View';
import { Checkbox } from '../forms';

import GraphButton from './GraphButton';

type CategorySelectorProps = {
categoryGroups: Array<CategoryGroupEntity>;
categories: Array<CategoryEntity>;
selectedCategories: CategoryListProps['items'];
setSelectedCategories: (selectedCategories: CategoryEntity[]) => null;
};

export default function CategorySelector({
categoryGroups,
categories,
selectedCategories,
setSelectedCategories,
}: CategorySelectorProps) {
const [uncheckedHidden, setUncheckedHidden] = useState(false);

const selectedCategoryMap = useMemo(
() => selectedCategories.map(selected => selected.id),
[selectedCategories],
);
const allCategoriesSelected = categories.every(category =>
selectedCategoryMap.includes(category.id),
);

const allCategoriesUnselected = !categories.some(category =>
selectedCategoryMap.includes(category.id),
);

let selectAll: CategoryEntity[] = [];
categoryGroups.map(categoryGroup =>
categoryGroup.categories.map(category => selectAll.push(category)),
);

return (
<>
<div>
<Button onClick={() => setUncheckedHidden(state => !state)}>
{uncheckedHidden ? (
<>
<ViewShow width={15} height={15} style={{ marginRight: 5 }} />
Show unchecked
</>
) : (
<>
<ViewHide width={15} height={15} style={{ marginRight: 5 }} />
Hide unchecked
</>
)}
<View>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Button type="bare" onClick={() => setUncheckedHidden(state => !state)}>
<View>
{uncheckedHidden ? (
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<ViewShow width={15} height={15} style={{ marginRight: 5 }} />
<Text>Show unchecked</Text>
</View>
) : (
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<ViewHide width={15} height={15} style={{ marginRight: 5 }} />
<Text>Hide unchecked</Text>
</View>
)}
</View>
</Button>
</div>
<View style={{ flex: 1 }} />
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<GraphButton
selected={allCategoriesSelected}
title="Select All"
onSelect={() => {
setSelectedCategories(selectAll);
}}
style={{ marginRight: 5, padding: 8 }}
>
<CheckAll width={15} height={15} />
</GraphButton>
<GraphButton
selected={allCategoriesUnselected}
title="Unselect All"
onSelect={() => {
setSelectedCategories([]);
}}
style={{ padding: 8 }}
>
<UncheckAll width={15} height={15} />
</GraphButton>
</View>
</View>

<ul
style={{
Expand All @@ -50,7 +99,7 @@ export default function CategorySelector({
paddingRight: 10,
height: 320,
flexGrow: 1,
overflowY: 'scroll',
overflowY: 'auto',
}}
>
{categoryGroups &&
Expand Down Expand Up @@ -166,6 +215,6 @@ export default function CategorySelector({
);
})}
</ul>
</>
</View>
);
}
59 changes: 59 additions & 0 deletions packages/desktop-client/src/components/reports/GraphButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { type HTMLProps } from 'react';

import { type CSSProperties, theme } from '../../style';
import Button from '../common/Button';
import HoverTarget from '../common/HoverTarget';
import Text from '../common/Text';
import { Tooltip } from '../tooltips';

type GraphButtonProps = HTMLProps<HTMLButtonElement> & {
selected?: boolean;
style?: CSSProperties;
onSelect?: (newValue) => void;
title?: string;
disabled?: boolean;
};

const GraphButton = ({
selected,
children,
onSelect,
title,
style,
disabled,
}: GraphButtonProps) => {
return (
<HoverTarget
style={{ flexShrink: 0 }}
renderContent={() => (
<Tooltip
position="bottom-left"
style={{
lineHeight: 1.5,
padding: '6px 10px',
backgroundColor: theme.menuAutoCompleteBackground,
color: theme.menuAutoCompleteText,
}}
>
<Text>{title}</Text>
</Tooltip>
)}
>
<Button
type="bare"
style={{
...(selected && {
backgroundColor: theme.buttonBareBackgroundHover,
}),
...style,
}}
onClick={onSelect}
disabled={disabled}
>
{children}
</Button>
</HoverTarget>
);
};

export default GraphButton;
12 changes: 12 additions & 0 deletions packages/desktop-client/src/components/reports/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ export function validateEnd(allMonths, start, end) {
return boundedRange(earliest, start, end);
}

export function validateRange(allMonths, start, end) {
const latest = monthUtils.currentMonth();
const earliest = allMonths[allMonths.length - 1].name;
if (end > latest) {
end = latest;
}
if (start < earliest) {
start = earliest;
}
return [start, end];
}

function boundedRange(earliest, start, end) {
const latest = monthUtils.currentMonth();
if (end > latest) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';

import AnimatedLoading from '../../icons/AnimatedLoading';
import { theme, styles } from '../../style';
import Block from '../common/Block';
import View from '../common/View';

type LoadingIndicatorProps = {
message?: string;
};

const LoadingIndicator = ({ message }: LoadingIndicatorProps) => {
return (
<View
style={{
flex: 1,
gap: 20,
justifyContent: 'center',
alignItems: 'center',
...styles.delayedFadeIn,
}}
>
{message && (
<Block style={{ marginBottom: 20, fontSize: 18 }}>{message}</Block>
)}
<AnimatedLoading
style={{ width: 25, height: 25, color: theme.pageTextDark }}
/>
</View>
);
};

export default LoadingIndicator;
15 changes: 0 additions & 15 deletions packages/desktop-client/src/components/reports/Overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import { useSelector } from 'react-redux';

import useFeatureFlag from '../../hooks/useFeatureFlag';
import AnimatedLoading from '../../icons/AnimatedLoading';
import { styles } from '../../style';
import View from '../common/View';

Expand All @@ -12,20 +11,6 @@ import CustomReportCard from './reports/CustomReportCard';
import NetWorthCard from './reports/NetWorthCard';
import SankeyCard from './reports/SankeyCard';

export function LoadingIndicator() {
return (
<View
style={{
height: '100%',
alignItems: 'center',
justifyContent: 'center',
}}
>
<AnimatedLoading style={{ width: 25, height: 25 }} />
</View>
);
}

export default function Overview() {
let categorySpendingReportFeatureFlag = useFeatureFlag(
'categorySpendingReport',
Expand Down
Loading

0 comments on commit e48f36c

Please sign in to comment.