From 000c92d0ba9ab47f28420d0eef96eebcd26bd4b8 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 4 Jan 2024 11:21:42 -0500 Subject: [PATCH 01/24] Some initial UI work for adding SimpleFin. --- .../desktop-client/src/components/Modals.tsx | 9 ++ .../src/components/modals/CreateAccount.tsx | 55 +++++++++-- .../components/modals/SimpleFinInitialise.tsx | 92 +++++++++++++++++++ .../src/hooks/useSimpleFinStatus.ts | 32 +++++++ 4 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx create mode 100644 packages/desktop-client/src/hooks/useSimpleFinStatus.ts diff --git a/packages/desktop-client/src/components/Modals.tsx b/packages/desktop-client/src/components/Modals.tsx index 643ef4a0899..303a932004a 100644 --- a/packages/desktop-client/src/components/Modals.tsx +++ b/packages/desktop-client/src/components/Modals.tsx @@ -20,6 +20,7 @@ import EditRule from './modals/EditRule'; import FixEncryptionKey from './modals/FixEncryptionKey'; import GoCardlessExternalMsg from './modals/GoCardlessExternalMsg'; import GoCardlessInitialise from './modals/GoCardlessInitialise'; +import SimpleFinInitialise from './modals/SimpleFinInitialise'; import ImportTransactions from './modals/ImportTransactions'; import LoadBackup from './modals/LoadBackup'; import ManageRulesModal from './modals/ManageRulesModal'; @@ -192,6 +193,14 @@ export default function Modals() { /> ); + case 'simplefin-init': + return ( + + ); + case 'gocardless-external-msg': return ( { + const onConnectGoCardless = () => { if (!isGoCardlessSetupComplete) { onGoCardlessInit(); return; @@ -35,20 +38,40 @@ export default function CreateAccount({ authorizeBank(actions.pushModal); }; + const onConnectSimpleFin = () => { + if (!isSimpleFinSetupComplete) { + onSimpleFinInit(); + return; + } + + authorizeBank(actions.pushModal); + }; + const onGoCardlessInit = () => { actions.pushModal('gocardless-init', { onSuccess: () => setIsGoCardlessSetupComplete(true), }); }; + const onSimpleFinInit = () => { + actions.pushModal('simplefin-init', { + onSuccess: () => setIsSimpleFinSetupComplete(true), + }); + }; + const onCreateLocalAccount = () => { actions.pushModal('add-local-account'); }; - const { configured } = useGoCardlessStatus(); + const { configuredGoCardless } = useGoCardlessStatus(); useEffect(() => { - setIsGoCardlessSetupComplete(configured); - }, [configured]); + setIsGoCardlessSetupComplete(configuredGoCardless); + }, [configuredGoCardless]); + + const { configuredSimpleFin } = useSimpleFinStatus(); + useEffect(() => { + setIsSimpleFinSetupComplete(configuredSimpleFin); + }, [configuredSimpleFin]); return ( @@ -91,17 +114,37 @@ export default function CreateAccount({ fontWeight: 600, flex: 1, }} - onClick={onConnect} + onClick={onConnectGoCardless} > {isGoCardlessSetupComplete ? 'Link bank account with GoCardless' : 'Set up GoCardless for bank sync'} - Link a bank account to automatically download + Link a European bank account to automatically download transactions. GoCardless provides reliable, up-to-date information from hundreds of banks. + + {isSimpleFinSetupComplete + ? 'Link bank account with SimpleFIN' + : 'Set up SimpleFIN for bank sync'} + + + Link an American bank account to automatically download + transactions. SimpleFIN provides reliable, up-to-date + information from hundreds of banks. + ) : ( <> diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx new file mode 100644 index 00000000000..3a12080172e --- /dev/null +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -0,0 +1,92 @@ +import React, { useState } from 'react'; + +import { send } from 'loot-core/src/platform/client/fetch'; + +import { Error } from '../alerts'; +import { ButtonWithLoading } from '../common/Button'; +import ExternalLink from '../common/ExternalLink'; +import Input from '../common/Input'; +import Modal, { ModalButtons } from '../common/Modal'; +import type { ModalProps } from '../common/Modal'; +import Text from '../common/Text'; +import View from '../common/View'; +import { FormField, FormLabel } from '../forms'; + +type SimpleFinInitialiseProps = { + modalProps?: Partial; + onSuccess: () => void; +}; + +const SimpleFinInitialise = ({ + modalProps, + onSuccess, +}: SimpleFinInitialiseProps) => { + const [token, setToken] = useState(''); + const [isValid, setIsValid] = useState(true); + const [isLoading, setIsLoading] = useState(false); + + const onSubmit = async () => { + if (!token) { + setIsValid(false); + return; + } + + setIsLoading(true); + + await Promise.all([ + send('secret-set', { + name: 'simplefin_token', + value: token, + }), + ]); + + onSuccess(); + modalProps.onClose(); + setIsLoading(false); + }; + + return ( + + + + In order to enable bank-sync via SimpleFIN (only for USA banks) you + will need to create a token. This can be done by creating + an account with{' '} + + SimpleFIN + + . + + + + + setIsValid(true)} + /> + + + {!isValid && ( + + It is required to provide a token. + + )} + + + + + Save and continue + + + + ); +}; + +export default SimpleFinInitialise; diff --git a/packages/desktop-client/src/hooks/useSimpleFinStatus.ts b/packages/desktop-client/src/hooks/useSimpleFinStatus.ts new file mode 100644 index 00000000000..4a230a6a04a --- /dev/null +++ b/packages/desktop-client/src/hooks/useSimpleFinStatus.ts @@ -0,0 +1,32 @@ +import { useEffect, useState } from 'react'; + +import { send } from 'loot-core/src/platform/client/fetch'; + +import useSyncServerStatus from './useSyncServerStatus'; + +export default function useSimpleFinStatus() { + const [configured, setConfigured] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const status = useSyncServerStatus(); + + useEffect(() => { + async function fetch() { + setIsLoading(true); + + const results = await send('simplefin-status'); + + //setConfigured(results.configured || false); + setConfigured(true); + setIsLoading(false); + } + + if (status === 'online') { + fetch(); + } + }, [status]); + + return { + configured, + isLoading, + }; +} From 52a25d182bb282c942674e4c3d18c22afd097a6a Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Sat, 6 Jan 2024 19:45:02 -0500 Subject: [PATCH 02/24] SimpleFin proof of concept working. --- .../desktop-client/src/components/Modals.tsx | 1 + .../src/components/modals/CreateAccount.tsx | 25 +++++- .../modals/GoCardlessExternalMsg.tsx | 2 +- .../modals/SelectLinkedAccounts.jsx | 24 ++++-- packages/desktop-client/src/gocardless.ts | 1 + .../src/hooks/useGoCardlessStatus.ts | 6 +- .../src/hooks/useSimpleFinStatus.ts | 7 +- .../1704572023730_add_account_sync_source.sql | 5 ++ .../loot-core/src/client/actions/account.ts | 13 +++ .../loot-core/src/server/accounts/sync.ts | 81 +++++++++++++++--- packages/loot-core/src/server/main.ts | 84 +++++++++++++++++++ .../loot-core/src/server/server-config.ts | 2 + .../loot-core/src/types/server-handlers.d.ts | 9 ++ 13 files changed, 233 insertions(+), 27 deletions(-) create mode 100644 packages/loot-core/migrations/1704572023730_add_account_sync_source.sql diff --git a/packages/desktop-client/src/components/Modals.tsx b/packages/desktop-client/src/components/Modals.tsx index 236a0d9e408..ecad8669a35 100644 --- a/packages/desktop-client/src/components/Modals.tsx +++ b/packages/desktop-client/src/components/Modals.tsx @@ -109,6 +109,7 @@ export default function Modals() { requisitionId={options.requisitionId} localAccounts={accounts.filter(acct => acct.closed === 0)} actions={actions} + syncSource={options.syncSource} /> ); diff --git a/packages/desktop-client/src/components/modals/CreateAccount.tsx b/packages/desktop-client/src/components/modals/CreateAccount.tsx index beadaea2c85..12a3da9b378 100644 --- a/packages/desktop-client/src/components/modals/CreateAccount.tsx +++ b/packages/desktop-client/src/components/modals/CreateAccount.tsx @@ -13,6 +13,7 @@ import Modal from '../common/Modal'; import Paragraph from '../common/Paragraph'; import Text from '../common/Text'; import View from '../common/View'; +import { send } from 'loot-core/src/platform/client/fetch'; type CreateAccountProps = { modalProps: CommonModalProps; @@ -38,13 +39,33 @@ export default function CreateAccount({ authorizeBank(actions.pushModal); }; - const onConnectSimpleFin = () => { + const onConnectSimpleFin = async () => { if (!isSimpleFinSetupComplete) { onSimpleFinInit(); return; } - authorizeBank(actions.pushModal); + const results = await send('simplefin-accounts'); + + let newAccounts = []; + + for (let i = 0; i < results.accounts.accounts.length; i++) { + let oldAccount = results.accounts.accounts[i]; + + let newAccount = {}; + newAccount.account_id = oldAccount.id; + newAccount.name = oldAccount.name; + newAccount.type = "checking"; + newAccount.institution = {name: oldAccount.org.name}; + newAccount.orgDomain = oldAccount.org.domain; + + newAccounts.push(newAccount); + } + + actions.pushModal('select-linked-accounts', { + accounts: newAccounts, + syncSource: "simpleFin", + }); }; const onGoCardlessInit = () => { diff --git a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx index ccdcad5a0a5..7a50ef630d8 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessExternalMsg.tsx @@ -109,7 +109,7 @@ export default function GoCardlessExternalMsg({ isLoading: isBankOptionsLoading, isError: isBankOptionError, } = useAvailableBanks(country); - const { configured: isConfigured, isLoading: isConfigurationLoading } = + const { configuredGoCardless: isConfigured, isLoading: isConfigurationLoading } = useGoCardlessStatus(); async function onJump() { diff --git a/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx b/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx index 132f346688c..504b4105f09 100644 --- a/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx +++ b/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx @@ -16,6 +16,7 @@ export default function SelectLinkedAccounts({ externalAccounts, localAccounts, actions, + syncSource, }) { const [chosenAccounts, setChosenAccounts] = useState(() => { return Object.fromEntries( @@ -49,13 +50,22 @@ export default function SelectLinkedAccounts({ } // Finally link the matched account - actions.linkAccount( - requisitionId, - externalAccount, - chosenLocalAccountId !== addAccountOption.id - ? chosenLocalAccountId - : undefined, - ); + if (syncSource === "simpleFin") { + actions.linkAccountSimpleFin( + externalAccount, + chosenLocalAccountId !== addAccountOption.id + ? chosenLocalAccountId + : undefined, + ); + } else { + actions.linkAccount( + requisitionId, + externalAccount, + chosenLocalAccountId !== addAccountOption.id + ? chosenLocalAccountId + : undefined, + ); + } }, ); diff --git a/packages/desktop-client/src/gocardless.ts b/packages/desktop-client/src/gocardless.ts index fe987b84469..1274bd01585 100644 --- a/packages/desktop-client/src/gocardless.ts +++ b/packages/desktop-client/src/gocardless.ts @@ -46,6 +46,7 @@ export async function authorizeBank( accounts: data.accounts, requisitionId: data.id, upgradingAccountId, + syncSource: "goCardless", }); }, }); diff --git a/packages/desktop-client/src/hooks/useGoCardlessStatus.ts b/packages/desktop-client/src/hooks/useGoCardlessStatus.ts index bfacf126f02..7e5efa51341 100644 --- a/packages/desktop-client/src/hooks/useGoCardlessStatus.ts +++ b/packages/desktop-client/src/hooks/useGoCardlessStatus.ts @@ -5,7 +5,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import useSyncServerStatus from './useSyncServerStatus'; export default function useGoCardlessStatus() { - const [configured, setConfigured] = useState(null); + const [configuredGoCardless, setConfiguredGoCardless] = useState(null); const [isLoading, setIsLoading] = useState(false); const status = useSyncServerStatus(); @@ -15,7 +15,7 @@ export default function useGoCardlessStatus() { const results = await send('gocardless-status'); - setConfigured(results.configured || false); + setConfiguredGoCardless(results.configured || false); setIsLoading(false); } @@ -25,7 +25,7 @@ export default function useGoCardlessStatus() { }, [status]); return { - configured, + configuredGoCardless, isLoading, }; } diff --git a/packages/desktop-client/src/hooks/useSimpleFinStatus.ts b/packages/desktop-client/src/hooks/useSimpleFinStatus.ts index 4a230a6a04a..eeede404c2a 100644 --- a/packages/desktop-client/src/hooks/useSimpleFinStatus.ts +++ b/packages/desktop-client/src/hooks/useSimpleFinStatus.ts @@ -5,7 +5,7 @@ import { send } from 'loot-core/src/platform/client/fetch'; import useSyncServerStatus from './useSyncServerStatus'; export default function useSimpleFinStatus() { - const [configured, setConfigured] = useState(null); + const [configuredSimpleFin, setConfiguredSimpleFin] = useState(null); const [isLoading, setIsLoading] = useState(false); const status = useSyncServerStatus(); @@ -15,8 +15,7 @@ export default function useSimpleFinStatus() { const results = await send('simplefin-status'); - //setConfigured(results.configured || false); - setConfigured(true); + setConfiguredSimpleFin(results.configured || false); setIsLoading(false); } @@ -26,7 +25,7 @@ export default function useSimpleFinStatus() { }, [status]); return { - configured, + configuredSimpleFin, isLoading, }; } diff --git a/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql b/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql new file mode 100644 index 00000000000..7af2400895a --- /dev/null +++ b/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql @@ -0,0 +1,5 @@ +BEGIN TRANSACTION; + +ALTER TABLE accounts ADD COLUMN account_sync_source TEXT; + +COMMIT; diff --git a/packages/loot-core/src/client/actions/account.ts b/packages/loot-core/src/client/actions/account.ts index 41516b7a0f7..567b7a21c32 100644 --- a/packages/loot-core/src/client/actions/account.ts +++ b/packages/loot-core/src/client/actions/account.ts @@ -75,6 +75,19 @@ export function linkAccount(requisitionId, account, upgradingId) { }; } +// TODO: Need to impliment an unlink for simplefin. + +export function linkAccountSimpleFin(externalAccount, upgradingId) { + return async (dispatch: Dispatch) => { + await send('simplefin-accounts-link', { + externalAccount, + upgradingId, + }); + await dispatch(getPayees()); + await dispatch(getAccounts()); + }; +} + // TODO: type correctly or remove (unused) export function connectAccounts( institution, diff --git a/packages/loot-core/src/server/accounts/sync.ts b/packages/loot-core/src/server/accounts/sync.ts index 862648e4d9b..362dd5131ef 100644 --- a/packages/loot-core/src/server/accounts/sync.ts +++ b/packages/loot-core/src/server/accounts/sync.ts @@ -215,6 +215,41 @@ async function downloadGoCardlessTransactions( }; } +async function downloadSimpleFinTransactions( + acctId, + since, +) { + const userToken = await asyncStorage.getItem('user-token'); + if (!userToken) return; + + const res = await post( + getServer().SIMPLEFIN_SERVER + '/transactions', + { + accountId: acctId, + startDate: since, + }, + { + 'X-ACTUAL-TOKEN': userToken, + }, + ); + + if (res.error_code) { + throw BankSyncError(res.error_type, res.error_code); + } + + const { + transactions: { all }, + balances, + startingBalance, + } = res; + + return { + transactions: all, + accountBalance: balances, + startingBalance, + }; +} + async function resolvePayee(trans, payeeName, payeesToCreate) { if (trans.payee == null && payeeName) { // First check our registry of new payees (to avoid a db access) @@ -773,6 +808,8 @@ export async function addTransactions( return newTransactions; } +// TODO: This needs to be renamed to something more generic as it includes SimpleFin now. + export async function syncGoCardlessAccount( userId, userKey, @@ -809,14 +846,24 @@ export async function syncGoCardlessAccount( ]), ); - const { transactions: originalTransactions, accountBalance } = - await downloadGoCardlessTransactions( + let download; + + if (acctRow.account_sync_source === "simplefin") { + download = await downloadSimpleFinTransactions( + acctId, + startDate, + ); + } else if (acctRow.account_sync_source === "gocardless" || acctRow.account_sync_source === null) { + download = await downloadGoCardlessTransactions( userId, userKey, acctId, bankId, startDate, ); + } + + const { transactions: originalTransactions, accountBalance } = download; if (originalTransactions.length === 0) { return { added: [], updated: [] }; @@ -836,20 +883,34 @@ export async function syncGoCardlessAccount( // Otherwise, download transaction for the past 90 days const startingDay = monthUtils.subDays(monthUtils.currentDay(), 90); - const { transactions, startingBalance } = - await downloadGoCardlessTransactions( + let download; + + if (acctRow.account_sync_source === "simplefin") { + download = await downloadSimpleFinTransactions( + acctId, + startingDay, + ); + } else if (acctRow.account_sync_source === "gocardless" || acctRow.account_sync_source === null) { + download = await downloadGoCardlessTransactions( userId, userKey, acctId, bankId, startingDay, ); + } - // We need to add a transaction that represents the starting - // balance for everything to balance out. In order to get balance - // before the first imported transaction, we need to get the - // current balance from the accounts table and subtract all the - // imported transactions. + const { transactions, startingBalance } = download; + + let balanceToUse = startingBalance; + + if (acctRow.account_sync_source === "simplefin") { + const currentBalance = startingBalance; + const previousBalance = transactions.reduce((total, trans) => { + return total - parseInt(trans.transactionAmount.amount.replace('.', '')); + }, currentBalance); + balanceToUse = previousBalance; + } const oldestTransaction = transactions[transactions.length - 1]; @@ -863,7 +924,7 @@ export async function syncGoCardlessAccount( return runMutator(async () => { const initialId = await db.insertTransaction({ account: id, - amount: startingBalance, + amount: balanceToUse, category: acctRow.offbudget === 0 ? payee.category : null, payee: payee.id, date: oldestDate, diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index 431023d76b4..737eac91a6f 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -702,6 +702,58 @@ handlers['gocardless-accounts-link'] = async function ({ return 'ok'; }; +handlers['simplefin-accounts-link'] = async function ({ + externalAccount, + upgradingId, +}) { + let id; + + const bank = await link.findOrCreateBank(externalAccount.institution, externalAccount.orgDomain); + + if (upgradingId) { + const accRow = await db.first('SELECT * FROM accounts WHERE id = ?', [ + upgradingId, + ]); + id = accRow.id; + await db.update('accounts', { + id, + account_id: externalAccount.account_id, + bank: bank.id, + account_sync_source: "simplefin", + }); + } else { + id = uuidv4(); + await db.insertWithUUID('accounts', { + id, + account_id: externalAccount.account_id, + mask: "1234", //TODO: Do we have this? + name: externalAccount.name, + official_name: externalAccount.name, //TODO: Do we have this? + bank: bank.id, + account_sync_source: "simplefin", + }); + await db.insertPayee({ + name: '', + transfer_acct: id, + }); + } + + await bankSync.syncGoCardlessAccount( + undefined, + undefined, + id, + externalAccount.account_id, + bank.bank_id, + ); + + await connection.send('sync-event', { + type: 'success', + tables: ['transactions'], + }); + + return 'ok'; +}; + handlers['accounts-connect'] = async function ({ institution, publicToken, @@ -1117,6 +1169,38 @@ handlers['gocardless-status'] = async function () { ); }; +handlers['simplefin-status'] = async function () { + const userToken = await asyncStorage.getItem('user-token'); + + if (!userToken) { + return { error: 'unauthorized' }; + } + + return post( + getServer().SIMPLEFIN_SERVER + '/status', + {}, + { + 'X-ACTUAL-TOKEN': userToken, + }, + ); +}; + +handlers['simplefin-accounts'] = async function () { + const userToken = await asyncStorage.getItem('user-token'); + + if (!userToken) { + return { error: 'unauthorized' }; + } + + return post( + getServer().SIMPLEFIN_SERVER + '/accounts', + {}, + { + 'X-ACTUAL-TOKEN': userToken, + }, + ); +}; + handlers['gocardless-get-banks'] = async function (country) { const userToken = await asyncStorage.getItem('user-token'); diff --git a/packages/loot-core/src/server/server-config.ts b/packages/loot-core/src/server/server-config.ts index cde33082465..446d88eb035 100644 --- a/packages/loot-core/src/server/server-config.ts +++ b/packages/loot-core/src/server/server-config.ts @@ -6,6 +6,7 @@ type ServerConfig = { SIGNUP_SERVER: string; PLAID_SERVER: string; GOCARDLESS_SERVER: string; + SIMPLEFIN_SERVER: string; }; let config: ServerConfig | null = null; @@ -33,6 +34,7 @@ export function getServer(url?: string): ServerConfig | null { SIGNUP_SERVER: joinURL(url, '/account'), PLAID_SERVER: joinURL(url, '/plaid'), GOCARDLESS_SERVER: joinURL(url, '/gocardless'), + SIMPLEFIN_SERVER: joinURL(url, '/simplefin'), }; } return config; diff --git a/packages/loot-core/src/types/server-handlers.d.ts b/packages/loot-core/src/types/server-handlers.d.ts index 1f0d276e496..f5863125145 100644 --- a/packages/loot-core/src/types/server-handlers.d.ts +++ b/packages/loot-core/src/types/server-handlers.d.ts @@ -160,6 +160,11 @@ export interface ServerHandlers { upgradingId; }) => Promise<'ok'>; + 'simplefin-accounts-link': (arg: { + externalAccount; + upgradingId; + }) => Promise<'ok'>; + 'accounts-connect': (arg: { institution; publicToken; @@ -215,6 +220,10 @@ export interface ServerHandlers { 'gocardless-status': () => Promise<{ configured: boolean }>; + 'simplefin-status': () => Promise<{ configured: boolean }>; + + 'simplefin-accounts': () => Promise<{ configured: boolean }>; + 'gocardless-get-banks': (country: string) => Promise<{ data: GoCardlessInstitution[]; error?: { reason: string }; From b1d59e378c3b6f2d7f2d909923252443902045f3 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Wed, 10 Jan 2024 21:03:24 -0500 Subject: [PATCH 03/24] Adds linking & unlinking to existing accounts through the account menu UI. --- .../desktop-client/src/components/Modals.tsx | 1 + .../src/components/accounts/Account.jsx | 4 +- .../src/components/modals/CreateAccount.tsx | 67 +++++++++++-------- .../loot-core/src/client/actions/account.ts | 2 - packages/loot-core/src/server/main.ts | 21 ++++++ 5 files changed, 65 insertions(+), 30 deletions(-) diff --git a/packages/desktop-client/src/components/Modals.tsx b/packages/desktop-client/src/components/Modals.tsx index ecad8669a35..03e6da154b9 100644 --- a/packages/desktop-client/src/components/Modals.tsx +++ b/packages/desktop-client/src/components/Modals.tsx @@ -80,6 +80,7 @@ export default function Modals() { ); diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx index 37871916290..4443a2491ad 100644 --- a/packages/desktop-client/src/components/accounts/Account.jsx +++ b/packages/desktop-client/src/components/accounts/Account.jsx @@ -586,7 +586,9 @@ class AccountInternal extends PureComponent { switch (item) { case 'link': - authorizeBank(this.props.pushModal, { upgradingAccountId: accountId }); + this.props.pushModal('add-account', { + upgradingAccountId: accountId, + }); break; case 'unlink': this.props.unlinkAccount(accountId); diff --git a/packages/desktop-client/src/components/modals/CreateAccount.tsx b/packages/desktop-client/src/components/modals/CreateAccount.tsx index 12a3da9b378..602852785fb 100644 --- a/packages/desktop-client/src/components/modals/CreateAccount.tsx +++ b/packages/desktop-client/src/components/modals/CreateAccount.tsx @@ -23,6 +23,7 @@ type CreateAccountProps = { export default function CreateAccount({ modalProps, syncServerStatus, + upgradingAccountId, }: CreateAccountProps) { const actions = useActions(); const [isGoCardlessSetupComplete, setIsGoCardlessSetupComplete] = @@ -36,7 +37,11 @@ export default function CreateAccount({ return; } - authorizeBank(actions.pushModal); + if (upgradingAccountId === undefined) { + authorizeBank(actions.pushModal); + } else { + authorizeBank(actions.pushModal, { upgradingAccountId: upgradingAccountId }); + } }; const onConnectSimpleFin = async () => { @@ -94,36 +99,44 @@ export default function CreateAccount({ setIsSimpleFinSetupComplete(configuredSimpleFin); }, [configuredSimpleFin]); + let title = "Add Account"; + + if (upgradingAccountId !== undefined) { + title = "Link Account"; + } + return ( - + {() => ( - - - - - Create a local account if you want to add - transactions manually. You can also{' '} - - import QIF/OFX/QFX files into a local account - - . - + {upgradingAccountId === undefined && + + + + + Create a local account if you want to add + transactions manually. You can also{' '} + + import QIF/OFX/QFX files into a local account + + . + + - + } {syncServerStatus === 'online' ? ( <> diff --git a/packages/loot-core/src/client/actions/account.ts b/packages/loot-core/src/client/actions/account.ts index 567b7a21c32..2988e9ca473 100644 --- a/packages/loot-core/src/client/actions/account.ts +++ b/packages/loot-core/src/client/actions/account.ts @@ -75,8 +75,6 @@ export function linkAccount(requisitionId, account, upgradingId) { }; } -// TODO: Need to impliment an unlink for simplefin. - export function linkAccountSimpleFin(externalAccount, upgradingId) { return async (dispatch: Dispatch) => { await send('simplefin-accounts-link', { diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index 737eac91a6f..5eda41697b7 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -669,6 +669,7 @@ handlers['gocardless-accounts-link'] = async function ({ id, account_id: account.account_id, bank: bank.id, + account_sync_source: "gocardless", }); } else { id = uuidv4(); @@ -679,6 +680,7 @@ handlers['gocardless-accounts-link'] = async function ({ name: account.name, official_name: account.official_name, bank: bank.id, + account_sync_source: "gocardless", }); await db.insertPayee({ name: '', @@ -1363,6 +1365,20 @@ handlers['account-unlink'] = mutator(async function ({ id }) { return 'ok'; } + const accRow = await db.first('SELECT * FROM accounts WHERE id = ?', [ + id, + ]); + + let isGoCardless; + + if (accRow.account_sync_source === "gocardless") { + isGoCardless = true; + } else if (accRow.account_sync_source === "simplefin") { + isGoCardless = false; + } else { + isGoCardless = true; + } + await db.updateAccount({ id, account_id: null, @@ -1370,8 +1386,13 @@ handlers['account-unlink'] = mutator(async function ({ id }) { balance_current: null, balance_available: null, balance_limit: null, + account_sync_source: null, }); + if (isGoCardless === false) { + return; + } + const { count } = await db.first( 'SELECT COUNT(*) as count FROM accounts WHERE bank = ?', [bankId], From db12f67d23b26a8cbeac26ad29941c03127200df Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 11 Jan 2024 14:01:59 -0500 Subject: [PATCH 04/24] Added loading and lint fixes. --- .../desktop-client/src/components/Modals.tsx | 2 +- .../src/components/modals/CreateAccount.tsx | 57 ++++++++++++------- .../modals/GoCardlessExternalMsg.tsx | 6 +- .../components/modals/SimpleFinInitialise.tsx | 15 +++-- packages/desktop-client/src/gocardless.ts | 2 +- .../src/hooks/useGoCardlessStatus.ts | 4 +- .../src/hooks/useSimpleFinStatus.ts | 4 +- .../loot-core/src/server/accounts/sync.ts | 35 ++++++------ packages/loot-core/src/server/main.ts | 26 ++++----- 9 files changed, 86 insertions(+), 65 deletions(-) diff --git a/packages/desktop-client/src/components/Modals.tsx b/packages/desktop-client/src/components/Modals.tsx index 03e6da154b9..204253a6412 100644 --- a/packages/desktop-client/src/components/Modals.tsx +++ b/packages/desktop-client/src/components/Modals.tsx @@ -22,7 +22,6 @@ import EditRule from './modals/EditRule'; import FixEncryptionKey from './modals/FixEncryptionKey'; import GoCardlessExternalMsg from './modals/GoCardlessExternalMsg'; import GoCardlessInitialise from './modals/GoCardlessInitialise'; -import SimpleFinInitialise from './modals/SimpleFinInitialise'; import ImportTransactions from './modals/ImportTransactions'; import LoadBackup from './modals/LoadBackup'; import ManageRulesModal from './modals/ManageRulesModal'; @@ -32,6 +31,7 @@ import PlaidExternalMsg from './modals/PlaidExternalMsg'; import ReportBudgetSummary from './modals/ReportBudgetSummary'; import RolloverBudgetSummary from './modals/RolloverBudgetSummary'; import SelectLinkedAccounts from './modals/SelectLinkedAccounts'; +import SimpleFinInitialise from './modals/SimpleFinInitialise'; import SingleInput from './modals/SingleInput'; import SwitchBudgetType from './modals/SwitchBudgetType'; import DiscoverSchedules from './schedules/DiscoverSchedules'; diff --git a/packages/desktop-client/src/components/modals/CreateAccount.tsx b/packages/desktop-client/src/components/modals/CreateAccount.tsx index 602852785fb..f41d14766cb 100644 --- a/packages/desktop-client/src/components/modals/CreateAccount.tsx +++ b/packages/desktop-client/src/components/modals/CreateAccount.tsx @@ -1,5 +1,7 @@ import React, { useEffect, useState } from 'react'; +import { send } from 'loot-core/src/platform/client/fetch'; + import { authorizeBank } from '../../gocardless'; import { useActions } from '../../hooks/useActions'; import useGoCardlessStatus from '../../hooks/useGoCardlessStatus'; @@ -13,7 +15,6 @@ import Modal from '../common/Modal'; import Paragraph from '../common/Paragraph'; import Text from '../common/Text'; import View from '../common/View'; -import { send } from 'loot-core/src/platform/client/fetch'; type CreateAccountProps = { modalProps: CommonModalProps; @@ -40,7 +41,9 @@ export default function CreateAccount({ if (upgradingAccountId === undefined) { authorizeBank(actions.pushModal); } else { - authorizeBank(actions.pushModal, { upgradingAccountId: upgradingAccountId }); + authorizeBank(actions.pushModal, { + upgradingAccountId, + }); } }; @@ -50,27 +53,34 @@ export default function CreateAccount({ return; } + if (loadingSimpleFinAccounts) { + return; + } + + setLoadingSimpleFinAccounts(true); + const results = await send('simplefin-accounts'); - let newAccounts = []; + const newAccounts = []; for (let i = 0; i < results.accounts.accounts.length; i++) { - let oldAccount = results.accounts.accounts[i]; - - let newAccount = {}; + const oldAccount = results.accounts.accounts[i]; + const newAccount = {}; newAccount.account_id = oldAccount.id; newAccount.name = oldAccount.name; - newAccount.type = "checking"; - newAccount.institution = {name: oldAccount.org.name}; + newAccount.institution = { + name: oldAccount.org.name, + }; newAccount.orgDomain = oldAccount.org.domain; - newAccounts.push(newAccount); } actions.pushModal('select-linked-accounts', { accounts: newAccounts, - syncSource: "simpleFin", + syncSource: 'simpleFin', }); + + setLoadingSimpleFinAccounts(false); }; const onGoCardlessInit = () => { @@ -99,17 +109,19 @@ export default function CreateAccount({ setIsSimpleFinSetupComplete(configuredSimpleFin); }, [configuredSimpleFin]); - let title = "Add Account"; + let title = 'Add Account'; + const [loadingSimpleFinAccounts, setLoadingSimpleFinAccounts] = + useState(false); if (upgradingAccountId !== undefined) { - title = "Link Account"; + title = 'Link Account'; } return ( {() => ( - {upgradingAccountId === undefined && + {upgradingAccountId === undefined && ( Connect to an Actual server to set up{' '} @@ -222,7 +229,7 @@ export function CreateAccount({ to="https://actualbudget.org/docs/advanced/bank-sync" linkColor="muted" > - automatic syncing with GoCardless + automatic syncing. . diff --git a/packages/desktop-client/src/components/settings/Experimental.tsx b/packages/desktop-client/src/components/settings/Experimental.tsx index 273c1c21671..7e78c065ef0 100644 --- a/packages/desktop-client/src/components/settings/Experimental.tsx +++ b/packages/desktop-client/src/components/settings/Experimental.tsx @@ -98,6 +98,7 @@ export function ExperimentalFeatures() { Experimental OFX parser + SimpleFIN sync ) : ( = { goalTemplatesEnabled: false, customReports: false, experimentalOfxParser: true, + simpleFinSync: false, }; export function useFeatureFlag(name: FeatureFlag): boolean { diff --git a/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql b/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql index 7af2400895a..3aae8da909e 100644 --- a/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql +++ b/packages/loot-core/migrations/1704572023730_add_account_sync_source.sql @@ -2,4 +2,10 @@ BEGIN TRANSACTION; ALTER TABLE accounts ADD COLUMN account_sync_source TEXT; +UPDATE accounts SET + account_sync_source = CASE + WHEN account_id THEN 'goCardless' + ELSE NULL + END; + COMMIT; diff --git a/packages/loot-core/src/server/accounts/sync.ts b/packages/loot-core/src/server/accounts/sync.ts index 61a52f940b5..706bb32d10f 100644 --- a/packages/loot-core/src/server/accounts/sync.ts +++ b/packages/loot-core/src/server/accounts/sync.ts @@ -839,12 +839,9 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) { let download; - if (acctRow.account_sync_source === 'simplefin') { + if (acctRow.account_sync_source === 'simpleFin') { download = await downloadSimpleFinTransactions(acctId, startDate); - } else if ( - acctRow.account_sync_source === 'gocardless' || - acctRow.account_sync_source === null - ) { + } else if (acctRow.account_sync_source === 'goCardless') { download = await downloadGoCardlessTransactions( userId, userKey, @@ -876,12 +873,9 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) { let download; - if (acctRow.account_sync_source === 'simplefin') { + if (acctRow.account_sync_source === 'simpleFin') { download = await downloadSimpleFinTransactions(acctId, startingDay); - } else if ( - acctRow.account_sync_source === 'gocardless' || - acctRow.account_sync_source === null - ) { + } else if (acctRow.account_sync_source === 'goCardless') { download = await downloadGoCardlessTransactions( userId, userKey, @@ -895,7 +889,7 @@ export async function syncExternalAccount(userId, userKey, id, acctId, bankId) { let balanceToUse = startingBalance; - if (acctRow.account_sync_source === 'simplefin') { + if (acctRow.account_sync_source === 'simpleFin') { const currentBalance = startingBalance; const previousBalance = transactions.reduce((total, trans) => { return ( diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index 1964f3a906c..5489f02eeec 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -669,7 +669,7 @@ handlers['gocardless-accounts-link'] = async function ({ id, account_id: account.account_id, bank: bank.id, - account_sync_source: 'gocardless', + account_sync_source: 'goCardless', }); } else { id = uuidv4(); @@ -680,7 +680,7 @@ handlers['gocardless-accounts-link'] = async function ({ name: account.name, official_name: account.official_name, bank: bank.id, - account_sync_source: 'gocardless', + account_sync_source: 'goCardless', }); await db.insertPayee({ name: '', @@ -732,7 +732,7 @@ handlers['simplefin-accounts-link'] = async function ({ id, account_id: externalAccount.account_id, bank: bank.id, - account_sync_source: 'simplefin', + account_sync_source: 'simpleFin', }); } else { id = uuidv4(); @@ -742,7 +742,7 @@ handlers['simplefin-accounts-link'] = async function ({ name: externalAccount.name, official_name: externalAccount.name, bank: bank.id, - account_sync_source: 'simplefin', + account_sync_source: 'simpleFin', }); await db.insertPayee({ name: '', @@ -1377,15 +1377,7 @@ handlers['account-unlink'] = mutator(async function ({ id }) { const accRow = await db.first('SELECT * FROM accounts WHERE id = ?', [id]); - let isGoCardless; - - if (accRow.account_sync_source === 'gocardless') { - isGoCardless = true; - } else if (accRow.account_sync_source === 'simplefin') { - isGoCardless = false; - } else { - isGoCardless = true; - } + const isGoCardless = accRow.account_sync_source === 'goCardless'; await db.updateAccount({ id, diff --git a/packages/loot-core/src/types/prefs.d.ts b/packages/loot-core/src/types/prefs.d.ts index 4d183b709af..11e55444e3e 100644 --- a/packages/loot-core/src/types/prefs.d.ts +++ b/packages/loot-core/src/types/prefs.d.ts @@ -6,7 +6,8 @@ export type FeatureFlag = | 'reportBudget' | 'goalTemplatesEnabled' | 'customReports' - | 'experimentalOfxParser'; + | 'experimentalOfxParser' + | 'simpleFinSync'; export type LocalPrefs = Partial< { From 38db62e51d22ba9f61fb875ecad4a5df441effa3 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 16:20:55 -0500 Subject: [PATCH 15/24] Added account_sync_source to server schema. --- packages/loot-core/src/server/aql/schema/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/loot-core/src/server/aql/schema/index.ts b/packages/loot-core/src/server/aql/schema/index.ts index 1af6735bdc4..4809d4eafbe 100644 --- a/packages/loot-core/src/server/aql/schema/index.ts +++ b/packages/loot-core/src/server/aql/schema/index.ts @@ -52,6 +52,7 @@ export const schema = { reconciled: f('boolean', { default: false }), tombstone: f('boolean'), schedule: f('id', { ref: 'schedules' }), + account_sync_source: f('string'), // subtransactions is a special field added if the table has the // `splits: grouped` option }, From d83200f6a3b3f4786e4d36c426648485935f12bc Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 16:39:23 -0500 Subject: [PATCH 16/24] Adds account_sync_source to test. --- packages/loot-core/src/shared/transactions.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/loot-core/src/shared/transactions.test.ts b/packages/loot-core/src/shared/transactions.test.ts index a256f9c6479..c3eb59ae026 100644 --- a/packages/loot-core/src/shared/transactions.test.ts +++ b/packages/loot-core/src/shared/transactions.test.ts @@ -29,6 +29,7 @@ function makeTransaction(data: Partial): TransactionEntity { balance_current: null, balance_available: null, balance_limit: null, + account_sync_source: null, }, ...data, }; From 92959c44f07d76397afeeaa9cd07a99b1d6c6159 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 16:45:07 -0500 Subject: [PATCH 17/24] Fix for typecheck. --- .../src/components/modals/SimpleFinInitialise.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx index c7db9c3e081..3d9e62f683b 100644 --- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -41,7 +41,9 @@ export const SimpleFinInitialise = ({ ]); onSuccess(); - modalProps.onClose(); + if (modalProps != null) { + modalProps.onClose(); + } setIsLoading(false); }; From 058d57b400ca086696747da0d5546d2bf83bc139 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 16:46:58 -0500 Subject: [PATCH 18/24] Attempt to make typecheck happy. --- .../src/components/modals/SimpleFinInitialise.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx index 3d9e62f683b..399e35c283b 100644 --- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -41,7 +41,7 @@ export const SimpleFinInitialise = ({ ]); onSuccess(); - if (modalProps != null) { + if (modalProps !== undefined) { modalProps.onClose(); } setIsLoading(false); From 3631e365cfd1fda56786c66f6ce17481a716e86d Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 17:00:18 -0500 Subject: [PATCH 19/24] Added strict ignore. --- .../src/components/modals/GoCardlessInitialise.tsx | 1 + .../src/components/modals/SimpleFinInitialise.tsx | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx index 2a8555522b3..a6d877b576f 100644 --- a/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx +++ b/packages/desktop-client/src/components/modals/GoCardlessInitialise.tsx @@ -1,3 +1,4 @@ +// @ts-strict-ignore import React, { useState } from 'react'; import { send } from 'loot-core/src/platform/client/fetch'; diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx index 399e35c283b..002148ff188 100644 --- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -1,3 +1,4 @@ +// @ts-strict-ignore import React, { useState } from 'react'; import { send } from 'loot-core/src/platform/client/fetch'; @@ -41,9 +42,7 @@ export const SimpleFinInitialise = ({ ]); onSuccess(); - if (modalProps !== undefined) { - modalProps.onClose(); - } + modalProps.onClose(); setIsLoading(false); }; From ef1fcd42037de77473228d09d262a4663b26e7b4 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 17:15:04 -0500 Subject: [PATCH 20/24] Moved account_sync_source to the right model (face palm). --- packages/loot-core/src/server/aql/schema/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loot-core/src/server/aql/schema/index.ts b/packages/loot-core/src/server/aql/schema/index.ts index 4809d4eafbe..da99763db4c 100644 --- a/packages/loot-core/src/server/aql/schema/index.ts +++ b/packages/loot-core/src/server/aql/schema/index.ts @@ -52,7 +52,6 @@ export const schema = { reconciled: f('boolean', { default: false }), tombstone: f('boolean'), schedule: f('id', { ref: 'schedules' }), - account_sync_source: f('string'), // subtransactions is a special field added if the table has the // `splits: grouped` option }, @@ -69,6 +68,7 @@ export const schema = { closed: f('boolean'), sort_order: f('float'), tombstone: f('boolean'), + account_sync_source: f('string'), }, categories: { id: f('id'), From de85e712fe9cb8c8d37c074f7e605b4a213786fe Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 20:11:38 -0500 Subject: [PATCH 21/24] Hotfix for institution format. --- packages/loot-core/src/server/main.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index d45d404dbb9..30f2aab2a8a 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -711,13 +711,9 @@ handlers['simplefin-accounts-link'] = async function ({ }) { let id; - let institution = externalAccount.institution; - - if (institution == null) { - institution = { - name: 'Unknown', - }; - } + let institution = { + name: externalAccount.institution ?? 'Unknown', + }; const bank = await link.findOrCreateBank( institution, From ae340cd9cf647d908bd556c6e343f4a7b9aa67f0 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Thu, 18 Jan 2024 20:21:35 -0500 Subject: [PATCH 22/24] Lint cleanup. --- packages/loot-core/src/server/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loot-core/src/server/main.ts b/packages/loot-core/src/server/main.ts index 30f2aab2a8a..809eb37d3a1 100644 --- a/packages/loot-core/src/server/main.ts +++ b/packages/loot-core/src/server/main.ts @@ -711,7 +711,7 @@ handlers['simplefin-accounts-link'] = async function ({ }) { let id; - let institution = { + const institution = { name: externalAccount.institution ?? 'Unknown', }; From c613c3182347c94f1f6e4a1349caae6ea32cf0ce Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Sat, 20 Jan 2024 17:03:51 -0500 Subject: [PATCH 23/24] Removed unnecessary promise.all. --- .../src/components/modals/SimpleFinInitialise.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx index 002148ff188..4db5bff8822 100644 --- a/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx +++ b/packages/desktop-client/src/components/modals/SimpleFinInitialise.tsx @@ -34,12 +34,10 @@ export const SimpleFinInitialise = ({ setIsLoading(true); - await Promise.all([ - send('secret-set', { - name: 'simplefin_token', - value: token, - }), - ]); + await send('secret-set', { + name: 'simplefin_token', + value: token, + }); onSuccess(); modalProps.onClose(); From 9f64ece7b2f7c6035b5df4f082152c25ba2eca23 Mon Sep 17 00:00:00 2001 From: Zach Whelchel Date: Sat, 20 Jan 2024 17:06:43 -0500 Subject: [PATCH 24/24] Lint cleanup. --- packages/desktop-client/src/components/accounts/Account.jsx | 1 - .../src/components/modals/SelectLinkedAccounts.jsx | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/desktop-client/src/components/accounts/Account.jsx b/packages/desktop-client/src/components/accounts/Account.jsx index 9f210799dc5..37653a025b8 100644 --- a/packages/desktop-client/src/components/accounts/Account.jsx +++ b/packages/desktop-client/src/components/accounts/Account.jsx @@ -26,7 +26,6 @@ import { } from 'loot-core/src/shared/transactions'; import { applyChanges, groupById } from 'loot-core/src/shared/util'; -import { authorizeBank } from '../../gocardless'; import { useCategories } from '../../hooks/useCategories'; import { SelectedProviderWithItems } from '../../hooks/useSelected'; import { styles, theme } from '../../style'; diff --git a/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx b/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx index 10b4252d12d..8d8d82475bc 100644 --- a/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx +++ b/packages/desktop-client/src/components/modals/SelectLinkedAccounts.jsx @@ -50,7 +50,7 @@ export function SelectLinkedAccounts({ } // Finally link the matched account - if (syncSource === "simpleFin") { + if (syncSource === 'simpleFin') { actions.linkAccountSimpleFin( externalAccount, chosenLocalAccountId !== addAccountOption.id