[Feature] Hide category (#1060)

This commit is contained in:
Jack
2023-05-27 16:15:09 +02:00
committed by GitHub
parent 6253aaa015
commit c73416bdb8
5 changed files with 159 additions and 18 deletions

View File

@@ -229,10 +229,14 @@ class Budget extends PureComponent {
}),
});
} else {
this.props.updateCategory(category);
const cat = {
...category,
hidden: category.hidden ? 1 : 0,
};
this.props.updateCategory(cat);
this.setState({
categoryGroups: updateCategory(categoryGroups, category),
categoryGroups: updateCategory(categoryGroups, cat),
});
}
};
@@ -278,9 +282,14 @@ class Budget extends PureComponent {
}),
});
} else {
this.props.updateGroup(group);
const grp = {
...group,
hidden: group.hidden ? 1 : 0,
};
this.props.updateGroup(grp);
this.setState({
categoryGroups: updateGroup(categoryGroups, group),
categoryGroups: updateGroup(categoryGroups, grp),
});
}
};

View File

@@ -6,7 +6,11 @@ import React, {
useState,
useMemo,
} from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actions from 'loot-core/src/client/actions';
import * as monthUtils from 'loot-core/src/shared/months';
import useResizeObserver from '../../hooks/useResizeObserver';
@@ -14,6 +18,7 @@ import ExpandArrow from '../../icons/v0/ExpandArrow';
import ArrowThinLeft from '../../icons/v1/ArrowThinLeft';
import ArrowThinRight from '../../icons/v1/ArrowThinRight';
import CheveronDown from '../../icons/v1/CheveronDown';
import DotsHorizontalTriple from '../../icons/v1/DotsHorizontalTriple';
import { styles, colors } from '../../style';
import {
View,
@@ -42,7 +47,7 @@ function getScrollbarWidth() {
return Math.max(styles.scrollbarWidth - 2, 0);
}
export class BudgetTable extends Component {
class BudgetTable extends Component {
constructor(props) {
super(props);
this.budgetCategoriesRef = createRef();
@@ -50,6 +55,7 @@ export class BudgetTable extends Component {
this.state = {
editing: null,
draggingState: null,
showHiddenCategories: props.prefs['budget.showHiddenCategories'] ?? false,
};
}
@@ -166,6 +172,15 @@ export class BudgetTable extends Component {
this.setState({ editing: null });
}
toggleHiddenCategories = () => {
this.setState(prevState => ({
showHiddenCategories: !prevState.showHiddenCategories,
}));
this.props.savePrefs({
'budget.showHiddenCategories': !this.state.showHiddenCategories,
});
};
render() {
let {
type,
@@ -188,7 +203,7 @@ export class BudgetTable extends Component {
onShowNewGroup,
onHideNewGroup,
} = this.props;
let { editing, draggingState } = this.state;
let { editing, draggingState, showHiddenCategories } = this.state;
return (
<View
@@ -235,7 +250,10 @@ export class BudgetTable extends Component {
monthBounds={monthBounds}
type={type}
>
<BudgetTotals MonthComponent={dataComponents.BudgetTotalsComponent} />
<BudgetTotals
MonthComponent={dataComponents.BudgetTotalsComponent}
toggleHiddenCategories={this.toggleHiddenCategories}
/>
<IntersectionBoundary.Provider value={this.budgetCategoriesRef}>
<View
style={{
@@ -256,6 +274,7 @@ export class BudgetTable extends Component {
innerRef={el => (this.budgetDataNode = el)}
>
<BudgetCategories
showHiddenCategories={showHiddenCategories}
categoryGroups={categoryGroups}
newCategoryForGroup={newCategoryForGroup}
isAddingGroup={isAddingGroup}
@@ -287,6 +306,17 @@ export class BudgetTable extends Component {
}
}
const connected = connect(
state => ({
prefs: state.prefs.local,
}),
dispatch => bindActionCreators(actions, dispatch),
null,
{ forwardRef: true },
)(BudgetTable);
export { connected as BudgetTable };
export function SidebarCategory({
innerRef,
category,
@@ -313,6 +343,7 @@ export function SidebarCategory({
alignItems: 'center',
userSelect: 'none',
WebkitUserSelect: 'none',
opacity: category.hidden ? 0.33 : undefined,
}}
>
<div
@@ -352,12 +383,18 @@ export function SidebarCategory({
onMenuSelect={type => {
if (type === 'rename') {
onEditName(category.id);
} else {
} else if (type === 'delete') {
onDelete(category.id);
} else if (type === 'toggleVisibility') {
onSave({ ...category, hidden: !category.hidden });
}
setMenuOpen(false);
}}
items={[
{
name: 'toggleVisibility',
text: category.hidden ? 'Show' : 'Hide',
},
{ name: 'rename', text: 'Rename' },
{ name: 'delete', text: 'Delete' },
]}
@@ -513,13 +550,19 @@ export function SidebarGroup({
onEdit(group.id);
} else if (type === 'add-category') {
onShowNewCategory(group.id);
} else {
} else if (type === 'delete') {
onDelete(group.id);
} else if (type === 'toggleVisibility') {
onSave({ ...group, hidden: !group.hidden });
}
setMenuOpen(false);
}}
items={[
{ name: 'add-category', text: 'Add category' },
{
name: 'toggleVisibility',
text: group.hidden ? 'Show' : 'Hide',
},
{ name: 'rename', text: 'Rename' },
onDelete && { name: 'delete', text: 'Delete' },
]}
@@ -612,7 +655,11 @@ function RenderMonths({ component: Component, editingIndex, args, style }) {
});
}
const BudgetTotals = memo(function BudgetTotals({ MonthComponent }) {
const BudgetTotals = memo(function BudgetTotals({
MonthComponent,
toggleHiddenCategories,
}) {
const [menuOpen, setMenuOpen] = useState(false);
return (
<View
data-testid="budget-totals"
@@ -632,10 +679,54 @@ const BudgetTotals = memo(function BudgetTotals({ MonthComponent }) {
width: 200,
color: colors.n4,
justifyContent: 'center',
paddingLeft: 18,
paddingLeft: 15,
paddingRight: 5,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
userSelect: 'none',
WebkitUserSelect: 'none',
}}
>
Category
<View style={{ flexGrow: '1' }}>Category</View>
<Button
bare
onClick={() => {
setMenuOpen(true);
}}
style={{ color: 'currentColor', padding: 3 }}
>
<DotsHorizontalTriple
width={15}
height={15}
style={{ color: colors.n5 }}
/>
{menuOpen && (
<Tooltip
position="bottom-right"
width={200}
style={{ padding: 0 }}
onClose={() => {
setMenuOpen(false);
}}
>
<Menu
onMenuSelect={type => {
if (type === 'toggleVisibility') {
toggleHiddenCategories();
}
setMenuOpen(false);
}}
items={[
{
name: 'toggleVisibility',
text: 'Toggle hidden categories',
},
]}
/>
</Tooltip>
)}
</Button>
</View>
<RenderMonths component={MonthComponent} />
</View>
@@ -688,7 +779,10 @@ function ExpenseGroup({
<Row
collapsed={true}
backgroundColor={colors.n11}
style={{ fontWeight: 600 }}
style={{
fontWeight: 600,
opacity: group.hidden ? 0.33 : undefined,
}}
>
{dragState && !dragState.preview && dragState.type === 'group' && (
<View
@@ -774,7 +868,14 @@ function ExpenseCategory({
});
return (
<Row innerRef={dropRef} collapsed={true} backgroundColor="transparent">
<Row
innerRef={dropRef}
collapsed={true}
style={{
backgroundColor: 'transparent',
opacity: cat.hidden ? 0.5 : undefined,
}}
>
<DropHighlight pos={dropPos} offset={{ top: 1 }} />
<View
@@ -917,6 +1018,7 @@ const BudgetCategories = memo(
({
categoryGroups,
newCategoryForGroup,
showHiddenCategories,
isAddingGroup,
editingCell,
collapsed,
@@ -943,7 +1045,15 @@ const BudgetCategories = memo(
let items = Array.prototype.concat.apply(
[],
expenseGroups.map(group => {
let items = [{ type: 'expense-group', value: group }];
if (group.hidden && !showHiddenCategories) {
return [];
}
const groupCategories = group.categories.filter(
cat => showHiddenCategories || !cat.hidden,
);
let items = [{ type: 'expense-group', value: { ...group } }];
if (newCategoryForGroup === group.id) {
items.push({ type: 'new-category' });
@@ -951,7 +1061,7 @@ const BudgetCategories = memo(
return [
...items,
...(collapsed.includes(group.id) ? [] : group.categories).map(
...(collapsed.includes(group.id) ? [] : groupCategories).map(
cat => ({
type: 'expense-category',
value: cat,
@@ -973,7 +1083,9 @@ const BudgetCategories = memo(
newCategoryForGroup === incomeGroup.id && { type: 'new-category' },
...(collapsed.includes(incomeGroup.id)
? []
: incomeGroup.categories
: incomeGroup.categories.filter(
cat => showHiddenCategories || !cat.hidden,
)
).map(cat => ({
type: 'income-category',
value: cat,
@@ -983,7 +1095,13 @@ const BudgetCategories = memo(
}
return items;
}, [categoryGroups, collapsed, newCategoryForGroup, isAddingGroup]);
}, [
categoryGroups,
collapsed,
newCategoryForGroup,
isAddingGroup,
showHiddenCategories,
]);
let [dragState, setDragState] = useState(null);
let [savedCollapsed, setSavedCollapsed] = useState(null);

View File

@@ -0,0 +1,6 @@
BEGIN TRANSACTION;
ALTER TABLE categories ADD COLUMN hidden BOOLEAN NOT NULL DEFAULT 0;
ALTER TABLE category_groups ADD COLUMN hidden BOOLEAN NOT NULL DEFAULT 0;
COMMIT;

View File

@@ -72,6 +72,7 @@ export const schema = {
id: f('id'),
name: f('string'),
is_income: f('boolean'),
hidden: f('boolean'),
group: f('id', { ref: 'category_groups' }),
sort_order: f('float'),
tombstone: f('boolean'),
@@ -80,6 +81,7 @@ export const schema = {
id: f('id'),
name: f('string'),
is_income: f('boolean'),
hidden: f('boolean'),
sort_order: f('float'),
tombstone: f('boolean'),
},

View File

@@ -0,0 +1,6 @@
---
category: Features
authors: [Miodec]
---
Added the ability to hide category groups while keeping them in the same category group.