Add Copy last 6/12 months to budget menu (#4096)

* Add Copy last 12 months to budget menu

* add release note

* Make sure budget month actions use showUndoNotification
This commit is contained in:
Robert Dyer
2025-01-07 18:33:03 -06:00
committed by GitHub
parent c956f8003b
commit 7dad36528c
9 changed files with 174 additions and 2 deletions

View File

@@ -43,6 +43,12 @@ export function BudgetMonthMenu({
case 'set-3-avg':
onSetMonthsAverage(3);
break;
case 'set-6-avg':
onSetMonthsAverage(6);
break;
case 'set-12-avg':
onSetMonthsAverage(12);
break;
case 'check-templates':
onCheckTemplates();
break;
@@ -64,6 +70,14 @@ export function BudgetMonthMenu({
name: 'set-3-avg',
text: t('Set budgets to 3 month average'),
},
{
name: 'set-6-avg',
text: t('Set budgets to 6 month average'),
},
{
name: 'set-12-avg',
text: t('Set budgets to 12 month average'),
},
...(isGoalTemplatesEnabled
? [
{

View File

@@ -1,9 +1,11 @@
import React, { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from '@emotion/css';
import * as monthUtils from 'loot-core/src/shared/months';
import { useUndo } from '../../../../hooks/useUndo';
import { SvgDotsHorizontalTriple } from '../../../../icons/v1';
import { SvgArrowButtonDown1, SvgArrowButtonUp1 } from '../../../../icons/v2';
import { theme, styles } from '../../../../style';
@@ -32,6 +34,7 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
const [menuOpen, setMenuOpen] = useState(false);
const triggerRef = useRef(null);
const { showUndoNotification } = useUndo();
function onMenuOpen() {
setMenuOpen(true);
@@ -47,6 +50,9 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
? SvgArrowButtonDown1
: SvgArrowButtonUp1;
const displayMonth = monthUtils.format(month, 'MMMM yy');
const { t } = useTranslation();
return (
<View
data-testid="budget-summary"
@@ -89,7 +95,11 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
>
<Button
variant="bare"
aria-label={`${collapsed ? 'Expand' : 'Collapse'} month summary`}
aria-label={
collapsed
? t('Expand month summary')
: t('Collapse month summary')
}
className="hover-visible"
onPress={onToggleSummaryCollapse}
>
@@ -139,7 +149,7 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
<Button
ref={triggerRef}
variant="bare"
aria-label="Menu"
aria-label={t('Menu')}
onPress={onMenuOpen}
>
<SvgDotsHorizontalTriple
@@ -158,14 +168,36 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
onCopyLastMonthBudget={() => {
onBudgetAction(month, 'copy-last');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budgets have all been set to last months budgeted amounts.',
{ displayMonth },
),
});
}}
onSetBudgetsToZero={() => {
onBudgetAction(month, 'set-zero');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budgets have all been set to zero.',
{ displayMonth },
),
});
}}
onSetMonthsAverage={numberOfMonths => {
onBudgetAction(month, `set-${numberOfMonths}-avg`);
onMenuClose();
showUndoNotification({
message:
numberOfMonths === 12
? t(
`${displayMonth} budgets have all been set to yearly average.`,
)
: t(
`${displayMonth} budgets have all been set to ${numberOfMonths} month average.`,
),
});
}}
onCheckTemplates={() => {
onBudgetAction(month, 'check-templates');
@@ -174,14 +206,32 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
onApplyBudgetTemplates={() => {
onBudgetAction(month, 'apply-goal-template');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budget templates have been applied.',
{ displayMonth },
),
});
}}
onOverwriteWithBudgetTemplates={() => {
onBudgetAction(month, 'overwrite-goal-template');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budget templates have been overwritten.',
{ displayMonth },
),
});
}}
onEndOfMonthCleanup={() => {
onBudgetAction(month, 'cleanup-goal-template');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} end-of-month cleanup templates have been applied.',
{ displayMonth },
),
});
}}
/>
</Popover>

View File

@@ -41,6 +41,12 @@ export function BudgetMonthMenu({
case 'set-3-avg':
onSetMonthsAverage(3);
break;
case 'set-6-avg':
onSetMonthsAverage(6);
break;
case 'set-12-avg':
onSetMonthsAverage(12);
break;
case 'check-templates':
onCheckTemplates();
break;
@@ -59,6 +65,14 @@ export function BudgetMonthMenu({
name: 'set-3-avg',
text: t('Set budgets to 3 month average'),
},
{
name: 'set-6-avg',
text: t('Set budgets to 6 month average'),
},
{
name: 'set-12-avg',
text: t('Set budgets to 12 month average'),
},
...(isGoalTemplatesEnabled
? [
{

View File

@@ -6,6 +6,7 @@ import { css } from '@emotion/css';
import * as monthUtils from 'loot-core/src/shared/months';
import { useUndo } from '../../../../hooks/useUndo';
import { SvgDotsHorizontalTriple } from '../../../../icons/v1';
import { SvgArrowButtonDown1, SvgArrowButtonUp1 } from '../../../../icons/v2';
import { theme, styles } from '../../../../style';
@@ -36,6 +37,7 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
const [menuOpen, setMenuOpen] = useState(false);
const triggerRef = useRef(null);
const { showUndoNotification } = useUndo();
function onMenuOpen() {
setMenuOpen(true);
@@ -49,6 +51,8 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
? SvgArrowButtonDown1
: SvgArrowButtonUp1;
const displayMonth = monthUtils.format(month, 'MMMM yy');
return (
<View
style={{
@@ -160,14 +164,36 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
onCopyLastMonthBudget={() => {
onBudgetAction(month, 'copy-last');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budgets have all been set to last months budgeted amounts.',
{ displayMonth },
),
});
}}
onSetBudgetsToZero={() => {
onBudgetAction(month, 'set-zero');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budgets have all been set to zero.',
{ displayMonth },
),
});
}}
onSetMonthsAverage={numberOfMonths => {
onBudgetAction(month, `set-${numberOfMonths}-avg`);
onMenuClose();
showUndoNotification({
message:
numberOfMonths === 12
? t(
`${displayMonth} budgets have all been set to yearly average.`,
)
: t(
`${displayMonth} budgets have all been set to ${numberOfMonths} month average.`,
),
});
}}
onCheckTemplates={() => {
onBudgetAction(month, 'check-templates');
@@ -176,10 +202,22 @@ export function BudgetSummary({ month }: BudgetSummaryProps) {
onApplyBudgetTemplates={() => {
onBudgetAction(month, 'apply-goal-template');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budget templates have been applied.',
{ displayMonth },
),
});
}}
onOverwriteWithBudgetTemplates={() => {
onBudgetAction(month, 'overwrite-goal-template');
onMenuClose();
showUndoNotification({
message: t(
'{{displayMonth}} budget templates have been overwritten.',
{ displayMonth },
),
});
}}
/>
</Popover>

View File

@@ -29,6 +29,12 @@ export function applyBudgetAction(month, type, args) {
case 'set-3-avg':
await send('budget/set-3month-avg', { month });
break;
case 'set-6-avg':
await send('budget/set-6month-avg', { month });
break;
case 'set-12-avg':
await send('budget/set-12month-avg', { month });
break;
case 'check-templates':
dispatch(addNotification(await send('budget/check-templates')));
break;

View File

@@ -282,6 +282,44 @@ export async function set3MonthAvg({
});
}
export async function set12MonthAvg({
month,
}: {
month: string;
}): Promise<void> {
const categories = await db.all(
'SELECT * FROM v_categories WHERE tombstone = 0',
);
await batchMessages(async () => {
for (const cat of categories) {
if (cat.is_income === 1 && !isReflectBudget()) {
continue;
}
setNMonthAvg({ month, N: 12, category: cat.id });
}
});
}
export async function set6MonthAvg({
month,
}: {
month: string;
}): Promise<void> {
const categories = await db.all(
'SELECT * FROM v_categories WHERE tombstone = 0',
);
await batchMessages(async () => {
for (const cat of categories) {
if (cat.is_income === 1 && !isReflectBudget()) {
continue;
}
setNMonthAvg({ month, N: 6, category: cat.id });
}
});
}
export async function setNMonthAvg({
month,
N,

View File

@@ -20,6 +20,8 @@ app.method(
);
app.method('budget/set-zero', mutator(undoable(actions.setZero)));
app.method('budget/set-3month-avg', mutator(undoable(actions.set3MonthAvg)));
app.method('budget/set-6month-avg', mutator(undoable(actions.set6MonthAvg)));
app.method('budget/set-12month-avg', mutator(undoable(actions.set12MonthAvg)));
app.method('budget/set-n-month-avg', mutator(undoable(actions.setNMonthAvg)));
app.method(
'budget/check-templates',

View File

@@ -13,6 +13,10 @@ export interface BudgetHandlers {
'budget/set-3month-avg': (arg: { month: string }) => Promise<void>;
'budget/set-6month-avg': (arg: { month: string }) => Promise<void>;
'budget/set-12month-avg': (arg: { month: string }) => Promise<void>;
'budget/check-templates': () => Promise<Notification>;
'budget/apply-goal-template': (arg: {

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [psybers]
---
Add Copy last 6/12 months to budget menu.