diff --git a/packages/desktop-client/src/components/HelpMenu.tsx b/packages/desktop-client/src/components/HelpMenu.tsx index bde80fce19d..90944cf658c 100644 --- a/packages/desktop-client/src/components/HelpMenu.tsx +++ b/packages/desktop-client/src/components/HelpMenu.tsx @@ -84,10 +84,10 @@ export const HelpMenu = () => { openDocsForCurrentPage(); break; case 'keyboard-shortcuts': - dispatch(pushModal({ name: 'keyboard-shortcuts' })); + dispatch(pushModal({ modal: { name: 'keyboard-shortcuts' } })); break; case 'goal-templates': - dispatch(pushModal({ name: 'goal-templates' })); + dispatch(pushModal({ modal: { name: 'goal-templates' } })); break; } }; diff --git a/packages/desktop-client/src/components/ManageRules.tsx b/packages/desktop-client/src/components/ManageRules.tsx index 4bffaad19ee..a70dcef1e8c 100644 --- a/packages/desktop-client/src/components/ManageRules.tsx +++ b/packages/desktop-client/src/components/ManageRules.tsx @@ -220,12 +220,14 @@ export function ManageRules({ const onEditRule = useCallback(rule => { dispatch( pushModal({ - name: 'edit-rule', - options: { - rule, - onSave: async () => { - await loadRules(); - setLoading(false); + modal: { + name: 'edit-rule', + options: { + rule, + onSave: async () => { + await loadRules(); + setLoading(false); + }, }, }, }), @@ -256,12 +258,14 @@ export function ManageRules({ dispatch( pushModal({ - name: 'edit-rule', - options: { - rule, - onSave: async () => { - await loadRules(); - setLoading(false); + modal: { + name: 'edit-rule', + options: { + rule, + onSave: async () => { + await loadRules(); + setLoading(false); + }, }, }, }), diff --git a/packages/desktop-client/src/components/accounts/Account.tsx b/packages/desktop-client/src/components/accounts/Account.tsx index 25b0504d110..aa1caaab12b 100644 --- a/packages/desktop-client/src/components/accounts/Account.tsx +++ b/packages/desktop-client/src/components/accounts/Account.tsx @@ -647,14 +647,16 @@ class AccountInternal extends PureComponent< if (accountId && res?.length > 0) { this.props.dispatch( pushModal({ - name: 'import-transactions', - options: { - accountId, - filename: res[0], - onImported: (didChange: boolean) => { - if (didChange) { - this.fetchTransactions(); - } + modal: { + name: 'import-transactions', + options: { + accountId, + filename: res[0], + onImported: (didChange: boolean) => { + if (didChange) { + this.fetchTransactions(); + } + }, }, }, }), @@ -817,9 +819,11 @@ class AccountInternal extends PureComponent< case 'link': this.props.dispatch( pushModal({ - name: 'add-account', - options: { - upgradingAccountId: accountId, + modal: { + name: 'add-account', + options: { + upgradingAccountId: accountId, + }, }, }), ); @@ -827,11 +831,13 @@ class AccountInternal extends PureComponent< case 'unlink': this.props.dispatch( pushModal({ - name: 'confirm-unlink-account', - options: { - accountName: account.name, - onUnlink: () => { - this.props.dispatch(unlinkAccount({ id: accountId })); + modal: { + name: 'confirm-unlink-account', + options: { + accountName: account.name, + onUnlink: () => { + this.props.dispatch(unlinkAccount({ id: accountId })); + }, }, }, }), @@ -1227,12 +1233,14 @@ class AccountInternal extends PureComponent< if (transactions.length > 0) { this.props.dispatch( pushModal({ - name: 'confirm-transaction-edit', - options: { - onConfirm: () => { - onConfirm(ids); + modal: { + name: 'confirm-transaction-edit', + options: { + onConfirm: () => { + onConfirm(ids); + }, + confirmReason, }, - confirmReason, }, }), ); @@ -1330,7 +1338,9 @@ class AccountInternal extends PureComponent< ], } satisfies NewRuleEntity; - this.props.dispatch(pushModal({ name: 'edit-rule', options: { rule } })); + this.props.dispatch( + pushModal({ modal: { name: 'edit-rule', options: { rule } } }), + ); }; onSetTransfer = async (ids: string[]) => { @@ -1862,7 +1872,9 @@ class AccountInternal extends PureComponent< this.props.dispatch( - replaceModal({ name: 'add-account', options: {} }), + replaceModal({ + modal: { name: 'add-account', options: {} }, + }), ) } /> diff --git a/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx b/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx index c6d8695005a..cff671148c6 100644 --- a/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx +++ b/packages/desktop-client/src/components/admin/UserAccess/UserAccess.tsx @@ -284,9 +284,11 @@ function LockToggle({ style, onToggleSave }: LockToggleProps) { onPress={() => dispatch( pushModal({ - name: 'transfer-ownership', - options: { - onSave: () => onToggleSave(), + modal: { + name: 'transfer-ownership', + options: { + onSave: () => onToggleSave(), + }, }, }), ) diff --git a/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx b/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx index 6e7f22aaedc..2ad39f1dc1a 100644 --- a/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx +++ b/packages/desktop-client/src/components/admin/UserDirectory/UserDirectory.tsx @@ -191,12 +191,14 @@ function UserDirectoryContent({ user => { dispatch( pushModal({ - name: 'edit-user', - options: { - user, - onSave: async () => { - await loadUsers(); - setLoading(false); + modal: { + name: 'edit-user', + options: { + user, + onSave: async () => { + await loadUsers(); + setLoading(false); + }, }, }, }), @@ -215,12 +217,14 @@ function UserDirectoryContent({ dispatch( pushModal({ - name: 'edit-user', - options: { - user, - onSave: async () => { - await loadUsers(); - setLoading(false); + modal: { + name: 'edit-user', + options: { + user, + onSave: async () => { + await loadUsers(); + setLoading(false); + }, }, }, }), diff --git a/packages/desktop-client/src/components/budget/index.tsx b/packages/desktop-client/src/components/budget/index.tsx index 6302ad396e2..4ea5a277681 100644 --- a/packages/desktop-client/src/components/budget/index.tsx +++ b/packages/desktop-client/src/components/budget/index.tsx @@ -223,13 +223,17 @@ function BudgetInner(props: BudgetInnerProps) { if (mustTransfer) { dispatch( pushModal({ - name: 'confirm-category-delete', - options: { - category: id, - onDelete: transferCategory => { - if (id !== transferCategory) { - dispatch(deleteCategory({ id, transferId: transferCategory })); - } + modal: { + name: 'confirm-category-delete', + options: { + category: id, + onDelete: transferCategory => { + if (id !== transferCategory) { + dispatch( + deleteCategory({ id, transferId: transferCategory }), + ); + } + }, }, }, }), @@ -261,11 +265,13 @@ function BudgetInner(props: BudgetInnerProps) { if (mustTransfer) { dispatch( pushModal({ - name: 'confirm-category-delete', - options: { - group: id, - onDelete: transferCategory => { - dispatch(deleteGroup({ id, transferId: transferCategory })); + modal: { + name: 'confirm-category-delete', + options: { + group: id, + onDelete: transferCategory => { + dispatch(deleteGroup({ id, transferId: transferCategory })); + }, }, }, }), diff --git a/packages/desktop-client/src/components/manager/BudgetList.tsx b/packages/desktop-client/src/components/manager/BudgetList.tsx index d1bdb042309..5e72317a91e 100644 --- a/packages/desktop-client/src/components/manager/BudgetList.tsx +++ b/packages/desktop-client/src/components/manager/BudgetList.tsx @@ -590,7 +590,9 @@ export function BudgetList({ showHeader = true, quickSwitchMode = false }) { dispatch(pushModal({ name: 'files-settings' }))} + onOpenSettings={() => + dispatch(pushModal({ modal: { name: 'files-settings' } })) + } /> )} - dispatch(pushModal({ name: 'delete-budget', options: { file } })) + dispatch( + pushModal({ modal: { name: 'delete-budget', options: { file } } }), + ) } onDuplicate={(file: File) => { if (file && 'id' in file) { dispatch( pushModal({ - name: 'duplicate-budget', - options: { file, managePage: true }, + modal: { + name: 'duplicate-budget', + options: { file, managePage: true }, + }, }), ); } else { @@ -634,7 +640,7 @@ export function BudgetList({ showHeader = true, quickSwitchMode = false }) { color: theme.pageTextLight, }} onPress={() => { - dispatch(pushModal({ name: 'import' })); + dispatch(pushModal({ modal: { name: 'import' } })); }} > Import file diff --git a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx index 2b217fdc264..260238098cb 100644 --- a/packages/desktop-client/src/components/manager/WelcomeScreen.tsx +++ b/packages/desktop-client/src/components/manager/WelcomeScreen.tsx @@ -80,7 +80,9 @@ export function WelcomeScreen() { flexShrink: 0, }} > - { dispatch( pushModal({ - name: 'notes', - options: { - id: `account-${id}`, - name: account.name, - onSave: onSaveNotes, + modal: { + name: 'notes', + options: { + id: `account-${id}`, + name: account.name, + onSave: onSaveNotes, + }, }, }), ); @@ -149,13 +151,15 @@ function AccountHeader({ account }: { readonly account: AccountEntity }) { const onClick = useCallback(() => { dispatch( pushModal({ - name: 'account-menu', - options: { - accountId: account.id, - onSave, - onEditNotes, - onCloseAccount, - onReopenAccount, + modal: { + name: 'account-menu', + options: { + accountId: account.id, + onSave, + onEditNotes, + onCloseAccount, + onReopenAccount, + }, }, }), ); @@ -306,26 +310,28 @@ function TransactionListWithPreviews({ } else { dispatch( pushModal({ - name: 'scheduled-transaction-menu', - options: { - transactionId: transaction.id, - onPost: async transactionId => { - const parts = transactionId.split('/'); - await send('schedule/post-transaction', { id: parts[1] }); - dispatch( - collapseModals({ - rootModalName: 'scheduled-transaction-menu', - }), - ); - }, - onSkip: async transactionId => { - const parts = transactionId.split('/'); - await send('schedule/skip-next-date', { id: parts[1] }); - dispatch( - collapseModals({ - rootModalName: 'scheduled-transaction-menu', - }), - ); + modal: { + name: 'scheduled-transaction-menu', + options: { + transactionId: transaction.id, + onPost: async transactionId => { + const parts = transactionId.split('/'); + await send('schedule/post-transaction', { id: parts[1] }); + dispatch( + collapseModals({ + rootModalName: 'scheduled-transaction-menu', + }), + ); + }, + onSkip: async transactionId => { + const parts = transactionId.split('/'); + await send('schedule/skip-next-date', { id: parts[1] }); + dispatch( + collapseModals({ + rootModalName: 'scheduled-transaction-menu', + }), + ); + }, }, }, }), diff --git a/packages/desktop-client/src/components/mobile/accounts/Accounts.tsx b/packages/desktop-client/src/components/mobile/accounts/Accounts.tsx index 402c652ce14..9249194b377 100644 --- a/packages/desktop-client/src/components/mobile/accounts/Accounts.tsx +++ b/packages/desktop-client/src/components/mobile/accounts/Accounts.tsx @@ -320,7 +320,7 @@ export function Accounts() { ); const onAddAccount = useCallback(() => { - dispatch(replaceModal({ name: 'add-account', options: {} })); + dispatch(replaceModal({ modal: { name: 'add-account', options: {} } })); }, [dispatch]); const onSync = useCallback(async () => { diff --git a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx index 03f9b44cd73..49985be3327 100644 --- a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx +++ b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx @@ -242,48 +242,50 @@ function BudgetCell({ const onOpenCategoryBudgetMenu = () => { dispatch( pushModal({ - name: categoryBudgetMenuModal, - options: { - categoryId: category.id, - month, - onUpdateBudget: amount => { - onBudgetAction(month, 'budget-amount', { - category: category.id, - amount, - }); - }, - onCopyLastMonthAverage: () => { - onBudgetAction(month, 'copy-single-last', { - category: category.id, - }); - showUndoNotification({ - message: `${category.name} budget has been set last to month’s budgeted amount.`, - }); - }, - onSetMonthsAverage: numberOfMonths => { - if ( - numberOfMonths !== 3 && - numberOfMonths !== 6 && - numberOfMonths !== 12 - ) { - return; - } + modal: { + name: categoryBudgetMenuModal, + options: { + categoryId: category.id, + month, + onUpdateBudget: amount => { + onBudgetAction(month, 'budget-amount', { + category: category.id, + amount, + }); + }, + onCopyLastMonthAverage: () => { + onBudgetAction(month, 'copy-single-last', { + category: category.id, + }); + showUndoNotification({ + message: `${category.name} budget has been set last to month’s budgeted amount.`, + }); + }, + onSetMonthsAverage: numberOfMonths => { + if ( + numberOfMonths !== 3 && + numberOfMonths !== 6 && + numberOfMonths !== 12 + ) { + return; + } - onBudgetAction(month, `set-single-${numberOfMonths}-avg`, { - category: category.id, - }); - showUndoNotification({ - message: `${category.name} budget has been set to ${numberOfMonths === 12 ? 'yearly' : `${numberOfMonths} month`} average.`, - }); - }, - onApplyBudgetTemplate: () => { - onBudgetAction(month, 'apply-single-category-template', { - category: category.id, - }); - showUndoNotification({ - message: `${category.name} budget templates have been applied.`, - pre: categoryNotes, - }); + onBudgetAction(month, `set-single-${numberOfMonths}-avg`, { + category: category.id, + }); + showUndoNotification({ + message: `${category.name} budget has been set to ${numberOfMonths === 12 ? 'yearly' : `${numberOfMonths} month`} average.`, + }); + }, + onApplyBudgetTemplate: () => { + onBudgetAction(month, 'apply-single-category-template', { + category: category.id, + }); + showUndoNotification({ + message: `${category.name} budget templates have been applied.`, + pre: categoryNotes, + }); + }, }, }, }), @@ -446,28 +448,30 @@ const ExpenseCategory = memo(function ExpenseCategory({ const onTransfer = useCallback(() => { dispatch( pushModal({ - name: 'transfer', - options: { - title: category.name, - categoryId: category.id, - month, - amount: catBalance, - onSubmit: (amount, toCategoryId) => { - onBudgetAction(month, 'transfer-category', { - amount, - from: category.id, - to: toCategoryId, - }); - dispatch( - collapseModals({ - rootModalName: `${modalBudgetType}-balance-menu`, - }), - ); - showUndoNotification({ - message: `Transferred ${integerToCurrency(amount)} from ${category.name} to ${categoriesById[toCategoryId].name}.`, - }); + modal: { + name: 'transfer', + options: { + title: category.name, + categoryId: category.id, + month, + amount: catBalance, + onSubmit: (amount, toCategoryId) => { + onBudgetAction(month, 'transfer-category', { + amount, + from: category.id, + to: toCategoryId, + }); + dispatch( + collapseModals({ + rootModalName: `${modalBudgetType}-balance-menu`, + }), + ); + showUndoNotification({ + message: `Transferred ${integerToCurrency(amount)} from ${category.name} to ${categoriesById[toCategoryId].name}.`, + }); + }, + showToBeBudgeted: true, }, - showToBeBudgeted: true, }, }), ); @@ -486,24 +490,26 @@ const ExpenseCategory = memo(function ExpenseCategory({ const onCover = useCallback(() => { dispatch( pushModal({ - name: 'cover', - options: { - title: category.name, - month, - categoryId: category.id, - onSubmit: fromCategoryId => { - onBudgetAction(month, 'cover-overspending', { - to: category.id, - from: fromCategoryId, - }); - dispatch( - collapseModals({ - rootModalName: `${modalBudgetType}-balance-menu`, - }), - ); - showUndoNotification({ - message: `Covered ${category.name} overspending from ${categoriesById[fromCategoryId].name}.`, - }); + modal: { + name: 'cover', + options: { + title: category.name, + month, + categoryId: category.id, + onSubmit: fromCategoryId => { + onBudgetAction(month, 'cover-overspending', { + to: category.id, + from: fromCategoryId, + }); + dispatch( + collapseModals({ + rootModalName: `${modalBudgetType}-balance-menu`, + }), + ); + showUndoNotification({ + message: `Covered ${category.name} overspending from ${categoriesById[fromCategoryId].name}.`, + }); + }, }, }, }), @@ -522,12 +528,14 @@ const ExpenseCategory = memo(function ExpenseCategory({ const onOpenBalanceMenu = useCallback(() => { dispatch( pushModal({ - name: `${modalBudgetType}-balance-menu`, - options: { - categoryId: category.id, - month, - onCarryover, - ...(budgetType === 'rollover' && { onTransfer, onCover }), + modal: { + name: `${modalBudgetType}-balance-menu`, + options: { + categoryId: category.id, + month, + onCarryover, + ...(budgetType === 'rollover' && { onTransfer, onCover }), + }, }, }), ); diff --git a/packages/desktop-client/src/components/mobile/budget/index.tsx b/packages/desktop-client/src/components/mobile/budget/index.tsx index 903c9198ed3..2c96f961df7 100644 --- a/packages/desktop-client/src/components/mobile/budget/index.tsx +++ b/packages/desktop-client/src/components/mobile/budget/index.tsx @@ -96,19 +96,23 @@ export function Budget() { if (budgetType === 'report') { dispatch( pushModal({ - name: 'tracking-budget-summary', - options: { - month: startMonth, + modal: { + name: 'tracking-budget-summary', + options: { + month: startMonth, + }, }, }), ); } else { dispatch( pushModal({ - name: 'envelope-budget-summary', - options: { - month: startMonth, - onBudgetAction, + modal: { + name: 'envelope-budget-summary', + options: { + month: startMonth, + onBudgetAction, + }, }, }), ); @@ -118,12 +122,14 @@ export function Budget() { const onOpenNewCategoryGroupModal = useCallback(() => { dispatch( pushModal({ - name: 'new-category-group', - options: { - onValidate: name => (!name ? 'Name is required.' : null), - onSubmit: async name => { - dispatch(collapseModals({ rootModalName: 'budget-page-menu' })); - dispatch(createGroup({ name })); + modal: { + name: 'new-category-group', + options: { + onValidate: name => (!name ? 'Name is required.' : null), + onSubmit: async name => { + dispatch(collapseModals({ rootModalName: 'budget-page-menu' })); + dispatch(createGroup({ name })); + }, }, }, }), @@ -134,16 +140,18 @@ export function Budget() { (groupId, isIncome) => { dispatch( pushModal({ - name: 'new-category', - options: { - onValidate: name => (!name ? 'Name is required.' : null), - onSubmit: async name => { - dispatch( - collapseModals({ rootModalName: 'category-group-menu' }), - ); - dispatch( - createCategory({ name, groupId, isIncome, isHidden: false }), - ); + modal: { + name: 'new-category', + options: { + onValidate: name => (!name ? 'Name is required.' : null), + onSubmit: async name => { + dispatch( + collapseModals({ rootModalName: 'category-group-menu' }), + ); + dispatch( + createCategory({ name, groupId, isIncome, isHidden: false }), + ); + }, }, }, }), @@ -178,16 +186,18 @@ export function Budget() { if (mustTransfer) { dispatch( pushModal({ - name: 'confirm-category-delete', - options: { - group: groupId, - onDelete: transferCategory => { - dispatch( - collapseModals({ rootModalName: 'category-group-menu' }), - ); - dispatch( - deleteGroup({ id: groupId, transferId: transferCategory }), - ); + modal: { + name: 'confirm-category-delete', + options: { + group: groupId, + onDelete: transferCategory => { + dispatch( + collapseModals({ rootModalName: 'category-group-menu' }), + ); + dispatch( + deleteGroup({ id: groupId, transferId: transferCategory }), + ); + }, }, }, }), @@ -228,19 +238,23 @@ export function Budget() { if (mustTransfer) { dispatch( pushModal({ - name: 'confirm-category-delete', - options: { - category: categoryId, - onDelete: transferCategory => { - if (categoryId !== transferCategory) { - dispatch(collapseModals({ rootModalName: 'category-menu' })); - dispatch( - deleteCategory({ - id: categoryId, - transferId: transferCategory, - }), - ); - } + modal: { + name: 'confirm-category-delete', + options: { + category: categoryId, + onDelete: transferCategory => { + if (categoryId !== transferCategory) { + dispatch( + collapseModals({ rootModalName: 'category-menu' }), + ); + dispatch( + deleteCategory({ + id: categoryId, + transferId: transferCategory, + }), + ); + } + }, }, }, }), @@ -373,11 +387,13 @@ export function Budget() { const group = categoryGroups.find(g => g.id === id); dispatch( pushModal({ - name: 'notes', - options: { - id, - name: group.name, - onSave: onSaveNotes, + modal: { + name: 'notes', + options: { + id, + name: group.name, + onSave: onSaveNotes, + }, }, }), ); @@ -390,11 +406,13 @@ export function Budget() { const category = categories.find(c => c.id === id); dispatch( pushModal({ - name: 'notes', - options: { - id, - name: category.name, - onSave: onSaveNotes, + modal: { + name: 'notes', + options: { + id, + name: category.name, + onSave: onSaveNotes, + }, }, }), ); @@ -407,14 +425,16 @@ export function Budget() { const group = categoryGroups.find(g => g.id === id); dispatch( pushModal({ - name: 'category-group-menu', - options: { - groupId: group.id, - onSave: onSaveGroup, - onAddCategory: onOpenNewCategoryModal, - onEditNotes: onOpenCategoryGroupNotesModal, - onDelete: onDeleteGroup, - onToggleVisibility: onToggleGroupVisibility, + modal: { + name: 'category-group-menu', + options: { + groupId: group.id, + onSave: onSaveGroup, + onAddCategory: onOpenNewCategoryModal, + onEditNotes: onOpenCategoryGroupNotesModal, + onDelete: onDeleteGroup, + onToggleVisibility: onToggleGroupVisibility, + }, }, }), ); @@ -435,13 +455,15 @@ export function Budget() { const category = categories.find(c => c.id === id); dispatch( pushModal({ - name: 'category-menu', - options: { - categoryId: category.id, - onSave: onSaveCategory, - onEditNotes: onOpenCategoryNotesModal, - onDelete: onDeleteCategory, - onToggleVisibility: onToggleCategoryVisibility, + modal: { + name: 'category-menu', + options: { + categoryId: category.id, + onSave: onSaveCategory, + onEditNotes: onOpenCategoryNotesModal, + onDelete: onDeleteCategory, + onToggleVisibility: onToggleCategoryVisibility, + }, }, }), ); @@ -469,11 +491,13 @@ export function Budget() { month => { dispatch( pushModal({ - name: 'notes', - options: { - id: `budget-${month}`, - name: monthUtils.format(month, 'MMMM ‘yy'), - onSave: onSaveNotes, + modal: { + name: 'notes', + options: { + id: `budget-${month}`, + name: monthUtils.format(month, 'MMMM ‘yy'), + onSave: onSaveNotes, + }, }, }), ); @@ -482,18 +506,20 @@ export function Budget() { ); const onSwitchBudgetFile = useCallback(() => { - dispatch(pushModal({ name: 'budget-list' })); + dispatch(pushModal({ modal: { name: 'budget-list' } })); }, [dispatch]); const onOpenBudgetMonthMenu = useCallback( month => { dispatch( pushModal({ - name: `${budgetType === 'report' ? 'tracking' : 'envelope'}-budget-month-menu`, - options: { - month, - onBudgetAction, - onEditNotes: onOpenBudgetMonthNotesModal, + modal: { + name: `${budgetType === 'report' ? 'tracking' : 'envelope'}-budget-month-menu`, + options: { + month, + onBudgetAction, + onEditNotes: onOpenBudgetMonthNotesModal, + }, }, }), ); @@ -504,11 +530,13 @@ export function Budget() { const onOpenBudgetPageMenu = useCallback(() => { dispatch( pushModal({ - name: 'budget-page-menu', - options: { - onAddCategoryGroup: onOpenNewCategoryGroupModal, - onToggleHiddenCategories, - onSwitchBudgetFile, + modal: { + name: 'budget-page-menu', + options: { + onAddCategoryGroup: onOpenNewCategoryGroupModal, + onToggleHiddenCategories, + onSwitchBudgetFile, + }, }, }), ); diff --git a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx index e89a17ab478..c3806207043 100644 --- a/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx +++ b/packages/desktop-client/src/components/mobile/transactions/TransactionEdit.jsx @@ -550,10 +550,12 @@ const TransactionEditInner = memo(function TransactionEditInner({ // make this more appropriate? dispatch( pushModal({ - name: 'confirm-transaction-edit', - options: { - onConfirm: onConfirmSave, - confirmReason: 'editReconciled', + modal: { + name: 'confirm-transaction-edit', + options: { + onConfirm: onConfirmSave, + confirmReason: 'editReconciled', + }, }, }), ); @@ -599,15 +601,19 @@ const TransactionEditInner = memo(function TransactionEditInner({ case 'category': dispatch( pushModal({ - name: 'category-autocomplete', - options: { - categoryGroups, - month: monthUtils.monthFromDate(unserializedTransaction.date), - onSelect: categoryId => { - onUpdateInner(transactionToEdit, name, categoryId); - }, - onClose: () => { - onClearActiveEdit(); + modal: { + name: 'category-autocomplete', + options: { + categoryGroups, + month: monthUtils.monthFromDate( + unserializedTransaction.date, + ), + onSelect: categoryId => { + onUpdateInner(transactionToEdit, name, categoryId); + }, + onClose: () => { + onClearActiveEdit(); + }, }, }, }), @@ -616,13 +622,15 @@ const TransactionEditInner = memo(function TransactionEditInner({ case 'account': dispatch( pushModal({ - name: 'account-autocomplete', - options: { - onSelect: accountId => { - onUpdateInner(transactionToEdit, name, accountId); - }, - onClose: () => { - onClearActiveEdit(); + modal: { + name: 'account-autocomplete', + options: { + onSelect: accountId => { + onUpdateInner(transactionToEdit, name, accountId); + }, + onClose: () => { + onClearActiveEdit(); + }, }, }, }), @@ -631,13 +639,15 @@ const TransactionEditInner = memo(function TransactionEditInner({ case 'payee': dispatch( pushModal({ - name: 'payee-autocomplete', - options: { - onSelect: payeeId => { - onUpdateInner(transactionToEdit, name, payeeId); - }, - onClose: () => { - onClearActiveEdit(); + modal: { + name: 'payee-autocomplete', + options: { + onSelect: payeeId => { + onUpdateInner(transactionToEdit, name, payeeId); + }, + onClose: () => { + onClearActiveEdit(); + }, }, }, }), @@ -646,15 +656,19 @@ const TransactionEditInner = memo(function TransactionEditInner({ default: dispatch( pushModal({ - name: 'edit-field', - options: { - name, - month: monthUtils.monthFromDate(unserializedTransaction.date), - onSubmit: (name, value) => { - onUpdateInner(transactionToEdit, name, value); - }, - onClose: () => { - onClearActiveEdit(); + modal: { + name: 'edit-field', + options: { + name, + month: monthUtils.monthFromDate( + unserializedTransaction.date, + ), + onSubmit: (name, value) => { + onUpdateInner(transactionToEdit, name, value); + }, + onClose: () => { + onClearActiveEdit(); + }, }, }, }), @@ -682,18 +696,20 @@ const TransactionEditInner = memo(function TransactionEditInner({ const onConfirmDelete = () => { dispatch( pushModal({ - name: 'confirm-transaction-delete', - options: { - onConfirm: () => { - onDelete(id); - - if (unserializedTransaction.id !== id) { - // Only a child transaction was deleted. - onClearActiveEdit(); - return; - } + modal: { + name: 'confirm-transaction-delete', + options: { + onConfirm: () => { + onDelete(id); + + if (unserializedTransaction.id !== id) { + // Only a child transaction was deleted. + onClearActiveEdit(); + return; + } - navigate(-1); + navigate(-1); + }, }, }, }), @@ -703,10 +719,12 @@ const TransactionEditInner = memo(function TransactionEditInner({ if (unserializedTransaction.reconciled) { dispatch( pushModal({ - name: 'confirm-transaction-edit', - options: { - onConfirm: onConfirmDelete, - confirmReason: 'deleteReconciled', + modal: { + name: 'confirm-transaction-edit', + options: { + onConfirm: onConfirmDelete, + confirmReason: 'deleteReconciled', + }, }, }), ); diff --git a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx index a7601ba0ad3..9c6e49ca569 100644 --- a/packages/desktop-client/src/components/modals/CloseAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CloseAccountModal.tsx @@ -184,10 +184,12 @@ export function CloseAccountModal({ onClick: () => { dispatch( pushModal({ - name: 'account-autocomplete', - options: { - includeClosedAccounts: false, - onSelect: onSelectAccount, + modal: { + name: 'account-autocomplete', + options: { + includeClosedAccounts: false, + onSelect: onSelectAccount, + }, }, }), ); @@ -227,11 +229,13 @@ export function CloseAccountModal({ onClick: () => { dispatch( pushModal({ - name: 'category-autocomplete', - options: { - categoryGroups, - showHiddenCategories: true, - onSelect: onSelectCategory, + modal: { + name: 'category-autocomplete', + options: { + categoryGroups, + showHiddenCategories: true, + onSelect: onSelectCategory, + }, }, }), ); diff --git a/packages/desktop-client/src/components/modals/CoverModal.tsx b/packages/desktop-client/src/components/modals/CoverModal.tsx index 80ccc970a5b..08f9b4e7d34 100644 --- a/packages/desktop-client/src/components/modals/CoverModal.tsx +++ b/packages/desktop-client/src/components/modals/CoverModal.tsx @@ -50,12 +50,14 @@ export function CoverModal({ const onCategoryClick = useCallback(() => { dispatch( pushModal({ - name: 'category-autocomplete', - options: { - categoryGroups, - month, - onSelect: categoryId => { - setFromCategoryId(categoryId); + modal: { + name: 'category-autocomplete', + options: { + categoryGroups, + month, + onSelect: categoryId => { + setFromCategoryId(categoryId); + }, }, }, }), diff --git a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx index 21cb7368c63..d64114677ce 100644 --- a/packages/desktop-client/src/components/modals/CreateAccountModal.tsx +++ b/packages/desktop-client/src/components/modals/CreateAccountModal.tsx @@ -109,10 +109,12 @@ export function CreateAccountModal({ dispatch( pushModal({ - name: 'select-linked-accounts', - options: { - externalAccounts: newAccounts, - syncSource: 'simpleFin', + modal: { + name: 'select-linked-accounts', + options: { + externalAccounts: newAccounts, + syncSource: 'simpleFin', + }, }, }), ); @@ -120,9 +122,11 @@ export function CreateAccountModal({ console.error(err); dispatch( pushModal({ - name: 'simplefin-init', - options: { - onSuccess: () => setIsSimpleFinSetupComplete(true), + modal: { + name: 'simplefin-init', + options: { + onSuccess: () => setIsSimpleFinSetupComplete(true), + }, }, }), ); @@ -134,9 +138,11 @@ export function CreateAccountModal({ const onGoCardlessInit = () => { dispatch( pushModal({ - name: 'gocardless-init', - options: { - onSuccess: () => setIsGoCardlessSetupComplete(true), + modal: { + name: 'gocardless-init', + options: { + onSuccess: () => setIsGoCardlessSetupComplete(true), + }, }, }), ); @@ -145,9 +151,11 @@ export function CreateAccountModal({ const onSimpleFinInit = () => { dispatch( pushModal({ - name: 'simplefin-init', - options: { - onSuccess: () => setIsSimpleFinSetupComplete(true), + modal: { + name: 'simplefin-init', + options: { + onSuccess: () => setIsSimpleFinSetupComplete(true), + }, }, }), ); @@ -182,7 +190,7 @@ export function CreateAccountModal({ }; const onCreateLocalAccount = () => { - dispatch(pushModal({ name: 'add-local-account' })); + dispatch(pushModal({ modal: { name: 'add-local-account' } })); }; const { configuredGoCardless } = useGoCardlessStatus(); diff --git a/packages/desktop-client/src/components/modals/EnvelopeBudgetSummaryModal.tsx b/packages/desktop-client/src/components/modals/EnvelopeBudgetSummaryModal.tsx index 5899b281265..50d0b3e185d 100644 --- a/packages/desktop-client/src/components/modals/EnvelopeBudgetSummaryModal.tsx +++ b/packages/desktop-client/src/components/modals/EnvelopeBudgetSummaryModal.tsx @@ -45,21 +45,23 @@ export function EnvelopeBudgetSummaryModal({ const openTransferAvailableModal = () => { dispatch( pushModal({ - name: 'transfer', - options: { - title: t('Transfer: To Budget'), - month, - amount: sheetValue, - onSubmit: (amount, toCategoryId) => { - onBudgetAction(month, 'transfer-available', { - amount, - month, - category: toCategoryId, - }); - dispatch(collapseModals({ rootModalName: 'transfer' })); - showUndoNotification({ - message: `Transferred ${integerToCurrency(amount)} to ${categoriesById[toCategoryId].name}`, - }); + modal: { + name: 'transfer', + options: { + title: t('Transfer: To Budget'), + month, + amount: sheetValue, + onSubmit: (amount, toCategoryId) => { + onBudgetAction(month, 'transfer-available', { + amount, + month, + category: toCategoryId, + }); + dispatch(collapseModals({ rootModalName: 'transfer' })); + showUndoNotification({ + message: `Transferred ${integerToCurrency(amount)} to ${categoriesById[toCategoryId].name}`, + }); + }, }, }, }), @@ -69,19 +71,21 @@ export function EnvelopeBudgetSummaryModal({ const openCoverOverbudgetedModal = () => { dispatch( pushModal({ - name: 'cover', - options: { - title: t('Cover: Overbudgeted'), - month, - showToBeBudgeted: false, - onSubmit: categoryId => { - onBudgetAction(month, 'cover-overbudgeted', { - category: categoryId, - }); - dispatch(collapseModals({ rootModalName: 'cover' })); - showUndoNotification({ - message: `Covered overbudgeted from ${categoriesById[categoryId].name}`, - }); + modal: { + name: 'cover', + options: { + title: t('Cover: Overbudgeted'), + month, + showToBeBudgeted: false, + onSubmit: categoryId => { + onBudgetAction(month, 'cover-overbudgeted', { + category: categoryId, + }); + dispatch(collapseModals({ rootModalName: 'cover' })); + showUndoNotification({ + message: `Covered overbudgeted from ${categoriesById[categoryId].name}`, + }); + }, }, }, }), @@ -91,12 +95,14 @@ export function EnvelopeBudgetSummaryModal({ const onHoldBuffer = () => { dispatch( pushModal({ - name: 'hold-buffer', - options: { - month, - onSubmit: amount => { - onBudgetAction(month, 'hold', { amount }); - dispatch(collapseModals({ rootModalName: 'hold-buffer' })); + modal: { + name: 'hold-buffer', + options: { + month, + onSubmit: amount => { + onBudgetAction(month, 'hold', { amount }); + dispatch(collapseModals({ rootModalName: 'hold-buffer' })); + }, }, }, }), @@ -110,16 +116,18 @@ export function EnvelopeBudgetSummaryModal({ const onClick = ({ close }: { close: () => void }) => { dispatch( pushModal({ - name: 'envelope-summary-to-budget-menu', - options: { - month, - onTransfer: openTransferAvailableModal, - onCover: openCoverOverbudgetedModal, - onResetHoldBuffer: () => { - onResetHoldBuffer(); - close(); + modal: { + name: 'envelope-summary-to-budget-menu', + options: { + month, + onTransfer: openTransferAvailableModal, + onCover: openCoverOverbudgetedModal, + onResetHoldBuffer: () => { + onResetHoldBuffer(); + close(); + }, + onHoldBuffer, }, - onHoldBuffer, }, }), ); diff --git a/packages/desktop-client/src/components/modals/GoCardlessExternalMsgModal.tsx b/packages/desktop-client/src/components/modals/GoCardlessExternalMsgModal.tsx index a21fac8b727..a192b2ace40 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessExternalMsgModal.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessExternalMsgModal.tsx @@ -134,9 +134,11 @@ export function GoCardlessExternalMsgModal({ const onGoCardlessInit = () => { dispatch( pushModal({ - name: 'gocardless-init', - options: { - onSuccess: () => setIsGoCardlessSetupComplete(true), + modal: { + name: 'gocardless-init', + options: { + onSuccess: () => setIsGoCardlessSetupComplete(true), + }, }, }), ); diff --git a/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx b/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx index aee32f1537e..ecfcd7f959e 100644 --- a/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx +++ b/packages/desktop-client/src/components/modals/MergeUnusedPayeesModal.tsx @@ -84,7 +84,9 @@ export function MergeUnusedPayeesModal({ if (ruleId) { const rule = await send('rule-get', { id: ruleId }); - dispatch(replaceModal({ name: 'edit-rule', options: { rule } })); + dispatch( + replaceModal({ modal: { name: 'edit-rule', options: { rule } } }), + ); } }, [onMerge, dispatch], diff --git a/packages/desktop-client/src/components/modals/TransferModal.tsx b/packages/desktop-client/src/components/modals/TransferModal.tsx index 83ca1cf7efe..e9e2f561cc2 100644 --- a/packages/desktop-client/src/components/modals/TransferModal.tsx +++ b/packages/desktop-client/src/components/modals/TransferModal.tsx @@ -55,13 +55,15 @@ export function TransferModal({ const openCategoryModal = () => { dispatch( pushModal({ - name: 'category-autocomplete', - options: { - categoryGroups, - month, - showHiddenCategories: true, - onSelect: categoryId => { - setToCategoryId(categoryId); + modal: { + name: 'category-autocomplete', + options: { + categoryGroups, + month, + showHiddenCategories: true, + onSelect: categoryId => { + setToCategoryId(categoryId); + }, }, }, }), diff --git a/packages/desktop-client/src/components/modals/manager/FilesSettingsModal.tsx b/packages/desktop-client/src/components/modals/manager/FilesSettingsModal.tsx index cad32c42ffd..c96bea0abb0 100644 --- a/packages/desktop-client/src/components/modals/manager/FilesSettingsModal.tsx +++ b/packages/desktop-client/src/components/modals/manager/FilesSettingsModal.tsx @@ -29,10 +29,12 @@ function FileLocationSettings() { dispatch( pushModal({ - name: 'confirm-change-document-dir', - options: { - currentBudgetDirectory: documentDir, - newDirectory: chosenDirectory[0], + modal: { + name: 'confirm-change-document-dir', + options: { + currentBudgetDirectory: documentDir, + newDirectory: chosenDirectory[0], + }, }, }), ); diff --git a/packages/desktop-client/src/components/modals/manager/ImportModal.tsx b/packages/desktop-client/src/components/modals/manager/ImportModal.tsx index 8acdb4f869f..095323daf45 100644 --- a/packages/desktop-client/src/components/modals/manager/ImportModal.tsx +++ b/packages/desktop-client/src/components/modals/manager/ImportModal.tsx @@ -29,13 +29,13 @@ export function ImportModal() { function onSelectType(type: 'ynab4' | 'ynab5' | 'actual') { switch (type) { case 'ynab4': - dispatch(pushModal({ name: 'import-ynab4' })); + dispatch(pushModal({ modal: { name: 'import-ynab4' } })); break; case 'ynab5': - dispatch(pushModal({ name: 'import-ynab5' })); + dispatch(pushModal({ modal: { name: 'import-ynab5' } })); break; case 'actual': - dispatch(pushModal({ name: 'import-actual' })); + dispatch(pushModal({ modal: { name: 'import-actual' } })); break; default: } diff --git a/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx b/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx index 6d80e663c8a..b19c1fe5a93 100644 --- a/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx +++ b/packages/desktop-client/src/components/payees/ManagePayeesWithData.tsx @@ -91,7 +91,9 @@ export function ManagePayeesWithData({ }, [dispatch, refetchRuleCounts, refetchOrphanedPayees]); function onViewRules(id: PayeeEntity['id']) { - dispatch(pushModal({ name: 'manage-rules', options: { payeeId: id } })); + dispatch( + pushModal({ modal: { name: 'manage-rules', options: { payeeId: id } } }), + ); } function onCreateRule(id: PayeeEntity['id']) { @@ -115,7 +117,7 @@ export function ManagePayeesWithData({ }, ], }; - dispatch(pushModal({ name: 'edit-rule', options: { rule } })); + dispatch(pushModal({ modal: { name: 'edit-rule', options: { rule } } })); } return ( diff --git a/packages/desktop-client/src/components/schedules/ScheduleDetails.tsx b/packages/desktop-client/src/components/schedules/ScheduleDetails.tsx index f728e057f9a..e615be3ce3b 100644 --- a/packages/desktop-client/src/components/schedules/ScheduleDetails.tsx +++ b/packages/desktop-client/src/components/schedules/ScheduleDetails.tsx @@ -534,12 +534,14 @@ export function ScheduleDetails({ id, transaction }: ScheduleDetailsProps) { globalDispatch( pushModal({ - name: 'edit-rule', - options: { - rule, - onSave: async () => { - const schedule = await loadSchedule(); - dispatch({ type: 'set-schedule', schedule }); + modal: { + name: 'edit-rule', + options: { + rule, + onSave: async () => { + const schedule = await loadSchedule(); + dispatch({ type: 'set-schedule', schedule }); + }, }, }, }), diff --git a/packages/desktop-client/src/components/schedules/ScheduleLink.tsx b/packages/desktop-client/src/components/schedules/ScheduleLink.tsx index 44cb40f7a66..e1c14e35059 100644 --- a/packages/desktop-client/src/components/schedules/ScheduleLink.tsx +++ b/packages/desktop-client/src/components/schedules/ScheduleLink.tsx @@ -60,10 +60,12 @@ export function ScheduleLink({ async function onCreate() { dispatch( pushModal({ - name: 'schedule-edit', - options: { - id: null, - transaction: getTransaction(ids[0]), + modal: { + name: 'schedule-edit', + options: { + id: null, + transaction: getTransaction(ids[0]), + }, }, }), ); diff --git a/packages/desktop-client/src/components/schedules/index.tsx b/packages/desktop-client/src/components/schedules/index.tsx index 2c327e2f075..4025398d8f2 100644 --- a/packages/desktop-client/src/components/schedules/index.tsx +++ b/packages/desktop-client/src/components/schedules/index.tsx @@ -25,17 +25,19 @@ export function Schedules() { const onEdit = useCallback( (id: ScheduleEntity['id']) => { - dispatch(pushModal({ name: 'schedule-edit', options: { id } })); + dispatch( + pushModal({ modal: { name: 'schedule-edit', options: { id } } }), + ); }, [dispatch], ); const onAdd = useCallback(() => { - dispatch(pushModal({ name: 'schedule-edit', options: {} })); + dispatch(pushModal({ modal: { name: 'schedule-edit', options: {} } })); }, [dispatch]); const onDiscover = useCallback(() => { - dispatch(pushModal({ name: 'schedules-discover' })); + dispatch(pushModal({ modal: { name: 'schedules-discover' } })); }, [dispatch]); const onAction = useCallback( diff --git a/packages/desktop-client/src/components/settings/AuthSettings.tsx b/packages/desktop-client/src/components/settings/AuthSettings.tsx index f8caeb4899b..e4f0896a7ca 100644 --- a/packages/desktop-client/src/components/settings/AuthSettings.tsx +++ b/packages/desktop-client/src/components/settings/AuthSettings.tsx @@ -42,9 +42,11 @@ export function AuthSettings() { onPress={() => dispatch( pushModal({ - name: 'enable-openid', - options: { - onSave: async () => {}, + modal: { + name: 'enable-openid', + options: { + onSave: async () => {}, + }, }, }), ) @@ -68,9 +70,11 @@ export function AuthSettings() { onPress={() => dispatch( pushModal({ - name: 'enable-password-auth', - options: { - onSave: async () => {}, + modal: { + name: 'enable-password-auth', + options: { + onSave: async () => {}, + }, }, }), ) diff --git a/packages/desktop-client/src/components/settings/Encryption.tsx b/packages/desktop-client/src/components/settings/Encryption.tsx index cb4126e5dc8..2867ffcef87 100644 --- a/packages/desktop-client/src/components/settings/Encryption.tsx +++ b/packages/desktop-client/src/components/settings/Encryption.tsx @@ -22,7 +22,9 @@ export function EncryptionSettings() { function onChangeKey() { dispatch( - pushModal({ name: 'create-encryption-key', options: { recreate: true } }), + pushModal({ + modal: { name: 'create-encryption-key', options: { recreate: true } }, + }), ); } @@ -81,7 +83,11 @@ export function EncryptionSettings() { primaryAction={