diff --git a/packages/api/package.json b/packages/api/package.json index b44b0152ff5..4f9c4adc949 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@actual-app/api", - "version": "24.11.0", + "version": "24.12.0", "license": "MIT", "description": "An API for Actual", "engines": { diff --git a/packages/desktop-client/e2e/page-models/mobile-navigation.js b/packages/desktop-client/e2e/page-models/mobile-navigation.js index ebda4cbb777..6881b4d399e 100644 --- a/packages/desktop-client/e2e/page-models/mobile-navigation.js +++ b/packages/desktop-client/e2e/page-models/mobile-navigation.js @@ -1,3 +1,4 @@ +import { MobileAccountPage } from './mobile-account-page'; import { MobileAccountsPage } from './mobile-accounts-page'; import { MobileBudgetPage } from './mobile-budget-page'; import { MobileTransactionEntryPage } from './mobile-transaction-entry-page'; @@ -22,6 +23,13 @@ export class MobileNavigation { return new MobileAccountsPage(this.page); } + async goToUncategorizedPage() { + const button = this.page.getByRole('button', { name: /uncategorized/ }); + await button.click(); + + return new MobileAccountPage(this.page); + } + async goToTransactionEntryPage() { const link = this.page.getByRole('link', { name: 'Transaction' }); await link.click(); diff --git a/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-1-chromium-linux.png b/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-1-chromium-linux.png index 2f01d4b21a4..8b6fb7dfc07 100644 Binary files a/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-1-chromium-linux.png and b/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-2-chromium-linux.png b/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-2-chromium-linux.png index 2619303ee1f..e821884d439 100644 Binary files a/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-2-chromium-linux.png and b/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-2-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-3-chromium-linux.png b/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-3-chromium-linux.png index e91f7df9a86..986929ddd5d 100644 Binary files a/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-3-chromium-linux.png and b/packages/desktop-client/e2e/reports.test.js-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-3-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js b/packages/desktop-client/e2e/transactions.mobile.test.js index 0327dc2b585..822b3b4c2a8 100644 --- a/packages/desktop-client/e2e/transactions.mobile.test.js +++ b/packages/desktop-client/e2e/transactions.mobile.test.js @@ -48,11 +48,8 @@ test.describe('Mobile Transactions', () => { ); await expect(page).toMatchThemeScreenshots(); - const accountPage = await transactionEntryPage.createTransaction(); - - await expect(accountPage.transactions.nth(0)).toHaveText( - 'KrogerClothing-12.34', - ); + await transactionEntryPage.createTransaction(); + await expect(page.getByLabel('Transaction list')).toHaveCount(0); await expect(page).toMatchThemeScreenshots(); }); @@ -82,4 +79,74 @@ test.describe('Mobile Transactions', () => { 'KrogerClothing-12.34', ); }); + + test('creates an uncategorized transaction from `/accounts/uncategorized` page', async () => { + // Create uncategorized transaction + let transactionEntryPage = await navigation.goToTransactionEntryPage(); + await transactionEntryPage.amountField.fill('12.35'); + // Click anywhere to cancel active edit. + await transactionEntryPage.header.click(); + await transactionEntryPage.fillField( + page.getByTestId('account-field'), + 'Ally Savings', + ); + await transactionEntryPage.createTransaction(); + + const uncategorizedPage = await navigation.goToUncategorizedPage(); + transactionEntryPage = await uncategorizedPage.clickCreateTransaction(); + + await expect(transactionEntryPage.header).toHaveText('New Transaction'); + + await transactionEntryPage.amountField.fill('12.34'); + // Click anywhere to cancel active edit. + await transactionEntryPage.header.click(); + await transactionEntryPage.fillField( + page.getByTestId('payee-field'), + 'Kroger', + ); + + await transactionEntryPage.createTransaction(); + + await expect(uncategorizedPage.transactions.nth(0)).toHaveText( + 'KrogerUncategorized-12.34', + ); + await expect(page).toMatchThemeScreenshots(); + }); + + test('creates a categorized transaction from `/accounts/uncategorized` page', async () => { + // Create uncategorized transaction + let transactionEntryPage = await navigation.goToTransactionEntryPage(); + await transactionEntryPage.amountField.fill('12.35'); + // Click anywhere to cancel active edit. + await transactionEntryPage.header.click(); + await transactionEntryPage.fillField( + page.getByTestId('account-field'), + 'Ally Savings', + ); + await transactionEntryPage.createTransaction(); + + const uncategorizedPage = await navigation.goToUncategorizedPage(); + transactionEntryPage = await uncategorizedPage.clickCreateTransaction(); + + await expect(transactionEntryPage.header).toHaveText('New Transaction'); + + await transactionEntryPage.amountField.fill('12.34'); + // Click anywhere to cancel active edit. + await transactionEntryPage.header.click(); + await transactionEntryPage.fillField( + page.getByTestId('payee-field'), + 'Kroger', + ); + await transactionEntryPage.fillField( + page.getByTestId('category-field'), + 'Clothing', + ); + + await transactionEntryPage.createTransaction(); + + await expect(uncategorizedPage.transactions.nth(0)).toHaveText( + '(No payee)Uncategorized-12.35', + ); + await expect(page).toMatchThemeScreenshots(); + }); }); diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-1-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-1-chromium-linux.png new file mode 100644 index 00000000000..ad64d91030a Binary files /dev/null and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-2-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-2-chromium-linux.png new file mode 100644 index 00000000000..c7cd31e05e4 Binary files /dev/null and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-2-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-3-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-3-chromium-linux.png new file mode 100644 index 00000000000..bdcad535d4a Binary files /dev/null and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-categorized-transaction-from-accounts-uncategorized-page-3-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-7-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-7-chromium-linux.png index 09c4a4473d5..5d6a84f5a7a 100644 Binary files a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-7-chromium-linux.png and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-7-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-8-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-8-chromium-linux.png index 02118f4e429..c8ed30e1d63 100644 Binary files a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-8-chromium-linux.png and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-8-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-9-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-9-chromium-linux.png index 58a53f0cd3f..d10b3d513df 100644 Binary files a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-9-chromium-linux.png and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-a-transaction-via-footer-button-9-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-1-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-1-chromium-linux.png new file mode 100644 index 00000000000..72f98361371 Binary files /dev/null and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-2-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-2-chromium-linux.png new file mode 100644 index 00000000000..1a2ebaae049 Binary files /dev/null and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-2-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-3-chromium-linux.png b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-3-chromium-linux.png new file mode 100644 index 00000000000..533989cdf55 Binary files /dev/null and b/packages/desktop-client/e2e/transactions.mobile.test.js-snapshots/Mobile-Transactions-creates-an-uncategorized-transaction-from-accounts-uncategorized-page-3-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-1-chromium-linux.png b/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-1-chromium-linux.png index 6d47cb90a5e..bf1a5b83010 100644 Binary files a/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-1-chromium-linux.png and b/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-1-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-2-chromium-linux.png b/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-2-chromium-linux.png index 33925a4d26d..1cf49f768b1 100644 Binary files a/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-2-chromium-linux.png and b/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-2-chromium-linux.png differ diff --git a/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-3-chromium-linux.png b/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-3-chromium-linux.png index 5ec0c0efbc5..d6ad5f63278 100644 Binary files a/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-3-chromium-linux.png and b/packages/desktop-client/e2e/transactions.test.js-snapshots/Transactions-filters-transactions-by-category-3-chromium-linux.png differ diff --git a/packages/desktop-client/package.json b/packages/desktop-client/package.json index 6ac17296393..877539fa9f4 100644 --- a/packages/desktop-client/package.json +++ b/packages/desktop-client/package.json @@ -1,6 +1,6 @@ { "name": "@actual-app/web", - "version": "24.11.0", + "version": "24.12.0", "license": "MIT", "files": [ "build" diff --git a/packages/desktop-client/src/components/LoggedInUser.tsx b/packages/desktop-client/src/components/LoggedInUser.tsx index ec7df311bbf..8ad160f2294 100644 --- a/packages/desktop-client/src/components/LoggedInUser.tsx +++ b/packages/desktop-client/src/components/LoggedInUser.tsx @@ -6,6 +6,7 @@ import { useSelector } from 'react-redux'; import { type State } from 'loot-core/src/client/state-types'; import { useActions } from '../hooks/useActions'; +import { useNavigate } from '../hooks/useNavigate'; import { theme, styles } from '../style'; import { Button } from './common/Button2'; @@ -38,9 +39,11 @@ export function LoggedInUser({ getUserData().then(() => setLoading(false)); }, []); + const navigate = useNavigate(); + async function onChangePassword() { await closeBudget(); - window.__navigate('/change-password'); + navigate('/change-password'); } async function onMenuSelect(type) { @@ -52,14 +55,14 @@ export function LoggedInUser({ break; case 'sign-in': await closeBudget(); - window.__navigate('/login'); + navigate('/login'); break; case 'sign-out': signOut(); break; case 'config-server': await closeBudget(); - window.__navigate('/config-server'); + navigate('/config-server'); break; default: } diff --git a/packages/desktop-client/src/components/accounts/Header.tsx b/packages/desktop-client/src/components/accounts/Header.tsx index c45ae73eb1c..4a66ebc45de 100644 --- a/packages/desktop-client/src/components/accounts/Header.tsx +++ b/packages/desktop-client/src/components/accounts/Header.tsx @@ -369,7 +369,7 @@ export function AccountHeader({ onMakeAsNonSplitTransactions={onMakeAsNonSplitTransactions} /> )} - + {account && ( <> {account ? ( - + ) : ( - + { - if (!contextMenusEnabled) return; - e.preventDefault(); - setMenuOpen(true); - }} + onContextMenu={handleContextMenu} >
setMenuOpen(true)} + onPress={() => { + resetPosition(); + setMenuOpen(true); + }} > setMenuOpen(false)} - style={{ width: 200 }} + style={{ width: 200, margin: 1 }} isNonModal + {...position} > { diff --git a/packages/desktop-client/src/components/budget/SidebarGroup.tsx b/packages/desktop-client/src/components/budget/SidebarGroup.tsx index 20a81eba986..87e6eaad4d2 100644 --- a/packages/desktop-client/src/components/budget/SidebarGroup.tsx +++ b/packages/desktop-client/src/components/budget/SidebarGroup.tsx @@ -1,8 +1,9 @@ // @ts-strict-ignore -import React, { type CSSProperties, useRef, useState } from 'react'; +import React, { type CSSProperties, useRef } from 'react'; import { type ConnectDragSource } from 'react-dnd'; import { useTranslation } from 'react-i18next'; +import { useContextMenu } from '../../hooks/useContextMenu'; import { useFeatureFlag } from '../../hooks/useFeatureFlag'; import { SvgExpandArrow } from '../../icons/v0'; import { SvgCheveronDown } from '../../icons/v1'; @@ -58,9 +59,9 @@ export function SidebarGroup({ const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled'); const temporary = group.id === 'new'; - const [menuOpen, setMenuOpen] = useState(false); + const { setMenuOpen, menuOpen, handleContextMenu, resetPosition, position } = + useContextMenu(); const triggerRef = useRef(null); - const contextMenusEnabled = useFeatureFlag('contextMenus'); const displayed = ( { onToggleCollapse(group.id); }} - onContextMenu={e => { - if (!contextMenusEnabled) return; - e.preventDefault(); - setMenuOpen(true); - }} + onContextMenu={handleContextMenu} > {!dragPreview && ( setMenuOpen(true)} + onPress={() => { + resetPosition(); + setMenuOpen(true); + }} style={{ padding: 3 }} > @@ -122,8 +122,9 @@ export function SidebarGroup({ placement="bottom start" isOpen={menuOpen} onOpenChange={() => setMenuOpen(false)} - style={{ width: 200 }} + style={{ width: 200, margin: 1 }} isNonModal + {...position} > { diff --git a/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx b/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx index 78a42e0fd8d..0bb0491a2d8 100644 --- a/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx +++ b/packages/desktop-client/src/components/budget/envelope/EnvelopeBudgetComponents.tsx @@ -3,7 +3,6 @@ import React, { type CSSProperties, memo, useRef, - useState, } from 'react'; import { useTranslation, Trans } from 'react-i18next'; @@ -14,7 +13,7 @@ import { evalArithmetic } from 'loot-core/src/shared/arithmetic'; import * as monthUtils from 'loot-core/src/shared/months'; import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util'; -import { useFeatureFlag } from '../../../hooks/useFeatureFlag'; +import { useContextMenu } from '../../../hooks/useContextMenu'; import { useUndo } from '../../../hooks/useUndo'; import { SvgCheveronDown } from '../../../icons/v1'; import { styles, theme } from '../../../style'; @@ -207,8 +206,20 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ const budgetMenuTriggerRef = useRef(null); const balanceMenuTriggerRef = useRef(null); - const [budgetMenuOpen, setBudgetMenuOpen] = useState(false); - const [balanceMenuOpen, setBalanceMenuOpen] = useState(false); + const { + setMenuOpen: setBudgetMenuOpen, + menuOpen: budgetMenuOpen, + handleContextMenu: handleBudgetContextMenu, + resetPosition: resetBudgetPosition, + position: budgetPosition, + } = useContextMenu(); + const { + setMenuOpen: setBalanceMenuOpen, + menuOpen: balanceMenuOpen, + handleContextMenu: handleBalanceContextMenu, + resetPosition: resetBalancePosition, + position: balancePosition, + } = useContextMenu(); const onMenuAction = (...args: Parameters) => { onBudgetAction(...args); @@ -216,7 +227,6 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ }; const { showUndoNotification } = useUndo(); - const contextMenusEnabled = useFeatureFlag('contextMenus'); return ( { - if (!contextMenusEnabled) return; if (editing) return; - e.preventDefault(); - setBudgetMenuOpen(true); + handleBudgetContextMenu(e); }} > {!editing && ( @@ -261,9 +270,11 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ }} > diff --git a/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx b/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx index 1d72fea856e..d746aee4de2 100644 --- a/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx +++ b/packages/desktop-client/src/components/mobile/accounts/AccountTransactions.tsx @@ -73,7 +73,9 @@ export function AccountTransactions({ ) } leftContent={} - rightContent={} + rightContent={ + + } /> } padding={0} diff --git a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx index cbe373495e1..8005375a412 100644 --- a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx +++ b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx @@ -156,7 +156,7 @@ export function Status({ status, isSplit }) { function Footer({ transactions, - adding, + isAdding, onAdd, onSave, onSplit, @@ -232,7 +232,7 @@ function Footer({ Select account - ) : adding ? ( + ) : isAdding ? (