Skip to content

Commit 8b7fdfb

Browse files
authored
Merge pull request #378 from alegmarra/EUWECRY-1084
EUWECRY-1084: Refactor Quickstart app for UK/EU payment initiation
2 parents ccb3c50 + 5c8c0b9 commit 8b7fdfb

File tree

13 files changed

+225
-103
lines changed

13 files changed

+225
-103
lines changed

.env.example

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
1-
# Get your Plaid API keys from the dashboard: https://dashboard.plaid.com/account/keys
1+
# Get your Plaid API keys from the dashboard: https://dashboard.plaid.com/team/keys
22
PLAID_CLIENT_ID=
33
PLAID_SECRET=
4+
45
# Use 'sandbox' to test with fake credentials in Plaid's Sandbox environment
56
# Use 'development' to test with real credentials while developing
67
# Use 'production' to go live with real users
78
PLAID_ENV=sandbox
9+
810
# PLAID_PRODUCTS is a comma-separated list of products to use when
911
# initializing Link, e.g. PLAID_PRODUCTS=auth,transactions.
1012
# see https://plaid.com/docs/api/tokens/#link-token-create-request-products for a complete list.
1113
# Only institutions that support ALL listed products will be displayed in Link.
1214
# If you don't see the institution you want in Link, remove any products you aren't using.
13-
# Important: When moving to Production, make sure to update this list with only the products
15+
# Important:
16+
# When moving to Production, make sure to update this list with only the products
1417
# you plan to use. Otherwise, you may be billed for unneeded products.
15-
# NOTE: Income_verification has to be used seperately from all other products due to the specific
16-
# flow.
18+
# NOTE:
19+
# - 'income_verification' has to be used separately from all other products due to the specific flow.
20+
# - 'payment_initiation' has to be used separately from all other products due to the specific flow.
1721
PLAID_PRODUCTS=auth,transactions
22+
1823
# PLAID_COUNTRY_CODES is a comma-separated list of countries to use when
1924
# initializing Link, e.g. PLAID_COUNTRY_CODES=US,CA.
20-
# see https://plaid.com/docs/api/tokens/#link-token-create-request-country-codes for a complete list
25+
# Institutions from all listed countries will be shown. If Link is launched with multiple country codes,
26+
# only products that you are enabled for in all countries will be used by Link.
27+
# See https://plaid.com/docs/api/tokens/#link-token-create-request-country-codes for a complete list
2128
PLAID_COUNTRY_CODES=US,CA
29+
2230
# Only required for OAuth:
2331
# For sandbox, set PLAID_REDIRECT_URI to 'http://localhost:3000/'
2432
# The OAuth redirect flow requires an endpoint on the developer's website

frontend/src/App.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Context from "./Context";
88
import styles from "./App.module.scss";
99

1010
const App = () => {
11-
const { linkSuccess, isItemAccess, dispatch } = useContext(Context);
11+
const { linkSuccess, isItemAccess, isPaymentInitiation, dispatch } = useContext(Context);
1212

1313
const getInfo = useCallback(async () => {
1414
const response = await fetch("/api/info", { method: "POST" });
@@ -24,14 +24,16 @@ const App = () => {
2424
type: "SET_STATE",
2525
state: {
2626
products: data.products,
27+
isPaymentInitiation: paymentInitiation,
2728
},
2829
});
2930
return { paymentInitiation };
3031
}, [dispatch]);
3132

3233
const generateToken = useCallback(
33-
async (paymentInitiation) => {
34-
const path = paymentInitiation
34+
async (isPaymentInitiation) => {
35+
// Link tokens for 'payment_initiation' use a different creation flow in your backend.
36+
const path = isPaymentInitiation
3537
? "/api/create_link_token_for_payment"
3638
: "/api/create_link_token";
3739
const response = await fetch(path, {
@@ -55,7 +57,8 @@ const App = () => {
5557
}
5658
dispatch({ type: "SET_STATE", state: { linkToken: data.link_token } });
5759
}
58-
localStorage.setItem("link_token", data.link_token); //to use later for Oauth
60+
// Save the link_token to be used later in the Oauth flow.
61+
localStorage.setItem("link_token", data.link_token);
5962
},
6063
[dispatch]
6164
);
@@ -83,10 +86,17 @@ const App = () => {
8386
<div className={styles.App}>
8487
<div className={styles.container}>
8588
<Header />
86-
{linkSuccess && isItemAccess && (
89+
{linkSuccess && (
8790
<>
88-
<Products />
89-
<Items />
91+
{isPaymentInitiation && (
92+
<Products />
93+
)}
94+
{isItemAccess && (
95+
<>
96+
<Products />
97+
<Items />
98+
</>
99+
)}
90100
</>
91101
)}
92102
</div>

frontend/src/Components/Headers/index.tsx

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const Header = () => {
1717
isItemAccess,
1818
backend,
1919
linkTokenError,
20+
isPaymentInitiation,
2021
} = useContext(Context);
2122

2223
return (
@@ -90,40 +91,64 @@ const Header = () => {
9091
</>
9192
) : (
9293
<>
93-
{isItemAccess ? (
94+
{isPaymentInitiation ? (
95+
<>
9496
<h4 className={styles.subtitle}>
95-
Congrats! By linking an account, you have created an{" "}
96-
<InlineLink
97-
href="http://plaid.com/docs/quickstart/glossary/#item"
98-
target="_blank"
99-
>
100-
Item
101-
</InlineLink>
102-
.
103-
</h4>
104-
) : (
105-
<h4 className={styles.subtitle}>
106-
<Callout warning>
107-
Unable to create an item. Please check your backend server
97+
Congrats! Your payment is now confirmed.
98+
<p/>
99+
<Callout>
100+
You can see information of all your payments in the{' '}
101+
<InlineLink
102+
href="https://dashboard.plaid.com/activity/payments"
103+
target="_blank"
104+
>
105+
Payments Dashboard
106+
</InlineLink>
107+
.
108108
</Callout>
109109
</h4>
110-
)}
111-
<div className={styles.itemAccessContainer}>
112-
<p className={styles.itemAccessRow}>
113-
<span className={styles.idName}>item_id</span>
114-
<span className={styles.tokenText}>{itemId}</span>
115-
</p>
116-
117-
<p className={styles.itemAccessRow}>
118-
<span className={styles.idName}>access_token</span>
119-
<span className={styles.tokenText}>{accessToken}</span>
120-
</p>
121-
</div>
122-
{isItemAccess && (
123110
<p className={styles.requests}>
124-
Now that you have an access_token, you can make all of the
125-
following requests:
111+
Now that the 'payment_id' stored in your server, you can use it to access the payment information:
126112
</p>
113+
</>
114+
) : /* If not using the payment_initiation product, show the item_id and access_token information */ (
115+
<>
116+
{isItemAccess ? (
117+
<h4 className={styles.subtitle}>
118+
Congrats! By linking an account, you have created an{" "}
119+
<InlineLink
120+
href="http://plaid.com/docs/quickstart/glossary/#item"
121+
target="_blank"
122+
>
123+
Item
124+
</InlineLink>
125+
.
126+
</h4>
127+
) : (
128+
<h4 className={styles.subtitle}>
129+
<Callout warning>
130+
Unable to create an item. Please check your backend server
131+
</Callout>
132+
</h4>
133+
)}
134+
<div className={styles.itemAccessContainer}>
135+
<p className={styles.itemAccessRow}>
136+
<span className={styles.idName}>item_id</span>
137+
<span className={styles.tokenText}>{itemId}</span>
138+
</p>
139+
140+
<p className={styles.itemAccessRow}>
141+
<span className={styles.idName}>access_token</span>
142+
<span className={styles.tokenText}>{accessToken}</span>
143+
</p>
144+
</div>
145+
{isItemAccess && (
146+
<p className={styles.requests}>
147+
Now that you have an access_token, you can make all of the
148+
following requests:
149+
</p>
150+
)}
151+
</>
127152
)}
128153
</>
129154
)}

frontend/src/Components/Link/index.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { usePlaidLink } from "react-plaid-link";
33
import Button from "plaid-threads/Button";
44

55
import Context from "../../Context";
6+
import {Products} from "plaid";
67

78
const Link = () => {
8-
const { linkToken, dispatch } = useContext(Context);
9+
const { linkToken, isPaymentInitiation, dispatch } = useContext(Context);
910

1011
const onSuccess = React.useCallback(
1112
(public_token: string) => {
12-
// send public_token to server
13-
const setToken = async () => {
13+
// If the access_token is needed, send public_token to server
14+
const exchangePublicTokenForAccessToken = async () => {
1415
const response = await fetch("/api/set_access_token", {
1516
method: "POST",
1617
headers: {
@@ -39,7 +40,14 @@ const Link = () => {
3940
},
4041
});
4142
};
42-
setToken();
43+
44+
// 'payment_initiation' products do not require the public_token to be exchanged for an access_token.
45+
if (isPaymentInitiation){
46+
dispatch({ type: "SET_STATE", state: { isItemAccess: false } });
47+
} else {
48+
exchangePublicTokenForAccessToken();
49+
}
50+
4351
dispatch({ type: "SET_STATE", state: { linkSuccess: true } });
4452
window.history.pushState("", "", "/");
4553
},

frontend/src/Components/ProductTypes/Products.tsx

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,37 @@ const Products = () => {
4242
transformData={transformPaymentData}
4343
/>
4444
)}
45-
<Endpoint
46-
endpoint="auth"
47-
name="Auth"
48-
categories={authCategories}
49-
schema="/auth/get/"
50-
description="Retrieve account and routing numbers for checking and savings accounts."
51-
transformData={transformAuthData}
52-
/>
53-
<Endpoint
54-
endpoint="transactions"
55-
name="Transactions"
56-
categories={transactionsCategories}
57-
schema="/transactions/sync/"
58-
description="Retrieve transactions or incremental updates for credit and depository accounts."
59-
transformData={transformTransactionsData}
60-
/>
61-
<Endpoint
62-
endpoint="identity"
63-
name="Identity"
64-
categories={identityCategories}
65-
schema="/identity/get/"
66-
description="Retrieve Identity information on file with the bank. Reduce
67-
fraud by comparing user-submitted data to validate identity."
68-
transformData={transformIdentityData}
69-
/>
45+
{products.includes("auth") && (
46+
<Endpoint
47+
endpoint="auth"
48+
name="Auth"
49+
categories={authCategories}
50+
schema="/auth/get/"
51+
description="Retrieve account and routing numbers for checking and savings accounts."
52+
transformData={transformAuthData}
53+
/>
54+
)}
55+
{products.includes("transactions") && (
56+
<Endpoint
57+
endpoint="transactions"
58+
name="Transactions"
59+
categories={transactionsCategories}
60+
schema="/transactions/sync/"
61+
description="Retrieve transactions or incremental updates for credit and depository accounts."
62+
transformData={transformTransactionsData}
63+
/>
64+
)}
65+
{products.includes("identity") && (
66+
<Endpoint
67+
endpoint="identity"
68+
name="Identity"
69+
categories={identityCategories}
70+
schema="/identity/get/"
71+
description="Retrieve Identity information on file with the bank. Reduce
72+
fraud by comparing user-submitted data to validate identity."
73+
transformData={transformIdentityData}
74+
/>
75+
)}
7076
{products.includes("assets") && (
7177
<Endpoint
7278
endpoint="assets"
@@ -77,15 +83,17 @@ const Products = () => {
7783
transformData={transformAssetsData}
7884
/>
7985
)}
80-
<Endpoint
81-
endpoint="balance"
82-
name="Balance"
83-
categories={balanceCategories}
84-
schema="/accounts/balance/get/"
85-
description="Check balances in real time to prevent non-sufficient funds
86+
{!products.includes("payment_initiation") && (
87+
<Endpoint
88+
endpoint="balance"
89+
name="Balance"
90+
categories={balanceCategories}
91+
schema="/accounts/balance/get/"
92+
description="Check balances in real time to prevent non-sufficient funds
8693
fees."
87-
transformData={transformBalanceData}
88-
/>
94+
transformData={transformBalanceData}
95+
/>
96+
)}
8997
{products.includes("investments") && (
9098
<>
9199
<Endpoint

frontend/src/Context/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createContext, useReducer, Dispatch, ReactNode } from "react";
33
interface QuickstartState {
44
linkSuccess: boolean;
55
isItemAccess: boolean;
6+
isPaymentInitiation: boolean;
67
linkToken: string | null;
78
accessToken: string | null;
89
itemId: string | null;
@@ -19,6 +20,7 @@ interface QuickstartState {
1920
const initialState: QuickstartState = {
2021
linkSuccess: false,
2122
isItemAccess: true,
23+
isPaymentInitiation: false,
2224
linkToken: "", // Don't set to null or error message will show up briefly when site loads
2325
accessToken: null,
2426
itemId: null,

0 commit comments

Comments
 (0)