@cimplify/sdk 0.8.7 → 0.8.9
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/advanced.d.mts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/{client-6MsOWo8f.d.mts → client-D1rHAIZY.d.mts} +1 -1
- package/dist/{client-CVJ0S99a.d.ts → client-Dklt51q-.d.ts} +1 -1
- package/dist/{index-mrKi_VbR.d.mts → index-DKLWJwJd.d.mts} +1 -1
- package/dist/{index-B_JHO-ER.d.ts → index-DQp1xkcl.d.ts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +54 -0
- package/dist/index.mjs +54 -1
- package/dist/{payment-CLIWNMaP.d.mts → payment-BKjX2fAs.d.mts} +2 -1
- package/dist/{payment-CLIWNMaP.d.ts → payment-BKjX2fAs.d.ts} +2 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1132 -1056
- package/dist/react.mjs +934 -858
- package/dist/utils.d.mts +2 -2
- package/dist/utils.d.ts +2 -2
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1,55 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React3 = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
|
|
6
6
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
9
9
|
|
|
10
|
-
// src/
|
|
11
|
-
|
|
12
|
-
// src/types/elements.ts
|
|
13
|
-
var ELEMENT_TYPES = {
|
|
14
|
-
AUTH: "auth",
|
|
15
|
-
ADDRESS: "address",
|
|
16
|
-
PAYMENT: "payment",
|
|
17
|
-
CHECKOUT: "checkout"
|
|
18
|
-
};
|
|
19
|
-
var MESSAGE_TYPES = {
|
|
20
|
-
// Parent → Iframe
|
|
21
|
-
INIT: "init",
|
|
22
|
-
SET_TOKEN: "set_token",
|
|
23
|
-
SET_CART: "set_cart",
|
|
24
|
-
GET_DATA: "get_data",
|
|
25
|
-
PROCESS_CHECKOUT: "process_checkout",
|
|
26
|
-
ABORT_CHECKOUT: "abort_checkout",
|
|
27
|
-
// Iframe → Parent
|
|
28
|
-
READY: "ready",
|
|
29
|
-
HEIGHT_CHANGE: "height_change",
|
|
30
|
-
AUTHENTICATED: "authenticated",
|
|
31
|
-
REQUIRES_OTP: "requires_otp",
|
|
32
|
-
ERROR: "error",
|
|
33
|
-
ADDRESS_CHANGED: "address_changed",
|
|
34
|
-
ADDRESS_SELECTED: "address_selected",
|
|
35
|
-
PAYMENT_METHOD_SELECTED: "payment_method_selected",
|
|
36
|
-
TOKEN_REFRESHED: "token_refreshed",
|
|
37
|
-
LOGOUT_COMPLETE: "logout_complete",
|
|
38
|
-
CONTACT_PROVIDED: "contact_provided",
|
|
39
|
-
CHECKOUT_STATUS: "checkout_status",
|
|
40
|
-
CHECKOUT_COMPLETE: "checkout_complete",
|
|
41
|
-
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
42
|
-
REQUEST_SUBMIT: "request_submit"
|
|
43
|
-
};
|
|
44
|
-
var EVENT_TYPES = {
|
|
45
|
-
READY: "ready",
|
|
46
|
-
AUTHENTICATED: "authenticated",
|
|
47
|
-
REQUIRES_OTP: "requires_otp",
|
|
48
|
-
ERROR: "error",
|
|
49
|
-
CHANGE: "change",
|
|
50
|
-
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
51
|
-
REQUEST_SUBMIT: "request_submit"
|
|
52
|
-
};
|
|
10
|
+
// src/ads/index.tsx
|
|
53
11
|
|
|
54
12
|
// src/ads/identity.ts
|
|
55
13
|
var COOKIE_NAME = "_cimplify_uid";
|
|
@@ -201,7 +159,7 @@ function deriveAdsApiUrl() {
|
|
|
201
159
|
}
|
|
202
160
|
return "https://api.cimplify.io";
|
|
203
161
|
}
|
|
204
|
-
var AdContext =
|
|
162
|
+
var AdContext = React3.createContext({
|
|
205
163
|
siteId: null,
|
|
206
164
|
config: null,
|
|
207
165
|
isLoading: true,
|
|
@@ -209,7 +167,7 @@ var AdContext = React2.createContext({
|
|
|
209
167
|
apiBase: "https://api.cimplify.io"
|
|
210
168
|
});
|
|
211
169
|
function useAds() {
|
|
212
|
-
return
|
|
170
|
+
return React3.useContext(AdContext);
|
|
213
171
|
}
|
|
214
172
|
function AdProvider({
|
|
215
173
|
siteId,
|
|
@@ -218,10 +176,10 @@ function AdProvider({
|
|
|
218
176
|
children
|
|
219
177
|
}) {
|
|
220
178
|
const resolvedApiBase = apiBase || deriveAdsApiUrl();
|
|
221
|
-
const [config, setConfig] =
|
|
222
|
-
const [isLoading, setIsLoading] =
|
|
223
|
-
const [identity, setIdentity] =
|
|
224
|
-
|
|
179
|
+
const [config, setConfig] = React3.useState(null);
|
|
180
|
+
const [isLoading, setIsLoading] = React3.useState(true);
|
|
181
|
+
const [identity, setIdentity] = React3.useState(null);
|
|
182
|
+
React3.useEffect(() => {
|
|
225
183
|
const userIdentity = getUserIdentity(authenticatedAccountId);
|
|
226
184
|
setIdentity(userIdentity);
|
|
227
185
|
fetch(`${resolvedApiBase}/ads/config/${siteId}`).then((r) => r.json()).then((data) => {
|
|
@@ -244,11 +202,11 @@ function Ad({
|
|
|
244
202
|
onClick
|
|
245
203
|
}) {
|
|
246
204
|
const { siteId, config, isLoading, identity, apiBase } = useAds();
|
|
247
|
-
const [ad, setAd] =
|
|
248
|
-
const [error, setError] =
|
|
249
|
-
const impressionTracked =
|
|
250
|
-
const containerRef =
|
|
251
|
-
|
|
205
|
+
const [ad, setAd] = React3.useState(null);
|
|
206
|
+
const [error, setError] = React3.useState(false);
|
|
207
|
+
const impressionTracked = React3.useRef(false);
|
|
208
|
+
const containerRef = React3.useRef(null);
|
|
209
|
+
React3.useEffect(() => {
|
|
252
210
|
if (isLoading || !config?.enabled || !siteId || !identity) return;
|
|
253
211
|
const path = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
254
212
|
const referrer = typeof document !== "undefined" ? document.referrer : "";
|
|
@@ -291,7 +249,7 @@ function Ad({
|
|
|
291
249
|
}
|
|
292
250
|
}).catch(() => setError(true));
|
|
293
251
|
}, [siteId, config, isLoading, slot, identity, apiBase]);
|
|
294
|
-
|
|
252
|
+
React3.useEffect(() => {
|
|
295
253
|
if (!ad || impressionTracked.current || typeof window === "undefined" || !identity) return;
|
|
296
254
|
const observer = new IntersectionObserver(
|
|
297
255
|
([entry]) => {
|
|
@@ -368,12 +326,13 @@ function getSelections(item) {
|
|
|
368
326
|
}
|
|
369
327
|
return void 0;
|
|
370
328
|
}
|
|
371
|
-
function mapItem(item) {
|
|
329
|
+
function mapItem(item, fx) {
|
|
330
|
+
const amt = (value) => fx ? String(fx.convertPrice(value)) : String(value);
|
|
372
331
|
const result = {
|
|
373
332
|
name: item.name,
|
|
374
333
|
quantity: item.quantity,
|
|
375
|
-
unit_price:
|
|
376
|
-
total_price:
|
|
334
|
+
unit_price: amt(item.base_price),
|
|
335
|
+
total_price: amt(item.total_price),
|
|
377
336
|
line_type: item.line_type
|
|
378
337
|
};
|
|
379
338
|
if (item.image_url) result.image_url = item.image_url;
|
|
@@ -386,7 +345,7 @@ function mapItem(item) {
|
|
|
386
345
|
if (item.add_on_options?.length) {
|
|
387
346
|
result.add_ons = item.add_on_options.map((opt) => ({
|
|
388
347
|
name: opt.name,
|
|
389
|
-
price:
|
|
348
|
+
price: amt(opt.price ?? "0")
|
|
390
349
|
}));
|
|
391
350
|
}
|
|
392
351
|
if (item.special_instructions) {
|
|
@@ -394,623 +353,231 @@ function mapItem(item) {
|
|
|
394
353
|
}
|
|
395
354
|
return result;
|
|
396
355
|
}
|
|
397
|
-
function transformToCheckoutCart(cart) {
|
|
356
|
+
function transformToCheckoutCart(cart, fx) {
|
|
357
|
+
const amt = (value) => fx ? String(fx.convertPrice(value)) : String(value);
|
|
398
358
|
return {
|
|
399
|
-
items: cart.items.map(mapItem),
|
|
400
|
-
subtotal:
|
|
401
|
-
tax_amount:
|
|
402
|
-
total_discounts:
|
|
403
|
-
service_charge:
|
|
404
|
-
total:
|
|
405
|
-
currency: cart.pricing.currency
|
|
359
|
+
items: cart.items.map((item) => mapItem(item, fx)),
|
|
360
|
+
subtotal: amt(cart.pricing.subtotal),
|
|
361
|
+
tax_amount: amt(cart.pricing.tax_amount),
|
|
362
|
+
total_discounts: amt(cart.pricing.total_discounts),
|
|
363
|
+
service_charge: amt(cart.pricing.service_charge),
|
|
364
|
+
total: amt(cart.pricing.total_price),
|
|
365
|
+
currency: fx?.displayCurrency ?? cart.pricing.currency
|
|
406
366
|
};
|
|
407
367
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
textSecondary: isDark ? "#a1a1aa" : "#52525b",
|
|
413
|
-
textMuted: isDark ? "#71717a" : "#a1a1aa",
|
|
414
|
-
border: isDark ? "#27272a" : "#e4e4e7",
|
|
415
|
-
surface: isDark ? "#18181b" : "#fafafa",
|
|
416
|
-
error: "#dc2626",
|
|
417
|
-
primary: primaryColor
|
|
418
|
-
};
|
|
368
|
+
|
|
369
|
+
// src/types/common.ts
|
|
370
|
+
function money(value) {
|
|
371
|
+
return value;
|
|
419
372
|
}
|
|
420
|
-
function
|
|
421
|
-
|
|
422
|
-
|
|
373
|
+
function moneyFromNumber(value) {
|
|
374
|
+
return value.toFixed(2);
|
|
375
|
+
}
|
|
376
|
+
var SUPPORTED_CURRENCY_CODES = /* @__PURE__ */ new Set([
|
|
377
|
+
"USD",
|
|
378
|
+
"EUR",
|
|
379
|
+
"GBP",
|
|
380
|
+
"JPY",
|
|
381
|
+
"CNY",
|
|
382
|
+
"CHF",
|
|
383
|
+
"CAD",
|
|
384
|
+
"AUD",
|
|
385
|
+
"GHS",
|
|
386
|
+
"NGN",
|
|
387
|
+
"KES",
|
|
388
|
+
"ZAR",
|
|
389
|
+
"XOF",
|
|
390
|
+
"XAF",
|
|
391
|
+
"EGP",
|
|
392
|
+
"TZS",
|
|
393
|
+
"UGX",
|
|
394
|
+
"RWF",
|
|
395
|
+
"ETB",
|
|
396
|
+
"ZMW",
|
|
397
|
+
"BWP",
|
|
398
|
+
"MUR",
|
|
399
|
+
"NAD",
|
|
400
|
+
"MWK",
|
|
401
|
+
"AOA",
|
|
402
|
+
"CDF",
|
|
403
|
+
"GMD",
|
|
404
|
+
"GNF",
|
|
405
|
+
"LRD",
|
|
406
|
+
"SLL",
|
|
407
|
+
"MZN",
|
|
408
|
+
"BIF",
|
|
409
|
+
"INR",
|
|
410
|
+
"BRL",
|
|
411
|
+
"MXN",
|
|
412
|
+
"KRW",
|
|
413
|
+
"TRY",
|
|
414
|
+
"THB",
|
|
415
|
+
"MYR",
|
|
416
|
+
"PHP",
|
|
417
|
+
"IDR",
|
|
418
|
+
"VND",
|
|
419
|
+
"SGD",
|
|
420
|
+
"HKD",
|
|
421
|
+
"TWD",
|
|
422
|
+
"AED",
|
|
423
|
+
"SAR",
|
|
424
|
+
"ILS"
|
|
425
|
+
]);
|
|
426
|
+
function isSupportedCurrency(code) {
|
|
427
|
+
return SUPPORTED_CURRENCY_CODES.has(code);
|
|
428
|
+
}
|
|
429
|
+
function currencyCode(value) {
|
|
430
|
+
return value;
|
|
431
|
+
}
|
|
432
|
+
var ErrorCode = {
|
|
433
|
+
// General
|
|
434
|
+
UNKNOWN_ERROR: "UNKNOWN_ERROR",
|
|
435
|
+
NETWORK_ERROR: "NETWORK_ERROR",
|
|
436
|
+
TIMEOUT: "TIMEOUT",
|
|
437
|
+
UNAUTHORIZED: "UNAUTHORIZED",
|
|
438
|
+
NOT_FOUND: "NOT_FOUND"};
|
|
439
|
+
var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
|
|
440
|
+
function docsUrlForCode(code) {
|
|
441
|
+
return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
442
|
+
}
|
|
443
|
+
var ERROR_SUGGESTIONS = {
|
|
444
|
+
UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
|
|
445
|
+
NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
|
|
446
|
+
TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
|
|
447
|
+
UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
|
|
448
|
+
FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
|
|
449
|
+
NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
|
|
450
|
+
VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
|
|
451
|
+
CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
|
|
452
|
+
CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
|
|
453
|
+
CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
|
|
454
|
+
ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
|
|
455
|
+
VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
|
|
456
|
+
VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
|
|
457
|
+
ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
|
|
458
|
+
ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
|
|
459
|
+
CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
|
|
460
|
+
DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
|
|
461
|
+
CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
|
|
462
|
+
QUOTE_NOT_FOUND: "Quote could not be found. Refresh pricing and create a new quote before checkout.",
|
|
463
|
+
QUOTE_EXPIRED: "Quote has expired. Re-fetch pricing to generate a new quote with a valid expiry window.",
|
|
464
|
+
QUOTE_CONSUMED: "Quote has already been used. Request a fresh quote to prevent duplicate checkout attempts.",
|
|
465
|
+
QUOTE_STORAGE_UNAVAILABLE: "Quote storage is temporarily unavailable. Retry shortly and avoid charging until quote fetch succeeds.",
|
|
466
|
+
PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
|
|
467
|
+
PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
|
|
468
|
+
INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
|
|
469
|
+
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
470
|
+
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
471
|
+
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
472
|
+
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
473
|
+
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
474
|
+
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
475
|
+
BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
|
|
476
|
+
SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
|
|
477
|
+
OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
|
|
478
|
+
INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
|
|
479
|
+
BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
|
|
480
|
+
INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
|
|
481
|
+
ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
|
|
482
|
+
NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
|
|
483
|
+
PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
|
|
484
|
+
AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
|
|
485
|
+
AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
|
|
486
|
+
ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
|
|
487
|
+
CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
|
|
488
|
+
CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
|
|
489
|
+
REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
|
|
490
|
+
POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
|
|
491
|
+
FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
|
|
492
|
+
};
|
|
493
|
+
var ERROR_HINTS = Object.fromEntries(
|
|
494
|
+
Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
|
|
495
|
+
code,
|
|
496
|
+
{
|
|
497
|
+
docs_url: docsUrlForCode(code),
|
|
498
|
+
suggestion
|
|
499
|
+
}
|
|
500
|
+
])
|
|
501
|
+
);
|
|
502
|
+
var CimplifyError = class extends Error {
|
|
503
|
+
constructor(code, message, retryable = false, docs_url, suggestion) {
|
|
504
|
+
super(message);
|
|
505
|
+
this.code = code;
|
|
506
|
+
this.retryable = retryable;
|
|
507
|
+
this.docs_url = docs_url;
|
|
508
|
+
this.suggestion = suggestion;
|
|
509
|
+
this.name = "CimplifyError";
|
|
423
510
|
}
|
|
424
|
-
|
|
425
|
-
|
|
511
|
+
/** User-friendly message safe to display */
|
|
512
|
+
get userMessage() {
|
|
513
|
+
return this.message;
|
|
426
514
|
}
|
|
427
|
-
|
|
428
|
-
|
|
515
|
+
};
|
|
516
|
+
function getErrorHint(code) {
|
|
517
|
+
return ERROR_HINTS[code];
|
|
518
|
+
}
|
|
519
|
+
function enrichError(error, options = {}) {
|
|
520
|
+
const hint = getErrorHint(error.code);
|
|
521
|
+
if (hint) {
|
|
522
|
+
if (!error.docs_url) {
|
|
523
|
+
error.docs_url = hint.docs_url;
|
|
524
|
+
}
|
|
525
|
+
if (!error.suggestion) {
|
|
526
|
+
error.suggestion = hint.suggestion;
|
|
527
|
+
}
|
|
528
|
+
} else if (!error.docs_url) {
|
|
529
|
+
error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
|
|
429
530
|
}
|
|
430
|
-
if (
|
|
431
|
-
|
|
531
|
+
if (options.isTestMode && !error.message.includes("pk_test_")) {
|
|
532
|
+
error.message = `${error.message}
|
|
533
|
+
|
|
534
|
+
\u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
|
|
432
535
|
}
|
|
433
|
-
|
|
434
|
-
|
|
536
|
+
return error;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// src/types/result.ts
|
|
540
|
+
function ok(value) {
|
|
541
|
+
return { ok: true, value };
|
|
542
|
+
}
|
|
543
|
+
function err(error) {
|
|
544
|
+
return { ok: false, error };
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/catalogue.ts
|
|
548
|
+
function toCimplifyError(error) {
|
|
549
|
+
if (error instanceof CimplifyError) return enrichError(error);
|
|
550
|
+
if (error instanceof Error) {
|
|
551
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
435
552
|
}
|
|
436
|
-
|
|
437
|
-
|
|
553
|
+
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
554
|
+
}
|
|
555
|
+
async function safe(promise) {
|
|
556
|
+
try {
|
|
557
|
+
return ok(await promise);
|
|
558
|
+
} catch (error) {
|
|
559
|
+
return err(toCimplifyError(error));
|
|
438
560
|
}
|
|
439
|
-
|
|
440
|
-
|
|
561
|
+
}
|
|
562
|
+
function withQuery(path, params) {
|
|
563
|
+
const query = new URLSearchParams();
|
|
564
|
+
for (const [key, value] of Object.entries(params)) {
|
|
565
|
+
if (value === void 0) continue;
|
|
566
|
+
query.set(key, String(value));
|
|
441
567
|
}
|
|
442
|
-
|
|
443
|
-
|
|
568
|
+
const queryString = query.toString();
|
|
569
|
+
return queryString ? `${path}?${queryString}` : path;
|
|
570
|
+
}
|
|
571
|
+
function isRecord(value) {
|
|
572
|
+
return typeof value === "object" && value !== null;
|
|
573
|
+
}
|
|
574
|
+
function readFinalPrice(value) {
|
|
575
|
+
if (!isRecord(value)) return void 0;
|
|
576
|
+
const finalPrice = value.final_price;
|
|
577
|
+
if (typeof finalPrice === "string" || typeof finalPrice === "number") {
|
|
578
|
+
return finalPrice;
|
|
444
579
|
}
|
|
445
|
-
return
|
|
446
|
-
}
|
|
447
|
-
function CimplifyCheckout({
|
|
448
|
-
client,
|
|
449
|
-
businessId,
|
|
450
|
-
cartId,
|
|
451
|
-
locationId,
|
|
452
|
-
linkUrl,
|
|
453
|
-
orderTypes,
|
|
454
|
-
enrollInLink = true,
|
|
455
|
-
onComplete,
|
|
456
|
-
onError,
|
|
457
|
-
onStatusChange,
|
|
458
|
-
appearance,
|
|
459
|
-
demoMode,
|
|
460
|
-
className
|
|
461
|
-
}) {
|
|
462
|
-
const resolvedOrderTypes = React2.useMemo(
|
|
463
|
-
() => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
|
|
464
|
-
[orderTypes]
|
|
465
|
-
);
|
|
466
|
-
const [orderType, setOrderType] = React2.useState(resolvedOrderTypes[0] || "pickup");
|
|
467
|
-
const [status, setStatus] = React2.useState(null);
|
|
468
|
-
const [statusText, setStatusText] = React2.useState("");
|
|
469
|
-
const [isSubmitting, setIsSubmitting] = React2.useState(false);
|
|
470
|
-
const [isInitializing, setIsInitializing] = React2.useState(false);
|
|
471
|
-
const [errorMessage, setErrorMessage] = React2.useState(null);
|
|
472
|
-
const [resolvedBusinessId, setResolvedBusinessId] = React2.useState(businessId ?? null);
|
|
473
|
-
const [resolvedCartId, setResolvedCartId] = React2.useState(cartId ?? null);
|
|
474
|
-
const [resolvedCart, setResolvedCart] = React2.useState(null);
|
|
475
|
-
const checkoutMountRef = React2.useRef(null);
|
|
476
|
-
const elementsRef = React2.useRef(null);
|
|
477
|
-
const activeCheckoutRef = React2.useRef(null);
|
|
478
|
-
const initialAppearanceRef = React2.useRef(appearance);
|
|
479
|
-
const hasWarnedInlineAppearanceRef = React2.useRef(false);
|
|
480
|
-
const isMountedRef = React2.useRef(true);
|
|
481
|
-
const demoRunRef = React2.useRef(0);
|
|
482
|
-
const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
|
|
483
|
-
const isTestMode = client.isTestMode();
|
|
484
|
-
const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
|
|
485
|
-
const isDark = appearance?.theme === "dark";
|
|
486
|
-
const emitStatus = React2__default.default.useEffectEvent(
|
|
487
|
-
(nextStatus, context = {}) => {
|
|
488
|
-
setStatus(nextStatus);
|
|
489
|
-
setStatusText(context.display_text || "");
|
|
490
|
-
onStatusChange?.(nextStatus, context);
|
|
491
|
-
}
|
|
492
|
-
);
|
|
493
|
-
const fireError = React2__default.default.useEffectEvent(
|
|
494
|
-
(error) => {
|
|
495
|
-
onError?.(error);
|
|
496
|
-
}
|
|
497
|
-
);
|
|
498
|
-
React2.useEffect(() => {
|
|
499
|
-
if (!resolvedOrderTypes.includes(orderType)) {
|
|
500
|
-
setOrderType(resolvedOrderTypes[0] || "pickup");
|
|
501
|
-
}
|
|
502
|
-
}, [resolvedOrderTypes, orderType]);
|
|
503
|
-
React2.useEffect(() => {
|
|
504
|
-
if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
|
|
505
|
-
hasWarnedInlineAppearanceRef.current = true;
|
|
506
|
-
console.warn(
|
|
507
|
-
"[Cimplify] `appearance` prop reference changed after mount. Elements keep the initial appearance to avoid iframe remount. Memoize appearance with useMemo() to remove this warning."
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
}, [appearance]);
|
|
511
|
-
React2.useEffect(() => {
|
|
512
|
-
let cancelled = false;
|
|
513
|
-
async function bootstrap() {
|
|
514
|
-
if (isDemoCheckout) {
|
|
515
|
-
if (!cancelled) {
|
|
516
|
-
setResolvedBusinessId(businessId ?? null);
|
|
517
|
-
setResolvedCartId(cartId ?? "cart_demo");
|
|
518
|
-
setIsInitializing(false);
|
|
519
|
-
setErrorMessage(null);
|
|
520
|
-
}
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
const needsBusinessResolve = !businessId;
|
|
524
|
-
const needsCartResolve = !cartId;
|
|
525
|
-
if (!needsBusinessResolve && !needsCartResolve) {
|
|
526
|
-
if (!cancelled) {
|
|
527
|
-
setResolvedBusinessId(businessId || null);
|
|
528
|
-
setResolvedCartId(cartId || null);
|
|
529
|
-
setIsInitializing(false);
|
|
530
|
-
setErrorMessage(null);
|
|
531
|
-
}
|
|
532
|
-
client.cart.get().then((cartResult) => {
|
|
533
|
-
if (!cancelled && cartResult.ok && cartResult.value) {
|
|
534
|
-
setResolvedCart(cartResult.value);
|
|
535
|
-
}
|
|
536
|
-
}).catch(() => {
|
|
537
|
-
});
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
if (!cancelled) {
|
|
541
|
-
setIsInitializing(true);
|
|
542
|
-
setErrorMessage(null);
|
|
543
|
-
}
|
|
544
|
-
let nextBusinessId = businessId ?? null;
|
|
545
|
-
if (!nextBusinessId) {
|
|
546
|
-
try {
|
|
547
|
-
nextBusinessId = await client.resolveBusinessId();
|
|
548
|
-
} catch {
|
|
549
|
-
if (!cancelled) {
|
|
550
|
-
const message = "Unable to initialize checkout business context.";
|
|
551
|
-
setResolvedBusinessId(null);
|
|
552
|
-
setResolvedCartId(null);
|
|
553
|
-
setErrorMessage(message);
|
|
554
|
-
setIsInitializing(false);
|
|
555
|
-
fireError({ code: "BUSINESS_ID_REQUIRED", message });
|
|
556
|
-
}
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
let nextCartId = cartId ?? null;
|
|
561
|
-
if (!nextCartId) {
|
|
562
|
-
const cartResult = await client.cart.get();
|
|
563
|
-
if (!cartResult.ok || !cartResult.value?.id || cartResult.value.items.length === 0) {
|
|
564
|
-
if (!cancelled) {
|
|
565
|
-
const message = "Your cart is empty. Add items before checkout.";
|
|
566
|
-
setResolvedBusinessId(nextBusinessId);
|
|
567
|
-
setResolvedCartId(null);
|
|
568
|
-
setErrorMessage(message);
|
|
569
|
-
setIsInitializing(false);
|
|
570
|
-
fireError({ code: "CART_EMPTY", message });
|
|
571
|
-
}
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
nextCartId = cartResult.value.id;
|
|
575
|
-
if (!cancelled) {
|
|
576
|
-
setResolvedCart(cartResult.value);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
if (!cancelled) {
|
|
580
|
-
setResolvedBusinessId(nextBusinessId);
|
|
581
|
-
setResolvedCartId(nextCartId);
|
|
582
|
-
setIsInitializing(false);
|
|
583
|
-
setErrorMessage(null);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
void bootstrap();
|
|
587
|
-
return () => {
|
|
588
|
-
cancelled = true;
|
|
589
|
-
};
|
|
590
|
-
}, [businessId, cartId, client, isDemoCheckout]);
|
|
591
|
-
React2.useEffect(() => {
|
|
592
|
-
return () => {
|
|
593
|
-
isMountedRef.current = false;
|
|
594
|
-
demoRunRef.current += 1;
|
|
595
|
-
activeCheckoutRef.current?.abort();
|
|
596
|
-
activeCheckoutRef.current = null;
|
|
597
|
-
};
|
|
598
|
-
}, []);
|
|
599
|
-
const handleSubmit = React2__default.default.useEffectEvent(async () => {
|
|
600
|
-
if (isSubmitting || isInitializing || !resolvedCartId) {
|
|
601
|
-
if (!resolvedCartId && !isInitializing) {
|
|
602
|
-
const message = "Your cart is empty. Add items before checkout.";
|
|
603
|
-
setErrorMessage(message);
|
|
604
|
-
fireError({ code: "CART_EMPTY", message });
|
|
605
|
-
}
|
|
606
|
-
return;
|
|
607
|
-
}
|
|
608
|
-
setErrorMessage(null);
|
|
609
|
-
setIsSubmitting(true);
|
|
610
|
-
emitStatus("preparing", { display_text: statusToLabel("preparing") });
|
|
611
|
-
if (isDemoCheckout) {
|
|
612
|
-
const runId = demoRunRef.current + 1;
|
|
613
|
-
demoRunRef.current = runId;
|
|
614
|
-
const wait = async (ms) => {
|
|
615
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
616
|
-
return isMountedRef.current && runId === demoRunRef.current;
|
|
617
|
-
};
|
|
618
|
-
try {
|
|
619
|
-
if (!await wait(400)) return;
|
|
620
|
-
emitStatus("processing", { display_text: statusToLabel("processing") });
|
|
621
|
-
if (!await wait(900)) return;
|
|
622
|
-
emitStatus("polling", { display_text: statusToLabel("polling") });
|
|
623
|
-
if (!await wait(1200)) return;
|
|
624
|
-
const result = {
|
|
625
|
-
success: true,
|
|
626
|
-
order: {
|
|
627
|
-
id: `ord_demo_${Date.now()}`,
|
|
628
|
-
order_number: `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`,
|
|
629
|
-
status: "confirmed",
|
|
630
|
-
total: "0.00",
|
|
631
|
-
currency: "USD"
|
|
632
|
-
}
|
|
633
|
-
};
|
|
634
|
-
emitStatus("success", {
|
|
635
|
-
order_id: result.order?.id,
|
|
636
|
-
order_number: result.order?.order_number,
|
|
637
|
-
display_text: statusToLabel("success")
|
|
638
|
-
});
|
|
639
|
-
onComplete(result);
|
|
640
|
-
} finally {
|
|
641
|
-
if (isMountedRef.current && runId === demoRunRef.current) {
|
|
642
|
-
setIsSubmitting(false);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
if (!elementsRef.current) {
|
|
648
|
-
const message = "Checkout is still initializing. Please try again.";
|
|
649
|
-
setErrorMessage(message);
|
|
650
|
-
fireError({ code: "CHECKOUT_NOT_READY", message });
|
|
651
|
-
setIsSubmitting(false);
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
const checkout = elementsRef.current.processCheckout({
|
|
655
|
-
cart_id: resolvedCartId,
|
|
656
|
-
location_id: locationId ?? client.getLocationId() ?? void 0,
|
|
657
|
-
order_type: orderType,
|
|
658
|
-
enroll_in_link: enrollInLink,
|
|
659
|
-
on_status_change: emitStatus
|
|
660
|
-
});
|
|
661
|
-
activeCheckoutRef.current = checkout;
|
|
662
|
-
try {
|
|
663
|
-
const result = await checkout;
|
|
664
|
-
if (result.success) {
|
|
665
|
-
onComplete(result);
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
const code = result.error?.code || "CHECKOUT_FAILED";
|
|
669
|
-
const message = result.error?.message || "Payment failed.";
|
|
670
|
-
setErrorMessage(message);
|
|
671
|
-
fireError({ code, message });
|
|
672
|
-
} finally {
|
|
673
|
-
if (isMountedRef.current) {
|
|
674
|
-
activeCheckoutRef.current = null;
|
|
675
|
-
setIsSubmitting(false);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
});
|
|
679
|
-
React2.useEffect(() => {
|
|
680
|
-
if (isDemoCheckout || !resolvedBusinessId) {
|
|
681
|
-
elementsRef.current = null;
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
const elements = client.elements(resolvedBusinessId, {
|
|
685
|
-
appearance: initialAppearanceRef.current,
|
|
686
|
-
linkUrl
|
|
687
|
-
});
|
|
688
|
-
elementsRef.current = elements;
|
|
689
|
-
const checkout = elements.create("checkout", {
|
|
690
|
-
orderTypes: resolvedOrderTypes,
|
|
691
|
-
defaultOrderType: resolvedOrderTypes[0]
|
|
692
|
-
});
|
|
693
|
-
if (checkoutMountRef.current) {
|
|
694
|
-
checkout.mount(checkoutMountRef.current);
|
|
695
|
-
}
|
|
696
|
-
checkout.on("ready", () => {
|
|
697
|
-
if (resolvedCart) {
|
|
698
|
-
checkout.setCart(transformToCheckoutCart(resolvedCart));
|
|
699
|
-
}
|
|
700
|
-
});
|
|
701
|
-
checkout.on("order_type_changed", (data) => {
|
|
702
|
-
const typed = data;
|
|
703
|
-
if (typed.orderType) {
|
|
704
|
-
setOrderType(typed.orderType);
|
|
705
|
-
}
|
|
706
|
-
});
|
|
707
|
-
checkout.on("request_submit", () => {
|
|
708
|
-
void handleSubmit();
|
|
709
|
-
});
|
|
710
|
-
return () => {
|
|
711
|
-
activeCheckoutRef.current?.abort();
|
|
712
|
-
activeCheckoutRef.current = null;
|
|
713
|
-
elements.destroy();
|
|
714
|
-
elementsRef.current = null;
|
|
715
|
-
};
|
|
716
|
-
}, [client, resolvedBusinessId, isDemoCheckout]);
|
|
717
|
-
React2.useEffect(() => {
|
|
718
|
-
if (!resolvedCart || !elementsRef.current) return;
|
|
719
|
-
const checkoutElement = elementsRef.current.getElement("checkout");
|
|
720
|
-
if (checkoutElement) {
|
|
721
|
-
checkoutElement.setCart(transformToCheckoutCart(resolvedCart));
|
|
722
|
-
}
|
|
723
|
-
}, [resolvedCart]);
|
|
724
|
-
const colors = shellColors(isDark ?? false, primaryColor);
|
|
725
|
-
if (isInitializing) {
|
|
726
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
|
|
727
|
-
}
|
|
728
|
-
if (!isDemoCheckout && (!resolvedBusinessId || !resolvedCartId)) {
|
|
729
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { fontSize: 13, color: colors.error }, children: errorMessage || "Unable to initialize checkout. Please refresh and try again." }) });
|
|
730
|
-
}
|
|
731
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-cimplify-checkout": "", children: [
|
|
732
|
-
isTestMode && !isDemoCheckout && /* @__PURE__ */ jsxRuntime.jsx(
|
|
733
|
-
"p",
|
|
734
|
-
{
|
|
735
|
-
"data-cimplify-test-mode": "",
|
|
736
|
-
style: {
|
|
737
|
-
marginBottom: "10px",
|
|
738
|
-
fontSize: "12px",
|
|
739
|
-
fontWeight: 600,
|
|
740
|
-
color: "#92400e"
|
|
741
|
-
},
|
|
742
|
-
children: "Test mode - no real charges"
|
|
743
|
-
}
|
|
744
|
-
),
|
|
745
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
|
|
746
|
-
status && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
|
|
747
|
-
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
|
|
748
|
-
] });
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// src/utils/price.ts
|
|
752
|
-
var CURRENCY_SYMBOLS = {
|
|
753
|
-
// Major world currencies
|
|
754
|
-
USD: "$",
|
|
755
|
-
EUR: "\u20AC",
|
|
756
|
-
GBP: "\xA3",
|
|
757
|
-
JPY: "\xA5",
|
|
758
|
-
CNY: "\xA5",
|
|
759
|
-
CHF: "CHF",
|
|
760
|
-
CAD: "C$",
|
|
761
|
-
AUD: "A$",
|
|
762
|
-
NZD: "NZ$",
|
|
763
|
-
HKD: "HK$",
|
|
764
|
-
SGD: "S$",
|
|
765
|
-
INR: "\u20B9",
|
|
766
|
-
BRL: "R$",
|
|
767
|
-
MXN: "MX$",
|
|
768
|
-
KRW: "\u20A9",
|
|
769
|
-
RUB: "\u20BD",
|
|
770
|
-
TRY: "\u20BA",
|
|
771
|
-
THB: "\u0E3F",
|
|
772
|
-
PLN: "z\u0142",
|
|
773
|
-
SEK: "kr",
|
|
774
|
-
NOK: "kr",
|
|
775
|
-
DKK: "kr",
|
|
776
|
-
CZK: "K\u010D",
|
|
777
|
-
HUF: "Ft",
|
|
778
|
-
ILS: "\u20AA",
|
|
779
|
-
AED: "\u062F.\u0625",
|
|
780
|
-
SAR: "\uFDFC",
|
|
781
|
-
MYR: "RM",
|
|
782
|
-
PHP: "\u20B1",
|
|
783
|
-
IDR: "Rp",
|
|
784
|
-
VND: "\u20AB",
|
|
785
|
-
TWD: "NT$",
|
|
786
|
-
// African currencies
|
|
787
|
-
GHS: "GH\u20B5",
|
|
788
|
-
NGN: "\u20A6",
|
|
789
|
-
KES: "KSh",
|
|
790
|
-
ZAR: "R",
|
|
791
|
-
XOF: "CFA",
|
|
792
|
-
XAF: "FCFA",
|
|
793
|
-
EGP: "E\xA3",
|
|
794
|
-
MAD: "MAD",
|
|
795
|
-
TZS: "TSh",
|
|
796
|
-
UGX: "USh",
|
|
797
|
-
RWF: "FRw",
|
|
798
|
-
ETB: "Br",
|
|
799
|
-
ZMW: "ZK",
|
|
800
|
-
BWP: "P",
|
|
801
|
-
MUR: "\u20A8",
|
|
802
|
-
SCR: "\u20A8",
|
|
803
|
-
NAD: "N$",
|
|
804
|
-
SZL: "E",
|
|
805
|
-
LSL: "L",
|
|
806
|
-
MWK: "MK",
|
|
807
|
-
AOA: "Kz",
|
|
808
|
-
CDF: "FC",
|
|
809
|
-
GMD: "D",
|
|
810
|
-
GNF: "FG",
|
|
811
|
-
LRD: "L$",
|
|
812
|
-
SLL: "Le",
|
|
813
|
-
MZN: "MT",
|
|
814
|
-
SDG: "SDG",
|
|
815
|
-
SSP: "SSP",
|
|
816
|
-
SOS: "Sh.So.",
|
|
817
|
-
DJF: "Fdj",
|
|
818
|
-
ERN: "Nfk",
|
|
819
|
-
CVE: "$",
|
|
820
|
-
STN: "Db",
|
|
821
|
-
KMF: "CF",
|
|
822
|
-
BIF: "FBu"
|
|
823
|
-
};
|
|
824
|
-
function getCurrencySymbol(currencyCode2) {
|
|
825
|
-
return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
|
|
826
|
-
}
|
|
827
|
-
function formatPrice(amount, currency = "GHS", locale = "en-US") {
|
|
828
|
-
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
829
|
-
if (isNaN(numAmount)) {
|
|
830
|
-
return `${getCurrencySymbol(currency)}0.00`;
|
|
831
|
-
}
|
|
832
|
-
try {
|
|
833
|
-
return new Intl.NumberFormat(locale, {
|
|
834
|
-
style: "currency",
|
|
835
|
-
currency: currency.toUpperCase(),
|
|
836
|
-
minimumFractionDigits: 2,
|
|
837
|
-
maximumFractionDigits: 2
|
|
838
|
-
}).format(numAmount);
|
|
839
|
-
} catch {
|
|
840
|
-
return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
function parsePrice(value) {
|
|
844
|
-
if (value === void 0 || value === null) {
|
|
845
|
-
return 0;
|
|
846
|
-
}
|
|
847
|
-
if (typeof value === "number") {
|
|
848
|
-
return isNaN(value) ? 0 : value;
|
|
849
|
-
}
|
|
850
|
-
const cleaned = value.replace(/[^\d.-]/g, "");
|
|
851
|
-
const parsed = parseFloat(cleaned);
|
|
852
|
-
return isNaN(parsed) ? 0 : parsed;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
// src/types/common.ts
|
|
856
|
-
function money(value) {
|
|
857
|
-
return value;
|
|
858
|
-
}
|
|
859
|
-
function moneyFromNumber(value) {
|
|
860
|
-
return value.toFixed(2);
|
|
861
|
-
}
|
|
862
|
-
function currencyCode(value) {
|
|
863
|
-
return value;
|
|
864
|
-
}
|
|
865
|
-
var ErrorCode = {
|
|
866
|
-
// General
|
|
867
|
-
UNKNOWN_ERROR: "UNKNOWN_ERROR",
|
|
868
|
-
NETWORK_ERROR: "NETWORK_ERROR",
|
|
869
|
-
TIMEOUT: "TIMEOUT",
|
|
870
|
-
UNAUTHORIZED: "UNAUTHORIZED",
|
|
871
|
-
NOT_FOUND: "NOT_FOUND"};
|
|
872
|
-
var DOCS_ERROR_BASE_URL = "https://docs.cimplify.io/reference/error-codes";
|
|
873
|
-
function docsUrlForCode(code) {
|
|
874
|
-
return `${DOCS_ERROR_BASE_URL}#${code.toLowerCase().replace(/_/g, "-")}`;
|
|
875
|
-
}
|
|
876
|
-
var ERROR_SUGGESTIONS = {
|
|
877
|
-
UNKNOWN_ERROR: "An unexpected error occurred. Capture the request/response payload and retry with exponential backoff.",
|
|
878
|
-
NETWORK_ERROR: "Check the shopper's connection and retry. If this persists, inspect CORS, DNS, and API reachability.",
|
|
879
|
-
TIMEOUT: "The request exceeded the timeout. Retry once, then poll order status before charging again.",
|
|
880
|
-
UNAUTHORIZED: "Authentication is missing or expired. Ensure a valid access token is set and refresh the session if needed.",
|
|
881
|
-
FORBIDDEN: "The key/session lacks permission for this resource. Verify business ownership and API key scope.",
|
|
882
|
-
NOT_FOUND: "The requested resource does not exist or is not visible in this environment.",
|
|
883
|
-
VALIDATION_ERROR: "One or more fields are invalid. Validate required fields and enum values before retrying.",
|
|
884
|
-
CART_EMPTY: "The cart has no items. Redirect back to menu/catalogue and require at least one line item.",
|
|
885
|
-
CART_EXPIRED: "This cart is no longer active. Recreate a new cart and re-add shopper selections.",
|
|
886
|
-
CART_NOT_FOUND: "Cart could not be located. It may have expired or belongs to a different key/location.",
|
|
887
|
-
ITEM_UNAVAILABLE: "The selected item is unavailable at this location/time. Prompt the shopper to pick an alternative.",
|
|
888
|
-
VARIANT_NOT_FOUND: "The requested variant no longer exists. Refresh product data and require re-selection.",
|
|
889
|
-
VARIANT_OUT_OF_STOCK: "The selected variant is out of stock. Show in-stock variants and block checkout for this line.",
|
|
890
|
-
ADDON_REQUIRED: "A required add-on is missing. Ensure required modifier groups are completed before add-to-cart.",
|
|
891
|
-
ADDON_MAX_EXCEEDED: "Too many add-ons were selected. Enforce max selections client-side before submission.",
|
|
892
|
-
CHECKOUT_VALIDATION_FAILED: "Checkout payload failed validation. Verify customer, order type, and address fields are complete.",
|
|
893
|
-
DELIVERY_ADDRESS_REQUIRED: "Delivery orders require an address. Collect and pass address info before processing checkout.",
|
|
894
|
-
CUSTOMER_INFO_REQUIRED: "Customer details are required. Ensure name/email/phone are available before checkout.",
|
|
895
|
-
QUOTE_NOT_FOUND: "Quote could not be found. Refresh pricing and create a new quote before checkout.",
|
|
896
|
-
QUOTE_EXPIRED: "Quote has expired. Re-fetch pricing to generate a new quote with a valid expiry window.",
|
|
897
|
-
QUOTE_CONSUMED: "Quote has already been used. Request a fresh quote to prevent duplicate checkout attempts.",
|
|
898
|
-
QUOTE_STORAGE_UNAVAILABLE: "Quote storage is temporarily unavailable. Retry shortly and avoid charging until quote fetch succeeds.",
|
|
899
|
-
PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
|
|
900
|
-
PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
|
|
901
|
-
INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
|
|
902
|
-
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
903
|
-
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
904
|
-
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
905
|
-
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
906
|
-
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
907
|
-
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
908
|
-
BOOKING_CONFLICT: "The requested booking conflicts with an existing reservation. Pick another slot/resource.",
|
|
909
|
-
SERVICE_NOT_FOUND: "Requested service no longer exists. Refresh service catalogue and retry selection.",
|
|
910
|
-
OUT_OF_STOCK: "Inventory is depleted for this item. Remove it or reduce quantity before checkout.",
|
|
911
|
-
INSUFFICIENT_QUANTITY: "Requested quantity exceeds available inventory. Reduce quantity and retry.",
|
|
912
|
-
BUSINESS_ID_REQUIRED: "Business context could not be resolved. Verify the public key and business bootstrap call.",
|
|
913
|
-
INVALID_CART: "Cart is invalid for checkout. Sync cart state, ensure items exist, then retry.",
|
|
914
|
-
ORDER_TYPE_REQUIRED: "Order type is required. Provide one of delivery, pickup, or dine_in before checkout.",
|
|
915
|
-
NO_PAYMENT_ELEMENT: "PaymentElement is required for processCheckout(). Mount it before triggering checkout.",
|
|
916
|
-
PAYMENT_NOT_MOUNTED: "PaymentElement iframe is not mounted. Mount it in the DOM before processCheckout().",
|
|
917
|
-
AUTH_INCOMPLETE: "AuthElement has not completed authentication. Wait for AUTHENTICATED before checkout.",
|
|
918
|
-
AUTH_LOST: "Session was cleared during checkout. Re-authenticate and restart checkout safely.",
|
|
919
|
-
ALREADY_PROCESSING: "Checkout is already in progress. Disable duplicate submits until completion.",
|
|
920
|
-
CHECKOUT_NOT_READY: "Checkout elements are still initializing. Wait for readiness before submit.",
|
|
921
|
-
CANCELLED: "Checkout was cancelled. Preserve cart state and allow shopper to retry.",
|
|
922
|
-
REQUEST_TIMEOUT: "Provider call timed out. Poll payment/order status before issuing another charge attempt.",
|
|
923
|
-
POPUP_BLOCKED: "Browser blocked provider popup. Ask shopper to enable popups and retry.",
|
|
924
|
-
FX_QUOTE_FAILED: "Failed to lock FX quote. Retry currency quote or fallback to base currency."
|
|
925
|
-
};
|
|
926
|
-
var ERROR_HINTS = Object.fromEntries(
|
|
927
|
-
Object.entries(ERROR_SUGGESTIONS).map(([code, suggestion]) => [
|
|
928
|
-
code,
|
|
929
|
-
{
|
|
930
|
-
docs_url: docsUrlForCode(code),
|
|
931
|
-
suggestion
|
|
932
|
-
}
|
|
933
|
-
])
|
|
934
|
-
);
|
|
935
|
-
var CimplifyError = class extends Error {
|
|
936
|
-
constructor(code, message, retryable = false, docs_url, suggestion) {
|
|
937
|
-
super(message);
|
|
938
|
-
this.code = code;
|
|
939
|
-
this.retryable = retryable;
|
|
940
|
-
this.docs_url = docs_url;
|
|
941
|
-
this.suggestion = suggestion;
|
|
942
|
-
this.name = "CimplifyError";
|
|
943
|
-
}
|
|
944
|
-
/** User-friendly message safe to display */
|
|
945
|
-
get userMessage() {
|
|
946
|
-
return this.message;
|
|
947
|
-
}
|
|
948
|
-
};
|
|
949
|
-
function getErrorHint(code) {
|
|
950
|
-
return ERROR_HINTS[code];
|
|
951
|
-
}
|
|
952
|
-
function enrichError(error, options = {}) {
|
|
953
|
-
const hint = getErrorHint(error.code);
|
|
954
|
-
if (hint) {
|
|
955
|
-
if (!error.docs_url) {
|
|
956
|
-
error.docs_url = hint.docs_url;
|
|
957
|
-
}
|
|
958
|
-
if (!error.suggestion) {
|
|
959
|
-
error.suggestion = hint.suggestion;
|
|
960
|
-
}
|
|
961
|
-
} else if (!error.docs_url) {
|
|
962
|
-
error.docs_url = docsUrlForCode(error.code || ErrorCode.UNKNOWN_ERROR);
|
|
963
|
-
}
|
|
964
|
-
if (options.isTestMode && !error.message.includes("pk_test_")) {
|
|
965
|
-
error.message = `${error.message}
|
|
966
|
-
|
|
967
|
-
\u2139 Your API key is a test-mode key (pk_test_...). Verify test data/session before retrying.`;
|
|
968
|
-
}
|
|
969
|
-
return error;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
// src/types/result.ts
|
|
973
|
-
function ok(value) {
|
|
974
|
-
return { ok: true, value };
|
|
975
|
-
}
|
|
976
|
-
function err(error) {
|
|
977
|
-
return { ok: false, error };
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
// src/catalogue.ts
|
|
981
|
-
function toCimplifyError(error) {
|
|
982
|
-
if (error instanceof CimplifyError) return enrichError(error);
|
|
983
|
-
if (error instanceof Error) {
|
|
984
|
-
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, error.message, false));
|
|
985
|
-
}
|
|
986
|
-
return enrichError(new CimplifyError(ErrorCode.UNKNOWN_ERROR, String(error), false));
|
|
987
|
-
}
|
|
988
|
-
async function safe(promise) {
|
|
989
|
-
try {
|
|
990
|
-
return ok(await promise);
|
|
991
|
-
} catch (error) {
|
|
992
|
-
return err(toCimplifyError(error));
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
function withQuery(path, params) {
|
|
996
|
-
const query = new URLSearchParams();
|
|
997
|
-
for (const [key, value] of Object.entries(params)) {
|
|
998
|
-
if (value === void 0) continue;
|
|
999
|
-
query.set(key, String(value));
|
|
1000
|
-
}
|
|
1001
|
-
const queryString = query.toString();
|
|
1002
|
-
return queryString ? `${path}?${queryString}` : path;
|
|
1003
|
-
}
|
|
1004
|
-
function isRecord(value) {
|
|
1005
|
-
return typeof value === "object" && value !== null;
|
|
1006
|
-
}
|
|
1007
|
-
function readFinalPrice(value) {
|
|
1008
|
-
if (!isRecord(value)) return void 0;
|
|
1009
|
-
const finalPrice = value.final_price;
|
|
1010
|
-
if (typeof finalPrice === "string" || typeof finalPrice === "number") {
|
|
1011
|
-
return finalPrice;
|
|
1012
|
-
}
|
|
1013
|
-
return void 0;
|
|
580
|
+
return void 0;
|
|
1014
581
|
}
|
|
1015
582
|
function normalizeAddOnPayload(addOn) {
|
|
1016
583
|
if (!isRecord(addOn)) return addOn;
|
|
@@ -1440,28 +1007,132 @@ var CartOperations = class {
|
|
|
1440
1007
|
});
|
|
1441
1008
|
return ok(found);
|
|
1442
1009
|
}
|
|
1443
|
-
async findItem(productId, variantId) {
|
|
1444
|
-
const itemsResult = await this.getItems();
|
|
1445
|
-
if (!itemsResult.ok) return itemsResult;
|
|
1446
|
-
const found = itemsResult.value.find((item) => {
|
|
1447
|
-
const matchesProduct = item.item_id === productId;
|
|
1448
|
-
if (!variantId) return matchesProduct;
|
|
1449
|
-
const config = item.configuration;
|
|
1450
|
-
if ("variant" in config && config.variant) {
|
|
1451
|
-
return matchesProduct && config.variant.variant_id === variantId;
|
|
1452
|
-
}
|
|
1453
|
-
return matchesProduct;
|
|
1454
|
-
});
|
|
1455
|
-
return ok(found);
|
|
1010
|
+
async findItem(productId, variantId) {
|
|
1011
|
+
const itemsResult = await this.getItems();
|
|
1012
|
+
if (!itemsResult.ok) return itemsResult;
|
|
1013
|
+
const found = itemsResult.value.find((item) => {
|
|
1014
|
+
const matchesProduct = item.item_id === productId;
|
|
1015
|
+
if (!variantId) return matchesProduct;
|
|
1016
|
+
const config = item.configuration;
|
|
1017
|
+
if ("variant" in config && config.variant) {
|
|
1018
|
+
return matchesProduct && config.variant.variant_id === variantId;
|
|
1019
|
+
}
|
|
1020
|
+
return matchesProduct;
|
|
1021
|
+
});
|
|
1022
|
+
return ok(found);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
|
|
1026
|
+
// src/constants.ts
|
|
1027
|
+
var MOBILE_MONEY_PROVIDER = {
|
|
1028
|
+
MTN: "mtn",
|
|
1029
|
+
VODAFONE: "vodafone",
|
|
1030
|
+
AIRTEL: "airtel"
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
// src/utils/price.ts
|
|
1034
|
+
var CURRENCY_SYMBOLS = {
|
|
1035
|
+
// Major world currencies
|
|
1036
|
+
USD: "$",
|
|
1037
|
+
EUR: "\u20AC",
|
|
1038
|
+
GBP: "\xA3",
|
|
1039
|
+
JPY: "\xA5",
|
|
1040
|
+
CNY: "\xA5",
|
|
1041
|
+
CHF: "CHF",
|
|
1042
|
+
CAD: "C$",
|
|
1043
|
+
AUD: "A$",
|
|
1044
|
+
NZD: "NZ$",
|
|
1045
|
+
HKD: "HK$",
|
|
1046
|
+
SGD: "S$",
|
|
1047
|
+
INR: "\u20B9",
|
|
1048
|
+
BRL: "R$",
|
|
1049
|
+
MXN: "MX$",
|
|
1050
|
+
KRW: "\u20A9",
|
|
1051
|
+
RUB: "\u20BD",
|
|
1052
|
+
TRY: "\u20BA",
|
|
1053
|
+
THB: "\u0E3F",
|
|
1054
|
+
PLN: "z\u0142",
|
|
1055
|
+
SEK: "kr",
|
|
1056
|
+
NOK: "kr",
|
|
1057
|
+
DKK: "kr",
|
|
1058
|
+
CZK: "K\u010D",
|
|
1059
|
+
HUF: "Ft",
|
|
1060
|
+
ILS: "\u20AA",
|
|
1061
|
+
AED: "\u062F.\u0625",
|
|
1062
|
+
SAR: "\uFDFC",
|
|
1063
|
+
MYR: "RM",
|
|
1064
|
+
PHP: "\u20B1",
|
|
1065
|
+
IDR: "Rp",
|
|
1066
|
+
VND: "\u20AB",
|
|
1067
|
+
TWD: "NT$",
|
|
1068
|
+
// African currencies
|
|
1069
|
+
GHS: "GH\u20B5",
|
|
1070
|
+
NGN: "\u20A6",
|
|
1071
|
+
KES: "KSh",
|
|
1072
|
+
ZAR: "R",
|
|
1073
|
+
XOF: "CFA",
|
|
1074
|
+
XAF: "FCFA",
|
|
1075
|
+
EGP: "E\xA3",
|
|
1076
|
+
MAD: "MAD",
|
|
1077
|
+
TZS: "TSh",
|
|
1078
|
+
UGX: "USh",
|
|
1079
|
+
RWF: "FRw",
|
|
1080
|
+
ETB: "Br",
|
|
1081
|
+
ZMW: "ZK",
|
|
1082
|
+
BWP: "P",
|
|
1083
|
+
MUR: "\u20A8",
|
|
1084
|
+
SCR: "\u20A8",
|
|
1085
|
+
NAD: "N$",
|
|
1086
|
+
SZL: "E",
|
|
1087
|
+
LSL: "L",
|
|
1088
|
+
MWK: "MK",
|
|
1089
|
+
AOA: "Kz",
|
|
1090
|
+
CDF: "FC",
|
|
1091
|
+
GMD: "D",
|
|
1092
|
+
GNF: "FG",
|
|
1093
|
+
LRD: "L$",
|
|
1094
|
+
SLL: "Le",
|
|
1095
|
+
MZN: "MT",
|
|
1096
|
+
SDG: "SDG",
|
|
1097
|
+
SSP: "SSP",
|
|
1098
|
+
SOS: "Sh.So.",
|
|
1099
|
+
DJF: "Fdj",
|
|
1100
|
+
ERN: "Nfk",
|
|
1101
|
+
CVE: "$",
|
|
1102
|
+
STN: "Db",
|
|
1103
|
+
KMF: "CF",
|
|
1104
|
+
BIF: "FBu"
|
|
1105
|
+
};
|
|
1106
|
+
function getCurrencySymbol(currencyCode2) {
|
|
1107
|
+
return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
|
|
1108
|
+
}
|
|
1109
|
+
function formatPrice(amount, currency = "GHS", locale = "en-US") {
|
|
1110
|
+
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
1111
|
+
if (isNaN(numAmount)) {
|
|
1112
|
+
return `${getCurrencySymbol(currency)}0.00`;
|
|
1113
|
+
}
|
|
1114
|
+
try {
|
|
1115
|
+
return new Intl.NumberFormat(locale, {
|
|
1116
|
+
style: "currency",
|
|
1117
|
+
currency: currency.toUpperCase(),
|
|
1118
|
+
minimumFractionDigits: 2,
|
|
1119
|
+
maximumFractionDigits: 2
|
|
1120
|
+
}).format(numAmount);
|
|
1121
|
+
} catch {
|
|
1122
|
+
return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
function parsePrice(value) {
|
|
1126
|
+
if (value === void 0 || value === null) {
|
|
1127
|
+
return 0;
|
|
1456
1128
|
}
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
};
|
|
1129
|
+
if (typeof value === "number") {
|
|
1130
|
+
return isNaN(value) ? 0 : value;
|
|
1131
|
+
}
|
|
1132
|
+
const cleaned = value.replace(/[^\d.-]/g, "");
|
|
1133
|
+
const parsed = parseFloat(cleaned);
|
|
1134
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
1135
|
+
}
|
|
1465
1136
|
|
|
1466
1137
|
// src/utils/payment.ts
|
|
1467
1138
|
var PAYMENT_SUCCESS_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -3120,6 +2791,48 @@ var FxService = class {
|
|
|
3120
2791
|
}
|
|
3121
2792
|
};
|
|
3122
2793
|
|
|
2794
|
+
// src/types/elements.ts
|
|
2795
|
+
var ELEMENT_TYPES = {
|
|
2796
|
+
AUTH: "auth",
|
|
2797
|
+
ADDRESS: "address",
|
|
2798
|
+
PAYMENT: "payment",
|
|
2799
|
+
CHECKOUT: "checkout"
|
|
2800
|
+
};
|
|
2801
|
+
var MESSAGE_TYPES = {
|
|
2802
|
+
// Parent → Iframe
|
|
2803
|
+
INIT: "init",
|
|
2804
|
+
SET_TOKEN: "set_token",
|
|
2805
|
+
SET_CART: "set_cart",
|
|
2806
|
+
GET_DATA: "get_data",
|
|
2807
|
+
PROCESS_CHECKOUT: "process_checkout",
|
|
2808
|
+
ABORT_CHECKOUT: "abort_checkout",
|
|
2809
|
+
// Iframe → Parent
|
|
2810
|
+
READY: "ready",
|
|
2811
|
+
HEIGHT_CHANGE: "height_change",
|
|
2812
|
+
AUTHENTICATED: "authenticated",
|
|
2813
|
+
REQUIRES_OTP: "requires_otp",
|
|
2814
|
+
ERROR: "error",
|
|
2815
|
+
ADDRESS_CHANGED: "address_changed",
|
|
2816
|
+
ADDRESS_SELECTED: "address_selected",
|
|
2817
|
+
PAYMENT_METHOD_SELECTED: "payment_method_selected",
|
|
2818
|
+
TOKEN_REFRESHED: "token_refreshed",
|
|
2819
|
+
LOGOUT_COMPLETE: "logout_complete",
|
|
2820
|
+
CONTACT_PROVIDED: "contact_provided",
|
|
2821
|
+
CHECKOUT_STATUS: "checkout_status",
|
|
2822
|
+
CHECKOUT_COMPLETE: "checkout_complete",
|
|
2823
|
+
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
2824
|
+
REQUEST_SUBMIT: "request_submit"
|
|
2825
|
+
};
|
|
2826
|
+
var EVENT_TYPES = {
|
|
2827
|
+
READY: "ready",
|
|
2828
|
+
AUTHENTICATED: "authenticated",
|
|
2829
|
+
REQUIRES_OTP: "requires_otp",
|
|
2830
|
+
ERROR: "error",
|
|
2831
|
+
CHANGE: "change",
|
|
2832
|
+
ORDER_TYPE_CHANGED: "order_type_changed",
|
|
2833
|
+
REQUEST_SUBMIT: "request_submit"
|
|
2834
|
+
};
|
|
2835
|
+
|
|
3123
2836
|
// src/elements.ts
|
|
3124
2837
|
function toCheckoutError(code, message, recoverable) {
|
|
3125
2838
|
const hint = getErrorHint(code);
|
|
@@ -4406,247 +4119,610 @@ var CimplifyClient = class {
|
|
|
4406
4119
|
}
|
|
4407
4120
|
return createElements(this, businessId ?? this.businessId ?? void 0, options);
|
|
4408
4121
|
}
|
|
4409
|
-
};
|
|
4410
|
-
function createCimplifyClient(config = {}) {
|
|
4411
|
-
return new CimplifyClient(config);
|
|
4122
|
+
};
|
|
4123
|
+
function createCimplifyClient(config = {}) {
|
|
4124
|
+
return new CimplifyClient(config);
|
|
4125
|
+
}
|
|
4126
|
+
var LOCATION_STORAGE_KEY = "cimplify_location_id";
|
|
4127
|
+
var DISPLAY_CURRENCY_STORAGE_KEY = "cimplify_display_currency";
|
|
4128
|
+
var FX_REFRESH_INTERVAL = 12e4;
|
|
4129
|
+
var DEFAULT_CURRENCY = "USD";
|
|
4130
|
+
var DEFAULT_COUNTRY = "US";
|
|
4131
|
+
function createDefaultClient() {
|
|
4132
|
+
const processRef = globalThis.process;
|
|
4133
|
+
const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
|
|
4134
|
+
return createCimplifyClient({ publicKey: envPublicKey });
|
|
4135
|
+
}
|
|
4136
|
+
function getStoredLocationId() {
|
|
4137
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4138
|
+
return null;
|
|
4139
|
+
}
|
|
4140
|
+
const value = window.localStorage.getItem(LOCATION_STORAGE_KEY);
|
|
4141
|
+
if (!value) {
|
|
4142
|
+
return null;
|
|
4143
|
+
}
|
|
4144
|
+
const normalized = value.trim();
|
|
4145
|
+
return normalized.length > 0 ? normalized : null;
|
|
4146
|
+
}
|
|
4147
|
+
function setStoredLocationId(locationId) {
|
|
4148
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4149
|
+
return;
|
|
4150
|
+
}
|
|
4151
|
+
if (!locationId) {
|
|
4152
|
+
window.localStorage.removeItem(LOCATION_STORAGE_KEY);
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
window.localStorage.setItem(LOCATION_STORAGE_KEY, locationId);
|
|
4156
|
+
}
|
|
4157
|
+
function getStoredDisplayCurrency() {
|
|
4158
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4159
|
+
return null;
|
|
4160
|
+
}
|
|
4161
|
+
const value = window.localStorage.getItem(DISPLAY_CURRENCY_STORAGE_KEY);
|
|
4162
|
+
if (!value) {
|
|
4163
|
+
return null;
|
|
4164
|
+
}
|
|
4165
|
+
const normalized = value.trim().toUpperCase();
|
|
4166
|
+
return normalized.length > 0 ? normalized : null;
|
|
4167
|
+
}
|
|
4168
|
+
function setStoredDisplayCurrency(currency) {
|
|
4169
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4170
|
+
return;
|
|
4171
|
+
}
|
|
4172
|
+
if (!currency) {
|
|
4173
|
+
window.localStorage.removeItem(DISPLAY_CURRENCY_STORAGE_KEY);
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
window.localStorage.setItem(DISPLAY_CURRENCY_STORAGE_KEY, currency.toUpperCase());
|
|
4177
|
+
}
|
|
4178
|
+
function resolveInitialLocation(locations) {
|
|
4179
|
+
if (locations.length === 0) {
|
|
4180
|
+
return null;
|
|
4181
|
+
}
|
|
4182
|
+
const storedId = getStoredLocationId();
|
|
4183
|
+
if (storedId) {
|
|
4184
|
+
const matched = locations.find((location) => location.id === storedId);
|
|
4185
|
+
if (matched) {
|
|
4186
|
+
return matched;
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
return locations[0];
|
|
4190
|
+
}
|
|
4191
|
+
var CimplifyContext = React3.createContext(null);
|
|
4192
|
+
function CimplifyProvider({
|
|
4193
|
+
client,
|
|
4194
|
+
children,
|
|
4195
|
+
onLocationChange
|
|
4196
|
+
}) {
|
|
4197
|
+
const resolvedClient = React3.useMemo(() => client ?? createDefaultClient(), [client]);
|
|
4198
|
+
const onLocationChangeRef = React3.useRef(onLocationChange);
|
|
4199
|
+
const [business, setBusiness] = React3.useState(null);
|
|
4200
|
+
const [locations, setLocations] = React3.useState([]);
|
|
4201
|
+
const [currentLocation, setCurrentLocationState] = React3.useState(null);
|
|
4202
|
+
const [isReady, setIsReady] = React3.useState(false);
|
|
4203
|
+
React3.useEffect(() => {
|
|
4204
|
+
onLocationChangeRef.current = onLocationChange;
|
|
4205
|
+
}, [onLocationChange]);
|
|
4206
|
+
const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
|
|
4207
|
+
const baseCurrency = business?.default_currency || DEFAULT_CURRENCY;
|
|
4208
|
+
const [displayCurrencyOverride, setDisplayCurrencyOverride] = React3.useState(
|
|
4209
|
+
() => getStoredDisplayCurrency()
|
|
4210
|
+
);
|
|
4211
|
+
const [fxRate, setFxRate] = React3.useState(null);
|
|
4212
|
+
const displayCurrency = displayCurrencyOverride && displayCurrencyOverride !== baseCurrency ? displayCurrencyOverride : baseCurrency;
|
|
4213
|
+
const setDisplayCurrency = React3.useCallback(
|
|
4214
|
+
(currency) => {
|
|
4215
|
+
const normalized = currency?.trim().toUpperCase() || null;
|
|
4216
|
+
if (normalized && !isSupportedCurrency(normalized)) {
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
setDisplayCurrencyOverride(normalized);
|
|
4220
|
+
setStoredDisplayCurrency(normalized);
|
|
4221
|
+
if (!normalized || normalized === baseCurrency) {
|
|
4222
|
+
setFxRate(null);
|
|
4223
|
+
}
|
|
4224
|
+
},
|
|
4225
|
+
[baseCurrency]
|
|
4226
|
+
);
|
|
4227
|
+
React3.useEffect(() => {
|
|
4228
|
+
if (displayCurrency === baseCurrency || isDemoMode) {
|
|
4229
|
+
setFxRate(null);
|
|
4230
|
+
return;
|
|
4231
|
+
}
|
|
4232
|
+
let cancelled = false;
|
|
4233
|
+
async function fetchRate() {
|
|
4234
|
+
const result = await resolvedClient.fx.getRate(
|
|
4235
|
+
baseCurrency,
|
|
4236
|
+
displayCurrency
|
|
4237
|
+
);
|
|
4238
|
+
if (cancelled) return;
|
|
4239
|
+
if (result.ok) {
|
|
4240
|
+
setFxRate(result.value.rate);
|
|
4241
|
+
} else {
|
|
4242
|
+
setFxRate(null);
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
void fetchRate();
|
|
4246
|
+
const intervalId = setInterval(() => void fetchRate(), FX_REFRESH_INTERVAL);
|
|
4247
|
+
return () => {
|
|
4248
|
+
cancelled = true;
|
|
4249
|
+
clearInterval(intervalId);
|
|
4250
|
+
};
|
|
4251
|
+
}, [resolvedClient, baseCurrency, displayCurrency, isDemoMode]);
|
|
4252
|
+
const convertPrice = React3.useCallback(
|
|
4253
|
+
(amount) => {
|
|
4254
|
+
const num = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
4255
|
+
if (isNaN(num)) return 0;
|
|
4256
|
+
if (!fxRate || displayCurrency === baseCurrency) return num;
|
|
4257
|
+
return Math.round(num * fxRate * 100) / 100;
|
|
4258
|
+
},
|
|
4259
|
+
[fxRate, displayCurrency, baseCurrency]
|
|
4260
|
+
);
|
|
4261
|
+
const setCurrentLocation = React3.useCallback(
|
|
4262
|
+
(location) => {
|
|
4263
|
+
setCurrentLocationState(location);
|
|
4264
|
+
resolvedClient.setLocationId(location.id);
|
|
4265
|
+
setStoredLocationId(location.id);
|
|
4266
|
+
onLocationChangeRef.current?.(location);
|
|
4267
|
+
},
|
|
4268
|
+
[resolvedClient]
|
|
4269
|
+
);
|
|
4270
|
+
React3.useEffect(() => {
|
|
4271
|
+
let cancelled = false;
|
|
4272
|
+
async function bootstrap() {
|
|
4273
|
+
setIsReady(false);
|
|
4274
|
+
if (isDemoMode) {
|
|
4275
|
+
if (!cancelled) {
|
|
4276
|
+
setBusiness(null);
|
|
4277
|
+
setLocations([]);
|
|
4278
|
+
setCurrentLocationState(null);
|
|
4279
|
+
resolvedClient.setLocationId(null);
|
|
4280
|
+
setStoredLocationId(null);
|
|
4281
|
+
setIsReady(true);
|
|
4282
|
+
}
|
|
4283
|
+
return;
|
|
4284
|
+
}
|
|
4285
|
+
const [businessResult, locationsResult] = await Promise.all([
|
|
4286
|
+
resolvedClient.business.getInfo(),
|
|
4287
|
+
resolvedClient.business.getLocations()
|
|
4288
|
+
]);
|
|
4289
|
+
if (cancelled) {
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
const nextBusiness = businessResult.ok ? businessResult.value : null;
|
|
4293
|
+
const nextLocations = locationsResult.ok && Array.isArray(locationsResult.value) ? locationsResult.value : [];
|
|
4294
|
+
const initialLocation = resolveInitialLocation(nextLocations);
|
|
4295
|
+
setBusiness(nextBusiness);
|
|
4296
|
+
if (nextBusiness?.id) {
|
|
4297
|
+
resolvedClient.setBusinessId(nextBusiness.id);
|
|
4298
|
+
}
|
|
4299
|
+
setLocations(nextLocations);
|
|
4300
|
+
if (initialLocation) {
|
|
4301
|
+
setCurrentLocationState(initialLocation);
|
|
4302
|
+
resolvedClient.setLocationId(initialLocation.id);
|
|
4303
|
+
setStoredLocationId(initialLocation.id);
|
|
4304
|
+
} else {
|
|
4305
|
+
setCurrentLocationState(null);
|
|
4306
|
+
resolvedClient.setLocationId(null);
|
|
4307
|
+
setStoredLocationId(null);
|
|
4308
|
+
}
|
|
4309
|
+
setIsReady(true);
|
|
4310
|
+
}
|
|
4311
|
+
bootstrap().catch(() => {
|
|
4312
|
+
if (cancelled) {
|
|
4313
|
+
return;
|
|
4314
|
+
}
|
|
4315
|
+
setBusiness(null);
|
|
4316
|
+
setLocations([]);
|
|
4317
|
+
setCurrentLocationState(null);
|
|
4318
|
+
resolvedClient.setLocationId(null);
|
|
4319
|
+
setStoredLocationId(null);
|
|
4320
|
+
setIsReady(true);
|
|
4321
|
+
});
|
|
4322
|
+
return () => {
|
|
4323
|
+
cancelled = true;
|
|
4324
|
+
};
|
|
4325
|
+
}, [resolvedClient, isDemoMode]);
|
|
4326
|
+
const contextValue = React3.useMemo(
|
|
4327
|
+
() => ({
|
|
4328
|
+
client: resolvedClient,
|
|
4329
|
+
business,
|
|
4330
|
+
currency: baseCurrency,
|
|
4331
|
+
country: business?.country_code || DEFAULT_COUNTRY,
|
|
4332
|
+
locations,
|
|
4333
|
+
currentLocation,
|
|
4334
|
+
setCurrentLocation,
|
|
4335
|
+
isReady,
|
|
4336
|
+
isDemoMode,
|
|
4337
|
+
baseCurrency,
|
|
4338
|
+
displayCurrency,
|
|
4339
|
+
setDisplayCurrency,
|
|
4340
|
+
convertPrice,
|
|
4341
|
+
fxRate
|
|
4342
|
+
}),
|
|
4343
|
+
[
|
|
4344
|
+
resolvedClient,
|
|
4345
|
+
business,
|
|
4346
|
+
baseCurrency,
|
|
4347
|
+
locations,
|
|
4348
|
+
currentLocation,
|
|
4349
|
+
setCurrentLocation,
|
|
4350
|
+
isReady,
|
|
4351
|
+
isDemoMode,
|
|
4352
|
+
displayCurrency,
|
|
4353
|
+
setDisplayCurrency,
|
|
4354
|
+
convertPrice,
|
|
4355
|
+
fxRate
|
|
4356
|
+
]
|
|
4357
|
+
);
|
|
4358
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CimplifyContext.Provider, { value: contextValue, children });
|
|
4359
|
+
}
|
|
4360
|
+
function useCimplify() {
|
|
4361
|
+
const context = React3.useContext(CimplifyContext);
|
|
4362
|
+
if (!context) {
|
|
4363
|
+
throw new Error("useCimplify must be used within CimplifyProvider");
|
|
4364
|
+
}
|
|
4365
|
+
return context;
|
|
4412
4366
|
}
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
var FX_REFRESH_INTERVAL = 12e4;
|
|
4416
|
-
var DEFAULT_CURRENCY = "USD";
|
|
4417
|
-
var DEFAULT_COUNTRY = "US";
|
|
4418
|
-
function createDefaultClient() {
|
|
4419
|
-
const processRef = globalThis.process;
|
|
4420
|
-
const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
|
|
4421
|
-
return createCimplifyClient({ publicKey: envPublicKey });
|
|
4367
|
+
function useOptionalCimplify() {
|
|
4368
|
+
return React3.useContext(CimplifyContext);
|
|
4422
4369
|
}
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4370
|
+
var SPACE = { sm: 8};
|
|
4371
|
+
function shellColors(isDark, primaryColor) {
|
|
4372
|
+
return {
|
|
4373
|
+
text: isDark ? "#f4f4f5" : "#1a1a1a",
|
|
4374
|
+
textSecondary: isDark ? "#a1a1aa" : "#52525b",
|
|
4375
|
+
textMuted: isDark ? "#71717a" : "#a1a1aa",
|
|
4376
|
+
border: isDark ? "#27272a" : "#e4e4e7",
|
|
4377
|
+
surface: isDark ? "#18181b" : "#fafafa",
|
|
4378
|
+
error: "#dc2626",
|
|
4379
|
+
primary: primaryColor
|
|
4380
|
+
};
|
|
4433
4381
|
}
|
|
4434
|
-
function
|
|
4435
|
-
if (
|
|
4436
|
-
return;
|
|
4382
|
+
function statusToLabel(status) {
|
|
4383
|
+
if (!status) {
|
|
4384
|
+
return "";
|
|
4437
4385
|
}
|
|
4438
|
-
if (
|
|
4439
|
-
|
|
4440
|
-
return;
|
|
4386
|
+
if (status === "preparing") {
|
|
4387
|
+
return "Preparing checkout";
|
|
4441
4388
|
}
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
function getStoredDisplayCurrency() {
|
|
4445
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
4446
|
-
return null;
|
|
4389
|
+
if (status === "recovering") {
|
|
4390
|
+
return "Resuming payment";
|
|
4447
4391
|
}
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
return null;
|
|
4392
|
+
if (status === "processing") {
|
|
4393
|
+
return "Processing payment";
|
|
4451
4394
|
}
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
}
|
|
4455
|
-
function setStoredDisplayCurrency(currency) {
|
|
4456
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
4457
|
-
return;
|
|
4395
|
+
if (status === "awaiting_authorization") {
|
|
4396
|
+
return "Waiting for authorization";
|
|
4458
4397
|
}
|
|
4459
|
-
if (
|
|
4460
|
-
|
|
4461
|
-
return;
|
|
4398
|
+
if (status === "polling") {
|
|
4399
|
+
return "Confirming payment";
|
|
4462
4400
|
}
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
function resolveInitialLocation(locations) {
|
|
4466
|
-
if (locations.length === 0) {
|
|
4467
|
-
return null;
|
|
4401
|
+
if (status === "finalizing") {
|
|
4402
|
+
return "Finalizing order";
|
|
4468
4403
|
}
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
const matched = locations.find((location) => location.id === storedId);
|
|
4472
|
-
if (matched) {
|
|
4473
|
-
return matched;
|
|
4474
|
-
}
|
|
4404
|
+
if (status === "success") {
|
|
4405
|
+
return "Payment complete";
|
|
4475
4406
|
}
|
|
4476
|
-
return
|
|
4407
|
+
return "Payment failed";
|
|
4477
4408
|
}
|
|
4478
|
-
|
|
4479
|
-
function CimplifyProvider({
|
|
4409
|
+
function CimplifyCheckout({
|
|
4480
4410
|
client,
|
|
4481
|
-
|
|
4482
|
-
|
|
4411
|
+
businessId,
|
|
4412
|
+
cartId,
|
|
4413
|
+
locationId,
|
|
4414
|
+
linkUrl,
|
|
4415
|
+
orderTypes,
|
|
4416
|
+
enrollInLink = true,
|
|
4417
|
+
onComplete,
|
|
4418
|
+
onError,
|
|
4419
|
+
onStatusChange,
|
|
4420
|
+
appearance,
|
|
4421
|
+
demoMode,
|
|
4422
|
+
className
|
|
4483
4423
|
}) {
|
|
4484
|
-
const
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
const [locations, setLocations] = React2.useState([]);
|
|
4488
|
-
const [currentLocation, setCurrentLocationState] = React2.useState(null);
|
|
4489
|
-
const [isReady, setIsReady] = React2.useState(false);
|
|
4490
|
-
React2.useEffect(() => {
|
|
4491
|
-
onLocationChangeRef.current = onLocationChange;
|
|
4492
|
-
}, [onLocationChange]);
|
|
4493
|
-
const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
|
|
4494
|
-
const baseCurrency = business?.default_currency || DEFAULT_CURRENCY;
|
|
4495
|
-
const [displayCurrencyOverride, setDisplayCurrencyOverride] = React2.useState(
|
|
4496
|
-
() => getStoredDisplayCurrency()
|
|
4424
|
+
const resolvedOrderTypes = React3.useMemo(
|
|
4425
|
+
() => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
|
|
4426
|
+
[orderTypes]
|
|
4497
4427
|
);
|
|
4498
|
-
const [
|
|
4499
|
-
const
|
|
4500
|
-
const
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4428
|
+
const [orderType, setOrderType] = React3.useState(resolvedOrderTypes[0] || "pickup");
|
|
4429
|
+
const [status, setStatus] = React3.useState(null);
|
|
4430
|
+
const [statusText, setStatusText] = React3.useState("");
|
|
4431
|
+
const [isSubmitting, setIsSubmitting] = React3.useState(false);
|
|
4432
|
+
const [isInitializing, setIsInitializing] = React3.useState(false);
|
|
4433
|
+
const [errorMessage, setErrorMessage] = React3.useState(null);
|
|
4434
|
+
const [resolvedBusinessId, setResolvedBusinessId] = React3.useState(businessId ?? null);
|
|
4435
|
+
const [resolvedCartId, setResolvedCartId] = React3.useState(cartId ?? null);
|
|
4436
|
+
const [resolvedCart, setResolvedCart] = React3.useState(null);
|
|
4437
|
+
const checkoutMountRef = React3.useRef(null);
|
|
4438
|
+
const elementsRef = React3.useRef(null);
|
|
4439
|
+
const activeCheckoutRef = React3.useRef(null);
|
|
4440
|
+
const initialAppearanceRef = React3.useRef(appearance);
|
|
4441
|
+
const hasWarnedInlineAppearanceRef = React3.useRef(false);
|
|
4442
|
+
const isMountedRef = React3.useRef(true);
|
|
4443
|
+
const demoRunRef = React3.useRef(0);
|
|
4444
|
+
const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
|
|
4445
|
+
const isTestMode = client.isTestMode();
|
|
4446
|
+
const cimplifyCtx = useOptionalCimplify();
|
|
4447
|
+
const fxOptions = React3.useMemo(() => {
|
|
4448
|
+
if (!cimplifyCtx?.fxRate) return void 0;
|
|
4449
|
+
if (cimplifyCtx.displayCurrency === cimplifyCtx.baseCurrency) return void 0;
|
|
4450
|
+
return {
|
|
4451
|
+
displayCurrency: cimplifyCtx.displayCurrency,
|
|
4452
|
+
convertPrice: cimplifyCtx.convertPrice
|
|
4453
|
+
};
|
|
4454
|
+
}, [cimplifyCtx?.fxRate, cimplifyCtx?.displayCurrency, cimplifyCtx?.baseCurrency, cimplifyCtx?.convertPrice]);
|
|
4455
|
+
const fxOptionsRef = React3.useRef(fxOptions);
|
|
4456
|
+
fxOptionsRef.current = fxOptions;
|
|
4457
|
+
const resolvedCartRef = React3.useRef(resolvedCart);
|
|
4458
|
+
resolvedCartRef.current = resolvedCart;
|
|
4459
|
+
const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
|
|
4460
|
+
const isDark = appearance?.theme === "dark";
|
|
4461
|
+
const emitStatus = React3__default.default.useEffectEvent(
|
|
4462
|
+
(nextStatus, context = {}) => {
|
|
4463
|
+
setStatus(nextStatus);
|
|
4464
|
+
setStatusText(context.display_text || "");
|
|
4465
|
+
onStatusChange?.(nextStatus, context);
|
|
4466
|
+
}
|
|
4510
4467
|
);
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
return;
|
|
4468
|
+
const fireError = React3__default.default.useEffectEvent(
|
|
4469
|
+
(error) => {
|
|
4470
|
+
onError?.(error);
|
|
4515
4471
|
}
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4472
|
+
);
|
|
4473
|
+
React3.useEffect(() => {
|
|
4474
|
+
if (!resolvedOrderTypes.includes(orderType)) {
|
|
4475
|
+
setOrderType(resolvedOrderTypes[0] || "pickup");
|
|
4476
|
+
}
|
|
4477
|
+
}, [resolvedOrderTypes, orderType]);
|
|
4478
|
+
React3.useEffect(() => {
|
|
4479
|
+
if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
|
|
4480
|
+
hasWarnedInlineAppearanceRef.current = true;
|
|
4481
|
+
console.warn(
|
|
4482
|
+
"[Cimplify] `appearance` prop reference changed after mount. Elements keep the initial appearance to avoid iframe remount. Memoize appearance with useMemo() to remove this warning."
|
|
4521
4483
|
);
|
|
4522
|
-
|
|
4523
|
-
|
|
4484
|
+
}
|
|
4485
|
+
}, [appearance]);
|
|
4486
|
+
React3.useEffect(() => {
|
|
4487
|
+
let cancelled = false;
|
|
4488
|
+
async function bootstrap() {
|
|
4489
|
+
if (isDemoCheckout) {
|
|
4490
|
+
if (!cancelled) {
|
|
4491
|
+
setResolvedBusinessId(businessId ?? null);
|
|
4492
|
+
setResolvedCartId(cartId ?? "cart_demo");
|
|
4493
|
+
setIsInitializing(false);
|
|
4494
|
+
setErrorMessage(null);
|
|
4495
|
+
}
|
|
4496
|
+
return;
|
|
4497
|
+
}
|
|
4498
|
+
const needsBusinessResolve = !businessId;
|
|
4499
|
+
const needsCartResolve = !cartId;
|
|
4500
|
+
if (!needsBusinessResolve && !needsCartResolve) {
|
|
4501
|
+
if (!cancelled) {
|
|
4502
|
+
setResolvedBusinessId(businessId || null);
|
|
4503
|
+
setResolvedCartId(cartId || null);
|
|
4504
|
+
setIsInitializing(false);
|
|
4505
|
+
setErrorMessage(null);
|
|
4506
|
+
}
|
|
4507
|
+
client.cart.get().then((cartResult) => {
|
|
4508
|
+
if (!cancelled && cartResult.ok && cartResult.value) {
|
|
4509
|
+
setResolvedCart(cartResult.value);
|
|
4510
|
+
}
|
|
4511
|
+
}).catch(() => {
|
|
4512
|
+
});
|
|
4513
|
+
return;
|
|
4514
|
+
}
|
|
4515
|
+
if (!cancelled) {
|
|
4516
|
+
setIsInitializing(true);
|
|
4517
|
+
setErrorMessage(null);
|
|
4518
|
+
}
|
|
4519
|
+
let nextBusinessId = businessId ?? null;
|
|
4520
|
+
if (!nextBusinessId) {
|
|
4521
|
+
try {
|
|
4522
|
+
nextBusinessId = await client.resolveBusinessId();
|
|
4523
|
+
} catch {
|
|
4524
|
+
if (!cancelled) {
|
|
4525
|
+
const message = "Unable to initialize checkout business context.";
|
|
4526
|
+
setResolvedBusinessId(null);
|
|
4527
|
+
setResolvedCartId(null);
|
|
4528
|
+
setErrorMessage(message);
|
|
4529
|
+
setIsInitializing(false);
|
|
4530
|
+
fireError({ code: "BUSINESS_ID_REQUIRED", message });
|
|
4531
|
+
}
|
|
4532
|
+
return;
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
let nextCartId = cartId ?? null;
|
|
4536
|
+
if (!nextCartId) {
|
|
4537
|
+
const cartResult = await client.cart.get();
|
|
4538
|
+
if (!cartResult.ok || !cartResult.value?.id || cartResult.value.items.length === 0) {
|
|
4539
|
+
if (!cancelled) {
|
|
4540
|
+
const message = "Your cart is empty. Add items before checkout.";
|
|
4541
|
+
setResolvedBusinessId(nextBusinessId);
|
|
4542
|
+
setResolvedCartId(null);
|
|
4543
|
+
setErrorMessage(message);
|
|
4544
|
+
setIsInitializing(false);
|
|
4545
|
+
fireError({ code: "CART_EMPTY", message });
|
|
4546
|
+
}
|
|
4547
|
+
return;
|
|
4548
|
+
}
|
|
4549
|
+
nextCartId = cartResult.value.id;
|
|
4550
|
+
if (!cancelled) {
|
|
4551
|
+
setResolvedCart(cartResult.value);
|
|
4552
|
+
}
|
|
4553
|
+
}
|
|
4554
|
+
if (!cancelled) {
|
|
4555
|
+
setResolvedBusinessId(nextBusinessId);
|
|
4556
|
+
setResolvedCartId(nextCartId);
|
|
4557
|
+
setIsInitializing(false);
|
|
4558
|
+
setErrorMessage(null);
|
|
4524
4559
|
}
|
|
4525
4560
|
}
|
|
4526
|
-
void
|
|
4527
|
-
const intervalId = setInterval(() => void fetchRate(), FX_REFRESH_INTERVAL);
|
|
4561
|
+
void bootstrap();
|
|
4528
4562
|
return () => {
|
|
4529
4563
|
cancelled = true;
|
|
4530
|
-
clearInterval(intervalId);
|
|
4531
4564
|
};
|
|
4532
|
-
}, [
|
|
4533
|
-
|
|
4534
|
-
(
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
}
|
|
4540
|
-
|
|
4541
|
-
)
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4565
|
+
}, [businessId, cartId, client, isDemoCheckout]);
|
|
4566
|
+
React3.useEffect(() => {
|
|
4567
|
+
return () => {
|
|
4568
|
+
isMountedRef.current = false;
|
|
4569
|
+
demoRunRef.current += 1;
|
|
4570
|
+
activeCheckoutRef.current?.abort();
|
|
4571
|
+
activeCheckoutRef.current = null;
|
|
4572
|
+
};
|
|
4573
|
+
}, []);
|
|
4574
|
+
const handleSubmit = React3__default.default.useEffectEvent(async () => {
|
|
4575
|
+
if (isSubmitting || isInitializing || !resolvedCartId) {
|
|
4576
|
+
if (!resolvedCartId && !isInitializing) {
|
|
4577
|
+
const message = "Your cart is empty. Add items before checkout.";
|
|
4578
|
+
setErrorMessage(message);
|
|
4579
|
+
fireError({ code: "CART_EMPTY", message });
|
|
4580
|
+
}
|
|
4581
|
+
return;
|
|
4582
|
+
}
|
|
4583
|
+
setErrorMessage(null);
|
|
4584
|
+
setIsSubmitting(true);
|
|
4585
|
+
emitStatus("preparing", { display_text: statusToLabel("preparing") });
|
|
4586
|
+
if (isDemoCheckout) {
|
|
4587
|
+
const runId = demoRunRef.current + 1;
|
|
4588
|
+
demoRunRef.current = runId;
|
|
4589
|
+
const wait = async (ms) => {
|
|
4590
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
4591
|
+
return isMountedRef.current && runId === demoRunRef.current;
|
|
4592
|
+
};
|
|
4593
|
+
try {
|
|
4594
|
+
if (!await wait(400)) return;
|
|
4595
|
+
emitStatus("processing", { display_text: statusToLabel("processing") });
|
|
4596
|
+
if (!await wait(900)) return;
|
|
4597
|
+
emitStatus("polling", { display_text: statusToLabel("polling") });
|
|
4598
|
+
if (!await wait(1200)) return;
|
|
4599
|
+
const result = {
|
|
4600
|
+
success: true,
|
|
4601
|
+
order: {
|
|
4602
|
+
id: `ord_demo_${Date.now()}`,
|
|
4603
|
+
order_number: `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`,
|
|
4604
|
+
status: "confirmed",
|
|
4605
|
+
total: "0.00",
|
|
4606
|
+
currency: "USD"
|
|
4607
|
+
}
|
|
4608
|
+
};
|
|
4609
|
+
emitStatus("success", {
|
|
4610
|
+
order_id: result.order?.id,
|
|
4611
|
+
order_number: result.order?.order_number,
|
|
4612
|
+
display_text: statusToLabel("success")
|
|
4613
|
+
});
|
|
4614
|
+
onComplete(result);
|
|
4615
|
+
} finally {
|
|
4616
|
+
if (isMountedRef.current && runId === demoRunRef.current) {
|
|
4617
|
+
setIsSubmitting(false);
|
|
4563
4618
|
}
|
|
4564
|
-
return;
|
|
4565
4619
|
}
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4620
|
+
return;
|
|
4621
|
+
}
|
|
4622
|
+
if (!elementsRef.current) {
|
|
4623
|
+
const message = "Checkout is still initializing. Please try again.";
|
|
4624
|
+
setErrorMessage(message);
|
|
4625
|
+
fireError({ code: "CHECKOUT_NOT_READY", message });
|
|
4626
|
+
setIsSubmitting(false);
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4629
|
+
const checkout = elementsRef.current.processCheckout({
|
|
4630
|
+
cart_id: resolvedCartId,
|
|
4631
|
+
location_id: locationId ?? client.getLocationId() ?? void 0,
|
|
4632
|
+
order_type: orderType,
|
|
4633
|
+
enroll_in_link: enrollInLink,
|
|
4634
|
+
on_status_change: emitStatus,
|
|
4635
|
+
pay_currency: fxOptions?.displayCurrency
|
|
4636
|
+
});
|
|
4637
|
+
activeCheckoutRef.current = checkout;
|
|
4638
|
+
try {
|
|
4639
|
+
const result = await checkout;
|
|
4640
|
+
if (result.success) {
|
|
4641
|
+
onComplete(result);
|
|
4571
4642
|
return;
|
|
4572
4643
|
}
|
|
4573
|
-
const
|
|
4574
|
-
const
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
if (initialLocation) {
|
|
4582
|
-
setCurrentLocationState(initialLocation);
|
|
4583
|
-
resolvedClient.setLocationId(initialLocation.id);
|
|
4584
|
-
setStoredLocationId(initialLocation.id);
|
|
4585
|
-
} else {
|
|
4586
|
-
setCurrentLocationState(null);
|
|
4587
|
-
resolvedClient.setLocationId(null);
|
|
4588
|
-
setStoredLocationId(null);
|
|
4644
|
+
const code = result.error?.code || "CHECKOUT_FAILED";
|
|
4645
|
+
const message = result.error?.message || "Payment failed.";
|
|
4646
|
+
setErrorMessage(message);
|
|
4647
|
+
fireError({ code, message });
|
|
4648
|
+
} finally {
|
|
4649
|
+
if (isMountedRef.current) {
|
|
4650
|
+
activeCheckoutRef.current = null;
|
|
4651
|
+
setIsSubmitting(false);
|
|
4589
4652
|
}
|
|
4590
|
-
setIsReady(true);
|
|
4591
4653
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4654
|
+
});
|
|
4655
|
+
React3.useEffect(() => {
|
|
4656
|
+
if (isDemoCheckout || !resolvedBusinessId) {
|
|
4657
|
+
elementsRef.current = null;
|
|
4658
|
+
return;
|
|
4659
|
+
}
|
|
4660
|
+
const elements = client.elements(resolvedBusinessId, {
|
|
4661
|
+
appearance: initialAppearanceRef.current,
|
|
4662
|
+
linkUrl
|
|
4663
|
+
});
|
|
4664
|
+
elementsRef.current = elements;
|
|
4665
|
+
const checkout = elements.create("checkout", {
|
|
4666
|
+
orderTypes: resolvedOrderTypes,
|
|
4667
|
+
defaultOrderType: resolvedOrderTypes[0]
|
|
4668
|
+
});
|
|
4669
|
+
if (checkoutMountRef.current) {
|
|
4670
|
+
checkout.mount(checkoutMountRef.current);
|
|
4671
|
+
}
|
|
4672
|
+
checkout.on("ready", () => {
|
|
4673
|
+
const cart = resolvedCartRef.current;
|
|
4674
|
+
if (cart) {
|
|
4675
|
+
checkout.setCart(transformToCheckoutCart(cart, fxOptionsRef.current));
|
|
4595
4676
|
}
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4677
|
+
});
|
|
4678
|
+
checkout.on("order_type_changed", (data) => {
|
|
4679
|
+
const typed = data;
|
|
4680
|
+
if (typed.orderType) {
|
|
4681
|
+
setOrderType(typed.orderType);
|
|
4682
|
+
}
|
|
4683
|
+
});
|
|
4684
|
+
checkout.on("request_submit", () => {
|
|
4685
|
+
void handleSubmit();
|
|
4602
4686
|
});
|
|
4603
4687
|
return () => {
|
|
4604
|
-
|
|
4688
|
+
activeCheckoutRef.current?.abort();
|
|
4689
|
+
activeCheckoutRef.current = null;
|
|
4690
|
+
elements.destroy();
|
|
4691
|
+
elementsRef.current = null;
|
|
4605
4692
|
};
|
|
4606
|
-
}, [
|
|
4607
|
-
|
|
4608
|
-
()
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
isDemoMode,
|
|
4618
|
-
baseCurrency,
|
|
4619
|
-
displayCurrency,
|
|
4620
|
-
setDisplayCurrency,
|
|
4621
|
-
convertPrice,
|
|
4622
|
-
fxRate
|
|
4623
|
-
}),
|
|
4624
|
-
[
|
|
4625
|
-
resolvedClient,
|
|
4626
|
-
business,
|
|
4627
|
-
baseCurrency,
|
|
4628
|
-
locations,
|
|
4629
|
-
currentLocation,
|
|
4630
|
-
setCurrentLocation,
|
|
4631
|
-
isReady,
|
|
4632
|
-
isDemoMode,
|
|
4633
|
-
displayCurrency,
|
|
4634
|
-
setDisplayCurrency,
|
|
4635
|
-
convertPrice,
|
|
4636
|
-
fxRate
|
|
4637
|
-
]
|
|
4638
|
-
);
|
|
4639
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CimplifyContext.Provider, { value: contextValue, children });
|
|
4640
|
-
}
|
|
4641
|
-
function useCimplify() {
|
|
4642
|
-
const context = React2.useContext(CimplifyContext);
|
|
4643
|
-
if (!context) {
|
|
4644
|
-
throw new Error("useCimplify must be used within CimplifyProvider");
|
|
4693
|
+
}, [client, resolvedBusinessId, isDemoCheckout]);
|
|
4694
|
+
React3.useEffect(() => {
|
|
4695
|
+
if (!resolvedCart || !elementsRef.current) return;
|
|
4696
|
+
const checkoutElement = elementsRef.current.getElement("checkout");
|
|
4697
|
+
if (checkoutElement) {
|
|
4698
|
+
checkoutElement.setCart(transformToCheckoutCart(resolvedCart, fxOptions));
|
|
4699
|
+
}
|
|
4700
|
+
}, [resolvedCart, fxOptions]);
|
|
4701
|
+
const colors = shellColors(isDark ?? false, primaryColor);
|
|
4702
|
+
if (isInitializing) {
|
|
4703
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
|
|
4645
4704
|
}
|
|
4646
|
-
|
|
4647
|
-
}
|
|
4648
|
-
|
|
4649
|
-
return
|
|
4705
|
+
if (!isDemoCheckout && (!resolvedBusinessId || !resolvedCartId)) {
|
|
4706
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { fontSize: 13, color: colors.error }, children: errorMessage || "Unable to initialize checkout. Please refresh and try again." }) });
|
|
4707
|
+
}
|
|
4708
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-cimplify-checkout": "", children: [
|
|
4709
|
+
isTestMode && !isDemoCheckout && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4710
|
+
"p",
|
|
4711
|
+
{
|
|
4712
|
+
"data-cimplify-test-mode": "",
|
|
4713
|
+
style: {
|
|
4714
|
+
marginBottom: "10px",
|
|
4715
|
+
fontSize: "12px",
|
|
4716
|
+
fontWeight: 600,
|
|
4717
|
+
color: "#92400e"
|
|
4718
|
+
},
|
|
4719
|
+
children: "Test mode - no real charges"
|
|
4720
|
+
}
|
|
4721
|
+
),
|
|
4722
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
|
|
4723
|
+
status && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
|
|
4724
|
+
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
|
|
4725
|
+
] });
|
|
4650
4726
|
}
|
|
4651
4727
|
function Price({ amount, className, prefix }) {
|
|
4652
4728
|
const { displayCurrency, convertPrice } = useCimplify();
|
|
@@ -4672,9 +4748,9 @@ function useProducts(options = {}) {
|
|
|
4672
4748
|
}
|
|
4673
4749
|
const enabled = options.enabled ?? true;
|
|
4674
4750
|
const locationId = client.getLocationId();
|
|
4675
|
-
const previousLocationIdRef =
|
|
4676
|
-
const requestIdRef =
|
|
4677
|
-
const queryOptions =
|
|
4751
|
+
const previousLocationIdRef = React3.useRef(locationId);
|
|
4752
|
+
const requestIdRef = React3.useRef(0);
|
|
4753
|
+
const queryOptions = React3.useMemo(
|
|
4678
4754
|
() => ({
|
|
4679
4755
|
category: options.category,
|
|
4680
4756
|
collection: options.collection,
|
|
@@ -4684,25 +4760,25 @@ function useProducts(options = {}) {
|
|
|
4684
4760
|
}),
|
|
4685
4761
|
[options.category, options.collection, options.featured, options.limit, options.search]
|
|
4686
4762
|
);
|
|
4687
|
-
const cacheKey =
|
|
4763
|
+
const cacheKey = React3.useMemo(
|
|
4688
4764
|
() => buildProductsCacheKey(client, locationId, queryOptions),
|
|
4689
4765
|
[client, locationId, queryOptions]
|
|
4690
4766
|
);
|
|
4691
4767
|
const cached = productsCache.get(cacheKey);
|
|
4692
|
-
const [products, setProducts] =
|
|
4693
|
-
const [isComplete, setIsComplete] =
|
|
4694
|
-
const [totalAvailable, setTotalAvailable] =
|
|
4695
|
-
const [pagination, setPagination] =
|
|
4696
|
-
const [isLoading, setIsLoading] =
|
|
4697
|
-
const [error, setError] =
|
|
4698
|
-
|
|
4768
|
+
const [products, setProducts] = React3.useState(cached?.products ?? []);
|
|
4769
|
+
const [isComplete, setIsComplete] = React3.useState(cached?.is_complete ?? true);
|
|
4770
|
+
const [totalAvailable, setTotalAvailable] = React3.useState(cached?.total_available);
|
|
4771
|
+
const [pagination, setPagination] = React3.useState(cached?.pagination);
|
|
4772
|
+
const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
|
|
4773
|
+
const [error, setError] = React3.useState(null);
|
|
4774
|
+
React3.useEffect(() => {
|
|
4699
4775
|
if (previousLocationIdRef.current !== locationId) {
|
|
4700
4776
|
productsCache.clear();
|
|
4701
4777
|
productsInflight.clear();
|
|
4702
4778
|
previousLocationIdRef.current = locationId;
|
|
4703
4779
|
}
|
|
4704
4780
|
}, [locationId]);
|
|
4705
|
-
const load =
|
|
4781
|
+
const load = React3.useCallback(
|
|
4706
4782
|
async (force = false) => {
|
|
4707
4783
|
if (!enabled) {
|
|
4708
4784
|
setIsLoading(false);
|
|
@@ -4765,10 +4841,10 @@ function useProducts(options = {}) {
|
|
|
4765
4841
|
},
|
|
4766
4842
|
[cacheKey, client, enabled, queryOptions]
|
|
4767
4843
|
);
|
|
4768
|
-
|
|
4844
|
+
React3.useEffect(() => {
|
|
4769
4845
|
void load(false);
|
|
4770
4846
|
}, [load]);
|
|
4771
|
-
const refetch =
|
|
4847
|
+
const refetch = React3.useCallback(async () => {
|
|
4772
4848
|
productsCache.delete(cacheKey);
|
|
4773
4849
|
await load(true);
|
|
4774
4850
|
}, [cacheKey, load]);
|
|
@@ -4802,27 +4878,27 @@ function useProduct(slugOrId, options = {}) {
|
|
|
4802
4878
|
}
|
|
4803
4879
|
const enabled = options.enabled ?? true;
|
|
4804
4880
|
const locationId = client.getLocationId();
|
|
4805
|
-
const previousLocationIdRef =
|
|
4806
|
-
const requestIdRef =
|
|
4807
|
-
const normalizedSlugOrId =
|
|
4808
|
-
const cacheKey =
|
|
4881
|
+
const previousLocationIdRef = React3.useRef(locationId);
|
|
4882
|
+
const requestIdRef = React3.useRef(0);
|
|
4883
|
+
const normalizedSlugOrId = React3.useMemo(() => (slugOrId || "").trim(), [slugOrId]);
|
|
4884
|
+
const cacheKey = React3.useMemo(
|
|
4809
4885
|
() => buildProductCacheKey(client, locationId, normalizedSlugOrId),
|
|
4810
4886
|
[client, locationId, normalizedSlugOrId]
|
|
4811
4887
|
);
|
|
4812
4888
|
const cached = productCache.get(cacheKey);
|
|
4813
|
-
const [product, setProduct] =
|
|
4814
|
-
const [isLoading, setIsLoading] =
|
|
4889
|
+
const [product, setProduct] = React3.useState(cached?.product ?? null);
|
|
4890
|
+
const [isLoading, setIsLoading] = React3.useState(
|
|
4815
4891
|
enabled && normalizedSlugOrId.length > 0 && !cached
|
|
4816
4892
|
);
|
|
4817
|
-
const [error, setError] =
|
|
4818
|
-
|
|
4893
|
+
const [error, setError] = React3.useState(null);
|
|
4894
|
+
React3.useEffect(() => {
|
|
4819
4895
|
if (previousLocationIdRef.current !== locationId) {
|
|
4820
4896
|
productCache.clear();
|
|
4821
4897
|
productInflight.clear();
|
|
4822
4898
|
previousLocationIdRef.current = locationId;
|
|
4823
4899
|
}
|
|
4824
4900
|
}, [locationId]);
|
|
4825
|
-
const load =
|
|
4901
|
+
const load = React3.useCallback(
|
|
4826
4902
|
async (force = false) => {
|
|
4827
4903
|
if (!enabled || normalizedSlugOrId.length === 0) {
|
|
4828
4904
|
setProduct(null);
|
|
@@ -4875,10 +4951,10 @@ function useProduct(slugOrId, options = {}) {
|
|
|
4875
4951
|
},
|
|
4876
4952
|
[cacheKey, client, enabled, normalizedSlugOrId]
|
|
4877
4953
|
);
|
|
4878
|
-
|
|
4954
|
+
React3.useEffect(() => {
|
|
4879
4955
|
void load(false);
|
|
4880
4956
|
}, [load]);
|
|
4881
|
-
const refetch =
|
|
4957
|
+
const refetch = React3.useCallback(async () => {
|
|
4882
4958
|
productCache.delete(cacheKey);
|
|
4883
4959
|
await load(true);
|
|
4884
4960
|
}, [cacheKey, load]);
|
|
@@ -4896,12 +4972,12 @@ function useCategories(options = {}) {
|
|
|
4896
4972
|
throw new Error("useCategories must be used within CimplifyProvider or passed { client }.");
|
|
4897
4973
|
}
|
|
4898
4974
|
const enabled = options.enabled ?? true;
|
|
4899
|
-
const cacheKey =
|
|
4975
|
+
const cacheKey = React3.useMemo(() => buildCategoriesCacheKey(client), [client]);
|
|
4900
4976
|
const cached = categoriesCache.get(cacheKey);
|
|
4901
|
-
const [categories, setCategories] =
|
|
4902
|
-
const [isLoading, setIsLoading] =
|
|
4903
|
-
const [error, setError] =
|
|
4904
|
-
const load =
|
|
4977
|
+
const [categories, setCategories] = React3.useState(cached ?? []);
|
|
4978
|
+
const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
|
|
4979
|
+
const [error, setError] = React3.useState(null);
|
|
4980
|
+
const load = React3.useCallback(
|
|
4905
4981
|
async (force = false) => {
|
|
4906
4982
|
if (!enabled) {
|
|
4907
4983
|
setIsLoading(false);
|
|
@@ -4945,10 +5021,10 @@ function useCategories(options = {}) {
|
|
|
4945
5021
|
},
|
|
4946
5022
|
[cacheKey, client, enabled]
|
|
4947
5023
|
);
|
|
4948
|
-
|
|
5024
|
+
React3.useEffect(() => {
|
|
4949
5025
|
void load(false);
|
|
4950
5026
|
}, [load]);
|
|
4951
|
-
const refetch =
|
|
5027
|
+
const refetch = React3.useCallback(async () => {
|
|
4952
5028
|
categoriesCache.delete(cacheKey);
|
|
4953
5029
|
await load(true);
|
|
4954
5030
|
}, [cacheKey, load]);
|
|
@@ -5469,7 +5545,7 @@ function useCart(options = {}) {
|
|
|
5469
5545
|
const locationId = options.locationId ?? client.getLocationId();
|
|
5470
5546
|
const isDemoMode = options.demoMode ?? context?.isDemoMode ?? client.getPublicKey().trim().length === 0;
|
|
5471
5547
|
const currency = options.currency ?? context?.currency ?? "USD";
|
|
5472
|
-
const store =
|
|
5548
|
+
const store = React3.useMemo(
|
|
5473
5549
|
() => getOrCreateStore({
|
|
5474
5550
|
client,
|
|
5475
5551
|
locationId,
|
|
@@ -5478,43 +5554,43 @@ function useCart(options = {}) {
|
|
|
5478
5554
|
}),
|
|
5479
5555
|
[client, currency, isDemoMode, locationId]
|
|
5480
5556
|
);
|
|
5481
|
-
const snapshot =
|
|
5557
|
+
const snapshot = React3.useSyncExternalStore(
|
|
5482
5558
|
store.subscribe,
|
|
5483
5559
|
store.getSnapshot,
|
|
5484
5560
|
store.getSnapshot
|
|
5485
5561
|
);
|
|
5486
|
-
|
|
5562
|
+
React3.useEffect(() => {
|
|
5487
5563
|
void store.initialize();
|
|
5488
5564
|
}, [store]);
|
|
5489
|
-
const addItem =
|
|
5565
|
+
const addItem = React3.useCallback(
|
|
5490
5566
|
async (product, quantity, addOptions) => {
|
|
5491
5567
|
await store.addItem(product, quantity, addOptions);
|
|
5492
5568
|
},
|
|
5493
5569
|
[store]
|
|
5494
5570
|
);
|
|
5495
|
-
const removeItem =
|
|
5571
|
+
const removeItem = React3.useCallback(
|
|
5496
5572
|
async (itemId) => {
|
|
5497
5573
|
await store.removeItem(itemId);
|
|
5498
5574
|
},
|
|
5499
5575
|
[store]
|
|
5500
5576
|
);
|
|
5501
|
-
const updateQuantity =
|
|
5577
|
+
const updateQuantity = React3.useCallback(
|
|
5502
5578
|
async (itemId, quantity) => {
|
|
5503
5579
|
await store.updateQuantity(itemId, quantity);
|
|
5504
5580
|
},
|
|
5505
5581
|
[store]
|
|
5506
5582
|
);
|
|
5507
|
-
const clearCart =
|
|
5583
|
+
const clearCart = React3.useCallback(async () => {
|
|
5508
5584
|
await store.clearCart();
|
|
5509
5585
|
}, [store]);
|
|
5510
|
-
const sync =
|
|
5586
|
+
const sync = React3.useCallback(async () => {
|
|
5511
5587
|
try {
|
|
5512
5588
|
await store.sync();
|
|
5513
5589
|
} catch (syncError) {
|
|
5514
5590
|
throw syncError;
|
|
5515
5591
|
}
|
|
5516
5592
|
}, [store]);
|
|
5517
|
-
const itemCount =
|
|
5593
|
+
const itemCount = React3.useMemo(
|
|
5518
5594
|
() => snapshot.items.reduce((sum, item) => sum + item.quantity, 0),
|
|
5519
5595
|
[snapshot.items]
|
|
5520
5596
|
);
|
|
@@ -5545,22 +5621,22 @@ function useOrder(orderId, options = {}) {
|
|
|
5545
5621
|
if (!client) {
|
|
5546
5622
|
throw new Error("useOrder must be used within CimplifyProvider or passed { client }.");
|
|
5547
5623
|
}
|
|
5548
|
-
const normalizedOrderId =
|
|
5624
|
+
const normalizedOrderId = React3.useMemo(() => (orderId || "").trim(), [orderId]);
|
|
5549
5625
|
const enabled = options.enabled ?? true;
|
|
5550
5626
|
const poll = options.poll ?? false;
|
|
5551
5627
|
const pollInterval = options.pollInterval ?? 5e3;
|
|
5552
|
-
const requestIdRef =
|
|
5553
|
-
const cacheKey =
|
|
5628
|
+
const requestIdRef = React3.useRef(0);
|
|
5629
|
+
const cacheKey = React3.useMemo(
|
|
5554
5630
|
() => buildOrderCacheKey(client, normalizedOrderId),
|
|
5555
5631
|
[client, normalizedOrderId]
|
|
5556
5632
|
);
|
|
5557
5633
|
const cached = orderCache.get(cacheKey);
|
|
5558
|
-
const [order, setOrder] =
|
|
5559
|
-
const [isLoading, setIsLoading] =
|
|
5634
|
+
const [order, setOrder] = React3.useState(cached?.order ?? null);
|
|
5635
|
+
const [isLoading, setIsLoading] = React3.useState(
|
|
5560
5636
|
enabled && normalizedOrderId.length > 0 && !cached
|
|
5561
5637
|
);
|
|
5562
|
-
const [error, setError] =
|
|
5563
|
-
const load =
|
|
5638
|
+
const [error, setError] = React3.useState(null);
|
|
5639
|
+
const load = React3.useCallback(
|
|
5564
5640
|
async (force = false) => {
|
|
5565
5641
|
if (!enabled || normalizedOrderId.length === 0) {
|
|
5566
5642
|
setOrder(null);
|
|
@@ -5613,10 +5689,10 @@ function useOrder(orderId, options = {}) {
|
|
|
5613
5689
|
},
|
|
5614
5690
|
[cacheKey, client, enabled, normalizedOrderId]
|
|
5615
5691
|
);
|
|
5616
|
-
|
|
5692
|
+
React3.useEffect(() => {
|
|
5617
5693
|
void load(false);
|
|
5618
5694
|
}, [load]);
|
|
5619
|
-
|
|
5695
|
+
React3.useEffect(() => {
|
|
5620
5696
|
if (!poll || !enabled || normalizedOrderId.length === 0) {
|
|
5621
5697
|
return;
|
|
5622
5698
|
}
|
|
@@ -5627,7 +5703,7 @@ function useOrder(orderId, options = {}) {
|
|
|
5627
5703
|
window.clearInterval(timer);
|
|
5628
5704
|
};
|
|
5629
5705
|
}, [enabled, load, normalizedOrderId.length, poll, pollInterval]);
|
|
5630
|
-
const refetch =
|
|
5706
|
+
const refetch = React3.useCallback(async () => {
|
|
5631
5707
|
orderCache.delete(cacheKey);
|
|
5632
5708
|
await load(true);
|
|
5633
5709
|
}, [cacheKey, load]);
|
|
@@ -5678,10 +5754,10 @@ function useLocations(options = {}) {
|
|
|
5678
5754
|
};
|
|
5679
5755
|
}
|
|
5680
5756
|
const client = options.client;
|
|
5681
|
-
const [locations, setLocations] =
|
|
5682
|
-
const [currentLocation, setCurrentLocationState] =
|
|
5683
|
-
const [isLoading, setIsLoading] =
|
|
5684
|
-
const setCurrentLocation =
|
|
5757
|
+
const [locations, setLocations] = React3.useState([]);
|
|
5758
|
+
const [currentLocation, setCurrentLocationState] = React3.useState(null);
|
|
5759
|
+
const [isLoading, setIsLoading] = React3.useState(true);
|
|
5760
|
+
const setCurrentLocation = React3.useCallback(
|
|
5685
5761
|
(location) => {
|
|
5686
5762
|
setCurrentLocationState(location);
|
|
5687
5763
|
if (client) {
|
|
@@ -5691,7 +5767,7 @@ function useLocations(options = {}) {
|
|
|
5691
5767
|
},
|
|
5692
5768
|
[client]
|
|
5693
5769
|
);
|
|
5694
|
-
|
|
5770
|
+
React3.useEffect(() => {
|
|
5695
5771
|
if (!client) {
|
|
5696
5772
|
setLocations([]);
|
|
5697
5773
|
setCurrentLocationState(null);
|
|
@@ -5749,24 +5825,24 @@ function useCollections(options = {}) {
|
|
|
5749
5825
|
}
|
|
5750
5826
|
const enabled = options.enabled ?? true;
|
|
5751
5827
|
const locationId = client.getLocationId();
|
|
5752
|
-
const previousLocationIdRef =
|
|
5753
|
-
const requestIdRef =
|
|
5754
|
-
const cacheKey =
|
|
5828
|
+
const previousLocationIdRef = React3.useRef(locationId);
|
|
5829
|
+
const requestIdRef = React3.useRef(0);
|
|
5830
|
+
const cacheKey = React3.useMemo(
|
|
5755
5831
|
() => buildCollectionsCacheKey(client, locationId),
|
|
5756
5832
|
[client, locationId]
|
|
5757
5833
|
);
|
|
5758
5834
|
const cached = collectionsCache.get(cacheKey);
|
|
5759
|
-
const [collections, setCollections] =
|
|
5760
|
-
const [isLoading, setIsLoading] =
|
|
5761
|
-
const [error, setError] =
|
|
5762
|
-
|
|
5835
|
+
const [collections, setCollections] = React3.useState(cached?.collections ?? []);
|
|
5836
|
+
const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
|
|
5837
|
+
const [error, setError] = React3.useState(null);
|
|
5838
|
+
React3.useEffect(() => {
|
|
5763
5839
|
if (previousLocationIdRef.current !== locationId) {
|
|
5764
5840
|
collectionsCache.clear();
|
|
5765
5841
|
collectionsInflight.clear();
|
|
5766
5842
|
previousLocationIdRef.current = locationId;
|
|
5767
5843
|
}
|
|
5768
5844
|
}, [locationId]);
|
|
5769
|
-
const load =
|
|
5845
|
+
const load = React3.useCallback(
|
|
5770
5846
|
async (force = false) => {
|
|
5771
5847
|
if (!enabled) {
|
|
5772
5848
|
setIsLoading(false);
|
|
@@ -5816,10 +5892,10 @@ function useCollections(options = {}) {
|
|
|
5816
5892
|
},
|
|
5817
5893
|
[cacheKey, client, enabled]
|
|
5818
5894
|
);
|
|
5819
|
-
|
|
5895
|
+
React3.useEffect(() => {
|
|
5820
5896
|
void load(false);
|
|
5821
5897
|
}, [load]);
|
|
5822
|
-
const refetch =
|
|
5898
|
+
const refetch = React3.useCallback(async () => {
|
|
5823
5899
|
collectionsCache.delete(cacheKey);
|
|
5824
5900
|
await load(true);
|
|
5825
5901
|
}, [cacheKey, load]);
|
|
@@ -5845,28 +5921,28 @@ function useCollection(idOrSlug, options = {}) {
|
|
|
5845
5921
|
}
|
|
5846
5922
|
const enabled = options.enabled ?? true;
|
|
5847
5923
|
const locationId = client.getLocationId();
|
|
5848
|
-
const previousLocationIdRef =
|
|
5849
|
-
const requestIdRef =
|
|
5850
|
-
const normalizedIdOrSlug =
|
|
5851
|
-
const cacheKey =
|
|
5924
|
+
const previousLocationIdRef = React3.useRef(locationId);
|
|
5925
|
+
const requestIdRef = React3.useRef(0);
|
|
5926
|
+
const normalizedIdOrSlug = React3.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
|
|
5927
|
+
const cacheKey = React3.useMemo(
|
|
5852
5928
|
() => buildCollectionCacheKey(client, locationId, normalizedIdOrSlug),
|
|
5853
5929
|
[client, locationId, normalizedIdOrSlug]
|
|
5854
5930
|
);
|
|
5855
5931
|
const cached = collectionCache.get(cacheKey);
|
|
5856
|
-
const [collection, setCollection] =
|
|
5857
|
-
const [products, setProducts] =
|
|
5858
|
-
const [isLoading, setIsLoading] =
|
|
5932
|
+
const [collection, setCollection] = React3.useState(cached?.collection ?? null);
|
|
5933
|
+
const [products, setProducts] = React3.useState(cached?.products ?? []);
|
|
5934
|
+
const [isLoading, setIsLoading] = React3.useState(
|
|
5859
5935
|
enabled && normalizedIdOrSlug.length > 0 && !cached
|
|
5860
5936
|
);
|
|
5861
|
-
const [error, setError] =
|
|
5862
|
-
|
|
5937
|
+
const [error, setError] = React3.useState(null);
|
|
5938
|
+
React3.useEffect(() => {
|
|
5863
5939
|
if (previousLocationIdRef.current !== locationId) {
|
|
5864
5940
|
collectionCache.clear();
|
|
5865
5941
|
collectionInflight.clear();
|
|
5866
5942
|
previousLocationIdRef.current = locationId;
|
|
5867
5943
|
}
|
|
5868
5944
|
}, [locationId]);
|
|
5869
|
-
const load =
|
|
5945
|
+
const load = React3.useCallback(
|
|
5870
5946
|
async (force = false) => {
|
|
5871
5947
|
if (!enabled || normalizedIdOrSlug.length === 0) {
|
|
5872
5948
|
setCollection(null);
|
|
@@ -5929,10 +6005,10 @@ function useCollection(idOrSlug, options = {}) {
|
|
|
5929
6005
|
},
|
|
5930
6006
|
[cacheKey, client, enabled, normalizedIdOrSlug]
|
|
5931
6007
|
);
|
|
5932
|
-
|
|
6008
|
+
React3.useEffect(() => {
|
|
5933
6009
|
void load(false);
|
|
5934
6010
|
}, [load]);
|
|
5935
|
-
const refetch =
|
|
6011
|
+
const refetch = React3.useCallback(async () => {
|
|
5936
6012
|
collectionCache.delete(cacheKey);
|
|
5937
6013
|
await load(true);
|
|
5938
6014
|
}, [cacheKey, load]);
|
|
@@ -5958,27 +6034,27 @@ function useBundle(idOrSlug, options = {}) {
|
|
|
5958
6034
|
}
|
|
5959
6035
|
const enabled = options.enabled ?? true;
|
|
5960
6036
|
const locationId = client.getLocationId();
|
|
5961
|
-
const previousLocationIdRef =
|
|
5962
|
-
const requestIdRef =
|
|
5963
|
-
const normalizedIdOrSlug =
|
|
5964
|
-
const cacheKey =
|
|
6037
|
+
const previousLocationIdRef = React3.useRef(locationId);
|
|
6038
|
+
const requestIdRef = React3.useRef(0);
|
|
6039
|
+
const normalizedIdOrSlug = React3.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
|
|
6040
|
+
const cacheKey = React3.useMemo(
|
|
5965
6041
|
() => buildBundleCacheKey(client, locationId, normalizedIdOrSlug),
|
|
5966
6042
|
[client, locationId, normalizedIdOrSlug]
|
|
5967
6043
|
);
|
|
5968
6044
|
const cached = bundleCache.get(cacheKey);
|
|
5969
|
-
const [bundle, setBundle] =
|
|
5970
|
-
const [isLoading, setIsLoading] =
|
|
6045
|
+
const [bundle, setBundle] = React3.useState(cached?.bundle ?? null);
|
|
6046
|
+
const [isLoading, setIsLoading] = React3.useState(
|
|
5971
6047
|
enabled && normalizedIdOrSlug.length > 0 && !cached
|
|
5972
6048
|
);
|
|
5973
|
-
const [error, setError] =
|
|
5974
|
-
|
|
6049
|
+
const [error, setError] = React3.useState(null);
|
|
6050
|
+
React3.useEffect(() => {
|
|
5975
6051
|
if (previousLocationIdRef.current !== locationId) {
|
|
5976
6052
|
bundleCache.clear();
|
|
5977
6053
|
bundleInflight.clear();
|
|
5978
6054
|
previousLocationIdRef.current = locationId;
|
|
5979
6055
|
}
|
|
5980
6056
|
}, [locationId]);
|
|
5981
|
-
const load =
|
|
6057
|
+
const load = React3.useCallback(
|
|
5982
6058
|
async (force = false) => {
|
|
5983
6059
|
if (!enabled || normalizedIdOrSlug.length === 0) {
|
|
5984
6060
|
setBundle(null);
|
|
@@ -6029,10 +6105,10 @@ function useBundle(idOrSlug, options = {}) {
|
|
|
6029
6105
|
},
|
|
6030
6106
|
[cacheKey, client, enabled, normalizedIdOrSlug]
|
|
6031
6107
|
);
|
|
6032
|
-
|
|
6108
|
+
React3.useEffect(() => {
|
|
6033
6109
|
void load(false);
|
|
6034
6110
|
}, [load]);
|
|
6035
|
-
const refetch =
|
|
6111
|
+
const refetch = React3.useCallback(async () => {
|
|
6036
6112
|
bundleCache.delete(cacheKey);
|
|
6037
6113
|
await load(true);
|
|
6038
6114
|
}, [cacheKey, load]);
|
|
@@ -6062,37 +6138,37 @@ function useComposite(idOrProductId, options = {}) {
|
|
|
6062
6138
|
}
|
|
6063
6139
|
const enabled = options.enabled ?? true;
|
|
6064
6140
|
const locationId = client.getLocationId();
|
|
6065
|
-
const previousLocationIdRef =
|
|
6066
|
-
const requestIdRef =
|
|
6067
|
-
const priceRequestIdRef =
|
|
6068
|
-
const normalizedIdOrProductId =
|
|
6141
|
+
const previousLocationIdRef = React3.useRef(locationId);
|
|
6142
|
+
const requestIdRef = React3.useRef(0);
|
|
6143
|
+
const priceRequestIdRef = React3.useRef(0);
|
|
6144
|
+
const normalizedIdOrProductId = React3.useMemo(
|
|
6069
6145
|
() => (idOrProductId || "").trim(),
|
|
6070
6146
|
[idOrProductId]
|
|
6071
6147
|
);
|
|
6072
|
-
const byProductId =
|
|
6148
|
+
const byProductId = React3.useMemo(
|
|
6073
6149
|
() => shouldFetchByProductId(normalizedIdOrProductId, options.byProductId),
|
|
6074
6150
|
[normalizedIdOrProductId, options.byProductId]
|
|
6075
6151
|
);
|
|
6076
|
-
const cacheKey =
|
|
6152
|
+
const cacheKey = React3.useMemo(
|
|
6077
6153
|
() => buildCompositeCacheKey(client, locationId, normalizedIdOrProductId, byProductId),
|
|
6078
6154
|
[byProductId, client, locationId, normalizedIdOrProductId]
|
|
6079
6155
|
);
|
|
6080
6156
|
const cached = compositeCache.get(cacheKey);
|
|
6081
|
-
const [composite, setComposite] =
|
|
6082
|
-
const [isLoading, setIsLoading] =
|
|
6157
|
+
const [composite, setComposite] = React3.useState(cached?.composite ?? null);
|
|
6158
|
+
const [isLoading, setIsLoading] = React3.useState(
|
|
6083
6159
|
enabled && normalizedIdOrProductId.length > 0 && !cached
|
|
6084
6160
|
);
|
|
6085
|
-
const [error, setError] =
|
|
6086
|
-
const [priceResult, setPriceResult] =
|
|
6087
|
-
const [isPriceLoading, setIsPriceLoading] =
|
|
6088
|
-
|
|
6161
|
+
const [error, setError] = React3.useState(null);
|
|
6162
|
+
const [priceResult, setPriceResult] = React3.useState(null);
|
|
6163
|
+
const [isPriceLoading, setIsPriceLoading] = React3.useState(false);
|
|
6164
|
+
React3.useEffect(() => {
|
|
6089
6165
|
if (previousLocationIdRef.current !== locationId) {
|
|
6090
6166
|
compositeCache.clear();
|
|
6091
6167
|
compositeInflight.clear();
|
|
6092
6168
|
previousLocationIdRef.current = locationId;
|
|
6093
6169
|
}
|
|
6094
6170
|
}, [locationId]);
|
|
6095
|
-
const load =
|
|
6171
|
+
const load = React3.useCallback(
|
|
6096
6172
|
async (force = false) => {
|
|
6097
6173
|
if (!enabled || normalizedIdOrProductId.length === 0) {
|
|
6098
6174
|
setComposite(null);
|
|
@@ -6145,10 +6221,10 @@ function useComposite(idOrProductId, options = {}) {
|
|
|
6145
6221
|
},
|
|
6146
6222
|
[byProductId, cacheKey, client, enabled, normalizedIdOrProductId]
|
|
6147
6223
|
);
|
|
6148
|
-
|
|
6224
|
+
React3.useEffect(() => {
|
|
6149
6225
|
void load(false);
|
|
6150
6226
|
}, [load]);
|
|
6151
|
-
const calculatePrice =
|
|
6227
|
+
const calculatePrice = React3.useCallback(
|
|
6152
6228
|
async (selections, overrideLocationId) => {
|
|
6153
6229
|
if (!composite) {
|
|
6154
6230
|
return null;
|
|
@@ -6182,7 +6258,7 @@ function useComposite(idOrProductId, options = {}) {
|
|
|
6182
6258
|
},
|
|
6183
6259
|
[client, composite]
|
|
6184
6260
|
);
|
|
6185
|
-
const refetch =
|
|
6261
|
+
const refetch = React3.useCallback(async () => {
|
|
6186
6262
|
compositeCache.delete(cacheKey);
|
|
6187
6263
|
await load(true);
|
|
6188
6264
|
}, [cacheKey, load]);
|
|
@@ -6197,13 +6273,13 @@ function useSearch(options = {}) {
|
|
|
6197
6273
|
const minLength = Math.max(0, options.minLength ?? 2);
|
|
6198
6274
|
const debounceMs = Math.max(0, options.debounceMs ?? 300);
|
|
6199
6275
|
const limit = Math.max(1, options.limit ?? 20);
|
|
6200
|
-
const [query, setQueryState] =
|
|
6201
|
-
const [results, setResults] =
|
|
6202
|
-
const [isLoading, setIsLoading] =
|
|
6203
|
-
const [error, setError] =
|
|
6204
|
-
const requestIdRef =
|
|
6205
|
-
const timerRef =
|
|
6206
|
-
|
|
6276
|
+
const [query, setQueryState] = React3.useState("");
|
|
6277
|
+
const [results, setResults] = React3.useState([]);
|
|
6278
|
+
const [isLoading, setIsLoading] = React3.useState(false);
|
|
6279
|
+
const [error, setError] = React3.useState(null);
|
|
6280
|
+
const requestIdRef = React3.useRef(0);
|
|
6281
|
+
const timerRef = React3.useRef(null);
|
|
6282
|
+
React3.useEffect(() => {
|
|
6207
6283
|
if (timerRef.current) {
|
|
6208
6284
|
clearTimeout(timerRef.current);
|
|
6209
6285
|
timerRef.current = null;
|
|
@@ -6250,10 +6326,10 @@ function useSearch(options = {}) {
|
|
|
6250
6326
|
}
|
|
6251
6327
|
};
|
|
6252
6328
|
}, [client, debounceMs, limit, minLength, options.category, query]);
|
|
6253
|
-
const setQuery =
|
|
6329
|
+
const setQuery = React3.useCallback((nextQuery) => {
|
|
6254
6330
|
setQueryState(nextQuery);
|
|
6255
6331
|
}, []);
|
|
6256
|
-
const clear =
|
|
6332
|
+
const clear = React3.useCallback(() => {
|
|
6257
6333
|
requestIdRef.current += 1;
|
|
6258
6334
|
if (timerRef.current) {
|
|
6259
6335
|
clearTimeout(timerRef.current);
|
|
@@ -6309,28 +6385,28 @@ function useQuote(input, options = {}) {
|
|
|
6309
6385
|
const autoRefresh = options.autoRefresh ?? true;
|
|
6310
6386
|
const refreshBeforeExpiryMs = Math.max(0, options.refreshBeforeExpiryMs ?? 3e4);
|
|
6311
6387
|
const locationId = client.getLocationId();
|
|
6312
|
-
const requestIdRef =
|
|
6313
|
-
const refreshTimerRef =
|
|
6314
|
-
const expiryTimerRef =
|
|
6315
|
-
const inputSignature =
|
|
6316
|
-
const normalizedInput =
|
|
6388
|
+
const requestIdRef = React3.useRef(0);
|
|
6389
|
+
const refreshTimerRef = React3.useRef(null);
|
|
6390
|
+
const expiryTimerRef = React3.useRef(null);
|
|
6391
|
+
const inputSignature = React3.useMemo(() => JSON.stringify(input ?? null), [input]);
|
|
6392
|
+
const normalizedInput = React3.useMemo(() => {
|
|
6317
6393
|
if (!input) {
|
|
6318
6394
|
return null;
|
|
6319
6395
|
}
|
|
6320
6396
|
const normalized = normalizeInput(input, locationId);
|
|
6321
6397
|
return normalized.product_id.length > 0 ? normalized : null;
|
|
6322
6398
|
}, [inputSignature, locationId]);
|
|
6323
|
-
const cacheKey =
|
|
6399
|
+
const cacheKey = React3.useMemo(
|
|
6324
6400
|
() => buildQuoteCacheKey(client, locationId, inputSignature),
|
|
6325
6401
|
[client, inputSignature, locationId]
|
|
6326
6402
|
);
|
|
6327
6403
|
const cached = quoteCache.get(cacheKey);
|
|
6328
|
-
const [quote, setQuote] =
|
|
6329
|
-
const [isLoading, setIsLoading] =
|
|
6330
|
-
const [error, setError] =
|
|
6331
|
-
const [isExpired, setIsExpired] =
|
|
6332
|
-
const [messages, setMessages] =
|
|
6333
|
-
const load =
|
|
6404
|
+
const [quote, setQuote] = React3.useState(cached?.quote ?? null);
|
|
6405
|
+
const [isLoading, setIsLoading] = React3.useState(enabled && normalizedInput !== null && !cached);
|
|
6406
|
+
const [error, setError] = React3.useState(null);
|
|
6407
|
+
const [isExpired, setIsExpired] = React3.useState(isQuoteExpired(cached?.quote ?? null));
|
|
6408
|
+
const [messages, setMessages] = React3.useState(cached?.quote?.ui_messages ?? []);
|
|
6409
|
+
const load = React3.useCallback(
|
|
6334
6410
|
async (force = false) => {
|
|
6335
6411
|
if (!enabled || !normalizedInput) {
|
|
6336
6412
|
setQuote(null);
|
|
@@ -6388,10 +6464,10 @@ function useQuote(input, options = {}) {
|
|
|
6388
6464
|
},
|
|
6389
6465
|
[cacheKey, client, enabled, normalizedInput]
|
|
6390
6466
|
);
|
|
6391
|
-
|
|
6467
|
+
React3.useEffect(() => {
|
|
6392
6468
|
void load(false);
|
|
6393
6469
|
}, [load]);
|
|
6394
|
-
const refresh =
|
|
6470
|
+
const refresh = React3.useCallback(async () => {
|
|
6395
6471
|
if (!enabled || !normalizedInput) {
|
|
6396
6472
|
return;
|
|
6397
6473
|
}
|
|
@@ -6428,7 +6504,7 @@ function useQuote(input, options = {}) {
|
|
|
6428
6504
|
}
|
|
6429
6505
|
}
|
|
6430
6506
|
}, [cacheKey, client, enabled, load, normalizedInput, quote]);
|
|
6431
|
-
|
|
6507
|
+
React3.useEffect(() => {
|
|
6432
6508
|
if (expiryTimerRef.current) {
|
|
6433
6509
|
clearTimeout(expiryTimerRef.current);
|
|
6434
6510
|
expiryTimerRef.current = null;
|
|
@@ -6452,7 +6528,7 @@ function useQuote(input, options = {}) {
|
|
|
6452
6528
|
}
|
|
6453
6529
|
};
|
|
6454
6530
|
}, [quote?.expires_at, quote?.quote_id]);
|
|
6455
|
-
|
|
6531
|
+
React3.useEffect(() => {
|
|
6456
6532
|
if (refreshTimerRef.current) {
|
|
6457
6533
|
clearTimeout(refreshTimerRef.current);
|
|
6458
6534
|
refreshTimerRef.current = null;
|
|
@@ -6477,15 +6553,15 @@ function useQuote(input, options = {}) {
|
|
|
6477
6553
|
}, [autoRefresh, enabled, quote?.expires_at, quote?.quote_id, refresh, refreshBeforeExpiryMs]);
|
|
6478
6554
|
return { quote, isLoading, error, refresh, isExpired, messages };
|
|
6479
6555
|
}
|
|
6480
|
-
var ElementsContext =
|
|
6556
|
+
var ElementsContext = React3.createContext({
|
|
6481
6557
|
elements: null,
|
|
6482
6558
|
isReady: false
|
|
6483
6559
|
});
|
|
6484
6560
|
function useElements() {
|
|
6485
|
-
return
|
|
6561
|
+
return React3.useContext(ElementsContext).elements;
|
|
6486
6562
|
}
|
|
6487
6563
|
function useElementsReady() {
|
|
6488
|
-
return
|
|
6564
|
+
return React3.useContext(ElementsContext).isReady;
|
|
6489
6565
|
}
|
|
6490
6566
|
function ElementsProvider({
|
|
6491
6567
|
client,
|
|
@@ -6493,10 +6569,10 @@ function ElementsProvider({
|
|
|
6493
6569
|
options,
|
|
6494
6570
|
children
|
|
6495
6571
|
}) {
|
|
6496
|
-
const [elements, setElements] =
|
|
6497
|
-
const [isReady, setIsReady] =
|
|
6498
|
-
const initialOptionsRef =
|
|
6499
|
-
|
|
6572
|
+
const [elements, setElements] = React3.useState(null);
|
|
6573
|
+
const [isReady, setIsReady] = React3.useState(false);
|
|
6574
|
+
const initialOptionsRef = React3.useRef(options);
|
|
6575
|
+
React3.useEffect(() => {
|
|
6500
6576
|
let cancelled = false;
|
|
6501
6577
|
let instance = null;
|
|
6502
6578
|
setIsReady(false);
|
|
@@ -6537,20 +6613,20 @@ function AuthElement({
|
|
|
6537
6613
|
onRequiresOtp,
|
|
6538
6614
|
onError
|
|
6539
6615
|
}) {
|
|
6540
|
-
const containerRef =
|
|
6541
|
-
const elementRef =
|
|
6616
|
+
const containerRef = React3.useRef(null);
|
|
6617
|
+
const elementRef = React3.useRef(null);
|
|
6542
6618
|
const elements = useElements();
|
|
6543
|
-
const onReadyRef =
|
|
6544
|
-
const onAuthenticatedRef =
|
|
6545
|
-
const onRequiresOtpRef =
|
|
6546
|
-
const onErrorRef =
|
|
6547
|
-
|
|
6619
|
+
const onReadyRef = React3.useRef(onReady);
|
|
6620
|
+
const onAuthenticatedRef = React3.useRef(onAuthenticated);
|
|
6621
|
+
const onRequiresOtpRef = React3.useRef(onRequiresOtp);
|
|
6622
|
+
const onErrorRef = React3.useRef(onError);
|
|
6623
|
+
React3.useEffect(() => {
|
|
6548
6624
|
onReadyRef.current = onReady;
|
|
6549
6625
|
onAuthenticatedRef.current = onAuthenticated;
|
|
6550
6626
|
onRequiresOtpRef.current = onRequiresOtp;
|
|
6551
6627
|
onErrorRef.current = onError;
|
|
6552
6628
|
}, [onReady, onAuthenticated, onRequiresOtp, onError]);
|
|
6553
|
-
|
|
6629
|
+
React3.useEffect(() => {
|
|
6554
6630
|
if (!elements || !containerRef.current) return;
|
|
6555
6631
|
const element = elements.create(ELEMENT_TYPES.AUTH, { prefillEmail });
|
|
6556
6632
|
elementRef.current = element;
|
|
@@ -6580,18 +6656,18 @@ function AddressElement({
|
|
|
6580
6656
|
onChange,
|
|
6581
6657
|
onError
|
|
6582
6658
|
}) {
|
|
6583
|
-
const containerRef =
|
|
6584
|
-
const elementRef =
|
|
6659
|
+
const containerRef = React3.useRef(null);
|
|
6660
|
+
const elementRef = React3.useRef(null);
|
|
6585
6661
|
const elements = useElements();
|
|
6586
|
-
const onReadyRef =
|
|
6587
|
-
const onChangeRef =
|
|
6588
|
-
const onErrorRef =
|
|
6589
|
-
|
|
6662
|
+
const onReadyRef = React3.useRef(onReady);
|
|
6663
|
+
const onChangeRef = React3.useRef(onChange);
|
|
6664
|
+
const onErrorRef = React3.useRef(onError);
|
|
6665
|
+
React3.useEffect(() => {
|
|
6590
6666
|
onReadyRef.current = onReady;
|
|
6591
6667
|
onChangeRef.current = onChange;
|
|
6592
6668
|
onErrorRef.current = onError;
|
|
6593
6669
|
}, [onReady, onChange, onError]);
|
|
6594
|
-
|
|
6670
|
+
React3.useEffect(() => {
|
|
6595
6671
|
if (!elements || !containerRef.current) return;
|
|
6596
6672
|
const element = elements.create(ELEMENT_TYPES.ADDRESS, { mode });
|
|
6597
6673
|
elementRef.current = element;
|
|
@@ -6618,18 +6694,18 @@ function PaymentElement({
|
|
|
6618
6694
|
onChange,
|
|
6619
6695
|
onError
|
|
6620
6696
|
}) {
|
|
6621
|
-
const containerRef =
|
|
6622
|
-
const elementRef =
|
|
6697
|
+
const containerRef = React3.useRef(null);
|
|
6698
|
+
const elementRef = React3.useRef(null);
|
|
6623
6699
|
const elements = useElements();
|
|
6624
|
-
const onReadyRef =
|
|
6625
|
-
const onChangeRef =
|
|
6626
|
-
const onErrorRef =
|
|
6627
|
-
|
|
6700
|
+
const onReadyRef = React3.useRef(onReady);
|
|
6701
|
+
const onChangeRef = React3.useRef(onChange);
|
|
6702
|
+
const onErrorRef = React3.useRef(onError);
|
|
6703
|
+
React3.useEffect(() => {
|
|
6628
6704
|
onReadyRef.current = onReady;
|
|
6629
6705
|
onChangeRef.current = onChange;
|
|
6630
6706
|
onErrorRef.current = onError;
|
|
6631
6707
|
}, [onReady, onChange, onError]);
|
|
6632
|
-
|
|
6708
|
+
React3.useEffect(() => {
|
|
6633
6709
|
if (!elements || !containerRef.current) return;
|
|
6634
6710
|
const element = elements.create(ELEMENT_TYPES.PAYMENT, { amount, currency });
|
|
6635
6711
|
elementRef.current = element;
|
|
@@ -6649,8 +6725,8 @@ function PaymentElement({
|
|
|
6649
6725
|
}
|
|
6650
6726
|
function useCheckout() {
|
|
6651
6727
|
const elements = useElements();
|
|
6652
|
-
const [isLoading, setIsLoading] =
|
|
6653
|
-
const submit =
|
|
6728
|
+
const [isLoading, setIsLoading] = React3.useState(false);
|
|
6729
|
+
const submit = React3.useCallback(
|
|
6654
6730
|
async (data) => {
|
|
6655
6731
|
if (!elements) {
|
|
6656
6732
|
return { success: false, error: { code: "NO_ELEMENTS", message: "Elements not initialized" } };
|
|
@@ -6664,7 +6740,7 @@ function useCheckout() {
|
|
|
6664
6740
|
},
|
|
6665
6741
|
[elements]
|
|
6666
6742
|
);
|
|
6667
|
-
const process =
|
|
6743
|
+
const process = React3.useCallback(
|
|
6668
6744
|
async (options) => {
|
|
6669
6745
|
if (!elements) {
|
|
6670
6746
|
return {
|