Skip to content

Commit

Permalink
[Mobile] Category budget actions modal (#2501)
Browse files Browse the repository at this point in the history
* Update autocomplete types

* Remote optional type

* Improve SingleInputModal

* Fix lint error

* Category budget modals

* Cleanup + release notes

* Cleanup

* Fix typecheck errors

* Update useMergedRefs

* Fix lint error

* Fix typecheck error

* VRT updates

* Focus amount on mount

* Fix errors

* Open modal on budget amount click

* Updates

* Remove unused props + updates

* Fix lint error

* Close budget menu modal on enter

* Delete comment

Co-authored-by: Matiss Janis Aboltins <[email protected]>

* Update release notes

---------

Co-authored-by: Matiss Janis Aboltins <[email protected]>
  • Loading branch information
joel-jeremy and MatissJanis authored Apr 13, 2024
1 parent 2d188b3 commit e500cba
Show file tree
Hide file tree
Showing 36 changed files with 800 additions and 358 deletions.
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.
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.
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.
45 changes: 40 additions & 5 deletions packages/desktop-client/src/components/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useSyncServerStatus } from '../hooks/useSyncServerStatus';
import { ModalTitle } from './common/Modal';
import { AccountAutocompleteModal } from './modals/AccountAutocompleteModal';
import { AccountMenuModal } from './modals/AccountMenuModal';
import { BudgetMenuModal } from './modals/BudgetMenuModal';
import { BudgetMonthMenuModal } from './modals/BudgetMonthMenuModal';
import { CategoryAutocompleteModal } from './modals/CategoryAutocompleteModal';
import { CategoryGroupMenuModal } from './modals/CategoryGroupMenuModal';
import { CategoryMenuModal } from './modals/CategoryMenuModal';
Expand All @@ -40,8 +40,10 @@ import { Notes } from './modals/Notes';
import { PayeeAutocompleteModal } from './modals/PayeeAutocompleteModal';
import { PlaidExternalMsg } from './modals/PlaidExternalMsg';
import { ReportBalanceMenuModal } from './modals/ReportBalanceMenuModal';
import { ReportBudgetMenuModal } from './modals/ReportBudgetMenuModal';
import { ReportBudgetSummaryModal } from './modals/ReportBudgetSummaryModal';
import { RolloverBalanceMenuModal } from './modals/RolloverBalanceMenuModal';
import { RolloverBudgetMenuModal } from './modals/RolloverBudgetMenuModal';
import { RolloverBudgetSummaryModal } from './modals/RolloverBudgetSummaryModal';
import { RolloverToBudgetMenuModal } from './modals/RolloverToBudgetMenuModal';
import { ScheduledTransactionMenuModal } from './modals/ScheduledTransactionMenuModal';
Expand Down Expand Up @@ -429,14 +431,47 @@ export function Modals() {
key={name}
modalProps={modalProps}
categoryId={options.categoryId}
categoryGroup={options.categoryGroup}
onSave={options.onSave}
onEditNotes={options.onEditNotes}
onDelete={options.onDelete}
onClose={options.onClose}
/>
);

case 'rollover-budget-menu':
return (
<NamespaceContext.Provider
key={name}
value={monthUtils.sheetForMonth(options.month)}
>
<RolloverBudgetMenuModal
modalProps={modalProps}
categoryId={options.categoryId}
onUpdateBudget={options.onUpdateBudget}
onCopyLastMonthAverage={options.onCopyLastMonthAverage}
onSetMonthsAverage={options.onSetMonthsAverage}
onApplyBudgetTemplate={options.onApplyBudgetTemplate}
/>
</NamespaceContext.Provider>
);

case 'report-budget-menu':
return (
<NamespaceContext.Provider
key={name}
value={monthUtils.sheetForMonth(options.month)}
>
<ReportBudgetMenuModal
modalProps={modalProps}
categoryId={options.categoryId}
onUpdateBudget={options.onUpdateBudget}
onCopyLastMonthAverage={options.onCopyLastMonthAverage}
onSetMonthsAverage={options.onSetMonthsAverage}
onApplyBudgetTemplate={options.onApplyBudgetTemplate}
/>
</NamespaceContext.Provider>
);

case 'category-group-menu':
return (
<CategoryGroupMenuModal
Expand Down Expand Up @@ -479,7 +514,7 @@ export function Modals() {
</NamespaceContext.Provider>
);

case 'rollover-to-budget-menu':
case 'rollover-summary-to-budget-menu':
return (
<NamespaceContext.Provider
key={name}
Expand Down Expand Up @@ -552,13 +587,13 @@ export function Modals() {
/>
);

case 'budget-menu':
case 'budget-month-menu':
return (
<NamespaceContext.Provider
key={name}
value={monthUtils.sheetForMonth(options.month)}
>
<BudgetMenuModal
<BudgetMonthMenuModal
modalProps={modalProps}
month={options.month}
onToggleHiddenCategories={options.onToggleHiddenCategories}
Expand Down
22 changes: 4 additions & 18 deletions packages/desktop-client/src/components/budget/BudgetTable.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React, { useRef, useState } from 'react';

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

import { useCategories } from '../../hooks/useCategories';
import { useLocalPref } from '../../hooks/useLocalPref';
import { theme, styles } from '../../style';
Expand Down Expand Up @@ -40,8 +38,8 @@ export function BudgetTable(props) {
);
const [editing, setEditing] = useState(null);

const onEditMonth = (id, monthIndex) => {
setEditing(id ? { id, cell: monthIndex } : null);
const onEditMonth = (id, month) => {
setEditing(id ? { id, cell: month } : null);
};

const onEditName = id => {
Expand Down Expand Up @@ -134,18 +132,6 @@ export function BudgetTable(props) {
}
};

const resolveMonth = monthIndex => {
return monthUtils.addMonths(startMonth, monthIndex);
};

const _onShowActivity = (catId, monthIndex) => {
onShowActivity(catId, resolveMonth(monthIndex));
};

const _onBudgetAction = (monthIndex, type, args) => {
onBudgetAction(resolveMonth(monthIndex), type, args);
};

const onCollapse = collapsedIds => {
setCollapsedPref(collapsedIds);
};
Expand Down Expand Up @@ -244,8 +230,8 @@ export function BudgetTable(props) {
onDeleteGroup={onDeleteGroup}
onReorderCategory={_onReorderCategory}
onReorderGroup={_onReorderGroup}
onBudgetAction={_onBudgetAction}
onShowActivity={_onShowActivity}
onBudgetAction={onBudgetAction}
onShowActivity={onShowActivity}
/>
</View>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ type ExpenseCategoryProps = {
dragState: DragState<CategoryEntity>;
MonthComponent: ComponentProps<typeof RenderMonths>['component'];
onEditName?: ComponentProps<typeof SidebarCategory>['onEditName'];
onEditMonth?: (id: string, monthIndex: number) => void;
onEditMonth?: (id: string, month: string) => void;
onSave?: ComponentProps<typeof SidebarCategory>['onSave'];
onDelete?: ComponentProps<typeof SidebarCategory>['onDelete'];
onDragChange: OnDragChangeCallback<CategoryEntity>;
onBudgetAction: (idx: number, action: string, arg: unknown) => void;
onShowActivity: (id: string, idx: number) => void;
onBudgetAction: (month: number, action: string, arg: unknown) => void;
onShowActivity: (id: string, month: string) => void;
onReorder: OnDropCallback;
};

Expand Down Expand Up @@ -101,7 +101,7 @@ export function ExpenseCategory({

<RenderMonths
component={MonthComponent}
editingIndex={
editingMonth={
editingCell && editingCell.id === cat.id && editingCell.cell
}
args={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ type IncomeCategoryProps = {
editingCell: { id: string; cell: string } | null;
MonthComponent: ComponentProps<typeof RenderMonths>['component'];
onEditName: ComponentProps<typeof SidebarCategory>['onEditName'];
onEditMonth?: (id: string, monthIndex: number) => void;
onEditMonth?: (id: string, month: string) => void;
onSave: ComponentProps<typeof SidebarCategory>['onSave'];
onDelete: ComponentProps<typeof SidebarCategory>['onDelete'];
onDragChange: OnDragChangeCallback<CategoryEntity>;
onBudgetAction: (idx: number, action: string, arg: unknown) => void;
onBudgetAction: (month: string, action: string, arg: unknown) => void;
onReorder: OnDropCallback;
onShowActivity: (id: string, idx: number) => void;
onShowActivity: (id: string, month: string) => void;
};

export function IncomeCategory({
Expand Down Expand Up @@ -76,7 +76,7 @@ export function IncomeCategory({
/>
<RenderMonths
component={MonthComponent}
editingIndex={
editingMonth={
editingCell && editingCell.id === cat.id && editingCell.cell
}
args={{
Expand Down
10 changes: 5 additions & 5 deletions packages/desktop-client/src/components/budget/RenderMonths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ import { NamespaceContext } from '../spreadsheet/NamespaceContext';
import { MonthsContext } from './MonthsContext';

type RenderMonthsProps = {
component?: ComponentType<{ monthIndex: number; editing: boolean }>;
editingIndex?: string | number;
component?: ComponentType<{ month: string; editing: boolean }>;
editingMonth?: string;
args?: object;
style?: CSSProperties;
};

export function RenderMonths({
component: Component,
editingIndex,
editingMonth,
args,
style,
}: RenderMonthsProps) {
const { months } = useContext(MonthsContext);

return months.map((month, index) => {
const editing = editingIndex === index;
const editing = editingMonth === month;

return (
<NamespaceContext.Provider
Expand All @@ -43,7 +43,7 @@ export function RenderMonths({
...style,
}}
>
<Component monthIndex={index} editing={editing} {...args} />
<Component month={month} editing={editing} {...args} />
</View>
</NamespaceContext.Provider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { BalanceMenu } from './BalanceMenu';
type BalanceTooltipProps = {
categoryId: string;
tooltip: { close: () => void };
monthIndex: number;
onBudgetAction: (idx: number, action: string, arg: unknown) => void;
month: string;
onBudgetAction: (month: string, action: string, arg: unknown) => void;
onClose?: () => void;
};

export function BalanceTooltip({
categoryId,
tooltip,
monthIndex,
month,
onBudgetAction,
onClose,
...tooltipProps
Expand All @@ -36,7 +36,7 @@ export function BalanceTooltip({
<BalanceMenu
categoryId={categoryId}
onCarryover={carryover => {
onBudgetAction?.(monthIndex, 'carryover', {
onBudgetAction?.(month, 'carryover', {
category: categoryId,
flag: carryover,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { type ComponentPropsWithoutRef } from 'react';

import { useFeatureFlag } from '../../../hooks/useFeatureFlag';
import { Menu } from '../../common/Menu';

type BudgetMenuProps = Omit<
ComponentPropsWithoutRef<typeof Menu>,
'onMenuSelect' | 'items'
> & {
onCopyLastMonthAverage: () => void;
onSetMonthsAverage: (numberOfMonths: number) => void;
onApplyBudgetTemplate: () => void;
};
export function BudgetMenu({
onCopyLastMonthAverage,
onSetMonthsAverage,
onApplyBudgetTemplate,
...props
}: BudgetMenuProps) {
const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
const onMenuSelect = (name: string) => {
switch (name) {
case 'copy-single-last':
onCopyLastMonthAverage?.();
break;
case 'set-single-3-avg':
onSetMonthsAverage?.(3);
break;
case 'set-single-6-avg':
onSetMonthsAverage?.(6);
break;
case 'set-single-12-avg':
onSetMonthsAverage?.(12);
break;
case 'apply-single-category-template':
onApplyBudgetTemplate?.();
break;
default:
throw new Error(`Unrecognized menu item: ${name}`);
}
};

return (
<Menu
{...props}
onMenuSelect={onMenuSelect}
items={[
{
name: 'copy-single-last',
text: 'Copy last month’s budget',
},
{
name: 'set-single-3-avg',
text: 'Set to 3 month average',
},
{
name: 'set-single-6-avg',
text: 'Set to 6 month average',
},
{
name: 'set-single-12-avg',
text: 'Set to yearly average',
},
...(isGoalTemplatesEnabled
? [
{
name: 'apply-single-category-template',
text: 'Apply budget template',
},
]
: []),
]}
/>
);
}
Loading

0 comments on commit e500cba

Please sign in to comment.