Skip to content

Commit 1cf6bfc

Browse files
committed
Release braintree-web 3.138.0 source
1 parent 0f3440d commit 1cf6bfc

File tree

8 files changed

+1122
-8
lines changed

8 files changed

+1122
-8
lines changed

.storybook/stories/PayPalCheckoutV6/PayPalCheckoutV6.stories.ts

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ PayPal Checkout V6 - Payment integration with multiple flow types.
1717
1818
**Payment Flow Types:**
1919
- **One-Time Payments**: Best for infrequent payments with higher AOV (retail, e-commerce)
20+
- **Checkout with Vault**: Single flow for payment + vault consent (subscriptions with initial charge)
2021
- **Vaulted Payments**: Ideal for high-frequency, low-AOV purchases (food delivery, marketplaces)
2122
- **Recurring Payments**: Perfect for subscriptions and automated billing (SaaS, streaming, utilities)
2223
- **Vault-Initiated Checkout**: Use a previously vaulted PayPal account for subsequent payments
2324
2425
**Implementation Features:**
2526
- One-time payment session creation
27+
- Checkout with vault session (payment + save)
2628
- Billing agreement/vault flow
2729
- Vault-initiated checkout
2830
- Payment tokenization
@@ -1093,3 +1095,211 @@ export const LineItemsAndShipping: StoryObj = {
10931095
["client.min.js", "paypal-checkout-v6.min.js"]
10941096
),
10951097
};
1098+
1099+
// Checkout with Vault Story
1100+
const createCheckoutWithVaultForm = (): HTMLElement => {
1101+
const container = document.createElement("div");
1102+
container.innerHTML = `
1103+
<div class="shared-container paypal-container">
1104+
<h2>PayPal V6 Checkout with Vault</h2>
1105+
1106+
<div class="paypal-description">
1107+
<p class="shared-description">
1108+
Create a one-time payment while simultaneously saving the PayPal account
1109+
for future transactions. The returned nonce can be used for both the
1110+
immediate charge and future recurring payments.
1111+
</p>
1112+
1113+
<div class="paypal-form-group">
1114+
<label class="paypal-checkbox-label">
1115+
<input type="checkbox" id="advancedOptionsToggle" class="paypal-checkbox" />
1116+
<span class="paypal-checkbox-text">Include line items and shipping options</span>
1117+
</label>
1118+
</div>
1119+
</div>
1120+
1121+
<div id="paypal-button" class="paypal-button-container"></div>
1122+
1123+
<div id="result" class="shared-result"></div>
1124+
</div>
1125+
`;
1126+
1127+
return container;
1128+
};
1129+
1130+
const CHECKOUT_WITH_VAULT_BASIC = {
1131+
amount: "10.00",
1132+
currency: "USD",
1133+
intent: "capture",
1134+
billingAgreementDetails: {
1135+
description: "Monthly subscription to Totally Real Products!",
1136+
},
1137+
};
1138+
1139+
const CHECKOUT_WITH_VAULT_ADVANCED = {
1140+
amount: "20.00",
1141+
currency: "USD",
1142+
intent: "capture",
1143+
billingAgreementDetails: {
1144+
description: "Premium subscription service with initial payment",
1145+
},
1146+
lineItems: [
1147+
{
1148+
quantity: "1",
1149+
unitAmount: "15.00",
1150+
name: "Premium Subscription (First Month)",
1151+
kind: "debit",
1152+
},
1153+
],
1154+
shippingOptions: [
1155+
{
1156+
id: "standard",
1157+
label: "Standard Shipping",
1158+
selected: true,
1159+
type: "SHIPPING",
1160+
amount: {
1161+
currency: "USD",
1162+
value: "5.00",
1163+
},
1164+
},
1165+
{
1166+
id: "express",
1167+
label: "Express Shipping",
1168+
selected: false,
1169+
type: "SHIPPING",
1170+
amount: {
1171+
currency: "USD",
1172+
value: "10.00",
1173+
},
1174+
},
1175+
],
1176+
amountBreakdown: {
1177+
itemTotal: "15.00",
1178+
shipping: "5.00",
1179+
},
1180+
};
1181+
1182+
const setupCheckoutWithVault = async (
1183+
container: HTMLElement
1184+
): Promise<void> => {
1185+
const clientToken = await getClientToken();
1186+
const resultDiv = container.querySelector("#result") as HTMLElement;
1187+
const advancedToggle = container.querySelector(
1188+
"#advancedOptionsToggle"
1189+
) as HTMLInputElement;
1190+
1191+
if (!clientToken) {
1192+
resultDiv.className =
1193+
"shared-result shared-result--visible shared-result--error";
1194+
resultDiv.innerHTML = `
1195+
<strong>Configuration Error</strong><br>
1196+
<small>Please add STORYBOOK_BRAINTREE_CLIENT_TOKEN to your .env file</small>
1197+
`;
1198+
return;
1199+
}
1200+
1201+
try {
1202+
const braintree = getBraintreeSDK(resultDiv);
1203+
const clientInstance = await braintree.client.create({
1204+
authorization: clientToken,
1205+
});
1206+
1207+
const paypalCheckoutV6Instance = await braintree.paypalCheckoutV6.create({
1208+
client: clientInstance,
1209+
});
1210+
1211+
await paypalCheckoutV6Instance.loadPayPalSDK();
1212+
1213+
const getSessionOptions = () => {
1214+
const baseOptions = advancedToggle.checked
1215+
? CHECKOUT_WITH_VAULT_ADVANCED
1216+
: CHECKOUT_WITH_VAULT_BASIC;
1217+
1218+
return {
1219+
...baseOptions,
1220+
onApprove: async (data: IPayPalV6ApproveData) => {
1221+
const tokenizeData = {
1222+
payerID: data.payerID || data.payerId || data.PayerID,
1223+
orderID: getOrderId(data),
1224+
};
1225+
1226+
const payload =
1227+
await paypalCheckoutV6Instance.tokenizePayment(tokenizeData);
1228+
1229+
const email =
1230+
payload.details?.email || payload.details?.payerEmail || "N/A";
1231+
const mode = advancedToggle.checked
1232+
? "with line items and shipping"
1233+
: "basic payment";
1234+
1235+
resultDiv.className =
1236+
"shared-result shared-result--visible shared-result--success";
1237+
resultDiv.innerHTML = `
1238+
<strong>Payment authorized & account vaulted!</strong><br>
1239+
<small>Nonce: ${payload.nonce}</small><br>
1240+
<small>Payer Email: ${email}</small><br>
1241+
<small>Amount: $${advancedToggle.checked ? "20.00" : "10.00"}</small><br>
1242+
<small>Mode: ${mode}</small>
1243+
`;
1244+
},
1245+
1246+
onCancel: () => {
1247+
resultDiv.className = "shared-result shared-result--visible";
1248+
resultDiv.innerHTML = `
1249+
<strong>Payment Cancelled</strong><br>
1250+
<small>Customer cancelled the checkout with vault flow.</small>
1251+
`;
1252+
},
1253+
1254+
onError: (err: IBraintreeError) => {
1255+
showDetailedError(resultDiv, "PayPal Error", err);
1256+
},
1257+
};
1258+
};
1259+
1260+
const paypalButtonContainer = container.querySelector(
1261+
"#paypal-button"
1262+
) as HTMLElement;
1263+
const button = document.createElement("button");
1264+
button.textContent = "Checkout with Vault";
1265+
button.className = "paypal-button";
1266+
button.style.cssText = `
1267+
background-color: #0070ba;
1268+
color: white;
1269+
border: none;
1270+
padding: 12px 24px;
1271+
font-size: 16px;
1272+
border-radius: 4px;
1273+
cursor: pointer;
1274+
font-weight: 500;
1275+
width: 100%;
1276+
`;
1277+
1278+
button.addEventListener("click", () => {
1279+
const session =
1280+
paypalCheckoutV6Instance.createCheckoutWithVaultSession(
1281+
getSessionOptions()
1282+
);
1283+
session.start();
1284+
});
1285+
1286+
paypalButtonContainer.appendChild(button);
1287+
} catch (error) {
1288+
showDetailedError(
1289+
resultDiv,
1290+
"Initialization Error",
1291+
error as IBraintreeError
1292+
);
1293+
}
1294+
};
1295+
1296+
export const CheckoutWithVault: StoryObj = {
1297+
render: createSimpleBraintreeStory(
1298+
async (container) => {
1299+
const formContainer = createCheckoutWithVaultForm();
1300+
container.appendChild(formContainer);
1301+
await setupCheckoutWithVault(formContainer);
1302+
},
1303+
["client.min.js", "paypal-checkout-v6.min.js"]
1304+
),
1305+
};

.storybook/types/global.d.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,7 @@ interface IPayPalCheckoutV6TokenizePayload {
997997
firstName?: string;
998998
lastName?: string;
999999
};
1000+
shippingOptionId?: string;
10001001
}
10011002

10021003
/**
@@ -1086,6 +1087,51 @@ interface IPayPalCheckoutV6Instance {
10861087
onCancel?: () => void;
10871088
onError?: (err: IBraintreeError) => void;
10881089
}) => IPayPalCheckoutV6Session;
1090+
createCheckoutWithVaultSession: (options: {
1091+
amount: string;
1092+
currency: string;
1093+
intent?: "capture" | "authorize" | "order";
1094+
billingAgreementDetails?: {
1095+
description: string;
1096+
};
1097+
returnUrl?: string;
1098+
cancelUrl?: string;
1099+
lineItems?: Array<{
1100+
quantity: string;
1101+
unitAmount: string;
1102+
name: string;
1103+
kind: "debit" | "credit";
1104+
unitTaxAmount?: string;
1105+
description?: string;
1106+
}>;
1107+
shippingOptions?: Array<{
1108+
id: string;
1109+
label: string;
1110+
selected: boolean;
1111+
type: "SHIPPING" | "PICKUP";
1112+
amount: { currency: string; value: string };
1113+
}>;
1114+
amountBreakdown?: {
1115+
itemTotal?: string;
1116+
shipping?: string;
1117+
handling?: string;
1118+
taxTotal?: string;
1119+
insurance?: string;
1120+
shippingDiscount?: string;
1121+
discount?: string;
1122+
};
1123+
displayName?: string;
1124+
userAuthenticationEmail?: string;
1125+
presentationMode?: string;
1126+
onShippingAddressChange?: (data: {
1127+
shippingAddress?: { city?: string; state?: string };
1128+
orderID?: string;
1129+
orderId?: string;
1130+
}) => void | Promise<unknown>;
1131+
onApprove: (data: IPayPalV6ApproveData) => void | Promise<void>;
1132+
onCancel?: () => void;
1133+
onError?: (err: IBraintreeError) => void;
1134+
}) => IPayPalCheckoutV6Session;
10891135
tokenizePayment: (data: {
10901136
billingToken?: string;
10911137
payerID?: string;

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
# CHANGELOG
22

3+
## 3.138.0 (2026-03-10)
4+
5+
- PayPal Checkout v6
6+
- Add `createCheckoutWithVaultSession` method to enable charging and vaulting in a single session
7+
38
## 3.137.0 (2026-03-02)
49

510
- Alternative Payment Method
611
- Add support for Alternative Payment Method `crypto`
12+
- Update Data Collector error object
713

814
## 3.136.0 (2026-02-10)
915

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "braintree-web",
3-
"version": "3.137.0",
3+
"version": "3.138.0",
44
"license": "MIT",
55
"main": "src/index.js",
66
"private": true,

src/paypal-checkout-v6/constants.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,22 @@ var ANALYTICS_EVENTS = {
2929
// Session Creation
3030
SESSION_CHECKOUT_CREATED: ANALYTICS_PREFIX + ".session.checkout.created",
3131
SESSION_VAULT_CREATED: ANALYTICS_PREFIX + ".session.vault.created",
32+
SESSION_CHECKOUT_WITH_VAULT_CREATED:
33+
ANALYTICS_PREFIX + ".session.checkout-with-vault.created",
3234

3335
// Payment Flow
3436
PAYMENT_STARTED: ANALYTICS_PREFIX + ".payment.started",
3537
PAYMENT_APPROVED: ANALYTICS_PREFIX + ".payment.approved",
3638
PAYMENT_CANCELED: ANALYTICS_PREFIX + ".payment.canceled",
3739

40+
// Checkout with Vault Flow
41+
CHECKOUT_WITH_VAULT_STARTED:
42+
ANALYTICS_PREFIX + ".checkout-with-vault.started",
43+
CHECKOUT_WITH_VAULT_APPROVED:
44+
ANALYTICS_PREFIX + ".checkout-with-vault.approved",
45+
CHECKOUT_WITH_VAULT_CANCELED:
46+
ANALYTICS_PREFIX + ".checkout-with-vault.canceled",
47+
3848
// Order Creation
3949
CREATE_ORDER_STARTED: ANALYTICS_PREFIX + ".create-order.started",
4050
CREATE_ORDER_SUCCEEDED: ANALYTICS_PREFIX + ".create-order.succeeded",

0 commit comments

Comments
 (0)