@lightspeed/online-payments-sdk 1.1.3 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LightspeedPayments = void 0;
3
+ exports.LightspeedPayments = exports.THEME_COLORS = void 0;
4
4
  var v1_1 = require("./v1");
5
+ var v1_2 = require("./v1");
6
+ Object.defineProperty(exports, "THEME_COLORS", { enumerable: true, get: function () { return v1_2.THEME_COLORS; } });
5
7
  exports.LightspeedPayments = {
6
8
  v1: v1_1.v1,
7
9
  };
@@ -6,13 +6,15 @@
6
6
  * Don't use * for exports. Be specific to prevent leaking internal APIs.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.v1 = exports.ProcessingError = exports.InvalidSessionError = exports.InvalidSessionPayloadError = exports.UnsupportedLocationError = void 0;
9
+ exports.v1 = exports.THEME_COLORS = exports.ProcessingError = exports.InvalidSessionError = exports.InvalidSessionPayloadError = exports.UnsupportedLocationError = void 0;
10
10
  var widget_1 = require("./widget");
11
11
  var error_1 = require("./error");
12
12
  Object.defineProperty(exports, "UnsupportedLocationError", { enumerable: true, get: function () { return error_1.UnsupportedLocationError; } });
13
13
  Object.defineProperty(exports, "InvalidSessionPayloadError", { enumerable: true, get: function () { return error_1.InvalidSessionPayloadError; } });
14
14
  Object.defineProperty(exports, "InvalidSessionError", { enumerable: true, get: function () { return error_1.InvalidSessionError; } });
15
15
  Object.defineProperty(exports, "ProcessingError", { enumerable: true, get: function () { return error_1.ProcessingError; } });
16
+ var themes_1 = require("./stripe/themes");
17
+ Object.defineProperty(exports, "THEME_COLORS", { enumerable: true, get: function () { return themes_1.THEME_COLORS; } });
16
18
  exports.v1 = {
17
19
  mountPaymentWidget: widget_1.mountPaymentWidget,
18
20
  };
@@ -60,6 +60,7 @@ var stripe_js_1 = require("@stripe/stripe-js");
60
60
  var ResultBuilder_1 = require("./ResultBuilder");
61
61
  var error_1 = require("../error");
62
62
  var themes_1 = require("./themes");
63
+ var terms_1 = require("./terms");
63
64
  /**
64
65
  * Initialize Stripe with the given context
65
66
  */
@@ -87,15 +88,25 @@ function initStripe(context, theme) {
87
88
  }
88
89
  /**
89
90
  * Create payment element options with default wallet settings
91
+ * @param defaultValues - Default values for the payment element
92
+ * @param theme - Theme configuration
93
+ * @param hideNameField - Whether to hide the billing details name field (used when address element is present to avoid duplicates with ACH)
90
94
  */
91
- function createPaymentElementOptions(defaultValues, theme) {
92
- var options = {
93
- wallets: {
95
+ function createPaymentElementOptions(defaultValues, theme, hideNameField) {
96
+ if (hideNameField === void 0) { hideNameField = false; }
97
+ var options = __assign(__assign({ wallets: {
94
98
  applePay: 'never',
95
99
  googlePay: 'never',
96
100
  link: 'never',
101
+ } }, (hideNameField && {
102
+ fields: {
103
+ billingDetails: {
104
+ name: 'never', // prevent duplicate Name field on the form when using ACH (only when address element is present)
105
+ },
97
106
  },
98
- };
107
+ })), { terms: {
108
+ usBankAccount: 'never', // Hide Stripe's default T&Cs (shown for ACH payments)
109
+ } });
99
110
  if (defaultValues) {
100
111
  options.defaultValues = {
101
112
  billingDetails: {
@@ -132,10 +143,49 @@ function createAddressElementOptions(defaultValues) {
132
143
  }
133
144
  return addressOptions;
134
145
  }
146
+ /**
147
+ * Create custom Terms & Conditions element for US Bank Account payments
148
+ * Styling is defined in lightspeed-global-styles.css
149
+ */
150
+ function createCustomTermsElement() {
151
+ var termsContainer = document.createElement('div');
152
+ termsContainer.className = 'stripe-custom-terms-container';
153
+ termsContainer.style.display = 'none'; // Hidden by default
154
+ var termsText = document.createElement('p');
155
+ termsText.className = 'stripe-custom-terms-text';
156
+ // Build terms HTML with translatable strings
157
+ var stripeTermsLink = "<a href=\"".concat(terms_1.ACH_TERMS_URL.STRIPE_ACH_AUTHORIZATION, "\" target=\"_blank\" rel=\"noopener noreferrer\">").concat(terms_1.ACH_TERMS_TEXT.STRIPE_TERMS_LINK_TEXT, "</a>");
158
+ var expandableToggle = "<span class=\"stripe-expandable-terms-toggle\">".concat(terms_1.ACH_TERMS_TEXT.EXPANDABLE_TERMS_LINK_TEXT, " <span class=\"stripe-terms-triangle\">\u25BC</span></span>");
159
+ termsText.innerHTML = "".concat(terms_1.ACH_TERMS_TEXT.TERMS_PREFIX, " ").concat(stripeTermsLink, " ").concat(terms_1.ACH_TERMS_TEXT.TERMS_CONJUNCTION, " ").concat(expandableToggle);
160
+ // Create expandable terms content
161
+ var expandableContent = document.createElement('div');
162
+ expandableContent.className = 'stripe-expandable-terms-content';
163
+ expandableContent.style.display = 'none';
164
+ expandableContent.innerHTML = "<p>".concat(terms_1.ACH_TERMS_TEXT.EXPANDED_TERMS_CONTENT, "</p>");
165
+ termsContainer.appendChild(termsText);
166
+ termsContainer.appendChild(expandableContent);
167
+ // Add click handler for expandable toggle
168
+ var toggle = termsText.querySelector('.stripe-expandable-terms-toggle');
169
+ var triangle = termsText.querySelector('.stripe-terms-triangle');
170
+ if (toggle && triangle) {
171
+ toggle.addEventListener('click', function (e) {
172
+ e.preventDefault();
173
+ var isExpanded = expandableContent.style.display !== 'none';
174
+ expandableContent.style.display = isExpanded ? 'none' : 'block';
175
+ triangle.textContent = isExpanded ? '▼' : '▲';
176
+ toggle.classList.toggle('expanded', !isExpanded);
177
+ });
178
+ }
179
+ return termsContainer;
180
+ }
135
181
  /**
136
182
  * Create and mount payment element
137
183
  */
138
- function createPaymentElement(elements, options, mountElement, eventBroadcaster) {
184
+ function createPaymentElement(elements, options, mountElement, eventBroadcaster, theme) {
185
+ // Apply theme class to mount element (generic approach)
186
+ if (theme) {
187
+ mountElement.classList.add("lsp-theme-".concat(theme));
188
+ }
139
189
  var paymentElement = elements.create('payment', options);
140
190
  paymentElement.on('ready', function () {
141
191
  return eventBroadcaster.publish({ status: 'Ready', code: 'Ready' });
@@ -144,7 +194,25 @@ function createPaymentElement(elements, options, mountElement, eventBroadcaster)
144
194
  paymentContainer.className = 'stripe-payment-element-container';
145
195
  mountElement.appendChild(paymentContainer);
146
196
  paymentElement.mount(paymentContainer);
147
- return { element: paymentElement, container: paymentContainer };
197
+ // Create custom terms element for US Bank Account
198
+ var customTermsElement = createCustomTermsElement();
199
+ mountElement.appendChild(customTermsElement);
200
+ // Listen for payment method changes to show/hide custom terms
201
+ paymentElement.on('change', function (event) {
202
+ var _a;
203
+ // Show custom terms only when US Bank Account is selected
204
+ if (((_a = event.value) === null || _a === void 0 ? void 0 : _a.type) === 'us_bank_account') {
205
+ customTermsElement.style.display = 'block';
206
+ }
207
+ else {
208
+ customTermsElement.style.display = 'none';
209
+ }
210
+ });
211
+ return {
212
+ element: paymentElement,
213
+ container: paymentContainer,
214
+ customTermsContainer: customTermsElement,
215
+ };
148
216
  }
149
217
  /**
150
218
  * Create and mount address element
@@ -160,7 +228,7 @@ function createAddressElement(elements, options, mountElement) {
160
228
  /**
161
229
  * Clean up elements and containers
162
230
  */
163
- function cleanupElements(paymentElement, addressElement, paymentContainer, addressContainer) {
231
+ function cleanupElements(paymentElement, addressElement, paymentContainer, addressContainer, customTermsContainer) {
164
232
  paymentElement.unmount();
165
233
  if (addressElement) {
166
234
  addressElement.unmount();
@@ -172,24 +240,44 @@ function cleanupElements(paymentElement, addressElement, paymentContainer, addre
172
240
  if (paymentContainer) {
173
241
  paymentContainer.remove();
174
242
  }
243
+ if (customTermsContainer) {
244
+ customTermsContainer.remove();
245
+ }
175
246
  }
176
247
  /**
177
248
  * Handle save card operation
178
249
  */
179
- function handleSaveCard(stripe, elements, session) {
250
+ function handleSaveCard(stripe, elements, session, addressElement) {
180
251
  return __awaiter(this, void 0, void 0, function () {
181
- var _a, error, setupIntent;
182
- return __generator(this, function (_b) {
183
- switch (_b.label) {
184
- case 0: return [4 /*yield*/, stripe.confirmSetup({
185
- elements: elements,
186
- redirect: 'if_required',
187
- confirmParams: {
188
- return_url: session.context.redirectUrl || window.location.href,
189
- },
190
- })];
252
+ var addressValue, _a, billingName, _b, error, setupIntent;
253
+ var _c;
254
+ return __generator(this, function (_d) {
255
+ switch (_d.label) {
256
+ case 0:
257
+ if (!addressElement) return [3 /*break*/, 2];
258
+ return [4 /*yield*/, addressElement.getValue()];
191
259
  case 1:
192
- _a = _b.sent(), error = _a.error, setupIntent = _a.setupIntent;
260
+ _a = _d.sent();
261
+ return [3 /*break*/, 3];
262
+ case 2:
263
+ _a = null;
264
+ _d.label = 3;
265
+ case 3:
266
+ addressValue = _a;
267
+ billingName = (_c = addressValue === null || addressValue === void 0 ? void 0 : addressValue.value) === null || _c === void 0 ? void 0 : _c.name;
268
+ return [4 /*yield*/, stripe.confirmSetup({
269
+ elements: elements,
270
+ redirect: 'if_required',
271
+ confirmParams: __assign({ return_url: session.context.redirectUrl || window.location.href }, (billingName && {
272
+ payment_method_data: {
273
+ billing_details: {
274
+ name: billingName,
275
+ },
276
+ },
277
+ })),
278
+ })];
279
+ case 4:
280
+ _b = _d.sent(), error = _b.error, setupIntent = _b.setupIntent;
193
281
  return [2 /*return*/, error
194
282
  ? ResultBuilder_1.EventBuilder.fromStripeError(error)
195
283
  : ResultBuilder_1.EventBuilder.fromSetupIntent(setupIntent)];
@@ -200,20 +288,37 @@ function handleSaveCard(stripe, elements, session) {
200
288
  /**
201
289
  * Handle payment operation
202
290
  */
203
- function handlePayment(stripe, elements, session) {
291
+ function handlePayment(stripe, elements, session, addressElement) {
204
292
  return __awaiter(this, void 0, void 0, function () {
205
- var _a, error, paymentIntent;
206
- return __generator(this, function (_b) {
207
- switch (_b.label) {
208
- case 0: return [4 /*yield*/, stripe.confirmPayment({
209
- elements: elements,
210
- redirect: 'if_required',
211
- confirmParams: {
212
- return_url: session.context.redirectUrl || window.location.href,
213
- },
214
- })];
293
+ var addressValue, _a, billingName, _b, error, paymentIntent;
294
+ var _c;
295
+ return __generator(this, function (_d) {
296
+ switch (_d.label) {
297
+ case 0:
298
+ if (!addressElement) return [3 /*break*/, 2];
299
+ return [4 /*yield*/, addressElement.getValue()];
215
300
  case 1:
216
- _a = _b.sent(), error = _a.error, paymentIntent = _a.paymentIntent;
301
+ _a = _d.sent();
302
+ return [3 /*break*/, 3];
303
+ case 2:
304
+ _a = null;
305
+ _d.label = 3;
306
+ case 3:
307
+ addressValue = _a;
308
+ billingName = (_c = addressValue === null || addressValue === void 0 ? void 0 : addressValue.value) === null || _c === void 0 ? void 0 : _c.name;
309
+ return [4 /*yield*/, stripe.confirmPayment({
310
+ elements: elements,
311
+ redirect: 'if_required',
312
+ confirmParams: __assign({ return_url: session.context.redirectUrl || window.location.href }, (billingName && {
313
+ payment_method_data: {
314
+ billing_details: {
315
+ name: billingName,
316
+ },
317
+ },
318
+ })),
319
+ })];
320
+ case 4:
321
+ _b = _d.sent(), error = _b.error, paymentIntent = _b.paymentIntent;
217
322
  return [2 /*return*/, error
218
323
  ? ResultBuilder_1.EventBuilder.fromStripeError(error)
219
324
  : ResultBuilder_1.EventBuilder.fromPaymentIntent(paymentIntent)];
@@ -224,7 +329,7 @@ function handlePayment(stripe, elements, session) {
224
329
  /**
225
330
  * Create common submit handler for widgets
226
331
  */
227
- function createSubmitHandler(stripe, elements, session, eventBroadcaster) {
332
+ function createSubmitHandler(stripe, elements, session, eventBroadcaster, addressElement) {
228
333
  var _this = this;
229
334
  return function () { return __awaiter(_this, void 0, void 0, function () {
230
335
  var result;
@@ -244,13 +349,13 @@ function createSubmitHandler(stripe, elements, session, eventBroadcaster) {
244
349
  throw new error_1.InvalidSessionPayloadError();
245
350
  }
246
351
  if (!(session.context.intent === 'save-card')) return [3 /*break*/, 2];
247
- return [4 /*yield*/, handleSaveCard(stripe, elements, session)];
352
+ return [4 /*yield*/, handleSaveCard(stripe, elements, session, addressElement)];
248
353
  case 1:
249
354
  result = _a.sent();
250
355
  _a.label = 2;
251
356
  case 2:
252
357
  if (!(session.context.intent === 'payment')) return [3 /*break*/, 4];
253
- return [4 /*yield*/, handlePayment(stripe, elements, session)];
358
+ return [4 /*yield*/, handlePayment(stripe, elements, session, addressElement)];
254
359
  case 3:
255
360
  result = _a.sent();
256
361
  _a.label = 4;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Translatable strings for Stripe payment elements.
4
+ * These strings are prepared for Transifex extraction.
5
+ *
6
+ * Usage with Transifex:
7
+ * - Extract these strings using Transifex CLI or integration
8
+ * - Replace with translated versions based on locale
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.ACH_TERMS_URL = exports.ACH_TERMS_TEXT = void 0;
12
+ exports.ACH_TERMS_TEXT = {
13
+ /**
14
+ * Main terms text displayed for US Bank Account payments.
15
+ * Contains placeholders for links that will be injected.
16
+ */
17
+ TERMS_PREFIX: 'By submitting your payment, you agree to authorize payments pursuant to',
18
+ STRIPE_TERMS_LINK_TEXT: "Stripe's terms",
19
+ TERMS_CONJUNCTION: 'and',
20
+ EXPANDABLE_TERMS_LINK_TEXT: 'these terms',
21
+ /**
22
+ * Expanded terms content for ACH authorization.
23
+ * This is the detailed legal text shown when user expands "these terms".
24
+ */
25
+ EXPANDED_TERMS_CONTENT: 'By providing your bank account details and confirming this payment, you authorize the merchant to debit your account for the amount shown. If you choose to save your bank account for future payments, this authorization will also apply to any future amounts owed for products or services provided by the merchant, until you cancel it. You also authorize the merchant to credit your account as necessary to correct any erroneous debits. You may revoke authorization at any time by contacting the merchant, allowing up to thirty (30) days for processing. You confirm that you are an authorized signer on the account and that sufficient funds will be available for each payment. ACH payments may take up to five (5) business days to complete, and you may be responsible for fees if a payment is returned.',
26
+ };
27
+ exports.ACH_TERMS_URL = {
28
+ STRIPE_ACH_AUTHORIZATION: 'https://stripe.com/legal/ach-payments/authorization',
29
+ };
@@ -1,6 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.THEME_COLORS = void 0;
3
4
  exports.getThemeConfig = getThemeConfig;
5
+ /**
6
+ * Theme color constants for styling containers
7
+ * Use these to match the SDK's dark theme colors in your application
8
+ */
9
+ exports.THEME_COLORS = {
10
+ DARK: {
11
+ BACKGROUND: '#1a1a1a',
12
+ TEXT: '#ffffff',
13
+ },
14
+ };
15
+ /**
16
+ * ID for the injected theme stylesheet element
17
+ */
18
+ var THEME_STYLESHEET_ID = 'lsp-theme-styles';
19
+ /**
20
+ * Inject theme stylesheets into the document head
21
+ * Each theme can define its own container styling
22
+ */
23
+ function ensureThemeStylesheet() {
24
+ if (document.getElementById(THEME_STYLESHEET_ID)) {
25
+ return;
26
+ }
27
+ var styleElement = document.createElement('style');
28
+ styleElement.id = THEME_STYLESHEET_ID;
29
+ styleElement.textContent = "\n /* Dark theme styles for the mount element */\n .lsp-theme-dark {\n background-color: ".concat(exports.THEME_COLORS.DARK.BACKGROUND, " !important;\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n /* Dark theme styles for Stripe custom terms elements */\n .lsp-theme-dark .stripe-terms-triangle {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-custom-terms-text {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-expandable-terms-content p {\n color: ").concat(exports.THEME_COLORS.DARK.TEXT, " !important;\n }\n \n /* Invoicing theme - no container styling needed */\n /* .lsp-theme-invoicing { } */\n ");
30
+ document.head.appendChild(styleElement);
31
+ }
4
32
  /**
5
33
  * Get theme configuration based on theme name
6
34
  */
@@ -37,6 +65,18 @@ function getThemeConfig(theme) {
37
65
  type: 'tabs',
38
66
  },
39
67
  };
68
+ case 'dark':
69
+ // Ensure theme stylesheet is injected
70
+ ensureThemeStylesheet();
71
+ return {
72
+ appearance: {
73
+ theme: 'night',
74
+ },
75
+ fonts: [],
76
+ layout: {
77
+ type: 'tabs',
78
+ },
79
+ };
40
80
  default:
41
81
  return undefined;
42
82
  }
@@ -45,22 +45,52 @@ var moto_1 = require("./widgets/moto");
45
45
  */
46
46
  function mount(mountElement, session, eventBroadcaster, defaultValues, theme) {
47
47
  return __awaiter(this, void 0, void 0, function () {
48
- var sessionType;
49
- return __generator(this, function (_a) {
50
- sessionType = session.metadata.sessionType;
51
- // Route to appropriate widget based on session type
52
- switch (sessionType) {
53
- case 'payment':
54
- case 'payment-with-save':
55
- return [2 /*return*/, (0, payment_1.mountPaymentWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
56
- case 'moto':
57
- case 'moto-with-save':
58
- case 'save':
59
- return [2 /*return*/, (0, moto_1.mountMotoWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
60
- default:
61
- throw new Error("Unsupported session type: ".concat(sessionType));
48
+ var sessionType, widgetController, _a, originalUnmount_1, error_1;
49
+ return __generator(this, function (_b) {
50
+ switch (_b.label) {
51
+ case 0:
52
+ sessionType = session.metadata.sessionType;
53
+ _b.label = 1;
54
+ case 1:
55
+ _b.trys.push([1, 8, , 9]);
56
+ widgetController = void 0;
57
+ _a = sessionType;
58
+ switch (_a) {
59
+ case 'payment': return [3 /*break*/, 2];
60
+ case 'payment-with-save': return [3 /*break*/, 2];
61
+ case 'moto': return [3 /*break*/, 4];
62
+ case 'moto-with-save': return [3 /*break*/, 4];
63
+ case 'save': return [3 /*break*/, 4];
64
+ }
65
+ return [3 /*break*/, 6];
66
+ case 2: return [4 /*yield*/, (0, payment_1.mountPaymentWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
67
+ case 3:
68
+ widgetController = _b.sent();
69
+ return [3 /*break*/, 7];
70
+ case 4: return [4 /*yield*/, (0, moto_1.mountMotoWidget)(mountElement, session, eventBroadcaster, defaultValues, theme)];
71
+ case 5:
72
+ widgetController = _b.sent();
73
+ return [3 /*break*/, 7];
74
+ case 6: throw new Error("Unsupported session type: ".concat(sessionType));
75
+ case 7:
76
+ originalUnmount_1 = widgetController.unmount;
77
+ widgetController.unmount = function () {
78
+ // Remove theme class on unmount (generic cleanup)
79
+ if (theme) {
80
+ mountElement.classList.remove("lsp-theme-".concat(theme));
81
+ }
82
+ originalUnmount_1();
83
+ };
84
+ return [2 /*return*/, widgetController];
85
+ case 8:
86
+ error_1 = _b.sent();
87
+ // Clean up theme class if mounting fails
88
+ if (theme) {
89
+ mountElement.classList.remove("lsp-theme-".concat(theme));
90
+ }
91
+ throw error_1;
92
+ case 9: return [2 /*return*/];
62
93
  }
63
- return [2 /*return*/];
64
94
  });
65
95
  });
66
96
  }
@@ -44,19 +44,19 @@ var shared_1 = require("../shared");
44
44
  */
45
45
  function mountMotoWidget(mountElement, session, eventBroadcaster, defaultValues, theme) {
46
46
  return __awaiter(this, void 0, void 0, function () {
47
- var _a, stripe, elements, paymentOptions, _b, paymentElement, paymentContainer;
47
+ var _a, stripe, elements, paymentOptions, _b, paymentElement, paymentContainer, customTermsContainer;
48
48
  return __generator(this, function (_c) {
49
49
  switch (_c.label) {
50
50
  case 0: return [4 /*yield*/, (0, shared_1.initStripe)(session.context, theme)];
51
51
  case 1:
52
52
  _a = _c.sent(), stripe = _a.stripe, elements = _a.elements;
53
53
  paymentOptions = (0, shared_1.createPaymentElementOptions)(defaultValues, theme);
54
- _b = (0, shared_1.createPaymentElement)(elements, paymentOptions, mountElement, eventBroadcaster), paymentElement = _b.element, paymentContainer = _b.container;
54
+ _b = (0, shared_1.createPaymentElement)(elements, paymentOptions, mountElement, eventBroadcaster, theme), paymentElement = _b.element, paymentContainer = _b.container, customTermsContainer = _b.customTermsContainer;
55
55
  return [2 /*return*/, {
56
56
  unmount: function () {
57
- (0, shared_1.cleanupElements)(paymentElement, null, paymentContainer, null);
57
+ (0, shared_1.cleanupElements)(paymentElement, null, paymentContainer, null, customTermsContainer);
58
58
  },
59
- submit: (0, shared_1.createSubmitHandler)(stripe, elements, session, eventBroadcaster),
59
+ submit: (0, shared_1.createSubmitHandler)(stripe, elements, session, eventBroadcaster, null),
60
60
  }];
61
61
  }
62
62
  });
@@ -43,7 +43,7 @@ var shared_1 = require("../shared");
43
43
  */
44
44
  function mountPaymentWidget(mountElement, session, eventBroadcaster, defaultValues, theme) {
45
45
  return __awaiter(this, void 0, void 0, function () {
46
- var _a, stripe, elements, addressOptions, _b, addressElement, addressContainer, paymentOptions, _c, paymentElement, paymentContainer;
46
+ var _a, stripe, elements, addressOptions, _b, addressElement, addressContainer, paymentOptions, _c, paymentElement, paymentContainer, customTermsContainer;
47
47
  return __generator(this, function (_d) {
48
48
  switch (_d.label) {
49
49
  case 0: return [4 /*yield*/, (0, shared_1.initStripe)(session.context, theme)];
@@ -51,13 +51,13 @@ function mountPaymentWidget(mountElement, session, eventBroadcaster, defaultValu
51
51
  _a = _d.sent(), stripe = _a.stripe, elements = _a.elements;
52
52
  addressOptions = (0, shared_1.createAddressElementOptions)(defaultValues);
53
53
  _b = (0, shared_1.createAddressElement)(elements, addressOptions, mountElement), addressElement = _b.element, addressContainer = _b.container;
54
- paymentOptions = (0, shared_1.createPaymentElementOptions)(defaultValues, theme);
55
- _c = (0, shared_1.createPaymentElement)(elements, paymentOptions, mountElement, eventBroadcaster), paymentElement = _c.element, paymentContainer = _c.container;
54
+ paymentOptions = (0, shared_1.createPaymentElementOptions)(defaultValues, theme, true);
55
+ _c = (0, shared_1.createPaymentElement)(elements, paymentOptions, mountElement, eventBroadcaster, theme), paymentElement = _c.element, paymentContainer = _c.container, customTermsContainer = _c.customTermsContainer;
56
56
  return [2 /*return*/, {
57
57
  unmount: function () {
58
- (0, shared_1.cleanupElements)(paymentElement, addressElement, paymentContainer, addressContainer);
58
+ (0, shared_1.cleanupElements)(paymentElement, addressElement, paymentContainer, addressContainer, customTermsContainer);
59
59
  },
60
- submit: (0, shared_1.createSubmitHandler)(stripe, elements, session, eventBroadcaster),
60
+ submit: (0, shared_1.createSubmitHandler)(stripe, elements, session, eventBroadcaster, addressElement),
61
61
  }];
62
62
  }
63
63
  });
@@ -46,7 +46,7 @@ var common_1 = require("./logging/common");
46
46
  var EventBroadcaster_1 = require("./EventBroadcaster");
47
47
  function mountPaymentWidget(session, config) {
48
48
  return __awaiter(this, void 0, void 0, function () {
49
- var eventBroadcaster, decodedSession, logger_2, widgetController, _a, error_2;
49
+ var eventBroadcaster, decodedSession, logger_2, configSummary, widgetController, _a, error_2;
50
50
  return __generator(this, function (_b) {
51
51
  switch (_b.label) {
52
52
  case 0:
@@ -62,7 +62,12 @@ function mountPaymentWidget(session, config) {
62
62
  logger_2.log('info', event.status, { event: event });
63
63
  return event;
64
64
  });
65
- logger_2.log('info', 'Mount');
65
+ configSummary = {
66
+ theme: config.theme || 'none',
67
+ listeners: config.listeners ? Object.keys(config.listeners) : [],
68
+ defaultValues: config.defaultValues ? Object.keys(config.defaultValues) : undefined,
69
+ };
70
+ logger_2.log('info', 'Mount', { configuration: configSummary });
66
71
  widgetController = void 0;
67
72
  _a = decodedSession.psp;
68
73
  switch (_a) {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export type * from './v1';
2
+ export { THEME_COLORS } from './v1';
2
3
  export declare const LightspeedPayments: {
3
4
  v1: import("./v1").LightspeedPaymentsV1;
4
5
  };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { v1 } from './v1';
2
+ export { THEME_COLORS } from './v1';
2
3
  export var LightspeedPayments = {
3
4
  v1: v1,
4
5
  };
@@ -10,6 +10,7 @@ export type { WidgetController, SessionType, DefaultValues } from './common';
10
10
  export type { Event } from './EventBroadcaster';
11
11
  export { UnsupportedLocationError, InvalidSessionPayloadError, InvalidSessionError, ProcessingError, } from './error';
12
12
  export type { PaymentWidgetConfiguration, PaymentWidgetTheme } from './widget';
13
+ export { THEME_COLORS } from './stripe/themes';
13
14
  export type LightspeedPaymentsV1 = {
14
15
  /**
15
16
  * Mounts the payment widget to the specified mount point.
package/dist/v1/index.js CHANGED
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import { mountPaymentWidget } from './widget';
8
8
  export { UnsupportedLocationError, InvalidSessionPayloadError, InvalidSessionError, ProcessingError, } from './error';
9
+ export { THEME_COLORS } from './stripe/themes';
9
10
  export var v1 = {
10
11
  mountPaymentWidget: mountPaymentWidget,
11
12
  };
@@ -18,8 +18,11 @@ export interface ElementContainers {
18
18
  export declare function initStripe(context: StripeContext, theme?: PaymentWidgetTheme): Promise<StripeInitResult>;
19
19
  /**
20
20
  * Create payment element options with default wallet settings
21
+ * @param defaultValues - Default values for the payment element
22
+ * @param theme - Theme configuration
23
+ * @param hideNameField - Whether to hide the billing details name field (used when address element is present to avoid duplicates with ACH)
21
24
  */
22
- export declare function createPaymentElementOptions(defaultValues?: DefaultValues, theme?: PaymentWidgetTheme): StripePaymentElementOptions;
25
+ export declare function createPaymentElementOptions(defaultValues?: DefaultValues, theme?: PaymentWidgetTheme, hideNameField?: boolean): StripePaymentElementOptions;
23
26
  /**
24
27
  * Create address element options
25
28
  */
@@ -27,9 +30,10 @@ export declare function createAddressElementOptions(defaultValues?: DefaultValue
27
30
  /**
28
31
  * Create and mount payment element
29
32
  */
30
- export declare function createPaymentElement(elements: StripeElements, options: StripePaymentElementOptions, mountElement: HTMLElement, eventBroadcaster: EventBroadcaster): {
33
+ export declare function createPaymentElement(elements: StripeElements, options: StripePaymentElementOptions, mountElement: HTMLElement, eventBroadcaster: EventBroadcaster, theme?: PaymentWidgetTheme): {
31
34
  element: StripePaymentElement;
32
35
  container: HTMLElement;
36
+ customTermsContainer: HTMLElement;
33
37
  };
34
38
  /**
35
39
  * Create and mount address element
@@ -41,16 +45,16 @@ export declare function createAddressElement(elements: StripeElements, options:
41
45
  /**
42
46
  * Clean up elements and containers
43
47
  */
44
- export declare function cleanupElements(paymentElement: StripePaymentElement, addressElement: StripeAddressElement | null, paymentContainer: HTMLElement, addressContainer: HTMLElement | null): void;
48
+ export declare function cleanupElements(paymentElement: StripePaymentElement, addressElement: StripeAddressElement | null, paymentContainer: HTMLElement, addressContainer: HTMLElement | null, customTermsContainer?: HTMLElement): void;
45
49
  /**
46
50
  * Handle save card operation
47
51
  */
48
- export declare function handleSaveCard(stripe: Stripe, elements: StripeElements, session: StripeSession): Promise<import("../EventBroadcaster").SucceededResultEvent | import("../EventBroadcaster").PendingResultEvent | import("../EventBroadcaster").DeclinedResultEvent | import("../EventBroadcaster").ErrorResultEvent>;
52
+ export declare function handleSaveCard(stripe: Stripe, elements: StripeElements, session: StripeSession, addressElement?: StripeAddressElement | null): Promise<import("../EventBroadcaster").SucceededResultEvent | import("../EventBroadcaster").PendingResultEvent | import("../EventBroadcaster").DeclinedResultEvent | import("../EventBroadcaster").ErrorResultEvent>;
49
53
  /**
50
54
  * Handle payment operation
51
55
  */
52
- export declare function handlePayment(stripe: Stripe, elements: StripeElements, session: StripeSession): Promise<import("../EventBroadcaster").SucceededResultEvent | import("../EventBroadcaster").PendingResultEvent | import("../EventBroadcaster").DeclinedResultEvent | import("../EventBroadcaster").ErrorResultEvent>;
56
+ export declare function handlePayment(stripe: Stripe, elements: StripeElements, session: StripeSession, addressElement?: StripeAddressElement | null): Promise<import("../EventBroadcaster").SucceededResultEvent | import("../EventBroadcaster").PendingResultEvent | import("../EventBroadcaster").DeclinedResultEvent | import("../EventBroadcaster").ErrorResultEvent>;
53
57
  /**
54
58
  * Create common submit handler for widgets
55
59
  */
56
- export declare function createSubmitHandler(stripe: Stripe, elements: StripeElements, session: StripeSession, eventBroadcaster: EventBroadcaster): () => Promise<import("../EventBroadcaster").SucceededResultEvent | import("../EventBroadcaster").PendingResultEvent | import("../EventBroadcaster").DeclinedResultEvent | import("../EventBroadcaster").ErrorResultEvent>;
60
+ export declare function createSubmitHandler(stripe: Stripe, elements: StripeElements, session: StripeSession, eventBroadcaster: EventBroadcaster, addressElement?: StripeAddressElement | null): () => Promise<import("../EventBroadcaster").SucceededResultEvent | import("../EventBroadcaster").PendingResultEvent | import("../EventBroadcaster").DeclinedResultEvent | import("../EventBroadcaster").ErrorResultEvent>;
@@ -49,6 +49,7 @@ import { loadStripe, } from '@stripe/stripe-js';
49
49
  import { EventBuilder } from './ResultBuilder';
50
50
  import { InvalidSessionPayloadError, ProcessingError } from '../error';
51
51
  import { getThemeConfig } from './themes';
52
+ import { ACH_TERMS_TEXT, ACH_TERMS_URL } from './terms';
52
53
  /**
53
54
  * Initialize Stripe with the given context
54
55
  */
@@ -76,15 +77,25 @@ export function initStripe(context, theme) {
76
77
  }
77
78
  /**
78
79
  * Create payment element options with default wallet settings
80
+ * @param defaultValues - Default values for the payment element
81
+ * @param theme - Theme configuration
82
+ * @param hideNameField - Whether to hide the billing details name field (used when address element is present to avoid duplicates with ACH)
79
83
  */
80
- export function createPaymentElementOptions(defaultValues, theme) {
81
- var options = {
82
- wallets: {
84
+ export function createPaymentElementOptions(defaultValues, theme, hideNameField) {
85
+ if (hideNameField === void 0) { hideNameField = false; }
86
+ var options = __assign(__assign({ wallets: {
83
87
  applePay: 'never',
84
88
  googlePay: 'never',
85
89
  link: 'never',
90
+ } }, (hideNameField && {
91
+ fields: {
92
+ billingDetails: {
93
+ name: 'never', // prevent duplicate Name field on the form when using ACH (only when address element is present)
94
+ },
86
95
  },
87
- };
96
+ })), { terms: {
97
+ usBankAccount: 'never', // Hide Stripe's default T&Cs (shown for ACH payments)
98
+ } });
88
99
  if (defaultValues) {
89
100
  options.defaultValues = {
90
101
  billingDetails: {
@@ -121,10 +132,49 @@ export function createAddressElementOptions(defaultValues) {
121
132
  }
122
133
  return addressOptions;
123
134
  }
135
+ /**
136
+ * Create custom Terms & Conditions element for US Bank Account payments
137
+ * Styling is defined in lightspeed-global-styles.css
138
+ */
139
+ function createCustomTermsElement() {
140
+ var termsContainer = document.createElement('div');
141
+ termsContainer.className = 'stripe-custom-terms-container';
142
+ termsContainer.style.display = 'none'; // Hidden by default
143
+ var termsText = document.createElement('p');
144
+ termsText.className = 'stripe-custom-terms-text';
145
+ // Build terms HTML with translatable strings
146
+ var stripeTermsLink = "<a href=\"".concat(ACH_TERMS_URL.STRIPE_ACH_AUTHORIZATION, "\" target=\"_blank\" rel=\"noopener noreferrer\">").concat(ACH_TERMS_TEXT.STRIPE_TERMS_LINK_TEXT, "</a>");
147
+ var expandableToggle = "<span class=\"stripe-expandable-terms-toggle\">".concat(ACH_TERMS_TEXT.EXPANDABLE_TERMS_LINK_TEXT, " <span class=\"stripe-terms-triangle\">\u25BC</span></span>");
148
+ termsText.innerHTML = "".concat(ACH_TERMS_TEXT.TERMS_PREFIX, " ").concat(stripeTermsLink, " ").concat(ACH_TERMS_TEXT.TERMS_CONJUNCTION, " ").concat(expandableToggle);
149
+ // Create expandable terms content
150
+ var expandableContent = document.createElement('div');
151
+ expandableContent.className = 'stripe-expandable-terms-content';
152
+ expandableContent.style.display = 'none';
153
+ expandableContent.innerHTML = "<p>".concat(ACH_TERMS_TEXT.EXPANDED_TERMS_CONTENT, "</p>");
154
+ termsContainer.appendChild(termsText);
155
+ termsContainer.appendChild(expandableContent);
156
+ // Add click handler for expandable toggle
157
+ var toggle = termsText.querySelector('.stripe-expandable-terms-toggle');
158
+ var triangle = termsText.querySelector('.stripe-terms-triangle');
159
+ if (toggle && triangle) {
160
+ toggle.addEventListener('click', function (e) {
161
+ e.preventDefault();
162
+ var isExpanded = expandableContent.style.display !== 'none';
163
+ expandableContent.style.display = isExpanded ? 'none' : 'block';
164
+ triangle.textContent = isExpanded ? '▼' : '▲';
165
+ toggle.classList.toggle('expanded', !isExpanded);
166
+ });
167
+ }
168
+ return termsContainer;
169
+ }
124
170
  /**
125
171
  * Create and mount payment element
126
172
  */
127
- export function createPaymentElement(elements, options, mountElement, eventBroadcaster) {
173
+ export function createPaymentElement(elements, options, mountElement, eventBroadcaster, theme) {
174
+ // Apply theme class to mount element (generic approach)
175
+ if (theme) {
176
+ mountElement.classList.add("lsp-theme-".concat(theme));
177
+ }
128
178
  var paymentElement = elements.create('payment', options);
129
179
  paymentElement.on('ready', function () {
130
180
  return eventBroadcaster.publish({ status: 'Ready', code: 'Ready' });
@@ -133,7 +183,25 @@ export function createPaymentElement(elements, options, mountElement, eventBroad
133
183
  paymentContainer.className = 'stripe-payment-element-container';
134
184
  mountElement.appendChild(paymentContainer);
135
185
  paymentElement.mount(paymentContainer);
136
- return { element: paymentElement, container: paymentContainer };
186
+ // Create custom terms element for US Bank Account
187
+ var customTermsElement = createCustomTermsElement();
188
+ mountElement.appendChild(customTermsElement);
189
+ // Listen for payment method changes to show/hide custom terms
190
+ paymentElement.on('change', function (event) {
191
+ var _a;
192
+ // Show custom terms only when US Bank Account is selected
193
+ if (((_a = event.value) === null || _a === void 0 ? void 0 : _a.type) === 'us_bank_account') {
194
+ customTermsElement.style.display = 'block';
195
+ }
196
+ else {
197
+ customTermsElement.style.display = 'none';
198
+ }
199
+ });
200
+ return {
201
+ element: paymentElement,
202
+ container: paymentContainer,
203
+ customTermsContainer: customTermsElement,
204
+ };
137
205
  }
138
206
  /**
139
207
  * Create and mount address element
@@ -149,7 +217,7 @@ export function createAddressElement(elements, options, mountElement) {
149
217
  /**
150
218
  * Clean up elements and containers
151
219
  */
152
- export function cleanupElements(paymentElement, addressElement, paymentContainer, addressContainer) {
220
+ export function cleanupElements(paymentElement, addressElement, paymentContainer, addressContainer, customTermsContainer) {
153
221
  paymentElement.unmount();
154
222
  if (addressElement) {
155
223
  addressElement.unmount();
@@ -161,24 +229,44 @@ export function cleanupElements(paymentElement, addressElement, paymentContainer
161
229
  if (paymentContainer) {
162
230
  paymentContainer.remove();
163
231
  }
232
+ if (customTermsContainer) {
233
+ customTermsContainer.remove();
234
+ }
164
235
  }
165
236
  /**
166
237
  * Handle save card operation
167
238
  */
168
- export function handleSaveCard(stripe, elements, session) {
239
+ export function handleSaveCard(stripe, elements, session, addressElement) {
169
240
  return __awaiter(this, void 0, void 0, function () {
170
- var _a, error, setupIntent;
171
- return __generator(this, function (_b) {
172
- switch (_b.label) {
173
- case 0: return [4 /*yield*/, stripe.confirmSetup({
174
- elements: elements,
175
- redirect: 'if_required',
176
- confirmParams: {
177
- return_url: session.context.redirectUrl || window.location.href,
178
- },
179
- })];
241
+ var addressValue, _a, billingName, _b, error, setupIntent;
242
+ var _c;
243
+ return __generator(this, function (_d) {
244
+ switch (_d.label) {
245
+ case 0:
246
+ if (!addressElement) return [3 /*break*/, 2];
247
+ return [4 /*yield*/, addressElement.getValue()];
180
248
  case 1:
181
- _a = _b.sent(), error = _a.error, setupIntent = _a.setupIntent;
249
+ _a = _d.sent();
250
+ return [3 /*break*/, 3];
251
+ case 2:
252
+ _a = null;
253
+ _d.label = 3;
254
+ case 3:
255
+ addressValue = _a;
256
+ billingName = (_c = addressValue === null || addressValue === void 0 ? void 0 : addressValue.value) === null || _c === void 0 ? void 0 : _c.name;
257
+ return [4 /*yield*/, stripe.confirmSetup({
258
+ elements: elements,
259
+ redirect: 'if_required',
260
+ confirmParams: __assign({ return_url: session.context.redirectUrl || window.location.href }, (billingName && {
261
+ payment_method_data: {
262
+ billing_details: {
263
+ name: billingName,
264
+ },
265
+ },
266
+ })),
267
+ })];
268
+ case 4:
269
+ _b = _d.sent(), error = _b.error, setupIntent = _b.setupIntent;
182
270
  return [2 /*return*/, error
183
271
  ? EventBuilder.fromStripeError(error)
184
272
  : EventBuilder.fromSetupIntent(setupIntent)];
@@ -189,20 +277,37 @@ export function handleSaveCard(stripe, elements, session) {
189
277
  /**
190
278
  * Handle payment operation
191
279
  */
192
- export function handlePayment(stripe, elements, session) {
280
+ export function handlePayment(stripe, elements, session, addressElement) {
193
281
  return __awaiter(this, void 0, void 0, function () {
194
- var _a, error, paymentIntent;
195
- return __generator(this, function (_b) {
196
- switch (_b.label) {
197
- case 0: return [4 /*yield*/, stripe.confirmPayment({
198
- elements: elements,
199
- redirect: 'if_required',
200
- confirmParams: {
201
- return_url: session.context.redirectUrl || window.location.href,
202
- },
203
- })];
282
+ var addressValue, _a, billingName, _b, error, paymentIntent;
283
+ var _c;
284
+ return __generator(this, function (_d) {
285
+ switch (_d.label) {
286
+ case 0:
287
+ if (!addressElement) return [3 /*break*/, 2];
288
+ return [4 /*yield*/, addressElement.getValue()];
204
289
  case 1:
205
- _a = _b.sent(), error = _a.error, paymentIntent = _a.paymentIntent;
290
+ _a = _d.sent();
291
+ return [3 /*break*/, 3];
292
+ case 2:
293
+ _a = null;
294
+ _d.label = 3;
295
+ case 3:
296
+ addressValue = _a;
297
+ billingName = (_c = addressValue === null || addressValue === void 0 ? void 0 : addressValue.value) === null || _c === void 0 ? void 0 : _c.name;
298
+ return [4 /*yield*/, stripe.confirmPayment({
299
+ elements: elements,
300
+ redirect: 'if_required',
301
+ confirmParams: __assign({ return_url: session.context.redirectUrl || window.location.href }, (billingName && {
302
+ payment_method_data: {
303
+ billing_details: {
304
+ name: billingName,
305
+ },
306
+ },
307
+ })),
308
+ })];
309
+ case 4:
310
+ _b = _d.sent(), error = _b.error, paymentIntent = _b.paymentIntent;
206
311
  return [2 /*return*/, error
207
312
  ? EventBuilder.fromStripeError(error)
208
313
  : EventBuilder.fromPaymentIntent(paymentIntent)];
@@ -213,7 +318,7 @@ export function handlePayment(stripe, elements, session) {
213
318
  /**
214
319
  * Create common submit handler for widgets
215
320
  */
216
- export function createSubmitHandler(stripe, elements, session, eventBroadcaster) {
321
+ export function createSubmitHandler(stripe, elements, session, eventBroadcaster, addressElement) {
217
322
  var _this = this;
218
323
  return function () { return __awaiter(_this, void 0, void 0, function () {
219
324
  var result;
@@ -233,13 +338,13 @@ export function createSubmitHandler(stripe, elements, session, eventBroadcaster)
233
338
  throw new InvalidSessionPayloadError();
234
339
  }
235
340
  if (!(session.context.intent === 'save-card')) return [3 /*break*/, 2];
236
- return [4 /*yield*/, handleSaveCard(stripe, elements, session)];
341
+ return [4 /*yield*/, handleSaveCard(stripe, elements, session, addressElement)];
237
342
  case 1:
238
343
  result = _a.sent();
239
344
  _a.label = 2;
240
345
  case 2:
241
346
  if (!(session.context.intent === 'payment')) return [3 /*break*/, 4];
242
- return [4 /*yield*/, handlePayment(stripe, elements, session)];
347
+ return [4 /*yield*/, handlePayment(stripe, elements, session, addressElement)];
243
348
  case 3:
244
349
  result = _a.sent();
245
350
  _a.label = 4;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Translatable strings for Stripe payment elements.
3
+ * These strings are prepared for Transifex extraction.
4
+ *
5
+ * Usage with Transifex:
6
+ * - Extract these strings using Transifex CLI or integration
7
+ * - Replace with translated versions based on locale
8
+ */
9
+ export declare const ACH_TERMS_TEXT: {
10
+ /**
11
+ * Main terms text displayed for US Bank Account payments.
12
+ * Contains placeholders for links that will be injected.
13
+ */
14
+ readonly TERMS_PREFIX: "By submitting your payment, you agree to authorize payments pursuant to";
15
+ readonly STRIPE_TERMS_LINK_TEXT: "Stripe's terms";
16
+ readonly TERMS_CONJUNCTION: "and";
17
+ readonly EXPANDABLE_TERMS_LINK_TEXT: "these terms";
18
+ /**
19
+ * Expanded terms content for ACH authorization.
20
+ * This is the detailed legal text shown when user expands "these terms".
21
+ */
22
+ readonly EXPANDED_TERMS_CONTENT: "By providing your bank account details and confirming this payment, you authorize the merchant to debit your account for the amount shown. If you choose to save your bank account for future payments, this authorization will also apply to any future amounts owed for products or services provided by the merchant, until you cancel it. You also authorize the merchant to credit your account as necessary to correct any erroneous debits. You may revoke authorization at any time by contacting the merchant, allowing up to thirty (30) days for processing. You confirm that you are an authorized signer on the account and that sufficient funds will be available for each payment. ACH payments may take up to five (5) business days to complete, and you may be responsible for fees if a payment is returned.";
23
+ };
24
+ export declare const ACH_TERMS_URL: {
25
+ readonly STRIPE_ACH_AUTHORIZATION: "https://stripe.com/legal/ach-payments/authorization";
26
+ };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Translatable strings for Stripe payment elements.
3
+ * These strings are prepared for Transifex extraction.
4
+ *
5
+ * Usage with Transifex:
6
+ * - Extract these strings using Transifex CLI or integration
7
+ * - Replace with translated versions based on locale
8
+ */
9
+ export var ACH_TERMS_TEXT = {
10
+ /**
11
+ * Main terms text displayed for US Bank Account payments.
12
+ * Contains placeholders for links that will be injected.
13
+ */
14
+ TERMS_PREFIX: 'By submitting your payment, you agree to authorize payments pursuant to',
15
+ STRIPE_TERMS_LINK_TEXT: "Stripe's terms",
16
+ TERMS_CONJUNCTION: 'and',
17
+ EXPANDABLE_TERMS_LINK_TEXT: 'these terms',
18
+ /**
19
+ * Expanded terms content for ACH authorization.
20
+ * This is the detailed legal text shown when user expands "these terms".
21
+ */
22
+ EXPANDED_TERMS_CONTENT: 'By providing your bank account details and confirming this payment, you authorize the merchant to debit your account for the amount shown. If you choose to save your bank account for future payments, this authorization will also apply to any future amounts owed for products or services provided by the merchant, until you cancel it. You also authorize the merchant to credit your account as necessary to correct any erroneous debits. You may revoke authorization at any time by contacting the merchant, allowing up to thirty (30) days for processing. You confirm that you are an authorized signer on the account and that sufficient funds will be available for each payment. ACH payments may take up to five (5) business days to complete, and you may be responsible for fees if a payment is returned.',
23
+ };
24
+ export var ACH_TERMS_URL = {
25
+ STRIPE_ACH_AUTHORIZATION: 'https://stripe.com/legal/ach-payments/authorization',
26
+ };
@@ -1,5 +1,15 @@
1
1
  import type { Appearance } from '@stripe/stripe-js';
2
2
  import { PaymentWidgetTheme } from '../widget';
3
+ /**
4
+ * Theme color constants for styling containers
5
+ * Use these to match the SDK's dark theme colors in your application
6
+ */
7
+ export declare const THEME_COLORS: {
8
+ readonly DARK: {
9
+ readonly BACKGROUND: "#1a1a1a";
10
+ readonly TEXT: "#ffffff";
11
+ };
12
+ };
3
13
  /**
4
14
  * Theme configuration for Stripe Elements appearance
5
15
  */
@@ -1,3 +1,30 @@
1
+ /**
2
+ * Theme color constants for styling containers
3
+ * Use these to match the SDK's dark theme colors in your application
4
+ */
5
+ export var THEME_COLORS = {
6
+ DARK: {
7
+ BACKGROUND: '#1a1a1a',
8
+ TEXT: '#ffffff',
9
+ },
10
+ };
11
+ /**
12
+ * ID for the injected theme stylesheet element
13
+ */
14
+ var THEME_STYLESHEET_ID = 'lsp-theme-styles';
15
+ /**
16
+ * Inject theme stylesheets into the document head
17
+ * Each theme can define its own container styling
18
+ */
19
+ function ensureThemeStylesheet() {
20
+ if (document.getElementById(THEME_STYLESHEET_ID)) {
21
+ return;
22
+ }
23
+ var styleElement = document.createElement('style');
24
+ styleElement.id = THEME_STYLESHEET_ID;
25
+ styleElement.textContent = "\n /* Dark theme styles for the mount element */\n .lsp-theme-dark {\n background-color: ".concat(THEME_COLORS.DARK.BACKGROUND, " !important;\n color: ").concat(THEME_COLORS.DARK.TEXT, " !important;\n }\n /* Dark theme styles for Stripe custom terms elements */\n .lsp-theme-dark .stripe-terms-triangle {\n color: ").concat(THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-custom-terms-text {\n color: ").concat(THEME_COLORS.DARK.TEXT, " !important;\n }\n .lsp-theme-dark .stripe-expandable-terms-content p {\n color: ").concat(THEME_COLORS.DARK.TEXT, " !important;\n }\n \n /* Invoicing theme - no container styling needed */\n /* .lsp-theme-invoicing { } */\n ");
26
+ document.head.appendChild(styleElement);
27
+ }
1
28
  /**
2
29
  * Get theme configuration based on theme name
3
30
  */
@@ -34,6 +61,18 @@ export function getThemeConfig(theme) {
34
61
  type: 'tabs',
35
62
  },
36
63
  };
64
+ case 'dark':
65
+ // Ensure theme stylesheet is injected
66
+ ensureThemeStylesheet();
67
+ return {
68
+ appearance: {
69
+ theme: 'night',
70
+ },
71
+ fonts: [],
72
+ layout: {
73
+ type: 'tabs',
74
+ },
75
+ };
37
76
  default:
38
77
  return undefined;
39
78
  }
@@ -41,22 +41,52 @@ import { mountMotoWidget } from './widgets/moto';
41
41
  */
42
42
  export function mount(mountElement, session, eventBroadcaster, defaultValues, theme) {
43
43
  return __awaiter(this, void 0, void 0, function () {
44
- var sessionType;
45
- return __generator(this, function (_a) {
46
- sessionType = session.metadata.sessionType;
47
- // Route to appropriate widget based on session type
48
- switch (sessionType) {
49
- case 'payment':
50
- case 'payment-with-save':
51
- return [2 /*return*/, mountPaymentWidget(mountElement, session, eventBroadcaster, defaultValues, theme)];
52
- case 'moto':
53
- case 'moto-with-save':
54
- case 'save':
55
- return [2 /*return*/, mountMotoWidget(mountElement, session, eventBroadcaster, defaultValues, theme)];
56
- default:
57
- throw new Error("Unsupported session type: ".concat(sessionType));
44
+ var sessionType, widgetController, _a, originalUnmount_1, error_1;
45
+ return __generator(this, function (_b) {
46
+ switch (_b.label) {
47
+ case 0:
48
+ sessionType = session.metadata.sessionType;
49
+ _b.label = 1;
50
+ case 1:
51
+ _b.trys.push([1, 8, , 9]);
52
+ widgetController = void 0;
53
+ _a = sessionType;
54
+ switch (_a) {
55
+ case 'payment': return [3 /*break*/, 2];
56
+ case 'payment-with-save': return [3 /*break*/, 2];
57
+ case 'moto': return [3 /*break*/, 4];
58
+ case 'moto-with-save': return [3 /*break*/, 4];
59
+ case 'save': return [3 /*break*/, 4];
60
+ }
61
+ return [3 /*break*/, 6];
62
+ case 2: return [4 /*yield*/, mountPaymentWidget(mountElement, session, eventBroadcaster, defaultValues, theme)];
63
+ case 3:
64
+ widgetController = _b.sent();
65
+ return [3 /*break*/, 7];
66
+ case 4: return [4 /*yield*/, mountMotoWidget(mountElement, session, eventBroadcaster, defaultValues, theme)];
67
+ case 5:
68
+ widgetController = _b.sent();
69
+ return [3 /*break*/, 7];
70
+ case 6: throw new Error("Unsupported session type: ".concat(sessionType));
71
+ case 7:
72
+ originalUnmount_1 = widgetController.unmount;
73
+ widgetController.unmount = function () {
74
+ // Remove theme class on unmount (generic cleanup)
75
+ if (theme) {
76
+ mountElement.classList.remove("lsp-theme-".concat(theme));
77
+ }
78
+ originalUnmount_1();
79
+ };
80
+ return [2 /*return*/, widgetController];
81
+ case 8:
82
+ error_1 = _b.sent();
83
+ // Clean up theme class if mounting fails
84
+ if (theme) {
85
+ mountElement.classList.remove("lsp-theme-".concat(theme));
86
+ }
87
+ throw error_1;
88
+ case 9: return [2 /*return*/];
58
89
  }
59
- return [2 /*return*/];
60
90
  });
61
91
  });
62
92
  }
@@ -41,19 +41,19 @@ import { initStripe, createPaymentElementOptions, createPaymentElement, cleanupE
41
41
  */
42
42
  export function mountMotoWidget(mountElement, session, eventBroadcaster, defaultValues, theme) {
43
43
  return __awaiter(this, void 0, void 0, function () {
44
- var _a, stripe, elements, paymentOptions, _b, paymentElement, paymentContainer;
44
+ var _a, stripe, elements, paymentOptions, _b, paymentElement, paymentContainer, customTermsContainer;
45
45
  return __generator(this, function (_c) {
46
46
  switch (_c.label) {
47
47
  case 0: return [4 /*yield*/, initStripe(session.context, theme)];
48
48
  case 1:
49
49
  _a = _c.sent(), stripe = _a.stripe, elements = _a.elements;
50
50
  paymentOptions = createPaymentElementOptions(defaultValues, theme);
51
- _b = createPaymentElement(elements, paymentOptions, mountElement, eventBroadcaster), paymentElement = _b.element, paymentContainer = _b.container;
51
+ _b = createPaymentElement(elements, paymentOptions, mountElement, eventBroadcaster, theme), paymentElement = _b.element, paymentContainer = _b.container, customTermsContainer = _b.customTermsContainer;
52
52
  return [2 /*return*/, {
53
53
  unmount: function () {
54
- cleanupElements(paymentElement, null, paymentContainer, null);
54
+ cleanupElements(paymentElement, null, paymentContainer, null, customTermsContainer);
55
55
  },
56
- submit: createSubmitHandler(stripe, elements, session, eventBroadcaster),
56
+ submit: createSubmitHandler(stripe, elements, session, eventBroadcaster, null),
57
57
  }];
58
58
  }
59
59
  });
@@ -40,7 +40,7 @@ import { initStripe, createPaymentElementOptions, createAddressElementOptions, c
40
40
  */
41
41
  export function mountPaymentWidget(mountElement, session, eventBroadcaster, defaultValues, theme) {
42
42
  return __awaiter(this, void 0, void 0, function () {
43
- var _a, stripe, elements, addressOptions, _b, addressElement, addressContainer, paymentOptions, _c, paymentElement, paymentContainer;
43
+ var _a, stripe, elements, addressOptions, _b, addressElement, addressContainer, paymentOptions, _c, paymentElement, paymentContainer, customTermsContainer;
44
44
  return __generator(this, function (_d) {
45
45
  switch (_d.label) {
46
46
  case 0: return [4 /*yield*/, initStripe(session.context, theme)];
@@ -48,13 +48,13 @@ export function mountPaymentWidget(mountElement, session, eventBroadcaster, defa
48
48
  _a = _d.sent(), stripe = _a.stripe, elements = _a.elements;
49
49
  addressOptions = createAddressElementOptions(defaultValues);
50
50
  _b = createAddressElement(elements, addressOptions, mountElement), addressElement = _b.element, addressContainer = _b.container;
51
- paymentOptions = createPaymentElementOptions(defaultValues, theme);
52
- _c = createPaymentElement(elements, paymentOptions, mountElement, eventBroadcaster), paymentElement = _c.element, paymentContainer = _c.container;
51
+ paymentOptions = createPaymentElementOptions(defaultValues, theme, true);
52
+ _c = createPaymentElement(elements, paymentOptions, mountElement, eventBroadcaster, theme), paymentElement = _c.element, paymentContainer = _c.container, customTermsContainer = _c.customTermsContainer;
53
53
  return [2 /*return*/, {
54
54
  unmount: function () {
55
- cleanupElements(paymentElement, addressElement, paymentContainer, addressContainer);
55
+ cleanupElements(paymentElement, addressElement, paymentContainer, addressContainer, customTermsContainer);
56
56
  },
57
- submit: createSubmitHandler(stripe, elements, session, eventBroadcaster),
57
+ submit: createSubmitHandler(stripe, elements, session, eventBroadcaster, addressElement),
58
58
  }];
59
59
  }
60
60
  });
@@ -1,6 +1,6 @@
1
1
  import { WidgetController, DefaultValues } from './common';
2
2
  import { EventListeners } from './EventBroadcaster';
3
- export type PaymentWidgetTheme = 'invoicing';
3
+ export type PaymentWidgetTheme = 'invoicing' | 'dark';
4
4
  export type PaymentWidgetConfiguration = {
5
5
  mountPoint: HTMLElement;
6
6
  defaultValues?: DefaultValues;
package/dist/v1/widget.js CHANGED
@@ -43,7 +43,7 @@ import { withLogging } from './logging/common';
43
43
  import { EventBroadcaster } from './EventBroadcaster';
44
44
  export function mountPaymentWidget(session, config) {
45
45
  return __awaiter(this, void 0, void 0, function () {
46
- var eventBroadcaster, decodedSession, logger_1, widgetController, _a, error_1;
46
+ var eventBroadcaster, decodedSession, logger_1, configSummary, widgetController, _a, error_1;
47
47
  return __generator(this, function (_b) {
48
48
  switch (_b.label) {
49
49
  case 0:
@@ -59,7 +59,12 @@ export function mountPaymentWidget(session, config) {
59
59
  logger_1.log('info', event.status, { event: event });
60
60
  return event;
61
61
  });
62
- logger_1.log('info', 'Mount');
62
+ configSummary = {
63
+ theme: config.theme || 'none',
64
+ listeners: config.listeners ? Object.keys(config.listeners) : [],
65
+ defaultValues: config.defaultValues ? Object.keys(config.defaultValues) : undefined,
66
+ };
67
+ logger_1.log('info', 'Mount', { configuration: configSummary });
63
68
  widgetController = void 0;
64
69
  _a = decodedSession.psp;
65
70
  switch (_a) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightspeed/online-payments-sdk",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Process online-payments with Lightspeed Payments",
5
5
  "author": "Lightspeed Commerce Inc.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -1 +1,62 @@
1
1
  @import '@adyen/adyen-web/styles/adyen.css';
2
+
3
+ /* Custom Terms & Conditions for US Bank Account (ACH) payments */
4
+ .stripe-custom-terms-container {
5
+ margin-top: 12px;
6
+ padding: 0;
7
+ }
8
+
9
+ .stripe-custom-terms-text {
10
+ margin: 0;
11
+ font-size: 12px;
12
+ line-height: 16px;
13
+ color: #6b7280;
14
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
15
+ font-weight: 400;
16
+ }
17
+
18
+ .stripe-custom-terms-text a {
19
+ color: #635bff;
20
+ text-decoration: underline;
21
+ }
22
+
23
+ .stripe-custom-terms-text a:hover {
24
+ color: #0a2540;
25
+ }
26
+
27
+ /* Expandable terms toggle */
28
+ .stripe-expandable-terms-toggle {
29
+ color: #635bff;
30
+ cursor: pointer;
31
+ text-decoration: underline;
32
+ }
33
+
34
+ .stripe-expandable-terms-toggle:hover {
35
+ color: #0a2540;
36
+ }
37
+
38
+ .stripe-terms-triangle {
39
+ display: inline-block;
40
+ font-size: 10px;
41
+ color: #000000;
42
+ margin-left: 2px;
43
+ }
44
+
45
+ /* Expandable terms content */
46
+ .stripe-expandable-terms-content {
47
+ margin-top: 8px;
48
+ padding: 0;
49
+ }
50
+
51
+ .stripe-expandable-terms-content p {
52
+ margin: 0 0 8px 0;
53
+ font-size: 12px;
54
+ line-height: 18px;
55
+ color: #6b7280;
56
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
57
+ font-weight: 400;
58
+ }
59
+
60
+ .stripe-expandable-terms-content p:last-child {
61
+ margin-bottom: 0;
62
+ }