mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 12:43:09 -05:00
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:
@@ -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
|
||||
? [
|
||||
{
|
||||
|
||||
@@ -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 month’s 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>
|
||||
|
||||
@@ -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
|
||||
? [
|
||||
{
|
||||
|
||||
@@ -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 month’s 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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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: {
|
||||
|
||||
6
upcoming-release-notes/4096.md
Normal file
6
upcoming-release-notes/4096.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Enhancements
|
||||
authors: [psybers]
|
||||
---
|
||||
|
||||
Add Copy last 6/12 months to budget menu.
|
||||
Reference in New Issue
Block a user