mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-14 20:00:33 +00:00
Compare commits
3 Commits
auth-pages
...
plaid-env-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9174203320 | ||
|
|
11cc4ffb0a | ||
|
|
c279b982e6 |
@@ -204,10 +204,7 @@ module.exports = {
|
|||||||
plaid: {
|
plaid: {
|
||||||
env: process.env.PLAID_ENV || 'sandbox',
|
env: process.env.PLAID_ENV || 'sandbox',
|
||||||
clientId: process.env.PLAID_CLIENT_ID,
|
clientId: process.env.PLAID_CLIENT_ID,
|
||||||
secretDevelopment: process.env.PLAID_SECRET_DEVELOPMENT,
|
secret: process.env.PLAID_SECRET,
|
||||||
secretSandbox: process.env.PLAID_SECRET_SANDBOX,
|
|
||||||
redirectSandBox: process.env.PLAID_SANDBOX_REDIRECT_URI,
|
|
||||||
redirectDevelopment: process.env.PLAID_DEVELOPMENT_REDIRECT_URI,
|
|
||||||
linkWebhook: process.env.PLAID_LINK_WEBHOOK,
|
linkWebhook: process.env.PLAID_LINK_WEBHOOK,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -218,6 +215,7 @@ module.exports = {
|
|||||||
key: process.env.LEMONSQUEEZY_API_KEY,
|
key: process.env.LEMONSQUEEZY_API_KEY,
|
||||||
storeId: process.env.LEMONSQUEEZY_STORE_ID,
|
storeId: process.env.LEMONSQUEEZY_STORE_ID,
|
||||||
webhookSecret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET,
|
webhookSecret: process.env.LEMONSQUEEZY_WEBHOOK_SECRET,
|
||||||
|
redirectTo: `${process.env.BASE_URL}/setup`,
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -70,10 +70,7 @@ export class PlaidClientWrapper {
|
|||||||
baseOptions: {
|
baseOptions: {
|
||||||
headers: {
|
headers: {
|
||||||
'PLAID-CLIENT-ID': config.plaid.clientId,
|
'PLAID-CLIENT-ID': config.plaid.clientId,
|
||||||
'PLAID-SECRET':
|
'PLAID-SECRET': config.plaid.secret,
|
||||||
config.plaid.env === 'development'
|
|
||||||
? config.plaid.secretDevelopment
|
|
||||||
: config.plaid.secretSandbox,
|
|
||||||
'Plaid-Version': '2020-09-14',
|
'Plaid-Version': '2020-09-14',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Service } from 'typedi';
|
|||||||
import { createCheckout } from '@lemonsqueezy/lemonsqueezy.js';
|
import { createCheckout } from '@lemonsqueezy/lemonsqueezy.js';
|
||||||
import { SystemUser } from '@/system/models';
|
import { SystemUser } from '@/system/models';
|
||||||
import { configureLemonSqueezy } from './utils';
|
import { configureLemonSqueezy } from './utils';
|
||||||
|
import config from '@/config';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class LemonSqueezyService {
|
export class LemonSqueezyService {
|
||||||
@@ -28,7 +29,7 @@ export class LemonSqueezyService {
|
|||||||
},
|
},
|
||||||
productOptions: {
|
productOptions: {
|
||||||
enabledVariants: [variantId],
|
enabledVariants: [variantId],
|
||||||
redirectUrl: `http://localhost:4000/dashboard/billing/`,
|
redirectUrl: config.lemonSqueezy.redirectTo,
|
||||||
receiptButtonText: 'Go to Dashboard',
|
receiptButtonText: 'Go to Dashboard',
|
||||||
receiptThankYouNote: 'Thank you for signing up to Lemon Stand!',
|
receiptThankYouNote: 'Thank you for signing up to Lemon Stand!',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import InvoiceMailDialog from '@/containers/Sales/Invoices/InvoiceMailDialog/Inv
|
|||||||
import EstimateMailDialog from '@/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialog';
|
import EstimateMailDialog from '@/containers/Sales/Estimates/EstimateMailDialog/EstimateMailDialog';
|
||||||
import ReceiptMailDialog from '@/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialog';
|
import ReceiptMailDialog from '@/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialog';
|
||||||
import PaymentMailDialog from '@/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialog';
|
import PaymentMailDialog from '@/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialog';
|
||||||
import { ConnectBankDialog } from '@/containers/CashFlow/ConnectBankDialog';
|
|
||||||
import { ExportDialog } from '@/containers/Dialogs/ExportDialog';
|
import { ExportDialog } from '@/containers/Dialogs/ExportDialog';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,7 +96,6 @@ export default function DialogsContainer() {
|
|||||||
<NotifyPaymentReceiveViaSMSDialog
|
<NotifyPaymentReceiveViaSMSDialog
|
||||||
dialogName={DialogsName.NotifyPaymentViaForm}
|
dialogName={DialogsName.NotifyPaymentViaForm}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BadDebtDialog dialogName={DialogsName.BadDebtForm} />
|
<BadDebtDialog dialogName={DialogsName.BadDebtForm} />
|
||||||
<SMSMessageDialog dialogName={DialogsName.SMSMessageForm} />
|
<SMSMessageDialog dialogName={DialogsName.SMSMessageForm} />
|
||||||
<RefundCreditNoteDialog dialogName={DialogsName.RefundCreditNote} />
|
<RefundCreditNoteDialog dialogName={DialogsName.RefundCreditNote} />
|
||||||
@@ -148,8 +146,6 @@ export default function DialogsContainer() {
|
|||||||
<EstimateMailDialog dialogName={DialogsName.EstimateMail} />
|
<EstimateMailDialog dialogName={DialogsName.EstimateMail} />
|
||||||
<ReceiptMailDialog dialogName={DialogsName.ReceiptMail} />
|
<ReceiptMailDialog dialogName={DialogsName.ReceiptMail} />
|
||||||
<PaymentMailDialog dialogName={DialogsName.PaymentMail} />
|
<PaymentMailDialog dialogName={DialogsName.PaymentMail} />
|
||||||
<ConnectBankDialog dialogName={DialogsName.ConnectBankCreditCard} />
|
|
||||||
|
|
||||||
<ExportDialog dialogName={DialogsName.Export} />
|
<ExportDialog dialogName={DialogsName.Export} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
FeatureCan,
|
FeatureCan,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { useRefreshCashflowAccounts } from '@/hooks/query';
|
import { useRefreshCashflowAccounts } from '@/hooks/query';
|
||||||
|
import { useOpenPlaidConnect } from '@/hooks/utils/useOpenPlaidConnect';
|
||||||
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
|
import { CashflowAction, AbilitySubject } from '@/constants/abilityOption';
|
||||||
|
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
@@ -39,6 +40,9 @@ function CashFlowAccountsActionsBar({
|
|||||||
}) {
|
}) {
|
||||||
const { refresh } = useRefreshCashflowAccounts();
|
const { refresh } = useRefreshCashflowAccounts();
|
||||||
|
|
||||||
|
// Opens the Plaid popup.
|
||||||
|
const { openPlaidAsync, isPlaidLoading } = useOpenPlaidConnect();
|
||||||
|
|
||||||
// Handle refresh button click.
|
// Handle refresh button click.
|
||||||
const handleRefreshBtnClick = () => {
|
const handleRefreshBtnClick = () => {
|
||||||
refresh();
|
refresh();
|
||||||
@@ -64,7 +68,7 @@ function CashFlowAccountsActionsBar({
|
|||||||
};
|
};
|
||||||
// Handle connect button click.
|
// Handle connect button click.
|
||||||
const handleConnectToBank = () => {
|
const handleConnectToBank = () => {
|
||||||
openDialog(DialogsName.ConnectBankCreditCard);
|
openPlaidAsync();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -116,6 +120,7 @@ function CashFlowAccountsActionsBar({
|
|||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
text={'Connect to Bank / Credit Card'}
|
text={'Connect to Bank / Credit Card'}
|
||||||
onClick={handleConnectToBank}
|
onClick={handleConnectToBank}
|
||||||
|
disabled={isPlaidLoading}
|
||||||
/>
|
/>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
</FeatureCan>
|
</FeatureCan>
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
|
||||||
import { Dialog, DialogSuspense } from '@/components';
|
|
||||||
import withDialogRedux from '@/components/DialogReduxConnect';
|
|
||||||
import { compose } from '@/utils';
|
|
||||||
|
|
||||||
const ConnectBankDialogBody = React.lazy(
|
|
||||||
() => import('./ConnectBankDialogBody'),
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect bank dialog.
|
|
||||||
*/
|
|
||||||
function ConnectBankDialogRoot({ dialogName, payload = {}, isOpen }) {
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
name={dialogName}
|
|
||||||
title={'Securly connect your bank or credit card.'}
|
|
||||||
isOpen={isOpen}
|
|
||||||
canEscapeJeyClose={true}
|
|
||||||
autoFocus={true}
|
|
||||||
>
|
|
||||||
<DialogSuspense>
|
|
||||||
<ConnectBankDialogBody dialogName={dialogName} />
|
|
||||||
</DialogSuspense>
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ConnectBankDialog = compose(withDialogRedux())(
|
|
||||||
ConnectBankDialogRoot,
|
|
||||||
);
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import * as R from 'ramda';
|
|
||||||
import { Form, Formik, FormikHelpers } from 'formik';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { ConnectBankDialogContent } from './ConnectBankDialogContent';
|
|
||||||
import { useGetPlaidLinkToken } from '@/hooks/query';
|
|
||||||
import { useSetBankingPlaidToken } from '@/hooks/state/banking';
|
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
|
||||||
import { CLASSES } from '@/constants';
|
|
||||||
import { AppToaster } from '@/components';
|
|
||||||
import { Intent } from '@blueprintjs/core';
|
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
|
||||||
|
|
||||||
const initialValues: ConnectBankDialogForm = {
|
|
||||||
serviceProvider: 'plaid',
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ConnectBankDialogForm {
|
|
||||||
serviceProvider: 'plaid';
|
|
||||||
}
|
|
||||||
|
|
||||||
function ConnectBankDialogBodyRoot({
|
|
||||||
// #withDialogActions
|
|
||||||
closeDialog,
|
|
||||||
}) {
|
|
||||||
const { mutateAsync: getPlaidLinkToken } = useGetPlaidLinkToken();
|
|
||||||
const setPlaidId = useSetBankingPlaidToken();
|
|
||||||
|
|
||||||
// Handles the form submitting.
|
|
||||||
const handleSubmit = (
|
|
||||||
values: ConnectBankDialogForm,
|
|
||||||
{ setSubmitting }: FormikHelpers<ConnectBankDialogForm>,
|
|
||||||
) => {
|
|
||||||
setSubmitting(true);
|
|
||||||
getPlaidLinkToken()
|
|
||||||
.then((res) => {
|
|
||||||
setSubmitting(false);
|
|
||||||
closeDialog(DialogsName.ConnectBankCreditCard);
|
|
||||||
setPlaidId(res.data.link_token);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
setSubmitting(false);
|
|
||||||
AppToaster.show({
|
|
||||||
message: 'Something went wrong.',
|
|
||||||
intent: Intent.DANGER,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames(CLASSES.DIALOG_BODY)}>
|
|
||||||
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
|
|
||||||
<Form>
|
|
||||||
<ConnectBankDialogContent />
|
|
||||||
</Form>
|
|
||||||
</Formik>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default R.compose(withDialogActions)(ConnectBankDialogBodyRoot);
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { Stack } from '@/components';
|
|
||||||
import { TellerIcon } from '../Icons/TellerIcon';
|
|
||||||
import { YodleeIcon } from '../Icons/YodleeIcon';
|
|
||||||
import { PlaidIcon } from '../Icons/PlaidIcon';
|
|
||||||
import { BankServiceCard } from './ConnectBankServiceCard';
|
|
||||||
|
|
||||||
const TopDesc = styled('p')`
|
|
||||||
margin-bottom: 20px;
|
|
||||||
color: #5f6b7c;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function ConnectBankDialogContent() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<TopDesc>
|
|
||||||
Connect your bank accounts and fetch the bank transactions using
|
|
||||||
one of our supported third-party service providers.
|
|
||||||
</TopDesc>
|
|
||||||
|
|
||||||
<Stack>
|
|
||||||
<BankServiceCard
|
|
||||||
title={'Plaid (US, UK & Canada)'}
|
|
||||||
icon={<PlaidIcon />}
|
|
||||||
>
|
|
||||||
Plaid gives the connection to 12,000 financial institutions across US, UK and Canada.
|
|
||||||
</BankServiceCard>
|
|
||||||
|
|
||||||
<BankServiceCard
|
|
||||||
title={'Teller (US) — Soon'}
|
|
||||||
icon={<TellerIcon />}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
Connect instantly with more than 5,000 financial institutions across US.
|
|
||||||
</BankServiceCard>
|
|
||||||
|
|
||||||
<BankServiceCard
|
|
||||||
title={'Yodlee (Global) — Soon'}
|
|
||||||
icon={<YodleeIcon />}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
Connect instantly with a global network of financial institutions.
|
|
||||||
</BankServiceCard>
|
|
||||||
</Stack>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
import { Group } from '@/components';
|
|
||||||
|
|
||||||
const BankServiceIcon = styled('div')`
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
border: 1px solid #c8cad0;
|
|
||||||
border-radius: 3px;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const BankServiceContent = styled(`div`)`
|
|
||||||
flex: 1 0;
|
|
||||||
`;
|
|
||||||
const BankServiceCardRoot = styled('button')`
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid #c8cad0;
|
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
background: transparent;
|
|
||||||
text-align: inherit;
|
|
||||||
padding: 14px;
|
|
||||||
|
|
||||||
&:not(:disabled) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
&:hover:not(:disabled) {
|
|
||||||
border-color: #0153cc;
|
|
||||||
}
|
|
||||||
&:disabled {
|
|
||||||
background: #f9fdff;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
const BankServiceTitle = styled(`h3`)`
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2d333d;
|
|
||||||
`;
|
|
||||||
const BankServiceDesc = styled('p')`
|
|
||||||
margin-top: 4px;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #738091;
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface BankServiceCardProps {
|
|
||||||
title: string;
|
|
||||||
children: React.ReactNode;
|
|
||||||
disabled?: boolean;
|
|
||||||
icon: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function BankServiceCard({
|
|
||||||
title,
|
|
||||||
children,
|
|
||||||
icon,
|
|
||||||
disabled,
|
|
||||||
}: BankServiceCardProps) {
|
|
||||||
return (
|
|
||||||
<BankServiceCardRoot disabled={disabled}>
|
|
||||||
<Group>
|
|
||||||
<BankServiceIcon>{icon}</BankServiceIcon>
|
|
||||||
<BankServiceContent>
|
|
||||||
<BankServiceTitle>{title}</BankServiceTitle>
|
|
||||||
<BankServiceDesc>{children}</BankServiceDesc>
|
|
||||||
</BankServiceContent>
|
|
||||||
</Group>
|
|
||||||
</BankServiceCardRoot>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from './ConnectBankDialog';
|
|
||||||
25
packages/webapp/src/hooks/utils/useOpenPlaidConnect.ts
Normal file
25
packages/webapp/src/hooks/utils/useOpenPlaidConnect.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useSetBankingPlaidToken } from '../state/banking';
|
||||||
|
import { AppToaster } from '@/components';
|
||||||
|
import { useGetPlaidLinkToken } from '../query';
|
||||||
|
import { Intent } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
export const useOpenPlaidConnect = () => {
|
||||||
|
const { mutateAsync: getPlaidLinkToken, isLoading } = useGetPlaidLinkToken();
|
||||||
|
const setPlaidId = useSetBankingPlaidToken();
|
||||||
|
|
||||||
|
const openPlaidAsync = useCallback(() => {
|
||||||
|
return getPlaidLinkToken()
|
||||||
|
.then((res) => {
|
||||||
|
setPlaidId(res.data.link_token);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: 'Something went wrong.',
|
||||||
|
intent: Intent.DANGER,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [getPlaidLinkToken, setPlaidId]);
|
||||||
|
|
||||||
|
return { openPlaidAsync, isPlaidLoading: isLoading };
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user