Skip to content

Commit

Permalink
Break apart budget/misc.js (actualbudget#1584)
Browse files Browse the repository at this point in the history
* Break apart budget/misc.js

* Release notes

* Rename release notes

* UI bolder "No server" text
  • Loading branch information
joel-jeremy committed Sep 5, 2023
1 parent 256d368 commit 5a58b30
Show file tree
Hide file tree
Showing 22 changed files with 1,496 additions and 1,375 deletions.
8 changes: 7 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,19 @@ module.exports = {
'./packages/desktop-client/src/components/UpdateNotification.*',
'./packages/desktop-client/src/components/accounts/Header.*',
'./packages/desktop-client/src/components/alerts.*',
'./packages/desktop-client/src/components/budget/BudgetCategories.*',
'./packages/desktop-client/src/components/budget/BudgetTotals.*',
'./packages/desktop-client/src/components/budget/ExpenseGroup.*',
'./packages/desktop-client/src/components/budget/IncomeGroup.*',
'./packages/desktop-client/src/components/budget/MobileBudget.*',
'./packages/desktop-client/src/components/budget/MobileBudgetTable.*',
'./packages/desktop-client/src/components/budget/MobileTable.*',
'./packages/desktop-client/src/components/budget/MonthCountSelector.*',
'./packages/desktop-client/src/components/budget/MonthPicker.*',
'./packages/desktop-client/src/components/budget/RenderMonths.*',
'./packages/desktop-client/src/components/budget/SidebarCategory.*',
'./packages/desktop-client/src/components/budget/SidebarGroup.*',
'./packages/desktop-client/src/components/budget/constants.*',
'./packages/desktop-client/src/components/budget/misc.*',
'./packages/desktop-client/src/components/budget/report/BudgetSummary.*',
'./packages/desktop-client/src/components/budget/report/components.*',
'./packages/desktop-client/src/components/budget/rollover/BudgetSummary.*',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
316 changes: 316 additions & 0 deletions packages/desktop-client/src/components/budget/BudgetCategories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
import React, { memo, useState, useMemo } from 'react';

import { colors } from '../../style';
import View from '../common/View';
import { DropHighlightPosContext } from '../sort';
import { Row } from '../table';

import { INCOME_HEADER_HEIGHT, MONTH_BOX_SHADOW } from './constants';
import ExpenseCategory from './ExpenseCategory';
import ExpenseGroup from './ExpenseGroup';
import IncomeCategory from './IncomeCategory';
import IncomeGroup from './IncomeGroup';
import IncomeHeader from './IncomeHeader';
import SidebarCategory from './SidebarCategory';
import SidebarGroup from './SidebarGroup';
import { separateGroups } from './util';

const BudgetCategories = memo(
({
categoryGroups,
newCategoryForGroup,
showHiddenCategories,
isAddingGroup,
editingCell,
collapsed,
setCollapsed,
dataComponents,
onBudgetAction,
onShowActivity,
onEditName,
onEditMonth,
onSaveCategory,
onSaveGroup,
onDeleteCategory,
onDeleteGroup,
onReorderCategory,
onReorderGroup,
onShowNewCategory,
onHideNewCategory,
onShowNewGroup,
onHideNewGroup,
}) => {
let items = useMemo(() => {
let [expenseGroups, incomeGroup] = separateGroups(categoryGroups);

let items = Array.prototype.concat.apply(
[],
expenseGroups.map(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' });
}

return [
...items,
...(collapsed.includes(group.id) ? [] : groupCategories).map(
cat => ({
type: 'expense-category',
value: cat,
}),
),
];
}),
);

if (isAddingGroup) {
items.push({ type: 'new-group' });
}

if (incomeGroup) {
items = items.concat(
[
{ type: 'income-separator' },
{ type: 'income-group', value: incomeGroup },
newCategoryForGroup === incomeGroup.id && { type: 'new-category' },
...(collapsed.includes(incomeGroup.id)
? []
: incomeGroup.categories.filter(
cat => showHiddenCategories || !cat.hidden,
)
).map(cat => ({
type: 'income-category',
value: cat,
})),
].filter(x => x),
);
}

return items;
}, [
categoryGroups,
collapsed,
newCategoryForGroup,
isAddingGroup,
showHiddenCategories,
]);

let [dragState, setDragState] = useState(null);
let [savedCollapsed, setSavedCollapsed] = useState(null);

// TODO: If we turn this into a reducer, we could probably memoize
// each item in the list for better perf
function onDragChange(newDragState) {
let { state } = newDragState;

if (state === 'start-preview') {
setDragState({
type: newDragState.type,
item: newDragState.item,
preview: true,
});
} else if (state === 'start') {
if (dragState) {
setDragState({
...dragState,
preview: false,
});
setSavedCollapsed(collapsed);
}
} else if (state === 'hover') {
setDragState({
...dragState,
hoveredId: newDragState.id,
hoveredPos: newDragState.pos,
});
} else if (state === 'end') {
setDragState(null);
setCollapsed(savedCollapsed || []);
}
}

function onToggleCollapse(id) {
if (collapsed.includes(id)) {
setCollapsed(collapsed.filter(id_ => id_ !== id));
} else {
setCollapsed([...collapsed, id]);
}
}

return (
<View
style={{
marginBottom: 10,
backgroundColor: 'white',
overflow: 'hidden',
boxShadow: MONTH_BOX_SHADOW,
borderRadius: '0 0 4px 4px',
flex: 1,
}}
>
{items.map((item, idx) => {
let content;
switch (item.type) {
case 'new-group':
content = (
<Row style={{ backgroundColor: colors.n11 }}>
<SidebarGroup
group={{ id: 'new', name: '' }}
editing={true}
onSave={onSaveGroup}
onHideNewGroup={onHideNewGroup}
onEdit={onEditName}
/>
</Row>
);
break;
case 'new-category':
content = (
<Row>
<SidebarCategory
category={{
name: '',
cat_group: newCategoryForGroup,
is_income:
newCategoryForGroup ===
categoryGroups.find(g => g.is_income).id,
id: 'new',
}}
editing={true}
onSave={onSaveCategory}
onHideNewCategory={onHideNewCategory}
onEditName={onEditName}
/>
</Row>
);
break;

case 'expense-group':
content = (
<ExpenseGroup
group={item.value}
editingCell={editingCell}
collapsed={collapsed.includes(item.value.id)}
MonthComponent={dataComponents.ExpenseGroupComponent}
dragState={dragState}
onEditName={onEditName}
onSave={onSaveGroup}
onDelete={onDeleteGroup}
onDragChange={onDragChange}
onReorderGroup={onReorderGroup}
onReorderCategory={onReorderCategory}
onToggleCollapse={onToggleCollapse}
onShowNewCategory={onShowNewCategory}
/>
);
break;
case 'expense-category':
content = (
<ExpenseCategory
cat={item.value}
editingCell={editingCell}
MonthComponent={dataComponents.ExpenseCategoryComponent}
dragState={dragState}
onEditName={onEditName}
onEditMonth={onEditMonth}
onSave={onSaveCategory}
onDelete={onDeleteCategory}
onDragChange={onDragChange}
onReorder={onReorderCategory}
onBudgetAction={onBudgetAction}
onShowActivity={onShowActivity}
/>
);
break;
case 'income-separator':
content = (
<View
style={{
height: INCOME_HEADER_HEIGHT,
backgroundColor: 'white',
}}
>
<IncomeHeader
MonthComponent={dataComponents.IncomeHeaderComponent}
onShowNewGroup={onShowNewGroup}
/>
</View>
);
break;
case 'income-group':
content = (
<IncomeGroup
group={item.value}
editingCell={editingCell}
MonthComponent={dataComponents.IncomeGroupComponent}
collapsed={collapsed.includes(item.value.id)}
onEditName={onEditName}
onSave={onSaveGroup}
onToggleCollapse={onToggleCollapse}
onShowNewCategory={onShowNewCategory}
/>
);
break;
case 'income-category':
content = (
<IncomeCategory
cat={item.value}
editingCell={editingCell}
isLast={idx === items.length - 1}
MonthComponent={dataComponents.IncomeCategoryComponent}
onEditName={onEditName}
onEditMonth={onEditMonth}
onSave={onSaveCategory}
onDelete={onDeleteCategory}
onDragChange={onDragChange}
onReorder={onReorderCategory}
onBudgetAction={onBudgetAction}
onShowActivity={onShowActivity}
/>
);
break;
default:
throw new Error('Unknown item type: ' + item.type);
}

let pos =
idx === 0 ? 'first' : idx === items.length - 1 ? 'last' : null;

return (
<DropHighlightPosContext.Provider
key={
item.value
? item.value.id
: item.type === 'income-separator'
? 'separator'
: idx
}
value={pos}
>
<View
style={
!dragState && {
':hover': { backgroundColor: '#fcfcfc' },
}
}
>
{content}
</View>
</DropHighlightPosContext.Provider>
);
})}
</View>
);
},
);

export default BudgetCategories;
40 changes: 40 additions & 0 deletions packages/desktop-client/src/components/budget/BudgetPageHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { memo } from 'react';

import * as monthUtils from 'loot-core/src/shared/months';

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

import { MonthPicker } from './MonthPicker';
import { getScrollbarWidth } from './util';

const BudgetPageHeader = memo(
({ startMonth, onMonthSelect, numMonths, monthBounds, style }) => {
function getValidMonth(month) {
let start = monthBounds.start;
let end = monthUtils.subMonths(monthBounds.end, numMonths - 1);

if (month < start) {
return start;
} else if (month > end) {
return end;
}
return month;
}

return (
<View style={{ marginLeft: 200 + 5, flexShrink: 0 }}>
<View style={{ marginRight: 5 + getScrollbarWidth() }}>
<MonthPicker
startMonth={startMonth}
numDisplayed={numMonths}
monthBounds={monthBounds}
style={{ paddingTop: 5 }}
onSelect={month => onMonthSelect(getValidMonth(month))}
/>
</View>
</View>
);
},
);

export default BudgetPageHeader;
Loading

0 comments on commit 5a58b30

Please sign in to comment.