From 3825e65693027ae95fe94193471c98a21c2f43bb Mon Sep 17 00:00:00 2001 From: Matiss Janis Aboltins Date: Thu, 6 Nov 2025 20:58:03 +0000 Subject: [PATCH] Add edit payee functionality to mobile page (#5874) --- .../e2e/page-models/mobile-payees-page.ts | 2 +- .../desktop-client/e2e/payees.mobile.test.ts | 14 +- ...opens-payee-edit-page-1-chromium-linux.png | Bin 0 -> 6414 bytes ...opens-payee-edit-page-2-chromium-linux.png | Bin 0 -> 6602 bytes ...opens-payee-edit-page-3-chromium-linux.png | Bin 0 -> 6598 bytes .../src/components/FinancesApp.tsx | 8 + .../mobile/ActionableGridListItem.tsx | 15 +- .../mobile/payees/MobilePayeeEditPage.tsx | 152 ++++++++++++++++++ .../mobile/payees/MobilePayeesPage.tsx | 8 + .../components/mobile/payees/PayeesList.tsx | 3 + .../mobile/payees/PayeesListItem.tsx | 49 ++++-- .../src/components/responsive/narrow.ts | 2 + .../src/components/responsive/wide.ts | 2 + upcoming-release-notes/5874.md | 6 + 14 files changed, 242 insertions(+), 19 deletions(-) create mode 100644 packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-1-chromium-linux.png create mode 100644 packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-2-chromium-linux.png create mode 100644 packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-3-chromium-linux.png create mode 100644 packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx create mode 100644 upcoming-release-notes/5874.md diff --git a/packages/desktop-client/e2e/page-models/mobile-payees-page.ts b/packages/desktop-client/e2e/page-models/mobile-payees-page.ts index 8e7bf30a2f..6f06bdb5c3 100644 --- a/packages/desktop-client/e2e/page-models/mobile-payees-page.ts +++ b/packages/desktop-client/e2e/page-models/mobile-payees-page.ts @@ -51,7 +51,7 @@ export class MobilePayeesPage { } /** - * Click on a payee to view/edit rules + * Click on a payee to open the edit page */ async clickPayee(index: number) { const payee = this.getNthPayee(index); diff --git a/packages/desktop-client/e2e/payees.mobile.test.ts b/packages/desktop-client/e2e/payees.mobile.test.ts index 07d4f45245..4c22818d55 100644 --- a/packages/desktop-client/e2e/payees.mobile.test.ts +++ b/packages/desktop-client/e2e/payees.mobile.test.ts @@ -62,7 +62,7 @@ test.describe('Mobile Payees', () => { await expect(page).toMatchThemeScreenshots(); }); - test('clicking on a payee opens rule creation form', async () => { + test('clicking on a payee opens payee edit page', async () => { await payeesPage.waitForLoadingToComplete(); const payeeCount = await payeesPage.getPayeeCount(); @@ -70,8 +70,16 @@ test.describe('Mobile Payees', () => { await payeesPage.clickPayee(0); - // Should navigate to rules page for creating a new rule - await expect(page).toHaveURL(/\/rules/); + // Should navigate to payee edit page + await expect(page).toHaveURL(/\/payees\/.+/); + + // Check that the edit page elements are visible + await expect( + page.getByRole('heading', { name: 'Edit Payee' }), + ).toBeVisible(); + await expect(page.getByPlaceholder('Payee name')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Save' })).toBeVisible(); + await expect(page).toMatchThemeScreenshots(); }); diff --git a/packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-1-chromium-linux.png b/packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-1-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..1aa091f00dc5ab03533608dad0b05d46fac8fca7 GIT binary patch literal 6414 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 MyIjFvzWuj<0H`mDy8r+H literal 0 HcmV?d00001 diff --git a/packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-2-chromium-linux.png b/packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-2-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..62b779c50180bbba47adbea2391d80ba311200ad GIT binary patch literal 6602 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 UXAWX{5RtOCcKE5r^1<`}0k=^poB#j- literal 0 HcmV?d00001 diff --git a/packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-3-chromium-linux.png b/packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-3-chromium-linux.png new file mode 100644 index 0000000000000000000000000000000000000000..f42ba3cf9e5f4ef49790796454eb4740c0bf44a7 GIT binary patch literal 6598 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 literal 0 HcmV?d00001 diff --git a/packages/desktop-client/src/components/FinancesApp.tsx b/packages/desktop-client/src/components/FinancesApp.tsx index 33db725208..547887baea 100644 --- a/packages/desktop-client/src/components/FinancesApp.tsx +++ b/packages/desktop-client/src/components/FinancesApp.tsx @@ -270,6 +270,14 @@ export function FinancesApp() { path="/payees" element={} /> + + + + } + /> } diff --git a/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx b/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx index e240a37d5e..11ad3e112b 100644 --- a/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx +++ b/packages/desktop-client/src/components/mobile/ActionableGridListItem.tsx @@ -9,7 +9,7 @@ import { useDrag } from '@use-gesture/react'; import { type WithRequired } from 'loot-core/types/util'; type ActionableGridListItemProps = { - actions?: ReactNode; + actions?: ReactNode | ((params: { close: () => void }) => ReactNode); actionsBackgroundColor?: string; actionsWidth?: number; children?: ReactNode; @@ -131,7 +131,18 @@ export function ActionableGridListItem({ minWidth: actionsWidth, }} > - {actions} + {typeof actions === 'function' + ? actions({ + close: () => { + api.start({ + x: 0, + onRest: () => { + setIsRevealed(false); + }, + }); + }, + }) + : actions} )} diff --git a/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx b/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx new file mode 100644 index 0000000000..3dd06f24f8 --- /dev/null +++ b/packages/desktop-client/src/components/mobile/payees/MobilePayeeEditPage.tsx @@ -0,0 +1,152 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { useTranslation, Trans } from 'react-i18next'; +import { useParams } from 'react-router'; + +import { Button } from '@actual-app/components/button'; +import { styles } from '@actual-app/components/styles'; +import { Text } from '@actual-app/components/text'; +import { theme } from '@actual-app/components/theme'; +import { View } from '@actual-app/components/view'; + +import { send } from 'loot-core/platform/client/fetch'; +import { type PayeeEntity } from 'loot-core/types/models'; + +import { MobileBackButton } from '@desktop-client/components/mobile/MobileBackButton'; +import { InputField } from '@desktop-client/components/mobile/MobileForms'; +import { MobilePageHeader, Page } from '@desktop-client/components/Page'; +import { useNavigate } from '@desktop-client/hooks/useNavigate'; +import { usePayees } from '@desktop-client/hooks/usePayees'; +import { useUndo } from '@desktop-client/hooks/useUndo'; +import { addNotification } from '@desktop-client/notifications/notificationsSlice'; +import { useDispatch } from '@desktop-client/redux'; + +export function MobilePayeeEditPage() { + const { t } = useTranslation(); + const navigate = useNavigate(); + const { id } = useParams<{ id: string }>(); + const dispatch = useDispatch(); + const { showUndoNotification } = useUndo(); + const payees = usePayees(); + + const [payee, setPayee] = useState(null); + const [editedPayeeName, setEditedPayeeName] = useState(''); + const [isLoading, setIsLoading] = useState(true); + + // Load payee by ID + useEffect(() => { + if (id) { + setIsLoading(true); + const foundPayee = payees.find(p => p.id === id); + if (foundPayee) { + setPayee(foundPayee); + setEditedPayeeName(foundPayee.name); + setIsLoading(false); + } else { + // Payee not found, navigate back to payees list + navigate('/payees'); + } + } + }, [id, payees, navigate]); + + const handleCancel = useCallback(() => { + navigate(-1); + }, [navigate]); + + const handleSave = useCallback(async () => { + if (!payee || !editedPayeeName.trim()) { + return; + } + + try { + await send('payees-batch-change', { + updated: [{ id: payee.id, name: editedPayeeName.trim() }], + }); + showUndoNotification({ + message: t('Payee {{oldName}} renamed to {{newName}}', { + oldName: payee.name, + newName: editedPayeeName.trim(), + }), + }); + navigate('/payees'); + } catch (error) { + console.error('Failed to update payee:', error); + dispatch( + addNotification({ + notification: { + type: 'error', + message: t('Failed to update payee. Please try again.'), + }, + }), + ); + } + }, [payee, editedPayeeName, dispatch, showUndoNotification, t, navigate]); + + // Show loading state while fetching payee + if (isLoading) { + return ( + } + /> + } + padding={0} + > + + + Loading payee... + + + + ); + } + + return ( + } + /> + } + footer={ + + + + } + > + + + + + ); +} diff --git a/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx b/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx index a2b441f209..df1fed0bbd 100644 --- a/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx +++ b/packages/desktop-client/src/components/mobile/payees/MobilePayeesPage.tsx @@ -43,6 +43,13 @@ export function MobilePayeesPage() { }, []); const handlePayeePress = useCallback( + (payee: PayeeEntity) => { + navigate(`/payees/${payee.id}`); + }, + [navigate], + ); + + const handlePayeeRuleAction = useCallback( async (payee: PayeeEntity) => { // View associated rules for the payee if ((ruleCounts.get(payee.id) ?? 0) > 0) { @@ -137,6 +144,7 @@ export function MobilePayeesPage() { isLoading={isLoading} onPayeePress={handlePayeePress} onPayeeDelete={handlePayeeDelete} + onPayeeRuleAction={handlePayeeRuleAction} /> ); diff --git a/packages/desktop-client/src/components/mobile/payees/PayeesList.tsx b/packages/desktop-client/src/components/mobile/payees/PayeesList.tsx index 14ebe68d78..bd48a02636 100644 --- a/packages/desktop-client/src/components/mobile/payees/PayeesList.tsx +++ b/packages/desktop-client/src/components/mobile/payees/PayeesList.tsx @@ -19,6 +19,7 @@ type PayeesListProps = { isLoading?: boolean; onPayeePress: (payee: PayeeEntity) => void; onPayeeDelete: (payee: PayeeEntity) => void; + onPayeeRuleAction: (payee: PayeeEntity) => void; }; export function PayeesList({ @@ -28,6 +29,7 @@ export function PayeesList({ isLoading = false, onPayeePress, onPayeeDelete, + onPayeeRuleAction, }: PayeesListProps) { const { t } = useTranslation(); @@ -90,6 +92,7 @@ export function PayeesList({ isRuleCountLoading={isRuleCountsLoading} onAction={() => onPayeePress(payee)} onDelete={() => onPayeeDelete(payee)} + onViewRules={() => onPayeeRuleAction(payee)} /> )} diff --git a/packages/desktop-client/src/components/mobile/payees/PayeesListItem.tsx b/packages/desktop-client/src/components/mobile/payees/PayeesListItem.tsx index 2c3ceb6fe2..938cf73f82 100644 --- a/packages/desktop-client/src/components/mobile/payees/PayeesListItem.tsx +++ b/packages/desktop-client/src/components/mobile/payees/PayeesListItem.tsx @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import React from 'react'; import { type GridListItemProps } from 'react-aria-components'; import { Trans, useTranslation } from 'react-i18next'; @@ -6,6 +6,7 @@ import { Button } from '@actual-app/components/button'; import { SvgBookmark } from '@actual-app/components/icons/v1'; import { SpaceBetween } from '@actual-app/components/space-between'; import { theme } from '@actual-app/components/theme'; +import { View } from '@actual-app/components/view'; import { type PayeeEntity } from 'loot-core/types/models'; import { type WithRequired } from 'loot-core/types/util'; @@ -17,13 +18,15 @@ type PayeesListItemProps = { ruleCount: number; isRuleCountLoading?: boolean; onDelete: () => void; + onViewRules: () => void; } & WithRequired, 'value'>; -export const PayeesListItem = memo(function PayeeListItem({ +export function PayeesListItem({ value: payee, ruleCount, isRuleCountLoading, onDelete, + onViewRules, ...props }: PayeesListItemProps) { const { t } = useTranslation(); @@ -37,18 +40,38 @@ export const PayeesListItem = memo(function PayeeListItem({ id={payee.id} value={payee} textValue={label} + actionsWidth={200} actions={ !payee.transfer_acct && ( - + + + + ) } {...props} @@ -112,4 +135,4 @@ export const PayeesListItem = memo(function PayeeListItem({ ); -}); +} diff --git a/packages/desktop-client/src/components/responsive/narrow.ts b/packages/desktop-client/src/components/responsive/narrow.ts index 14f722f2f6..99f0e2a2d9 100644 --- a/packages/desktop-client/src/components/responsive/narrow.ts +++ b/packages/desktop-client/src/components/responsive/narrow.ts @@ -8,5 +8,7 @@ export { MobileRuleEditPage as RuleEdit } from '../mobile/rules/MobileRuleEditPa export { CategoryPage as Category } from '../mobile/budget/CategoryPage'; export { MobilePayeesPage as Payees } from '../mobile/payees/MobilePayeesPage'; +export { MobilePayeeEditPage as PayeeEdit } from '../mobile/payees/MobilePayeeEditPage'; + export { MobileBankSyncPage as BankSync } from '../mobile/banksync/MobileBankSyncPage'; export { MobileBankSyncAccountEditPage as BankSyncAccountEdit } from '../mobile/banksync/MobileBankSyncAccountEditPage'; diff --git a/packages/desktop-client/src/components/responsive/wide.ts b/packages/desktop-client/src/components/responsive/wide.ts index d9b8d59f24..2dcd844bb9 100644 --- a/packages/desktop-client/src/components/responsive/wide.ts +++ b/packages/desktop-client/src/components/responsive/wide.ts @@ -10,6 +10,8 @@ export { Account } from '../accounts/Account'; export { ManageRulesPage as Rules } from '../ManageRulesPage'; export { ManageRulesPage as RuleEdit } from '../ManageRulesPage'; export { ManagePayeesPage as Payees } from '../payees/ManagePayeesPage'; +export { ManagePayeesPage as PayeeEdit } from '../payees/ManagePayeesPage'; + export { BankSync } from '../banksync'; export { UserDirectoryPage } from '../admin/UserDirectory/UserDirectoryPage'; diff --git a/upcoming-release-notes/5874.md b/upcoming-release-notes/5874.md new file mode 100644 index 0000000000..2a27238b09 --- /dev/null +++ b/upcoming-release-notes/5874.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [MatissJanis] +--- + +Mobile payees: add edit payee functionality