diff --git a/packages/webapp/src/components/DialogsContainer.tsx b/packages/webapp/src/components/DialogsContainer.tsx index 684aef05a..fc1195545 100644 --- a/packages/webapp/src/components/DialogsContainer.tsx +++ b/packages/webapp/src/components/DialogsContainer.tsx @@ -50,6 +50,7 @@ import InvoiceMailDialog from '@/containers/Sales/Invoices/InvoiceMailDialog/Inv import EstimateMailDialog from '@/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialog'; import ReceiptMailDialog from '@/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialog'; import PaymentMailDialog from '@/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialog'; +import { ConnectBankDialog } from '@/containers/CashFlow/ConnectBankDialog'; /** * Dialogs container. @@ -146,6 +147,7 @@ export default function DialogsContainer() { + ); } diff --git a/packages/webapp/src/constants/dialogs.ts b/packages/webapp/src/constants/dialogs.ts index c9bb52a0e..d2713cc13 100644 --- a/packages/webapp/src/constants/dialogs.ts +++ b/packages/webapp/src/constants/dialogs.ts @@ -53,4 +53,5 @@ export enum DialogsName { EstimateMail = 'estimate-mail', ReceiptMail = 'receipt-mail', PaymentMail = 'payment-mail', + ConnectBankCreditCard = 'connect-bank-credit-card' } diff --git a/packages/webapp/src/containers/Banking/Plaid/PlaidLanchLink.tsx b/packages/webapp/src/containers/Banking/Plaid/PlaidLanchLink.tsx index dcc5f1893..a925181da 100644 --- a/packages/webapp/src/containers/Banking/Plaid/PlaidLanchLink.tsx +++ b/packages/webapp/src/containers/Banking/Plaid/PlaidLanchLink.tsx @@ -1,3 +1,5 @@ +// @ts-nocheck +import { usePlaidExchangeToken } from '@/hooks/query'; import React, { useEffect } from 'react'; import { usePlaidLink, @@ -30,6 +32,8 @@ export function LaunchLink(props: LaunchLinkProps) { // const { generateLinkToken, deleteLinkToken } = useLink(); // const { setError, resetError } = useErrors(); + const { mutateAsync: exchangeAccessToken } = usePlaidExchangeToken(); + // define onSuccess, onExit and onEvent functions as configs for Plaid Link creation const onSuccess = async ( publicToken: string, @@ -45,6 +49,12 @@ export function LaunchLink(props: LaunchLinkProps) { // regular link mode: exchange public token for access token } else { // call to Plaid api endpoint: /item/public_token/exchange in order to obtain access_token which is then stored with the created item + debugger; + + await exchangeAccessToken({ + public_token: publicToken, + institution_id: metadata.institution.institution_id, + }); // await exchangeToken( // publicToken, // metadata.institution, diff --git a/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx b/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx index 23f7a6df7..66298dc8b 100644 --- a/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx +++ b/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx @@ -1,5 +1,4 @@ // @ts-nocheck -import React, { useState } from 'react'; import { Button, NavbarGroup, @@ -14,10 +13,7 @@ import { Icon, FormattedMessage as T, } from '@/components'; -import { - useGetPlaidLinkToken, - useRefreshCashflowAccounts, -} from '@/hooks/query'; +import { useRefreshCashflowAccounts } from '@/hooks/query'; import { CashflowAction, AbilitySubject } from '@/constants/abilityOption'; import withDialogActions from '@/containers/Dialog/withDialogActions'; @@ -29,7 +25,6 @@ import { ACCOUNT_TYPE } from '@/constants'; import { DialogsName } from '@/constants/dialogs'; import { compose } from '@/utils'; -import { LaunchLink } from '@/containers/Banking/Plaid/PlaidLanchLink'; /** * Cash Flow accounts actions bar. @@ -66,21 +61,13 @@ function CashFlowAccountsActionsBar({ const checked = event.target.checked; setCashflowAccountsTableState({ inactiveMode: checked }); }; - - const { mutateAsync: getPlaidLinkToken } = useGetPlaidLinkToken(); - const [linkToken, setLinkToken] = useState(''); - + // Handle connect button click. const handleConnectToBank = () => { - getPlaidLinkToken() - .then((res) => { - setLinkToken(res.data.link_token); - }) - .catch(() => {}); + openDialog(DialogsName.ConnectBankCreditCard); }; return ( - + + ); +} + +export const BankFeedsServiceProviders = [{ label: 'Plaid', key: 'plaid' }]; diff --git a/packages/webapp/src/containers/CashFlow/ConnectBankDialog/index.tsx b/packages/webapp/src/containers/CashFlow/ConnectBankDialog/index.tsx new file mode 100644 index 000000000..2267439d5 --- /dev/null +++ b/packages/webapp/src/containers/CashFlow/ConnectBankDialog/index.tsx @@ -0,0 +1 @@ +export * from './ConnectBankDialog'; diff --git a/packages/webapp/src/hooks/query/plaid.ts b/packages/webapp/src/hooks/query/plaid.ts index e90db7ca9..b4fd88e19 100644 --- a/packages/webapp/src/hooks/query/plaid.ts +++ b/packages/webapp/src/hooks/query/plaid.ts @@ -5,7 +5,7 @@ import useApiRequest from '../useRequest'; /** * Retrieves the plaid link token. */ -export function useGetPlaidLinkToken(props) { +export function useGetPlaidLinkToken(props = {}) { const apiRequest = useApiRequest(); return useMutation( @@ -15,3 +15,17 @@ export function useGetPlaidLinkToken(props) { }, ); } + +/** + * Retrieves the plaid link token. + */ +export function usePlaidExchangeToken(props = {}) { + const apiRequest = useApiRequest(); + + return useMutation( + (data) => apiRequest.post('banking/plaid/exchange-token', data, {}), + { + ...props, + }, + ); +} diff --git a/packages/webapp/src/hooks/state/banking.ts b/packages/webapp/src/hooks/state/banking.ts new file mode 100644 index 000000000..d7499dfd7 --- /dev/null +++ b/packages/webapp/src/hooks/state/banking.ts @@ -0,0 +1,20 @@ +import { getPlaidToken, setPlaidId } from '@/store/banking/banking.reducer'; +import { useCallback } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +export const useSetBankingPlaidToken = () => { + const dispatch = useDispatch(); + + return useCallback( + (plaidId: string) => { + dispatch(setPlaidId(plaidId)); + }, + [dispatch], + ); +}; + +export const useGetBankingPlaidToken = () => { + const plaidToken = useSelector(getPlaidToken); + + return plaidToken; +}; diff --git a/packages/webapp/src/store/banking/banking.reducer.ts b/packages/webapp/src/store/banking/banking.reducer.ts new file mode 100644 index 000000000..93023cdc0 --- /dev/null +++ b/packages/webapp/src/store/banking/banking.reducer.ts @@ -0,0 +1,20 @@ +import { PayloadAction, createSlice } from '@reduxjs/toolkit'; + +interface StorePlaidState { + plaidToken: string; +} + +export const PlaidSlice = createSlice({ + name: 'plaid', + initialState: { + plaidToken: '', + } as StorePlaidState, + reducers: { + setPlaidId: (state: StorePlaidState, action: PayloadAction) => { + state.plaidToken = action.payload; + }, + }, +}); + +export const { setPlaidId } = PlaidSlice.actions; +export const getPlaidToken = (state: any) => state.plaid.plaidToken; diff --git a/packages/webapp/src/store/reducers.tsx b/packages/webapp/src/store/reducers.tsx index 4a778e1de..ddcc6ff27 100644 --- a/packages/webapp/src/store/reducers.tsx +++ b/packages/webapp/src/store/reducers.tsx @@ -37,6 +37,7 @@ import creditNotes from './CreditNote/creditNote.reducer'; import vendorCredit from './VendorCredit/VendorCredit.reducer'; import warehouseTransfers from './WarehouseTransfer/warehouseTransfer.reducer'; import projects from './Project/projects.reducer'; +import { PlaidSlice } from './banking/banking.reducer'; const appReducer = combineReducers({ authentication, @@ -73,6 +74,7 @@ const appReducer = combineReducers({ vendorCredit, warehouseTransfers, projects, + plaid: PlaidSlice.reducer, }); // Reset the state of a redux store