From 3de3bba1ab30bb27147c50f7036ef1f9a9513a30 Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez Date: Fri, 10 Jan 2025 16:03:34 -0800 Subject: [PATCH] Update payloads --- .../desktop-client/src/components/App.tsx | 18 +++--- .../src/components/FinancesApp.tsx | 54 ++++++++++-------- .../src/components/Notifications.tsx | 2 +- .../src/components/ServerContext.tsx | 10 ++-- .../admin/UserAccess/UserAccess.tsx | 12 ++-- .../admin/UserAccess/UserAccessRow.tsx | 44 ++++++++------- .../admin/UserDirectory/UserDirectory.tsx | 28 ++++++---- .../src/components/budget/index.tsx | 12 ++-- .../manager/subscribe/OpenIdForm.tsx | 12 ++-- .../mobile/transactions/TransactionList.jsx | 4 +- .../src/components/modals/EditAccess.tsx | 20 ++++--- .../src/components/modals/EditUser.tsx | 20 ++++--- .../components/modals/TransferOwnership.tsx | 28 ++++++---- .../manager/ConfirmChangeDocumentDir.tsx | 6 +- .../modals/manager/DuplicateFileModal.tsx | 12 ++-- .../src/components/reports/Overview.tsx | 56 +++++++++++-------- .../components/reports/reports/Calendar.tsx | 12 ++-- .../components/reports/reports/CashFlow.tsx | 6 +- .../reports/reports/CustomReportListCards.tsx | 6 +- .../components/reports/reports/NetWorth.tsx | 6 +- .../components/reports/reports/Spending.tsx | 6 +- .../components/reports/reports/Summary.tsx | 18 ++++-- .../transactions/TransactionsTable.jsx | 6 +- packages/desktop-client/src/global-events.ts | 26 +++++---- packages/desktop-client/src/hooks/useUndo.ts | 28 ++++++---- .../src/client/accounts/accountsSlice.ts | 14 +++-- .../notifications/notificationsSlice.ts | 32 +++++++---- .../src/client/queries/queriesSlice.ts | 52 ++++++++++------- .../loot-core/src/client/shared-listeners.ts | 12 ++-- 29 files changed, 336 insertions(+), 226 deletions(-) diff --git a/packages/desktop-client/src/components/App.tsx b/packages/desktop-client/src/components/App.tsx index c3a247db268..287e2a77810 100644 --- a/packages/desktop-client/src/components/App.tsx +++ b/packages/desktop-client/src/components/App.tsx @@ -125,14 +125,16 @@ function AppInner() { if (userData?.tokenExpired) { dispatch( addNotification({ - type: 'error', - id: 'login-expired', - title: t('Login expired'), - sticky: true, - message: t('Login expired, please login again.'), - button: { - title: t('Go to login'), - action: () => dispatch(signOut()), + notification: { + type: 'error', + id: 'login-expired', + title: t('Login expired'), + sticky: true, + message: t('Login expired, please login again.'), + button: { + title: t('Go to login'), + action: () => dispatch(signOut()), + }, }, }), ); diff --git a/packages/desktop-client/src/components/FinancesApp.tsx b/packages/desktop-client/src/components/FinancesApp.tsx index 18187d97d2b..1ccd1cff3f5 100644 --- a/packages/desktop-client/src/components/FinancesApp.tsx +++ b/packages/desktop-client/src/components/FinancesApp.tsx @@ -111,15 +111,19 @@ export function FinancesApp() { await global.Actual.waitForUpdateReadyForDownload(); dispatch( addNotification({ - type: 'message', - title: t('A new version of Actual is available!'), - message: t('Click the button below to reload and apply the update.'), - sticky: true, - id: 'update-reload-notification', - button: { - title: t('Update now'), - action: async () => { - await global.Actual.applyAppUpdate(); + notification: { + type: 'message', + title: t('A new version of Actual is available!'), + message: t( + 'Click the button below to reload and apply the update.', + ), + sticky: true, + id: 'update-reload-notification', + button: { + title: t('Update now'), + action: async () => { + await global.Actual.applyAppUpdate(); + }, }, }, }), @@ -137,22 +141,24 @@ export function FinancesApp() { if (isOutdated && lastUsedVersion !== latestVersion) { dispatch( addNotification({ - type: 'message', - title: t('A new version of Actual is available!'), - message: t( - 'Version {{latestVersion}} of Actual was recently released.', - { latestVersion }, - ), - sticky: true, - id: 'update-notification', - button: { - title: t('Open changelog'), - action: () => { - window.open('https://actualbudget.org/docs/releases'); + notification: { + type: 'message', + title: t('A new version of Actual is available!'), + message: t( + 'Version {{latestVersion}} of Actual was recently released.', + { latestVersion }, + ), + sticky: true, + id: 'update-notification', + button: { + title: t('Open changelog'), + action: () => { + window.open('https://actualbudget.org/docs/releases'); + }, + }, + onClose: () => { + setLastUsedVersion(latestVersion); }, - }, - onClose: () => { - setLastUsedVersion(latestVersion); }, }), ); diff --git a/packages/desktop-client/src/components/Notifications.tsx b/packages/desktop-client/src/components/Notifications.tsx index fbc5b4f128e..b78bd1a8281 100644 --- a/packages/desktop-client/src/components/Notifications.tsx +++ b/packages/desktop-client/src/components/Notifications.tsx @@ -288,7 +288,7 @@ export function Notifications({ style }: { style?: CSSProperties }) { if (note.onClose) { note.onClose(); } - dispatch(removeNotification(note.id)); + dispatch(removeNotification({ id: note.id })); }} /> ))} diff --git a/packages/desktop-client/src/components/ServerContext.tsx b/packages/desktop-client/src/components/ServerContext.tsx index a68ca3dc7e1..d7c0f52df2d 100644 --- a/packages/desktop-client/src/components/ServerContext.tsx +++ b/packages/desktop-client/src/components/ServerContext.tsx @@ -109,9 +109,11 @@ export function ServerProvider({ children }: { children: ReactNode }) { if ('error' in data) { dispatch( addNotification({ - type: 'error', - title: t('Failed to refresh login methods'), - message: data.error ?? t('Unknown'), + notification: { + type: 'error', + title: t('Failed to refresh login methods'), + message: data.error ?? t('Unknown'), + }, }), ); setAvailableLoginMethods([]); @@ -121,7 +123,7 @@ export function ServerProvider({ children }: { children: ReactNode }) { setAvailableLoginMethods([]); } } - }, [serverURL]); + }, [dispatch, serverURL]); useEffect(() => { if (serverURL) { diff --git a/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx b/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx index 1cee180a667..c6d8695005a 100644 --- a/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx +++ b/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx @@ -87,11 +87,13 @@ function UserAccessContent({ if ('error' in data) { dispatch( addNotification({ - type: 'error', - id: 'error', - title: t('Error getting available users'), - sticky: true, - message: data.error, + notification: { + type: 'error', + id: 'error', + title: t('Error getting available users'), + sticky: true, + message: data.error, + }, }), ); return []; diff --git a/packages/desktop-client/src/components/admin/UserAccess/UserAccessRow.tsx b/packages/desktop-client/src/components/admin/UserAccess/UserAccessRow.tsx index 0bde1a87a8d..89e37006d57 100644 --- a/packages/desktop-client/src/components/admin/UserAccess/UserAccessRow.tsx +++ b/packages/desktop-client/src/components/admin/UserAccess/UserAccessRow.tsx @@ -52,12 +52,14 @@ export const UserAccessRow = memo( if (someDeletionsFailed) { dispatch( addNotification({ - type: 'error', - title: t('Access Revocation Incomplete'), - message: t( - 'Some access permissions were not revoked successfully.', - ), - sticky: true, + notification: { + type: 'error', + title: t('Access Revocation Incomplete'), + message: t( + 'Some access permissions were not revoked successfully.', + ), + sticky: true, + }, }), ); } @@ -69,15 +71,17 @@ export const UserAccessRow = memo( if (error === 'token-expired') { dispatch( addNotification({ - type: 'error', - id: 'login-expired', - title: t('Login expired'), - sticky: true, - message: getUserAccessErrors(error), - button: { - title: t('Go to login'), - action: () => { - dispatch(signOut()); + notification: { + type: 'error', + id: 'login-expired', + title: t('Login expired'), + sticky: true, + message: getUserAccessErrors(error), + button: { + title: t('Go to login'), + action: () => { + dispatch(signOut()); + }, }, }, }), @@ -85,10 +89,12 @@ export const UserAccessRow = memo( } else { dispatch( addNotification({ - type: 'error', - title: t('Something happened while editing access'), - sticky: true, - message: getUserAccessErrors(error), + notification: { + type: 'error', + title: t('Something happened while editing access'), + sticky: true, + message: getUserAccessErrors(error), + }, }), ); } diff --git a/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx b/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx index 3503f7d652f..6e7f22aaedc 100644 --- a/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx +++ b/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx @@ -148,24 +148,28 @@ function UserDirectoryContent({ if (error === 'token-expired') { dispatch( addNotification({ - type: 'error', - id: 'login-expired', - title: t('Login expired'), - sticky: true, - message: getUserDirectoryErrors(error), - button: { - title: t('Go to login'), - action: () => dispatch(signOut()), + notification: { + type: 'error', + id: 'login-expired', + title: t('Login expired'), + sticky: true, + message: getUserDirectoryErrors(error), + button: { + title: t('Go to login'), + action: () => dispatch(signOut()), + }, }, }), ); } else { dispatch( addNotification({ - type: 'error', - title: t('Something happened while deleting users'), - sticky: true, - message: getUserDirectoryErrors(error), + notification: { + type: 'error', + title: t('Something happened while deleting users'), + sticky: true, + message: getUserDirectoryErrors(error), + }, }), ); } diff --git a/packages/desktop-client/src/components/budget/index.tsx b/packages/desktop-client/src/components/budget/index.tsx index b69412fb14d..6302ad396e2 100644 --- a/packages/desktop-client/src/components/budget/index.tsx +++ b/packages/desktop-client/src/components/budget/index.tsx @@ -176,11 +176,13 @@ function BudgetInner(props: BudgetInnerProps) { const categoryNameAlreadyExistsNotification = name => { dispatch( addNotification({ - type: 'error', - message: t( - 'Category ‘{{name}}‘ already exists in group (May be Hidden)', - { name }, - ), + notification: { + type: 'error', + message: t( + 'Category ‘{{name}}‘ already exists in group (May be Hidden)', + { name }, + ), + }, }), ); }; diff --git a/packages/desktop-client/src/components/manager/subscribe/OpenIdForm.tsx b/packages/desktop-client/src/components/manager/subscribe/OpenIdForm.tsx index b0b659444a2..9b4d1143a02 100644 --- a/packages/desktop-client/src/components/manager/subscribe/OpenIdForm.tsx +++ b/packages/desktop-client/src/components/manager/subscribe/OpenIdForm.tsx @@ -74,11 +74,13 @@ export function OpenIdForm({ if ('error' in config) { dispatch( addNotification({ - type: 'error', - id: 'error', - title: t('Error getting OpenID config'), - sticky: true, - message: config.error, + notification: { + type: 'error', + id: 'error', + title: t('Error getting OpenID config'), + sticky: true, + message: config.error, + }, }), ); } else if ('openId' in config) { diff --git a/packages/desktop-client/src/components/mobile/transactions/TransactionList.jsx b/packages/desktop-client/src/components/mobile/transactions/TransactionList.jsx index 9978ee623b1..2fcfef8e17e 100644 --- a/packages/desktop-client/src/components/mobile/transactions/TransactionList.jsx +++ b/packages/desktop-client/src/components/mobile/transactions/TransactionList.jsx @@ -248,7 +248,9 @@ function SelectedTransactionsFloatingActionBar({ transactions, style }) { const dispatch = useDispatch(); useEffect(() => { - dispatch(setNotificationInset({ bottom: NOTIFICATION_BOTTOM_INSET })); + dispatch( + setNotificationInset({ inset: { bottom: NOTIFICATION_BOTTOM_INSET } }), + ); return () => { dispatch(setNotificationInset(null)); }; diff --git a/packages/desktop-client/src/components/modals/EditAccess.tsx b/packages/desktop-client/src/components/modals/EditAccess.tsx index eec812d1ae5..bdcbc6a05d4 100644 --- a/packages/desktop-client/src/components/modals/EditAccess.tsx +++ b/packages/desktop-client/src/components/modals/EditAccess.tsx @@ -70,15 +70,17 @@ export function EditUserAccess({ if (error === 'token-expired') { dispatch( addNotification({ - type: 'error', - id: 'login-expired', - title: t('Login expired'), - sticky: true, - message: getUserAccessErrors(error), - button: { - title: t('Go to login'), - action: () => { - dispatch(signOut()); + notification: { + type: 'error', + id: 'login-expired', + title: t('Login expired'), + sticky: true, + message: getUserAccessErrors(error), + button: { + title: t('Go to login'), + action: () => { + dispatch(signOut()); + }, }, }, }), diff --git a/packages/desktop-client/src/components/modals/EditUser.tsx b/packages/desktop-client/src/components/modals/EditUser.tsx index cdce1ac6f49..97ea237fda7 100644 --- a/packages/desktop-client/src/components/modals/EditUser.tsx +++ b/packages/desktop-client/src/components/modals/EditUser.tsx @@ -86,15 +86,17 @@ function useSaveUser() { if (error === 'token-expired') { dispatch( addNotification({ - type: 'error', - id: 'login-expired', - title: t('Login expired'), - sticky: true, - message: getUserDirectoryErrors(error), - button: { - title: t('Go to login'), - action: () => { - dispatch(signOut()); + notification: { + type: 'error', + id: 'login-expired', + title: t('Login expired'), + sticky: true, + message: getUserDirectoryErrors(error), + button: { + title: t('Go to login'), + action: () => { + dispatch(signOut()); + }, }, }, }), diff --git a/packages/desktop-client/src/components/modals/TransferOwnership.tsx b/packages/desktop-client/src/components/modals/TransferOwnership.tsx index 3b6bd9186d6..6ecb18e740a 100644 --- a/packages/desktop-client/src/components/modals/TransferOwnership.tsx +++ b/packages/desktop-client/src/components/modals/TransferOwnership.tsx @@ -55,12 +55,14 @@ export function TransferOwnership({ } else if ('error' in data) { dispatch( addNotification({ - type: 'error', - title: t('Error getting users'), - message: t( - 'Failed to complete ownership transfer. Please try again.', - ), - sticky: true, + notification: { + type: 'error', + title: t('Error getting users'), + message: t( + 'Failed to complete ownership transfer. Please try again.', + ), + sticky: true, + }, }), ); } else { @@ -194,12 +196,14 @@ export function TransferOwnership({ } catch (error) { dispatch( addNotification({ - type: 'error', - title: t('Failed to transfer ownership'), - message: t( - 'Failed to complete ownership transfer. Please try again.', - ), - sticky: true, + notification: { + type: 'error', + title: t('Failed to transfer ownership'), + message: t( + 'Failed to complete ownership transfer. Please try again.', + ), + sticky: true, + }, }), ); setIsTransferring(false); diff --git a/packages/desktop-client/src/components/modals/manager/ConfirmChangeDocumentDir.tsx b/packages/desktop-client/src/components/modals/manager/ConfirmChangeDocumentDir.tsx index d9c990b72ae..e6c3e734c77 100644 --- a/packages/desktop-client/src/components/modals/manager/ConfirmChangeDocumentDir.tsx +++ b/packages/desktop-client/src/components/modals/manager/ConfirmChangeDocumentDir.tsx @@ -74,8 +74,10 @@ export function ConfirmChangeDocumentDirModal({ dispatch( addNotification({ - type: 'message', - message: t('Actual’s data directory successfully changed.'), + notification: { + type: 'message', + message: t('Actual’s data directory successfully changed.'), + }, }), ); close(); diff --git a/packages/desktop-client/src/components/modals/manager/DuplicateFileModal.tsx b/packages/desktop-client/src/components/modals/manager/DuplicateFileModal.tsx index 6f88a09adf3..4acee96d0db 100644 --- a/packages/desktop-client/src/components/modals/manager/DuplicateFileModal.tsx +++ b/packages/desktop-client/src/components/modals/manager/DuplicateFileModal.tsx @@ -87,8 +87,10 @@ export function DuplicateFileModal({ ); dispatch( addNotification({ - type: 'message', - message: t('Duplicate file “{{newName}}” created.', { newName }), + notification: { + type: 'message', + message: t('Duplicate file “{{newName}}” created.', { newName }), + }, }), ); if (onComplete) onComplete({ status: 'success' }); @@ -98,8 +100,10 @@ export function DuplicateFileModal({ else console.error('Failed to duplicate budget:', e); dispatch( addNotification({ - type: 'error', - message: t('Failed to duplicate budget file.'), + notification: { + type: 'error', + message: t('Failed to duplicate budget file.'), + }, }), ); } finally { diff --git a/packages/desktop-client/src/components/reports/Overview.tsx b/packages/desktop-client/src/components/reports/Overview.tsx index c23d52fa490..d07ddd4e862 100644 --- a/packages/desktop-client/src/components/reports/Overview.tsx +++ b/packages/desktop-client/src/components/reports/Overview.tsx @@ -97,7 +97,7 @@ export function Overview() { const layout = baseLayout; const closeNotifications = () => { - dispatch(removeNotification('import')); + dispatch(removeNotification({ id: 'import' })); }; // Close import notifications when doing "undo" operation @@ -115,15 +115,17 @@ export function Overview() { const onDispatchSucessNotification = (message: string) => { dispatch( addNotification({ - id: 'import', - type: 'message', - sticky: true, - timeout: 30_000, // 30s - message, - messageActions: { - undo: () => { - closeNotifications(); - undo(); + notification: { + id: 'import', + type: 'message', + sticky: true, + timeout: 30_000, // 30s + message, + messageActions: { + undo: () => { + closeNotifications(); + undo(); + }, }, }, }), @@ -223,10 +225,12 @@ export function Overview() { if (!openFileDialog) { dispatch( addNotification({ - type: 'error', - message: t( - 'Fatal error occurred: unable to open import file dialog.', - ), + notification: { + type: 'error', + message: t( + 'Fatal error occurred: unable to open import file dialog.', + ), + }, }), ); return; @@ -252,9 +256,11 @@ export function Overview() { case 'json-parse-error': dispatch( addNotification({ - id: 'import', - type: 'error', - message: t('Failed parsing the imported JSON.'), + notification: { + id: 'import', + type: 'error', + message: t('Failed parsing the imported JSON.'), + }, }), ); break; @@ -262,9 +268,11 @@ export function Overview() { case 'validation-error': dispatch( addNotification({ - id: 'import', - type: 'error', - message: res.message, + notification: { + id: 'import', + type: 'error', + message: res.message, + }, }), ); break; @@ -272,9 +280,11 @@ export function Overview() { default: dispatch( addNotification({ - id: 'import', - type: 'error', - message: t('Failed importing the dashboard file.'), + notification: { + id: 'import', + type: 'error', + message: t('Failed importing the dashboard file.'), + }, }), ); break; diff --git a/packages/desktop-client/src/components/reports/reports/Calendar.tsx b/packages/desktop-client/src/components/reports/reports/Calendar.tsx index 8bcb044a926..87a59ccbd62 100644 --- a/packages/desktop-client/src/components/reports/reports/Calendar.tsx +++ b/packages/desktop-client/src/components/reports/reports/Calendar.tsx @@ -327,15 +327,19 @@ function CalendarInner({ widget, parameters }: CalendarInnerProps) { }); dispatch( addNotification({ - type: 'message', - message: t('Dashboard widget successfully saved.'), + notification: { + type: 'message', + message: t('Dashboard widget successfully saved.'), + }, }), ); } catch (error) { dispatch( addNotification({ - type: 'error', - message: t('Failed to save dashboard widget.'), + notification: { + type: 'error', + message: t('Failed to save dashboard widget.'), + }, }), ); console.error('Error saving widget:', error); diff --git a/packages/desktop-client/src/components/reports/reports/CashFlow.tsx b/packages/desktop-client/src/components/reports/reports/CashFlow.tsx index cf3ed4a6a4e..29aacd87c91 100644 --- a/packages/desktop-client/src/components/reports/reports/CashFlow.tsx +++ b/packages/desktop-client/src/components/reports/reports/CashFlow.tsx @@ -165,8 +165,10 @@ function CashFlowInner({ widget }: CashFlowInnerProps) { }); dispatch( addNotification({ - type: 'message', - message: t('Dashboard widget successfully saved.'), + notification: { + type: 'message', + message: t('Dashboard widget successfully saved.'), + }, }), ); } diff --git a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx index 78a1a168df2..e1c7797164d 100644 --- a/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx +++ b/packages/desktop-client/src/components/reports/reports/CustomReportListCards.tsx @@ -101,8 +101,10 @@ function CustomReportListCardsInner({ if (response.error) { dispatch( addNotification({ - type: 'error', - message: `Failed saving report name: ${response.error.message}`, + notification: { + type: 'error', + message: `Failed saving report name: ${response.error.message}`, + }, }), ); setNameMenuOpen(true); diff --git a/packages/desktop-client/src/components/reports/reports/NetWorth.tsx b/packages/desktop-client/src/components/reports/reports/NetWorth.tsx index 85ddc03f794..744ffb55bdf 100644 --- a/packages/desktop-client/src/components/reports/reports/NetWorth.tsx +++ b/packages/desktop-client/src/components/reports/reports/NetWorth.tsx @@ -137,8 +137,10 @@ function NetWorthInner({ widget }: NetWorthInnerProps) { }); dispatch( addNotification({ - type: 'message', - message: t('Dashboard widget successfully saved.'), + notification: { + type: 'message', + message: t('Dashboard widget successfully saved.'), + }, }), ); } diff --git a/packages/desktop-client/src/components/reports/reports/Spending.tsx b/packages/desktop-client/src/components/reports/reports/Spending.tsx index 23e986ceb94..911654f7a30 100644 --- a/packages/desktop-client/src/components/reports/reports/Spending.tsx +++ b/packages/desktop-client/src/components/reports/reports/Spending.tsx @@ -151,8 +151,10 @@ function SpendingInternal({ widget }: SpendingInternalProps) { }); dispatch( addNotification({ - type: 'message', - message: t('Dashboard widget successfully saved.'), + notification: { + type: 'message', + message: t('Dashboard widget successfully saved.'), + }, }), ); } diff --git a/packages/desktop-client/src/components/reports/reports/Summary.tsx b/packages/desktop-client/src/components/reports/reports/Summary.tsx index 3f55a9139b7..fc51312ae98 100644 --- a/packages/desktop-client/src/components/reports/reports/Summary.tsx +++ b/packages/desktop-client/src/components/reports/reports/Summary.tsx @@ -185,8 +185,10 @@ function SummaryInner({ widget }: SummaryInnerProps) { if (!widget) { dispatch( addNotification({ - type: 'error', - message: t('Cannot save: No widget available.'), + notification: { + type: 'error', + message: t('Cannot save: No widget available.'), + }, }), ); return; @@ -213,8 +215,10 @@ function SummaryInner({ widget }: SummaryInnerProps) { if (!widget) { dispatch( addNotification({ - type: 'error', - message: t('Cannot save: No widget available.'), + notification: { + type: 'error', + message: t('Cannot save: No widget available.'), + }, }), ); return; @@ -236,8 +240,10 @@ function SummaryInner({ widget }: SummaryInnerProps) { }); dispatch( addNotification({ - type: 'message', - message: t('Dashboard widget successfully saved.'), + notification: { + type: 'message', + message: t('Dashboard widget successfully saved.'), + }, }), ); } diff --git a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx index 3308f47e986..9360c02ade3 100644 --- a/packages/desktop-client/src/components/transactions/TransactionsTable.jsx +++ b/packages/desktop-client/src/components/transactions/TransactionsTable.jsx @@ -2248,8 +2248,10 @@ export const TransactionTable = forwardRef((props, ref) => { if (newTransactions[0].account == null) { dispatch( addNotification({ - type: 'error', - message: 'Account is a required field', + notification: { + type: 'error', + message: 'Account is a required field', + }, }), ); newNavigator.onEdit('temp', 'account'); diff --git a/packages/desktop-client/src/global-events.ts b/packages/desktop-client/src/global-events.ts index fb2e9684f8e..d573309fadf 100644 --- a/packages/desktop-client/src/global-events.ts +++ b/packages/desktop-client/src/global-events.ts @@ -65,10 +65,12 @@ export function handleGlobalEvents(store: AppStore) { if (type === 'unauthorized') { store.dispatch( addNotification({ - type: 'warning', - message: 'Unable to authenticate with server', - sticky: true, - id: 'auth-issue', + notification: { + type: 'warning', + message: 'Unable to authenticate with server', + sticky: true, + id: 'auth-issue', + }, }), ); } @@ -129,13 +131,15 @@ export function handleGlobalEvents(store: AppStore) { listen('fallback-write-error', () => { store.dispatch( addNotification({ - type: 'error', - title: 'Unable to save changes', - sticky: true, - message: - 'This browser only supports using the app in one tab at a time, ' + - 'and another tab has opened the app. No changes will be saved ' + - 'from this tab; please close it and continue working in the other one.', + notification: { + type: 'error', + title: 'Unable to save changes', + sticky: true, + message: + 'This browser only supports using the app in one tab at a time, ' + + 'and another tab has opened the app. No changes will be saved ' + + 'from this tab; please close it and continue working in the other one.', + }, }), ); }); diff --git a/packages/desktop-client/src/hooks/useUndo.ts b/packages/desktop-client/src/hooks/useUndo.ts index a7f7dd6222b..a1abfb48206 100644 --- a/packages/desktop-client/src/hooks/useUndo.ts +++ b/packages/desktop-client/src/hooks/useUndo.ts @@ -30,13 +30,15 @@ export function useUndo(): UndoActions { dispatch( addNotification({ - type: 'message', - timeout, - button: { - title: 'Undo', - action: undo, + notification: { + type: 'message', + timeout, + button: { + title: 'Undo', + action: undo, + }, + ...notification, }, - ...notification, }), ); }, @@ -51,13 +53,15 @@ export function useUndo(): UndoActions { dispatch( addNotification({ - type: 'message', - timeout, - button: { - title: 'Redo', - action: redo, + notification: { + type: 'message', + timeout, + button: { + title: 'Redo', + action: redo, + }, + ...notification, }, - ...notification, }), ); }, diff --git a/packages/loot-core/src/client/accounts/accountsSlice.ts b/packages/loot-core/src/client/accounts/accountsSlice.ts index 23d0ed42410..95b33ac1927 100644 --- a/packages/loot-core/src/client/accounts/accountsSlice.ts +++ b/packages/loot-core/src/client/accounts/accountsSlice.ts @@ -172,16 +172,20 @@ function handleSyncResponse( if (error.type === 'SyncError') { dispatch( addNotification({ - type: 'error', - message: error.message, + notification: { + type: 'error', + message: error.message, + }, }), ); } else { dispatch( addNotification({ - type: 'error', - message: error.message, - internal: error.internal, + notification: { + type: 'error', + message: error.message, + internal: error.internal, + }, }), ); } diff --git a/packages/loot-core/src/client/notifications/notificationsSlice.ts b/packages/loot-core/src/client/notifications/notificationsSlice.ts index 767f31b57b9..09dba9487d6 100644 --- a/packages/loot-core/src/client/notifications/notificationsSlice.ts +++ b/packages/loot-core/src/client/notifications/notificationsSlice.ts @@ -38,9 +38,15 @@ const initialState: NotificationsState = { inset: {}, }; -type AddNotificationPayload = Notification; -type RemoveNotificationPayload = NotificationWithId['id']; -type SetNotificationInsetPayload = NotificationsState['inset']; +type AddNotificationPayload = { + notification: Notification; +}; +type RemoveNotificationPayload = { + id: NotificationWithId['id']; +}; +type SetNotificationInsetPayload = { + inset: NotificationsState['inset']; +} | null; const notificationsSlice = createSlice({ name: sliceName, @@ -48,8 +54,8 @@ const notificationsSlice = createSlice({ reducers: { addNotification(state, action: PayloadAction) { const notification = { - ...action.payload, - id: action.payload.id || uuidv4(), + ...action.payload.notification, + id: action.payload.notification.id || uuidv4(), }; if (state.notifications.find(n => n.id === notification.id)) { @@ -59,11 +65,13 @@ const notificationsSlice = createSlice({ }, addGenericErrorNotification() { addNotification({ - type: 'error', - message: t( - 'Something internally went wrong. You may want to restart the app if anything looks wrong. ' + - 'Please report this as a new issue on Github.', - ), + notification: { + type: 'error', + message: t( + 'Something internally went wrong. You may want to restart the app if anything looks wrong. ' + + 'Please report this as a new issue on Github.', + ), + }, }); }, removeNotification( @@ -71,14 +79,14 @@ const notificationsSlice = createSlice({ action: PayloadAction, ) { state.notifications = state.notifications.filter( - notif => notif.id !== action.payload, + notif => notif.id !== action.payload.id, ); }, setNotificationInset( state, action: PayloadAction, ) { - state.inset = action.payload ? action.payload : {}; + state.inset = action.payload?.inset ? action.payload.inset : {}; }, }, }); diff --git a/packages/loot-core/src/client/queries/queriesSlice.ts b/packages/loot-core/src/client/queries/queriesSlice.ts index 0221a0ee3f4..b04cc224874 100644 --- a/packages/loot-core/src/client/queries/queriesSlice.ts +++ b/packages/loot-core/src/client/queries/queriesSlice.ts @@ -234,10 +234,12 @@ export const deleteCategory = createAppAsyncThunk( case 'category-type': dispatch( addNotification({ - type: 'error', - message: t( - 'A category must be transferred to another of the same type (expense or income)', - ), + notification: { + type: 'error', + message: t( + 'A category must be transferred to another of the same type (expense or income)', + ), + }, }), ); break; @@ -508,25 +510,33 @@ export const applyBudgetAction = createAppAsyncThunk( await send('budget/set-12month-avg', { month }); break; case 'check-templates': - dispatch(addNotification(await send('budget/check-templates'))); + dispatch( + addNotification({ + notification: await send('budget/check-templates'), + }), + ); break; case 'apply-goal-template': dispatch( - addNotification(await send('budget/apply-goal-template', { month })), + addNotification({ + notification: await send('budget/apply-goal-template', { month }), + }), ); break; case 'overwrite-goal-template': dispatch( - addNotification( - await send('budget/overwrite-goal-template', { month }), - ), + addNotification({ + notification: await send('budget/overwrite-goal-template', { + month, + }), + }), ); break; case 'cleanup-goal-template': dispatch( - addNotification( - await send('budget/cleanup-goal-template', { month }), - ), + addNotification({ + notification: await send('budget/cleanup-goal-template', { month }), + }), ); break; case 'hold': @@ -582,12 +592,12 @@ export const applyBudgetAction = createAppAsyncThunk( break; case 'apply-multiple-templates': dispatch( - addNotification( - await send('budget/apply-multiple-templates', { + addNotification({ + notification: await send('budget/apply-multiple-templates', { month, categoryIds: args.categories, }), - ), + }), ); break; case 'set-single-3-avg': @@ -645,8 +655,10 @@ export const importPreviewTransactions = createAppAsyncThunk( errors.forEach(error => { dispatch( addNotification({ - type: 'error', - message: error.message, + notification: { + type: 'error', + message: error.message, + }, }), ); }); @@ -689,8 +701,10 @@ export const importTransactions = createAppAsyncThunk( errors.forEach(error => { dispatch( addNotification({ - type: 'error', - message: error.message, + notification: { + type: 'error', + message: error.message, + }, }), ); }); diff --git a/packages/loot-core/src/client/shared-listeners.ts b/packages/loot-core/src/client/shared-listeners.ts index f7c1de845f5..4101a27a5c4 100644 --- a/packages/loot-core/src/client/shared-listeners.ts +++ b/packages/loot-core/src/client/shared-listeners.ts @@ -29,9 +29,11 @@ export function listenForSyncEvent(store: AppStore) { store.dispatch( addNotification({ - title: t('Syncing has been fixed!'), - message: t('Happy budgeting!'), - type: 'message', + notification: { + title: t('Syncing has been fixed!'), + message: t('Happy budgeting!'), + type: 'message', + }, }), ); } @@ -323,7 +325,9 @@ export function listenForSyncEvent(store: AppStore) { } if (notif) { - store.dispatch(addNotification({ type: 'error', ...notif })); + store.dispatch( + addNotification({ notification: { type: 'error', ...notif } }), + ); } } });