@cimplify/sdk 0.100.0 → 0.100.1
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 +3 -3
- package/dist/advanced.d.ts +3 -3
- package/dist/advanced.js +22 -22
- package/dist/advanced.mjs +3 -3
- package/dist/{chunk-J3UYIBKH.js → chunk-BHQCSHIG.js} +78 -72
- package/dist/{chunk-V5TU5JKA.mjs → chunk-DLW3RWRK.mjs} +30 -6
- package/dist/{chunk-I7L4VRHI.mjs → chunk-KEC2CX4R.mjs} +2 -2
- package/dist/{chunk-FECGCIVV.js → chunk-NH3HYUC3.js} +3 -3
- package/dist/{chunk-AETVRBKI.js → chunk-NIOUSKQQ.js} +1 -0
- package/dist/{chunk-7TEMLVDT.mjs → chunk-NKZIXLKW.mjs} +1 -1
- package/dist/{chunk-ZA5VKVUB.js → chunk-NR4Z2SFY.js} +4 -4
- package/dist/{chunk-K5EN2W2Q.mjs → chunk-O3YUHLZL.mjs} +1 -0
- package/dist/{chunk-OX5L6XE7.mjs → chunk-PTKAN4SI.mjs} +25 -15
- package/dist/{chunk-X6G6QERR.js → chunk-QGFKIAEM.js} +48 -38
- package/dist/{chunk-GWKIDFN6.mjs → chunk-T2B656RS.mjs} +8 -3
- package/dist/{chunk-64EDCDBR.js → chunk-WMEC5JWN.js} +32 -7
- package/dist/{client-C1vS5pf0.d.ts → client-B0Lku_lc.d.mts} +17 -16
- package/dist/{client-DmR3Z6pQ.d.ts → client-DRgEa78P.d.ts} +2 -2
- package/dist/{client-B5MeD8da.d.mts → client-DxgC_lXU.d.ts} +17 -16
- package/dist/{client-DQpvwf-p.d.mts → client-T5c-Nxq-.d.mts} +2 -2
- package/dist/{index-Br-vFygC.d.ts → index-CzKN1hjf.d.ts} +3 -3
- package/dist/{index-DUOCn1Cs.d.mts → index-DzuLT5wi.d.mts} +3 -3
- package/dist/index.d.mts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +117 -117
- package/dist/index.mjs +5 -5
- package/dist/{payment-BIpS9oPG.d.mts → payment-D8NEwCna.d.mts} +1 -1
- package/dist/{payment-CsuBKHqg.d.ts → payment-lZBP7h5M.d.ts} +1 -1
- package/dist/{price-IOOoVYS-.d.mts → price-DepWAmcL.d.mts} +1 -1
- package/dist/{price-Ml_uPoiY.d.ts → price-ncQb-TC8.d.ts} +1 -1
- package/dist/{product-BKV6TBj_.d.ts → product-B384_Qm2.d.mts} +12 -1
- package/dist/{product-BKV6TBj_.d.mts → product-B384_Qm2.d.ts} +12 -1
- package/dist/react.d.mts +10 -5
- package/dist/react.d.ts +10 -5
- package/dist/react.js +830 -446
- package/dist/react.mjs +711 -327
- package/dist/{server-CfpYhSV_.d.ts → server-B7O4ttpv.d.ts} +1 -1
- package/dist/{server-C0iEk55_.d.mts → server-oCGNIO_K.d.mts} +1 -1
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +10 -10
- package/dist/server.mjs +4 -4
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +3 -3
- package/dist/testing/msw.mjs +2 -2
- package/dist/testing/suite.d.mts +6 -6
- package/dist/testing/suite.d.ts +6 -6
- package/dist/testing/suite.js +25 -25
- package/dist/testing/suite.mjs +6 -6
- package/dist/testing.d.mts +5 -5
- package/dist/testing.d.ts +5 -5
- package/dist/testing.js +81 -81
- package/dist/testing.mjs +7 -7
- package/dist/utils.d.mts +4 -4
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +29 -29
- package/dist/utils.mjs +2 -2
- package/package.json +1 -1
- package/registry/cart-summary.json +1 -1
- package/registry/product-customizer.json +1 -1
- package/registry/sale-badge.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -3,10 +3,10 @@ import { DURATION_UNIT, getVariantDisplayName, INPUT_FIELD_TYPE, isMultiDayServi
|
|
|
3
3
|
export { getVariantDisplayName } from './chunk-4G5UWFC3.mjs';
|
|
4
4
|
import { splitGenUIContent, messagePreview } from './chunk-U4MW6PYU.mjs';
|
|
5
5
|
export { messagePreview, splitGenUIContent } from './chunk-U4MW6PYU.mjs';
|
|
6
|
-
import { SESSION_CLAIMED, SESSION_CLEARED, createCimplifyClient, MUTATION_ERROR } from './chunk-
|
|
7
|
-
import { generateIdempotencyKey, ELEMENT_TYPES, EVENT_TYPES, startSignIn } from './chunk-
|
|
8
|
-
import { parsePrice, formatMoney, formatPrice, getProductCurrency, getUnitPriceAtQuantity, isOnSale, getDiscountPercentage, getBasePrice, getPriceRange, formatPriceRange } from './chunk-
|
|
9
|
-
import { isSupportedCurrency, CimplifyError } from './chunk-
|
|
6
|
+
import { SESSION_CLAIMED, SESSION_CLEARED, createCimplifyClient, AUTH_TOKEN_CHANGED, MUTATION_ERROR } from './chunk-T2B656RS.mjs';
|
|
7
|
+
import { generateIdempotencyKey, ELEMENT_TYPES, EVENT_TYPES, startSignIn } from './chunk-PTKAN4SI.mjs';
|
|
8
|
+
import { parsePrice, formatMoney, formatPrice, getVariantUnitPrice, getProductCurrency, getUnitPriceAtQuantity, isOnSale, getDiscountPercentage, getBasePrice, getPriceRange, formatPriceRange } from './chunk-DLW3RWRK.mjs';
|
|
9
|
+
import { isSupportedCurrency, currencyCode, CimplifyError } from './chunk-O3YUHLZL.mjs';
|
|
10
10
|
import './chunk-3G6RQLXK.mjs';
|
|
11
11
|
import React14, { createContext, lazy, memo, Suspense, useMemo, useContext, useRef, useCallback, useState, useEffect, useId, useSyncExternalStore } from 'react';
|
|
12
12
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -574,10 +574,20 @@ function lineKeyFromItem(item) {
|
|
|
574
574
|
staffId: item.staffId
|
|
575
575
|
});
|
|
576
576
|
}
|
|
577
|
-
function attachInternalItemMetadata(item) {
|
|
578
|
-
|
|
577
|
+
function attachInternalItemMetadata(item, metadata = {}) {
|
|
578
|
+
const internalItem = {
|
|
579
|
+
...item,
|
|
580
|
+
_lineKey: lineKeyFromItem(item)
|
|
581
|
+
};
|
|
582
|
+
if (metadata.quotedUnitPrice !== void 0) {
|
|
583
|
+
internalItem._quotedUnitPrice = metadata.quotedUnitPrice;
|
|
584
|
+
}
|
|
585
|
+
return internalItem;
|
|
579
586
|
}
|
|
580
587
|
function calculateLineSubtotal(item) {
|
|
588
|
+
if (item._quotedUnitPrice !== void 0) {
|
|
589
|
+
return roundMoney(parsePrice(item._quotedUnitPrice) * item.quantity);
|
|
590
|
+
}
|
|
581
591
|
let unitPrice = parsePrice(item.product.default_price);
|
|
582
592
|
if (item.variant?.price_adjustment) {
|
|
583
593
|
unitPrice += parsePrice(item.variant.price_adjustment);
|
|
@@ -653,10 +663,7 @@ function emptyBase(currency, isLoading = true) {
|
|
|
653
663
|
return { items: [], subtotal: 0, tax: 0, total: 0, currency, isLoading };
|
|
654
664
|
}
|
|
655
665
|
function buildStoreKey(client, locationId) {
|
|
656
|
-
return [
|
|
657
|
-
client.getPublicKey() || "__no_public_key__",
|
|
658
|
-
locationId || "__no_location__"
|
|
659
|
-
].join(":");
|
|
666
|
+
return [client.getPublicKey() || "__no_public_key__", locationId || "__no_location__"].join(":");
|
|
660
667
|
}
|
|
661
668
|
function purgeLegacyCartCachesOnce() {
|
|
662
669
|
if (legacyCachesPurged) return;
|
|
@@ -685,7 +692,10 @@ function toProductFromServerItem(item, businessId) {
|
|
|
685
692
|
slug: item.item_id,
|
|
686
693
|
description: item.description,
|
|
687
694
|
image_url: item.image_url,
|
|
688
|
-
|
|
695
|
+
// Cart price_info is the accepted item price path. Do not reconstruct it
|
|
696
|
+
// from the catalogue base after a sale or shopper-specific quote.
|
|
697
|
+
default_price: item.price_info.final_price,
|
|
698
|
+
currency: item.price_info.currency,
|
|
689
699
|
type: "product",
|
|
690
700
|
inventory_type: "none",
|
|
691
701
|
variant_strategy: "fetch_all",
|
|
@@ -700,37 +710,44 @@ function mapServerCart(serverCart, fallbackCurrency) {
|
|
|
700
710
|
const variant = item.variant_info || item.variant_name ? {
|
|
701
711
|
id: item.variant_info?.id || item.variant_id || "",
|
|
702
712
|
name: item.variant_info?.name || item.variant_name || "Variant",
|
|
703
|
-
price_adjustment: item.variant_info?.price_adjustment
|
|
713
|
+
price_adjustment: item.variant_info?.price_adjustment,
|
|
714
|
+
price_info: item.price_info
|
|
704
715
|
} : void 0;
|
|
705
716
|
const quoteId = typeof item.metadata?.quote_id === "string" ? item.metadata.quote_id : void 0;
|
|
706
|
-
return attachInternalItemMetadata(
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
717
|
+
return attachInternalItemMetadata(
|
|
718
|
+
{
|
|
719
|
+
id: item.id,
|
|
720
|
+
product: toProductFromServerItem(item, serverCart.business_id),
|
|
721
|
+
quantity: clampQuantity(item.quantity),
|
|
722
|
+
locationId: serverCart.location_id,
|
|
723
|
+
variantId: item.variant_id,
|
|
724
|
+
variant,
|
|
725
|
+
quoteId,
|
|
726
|
+
addOnOptionIds: normalizeOptionIds(item.add_on_option_ids || void 0),
|
|
727
|
+
addOnOptions: (item.add_on_options || []).map((option) => ({
|
|
728
|
+
id: option.id,
|
|
729
|
+
name: option.name,
|
|
730
|
+
default_price: option.price
|
|
731
|
+
})),
|
|
732
|
+
bundleSelections: item.bundle_selections || void 0,
|
|
733
|
+
compositeSelections: item.composite_selections || void 0,
|
|
734
|
+
specialInstructions: item.special_instructions,
|
|
735
|
+
scheduledStart: item.scheduled_start || void 0,
|
|
736
|
+
scheduledEnd: item.scheduled_end || void 0,
|
|
737
|
+
staffId: item.staff_id || void 0,
|
|
738
|
+
units: item.units || void 0,
|
|
739
|
+
lineType: item.line_type,
|
|
740
|
+
confirmationCode: item.confirmation_code || void 0,
|
|
741
|
+
serviceStatus: item.service_status || void 0,
|
|
742
|
+
bundleResolved: item.bundle_resolved || void 0,
|
|
743
|
+
compositeResolved: item.composite_resolved || void 0,
|
|
744
|
+
customerInputs: item.customer_inputs || void 0
|
|
745
|
+
},
|
|
746
|
+
// CartItemDetails.total_price is the accepted configured unit amount,
|
|
747
|
+
// including add-ons. It is the only safe basis for optimistic quantity
|
|
748
|
+
// changes and line rendering after the server replaces the temp item.
|
|
749
|
+
{ quotedUnitPrice: item.total_price }
|
|
750
|
+
);
|
|
734
751
|
});
|
|
735
752
|
return {
|
|
736
753
|
items,
|
|
@@ -871,24 +888,27 @@ async function performAddItem(entry, product, quantity, options) {
|
|
|
871
888
|
addOnOptionIds: normalizeOptionIds(options.addOnOptionIds)
|
|
872
889
|
};
|
|
873
890
|
const lineKey = buildLineKey(product.id, normalizedOptions);
|
|
874
|
-
const tempItem = attachInternalItemMetadata(
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
891
|
+
const tempItem = attachInternalItemMetadata(
|
|
892
|
+
{
|
|
893
|
+
id: `tmp_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
|
|
894
|
+
product,
|
|
895
|
+
quantity: resolvedQuantity,
|
|
896
|
+
locationId: normalizedOptions.locationId,
|
|
897
|
+
variantId: normalizedOptions.variantId,
|
|
898
|
+
variant: normalizedOptions.variant,
|
|
899
|
+
quoteId: normalizedOptions.quoteId,
|
|
900
|
+
addOnOptionIds: normalizedOptions.addOnOptionIds,
|
|
901
|
+
addOnOptions: normalizedOptions.addOnOptions,
|
|
902
|
+
bundleSelections: normalizedOptions.bundleSelections,
|
|
903
|
+
compositeSelections: normalizedOptions.compositeSelections,
|
|
904
|
+
specialInstructions: normalizedOptions.specialInstructions,
|
|
905
|
+
scheduledStart: normalizedOptions.scheduledStart,
|
|
906
|
+
scheduledEnd: normalizedOptions.scheduledEnd,
|
|
907
|
+
staffId: normalizedOptions.staffId,
|
|
908
|
+
units: normalizedOptions.units
|
|
909
|
+
},
|
|
910
|
+
{ quotedUnitPrice: normalizedOptions.quotedUnitPrice }
|
|
911
|
+
);
|
|
892
912
|
const idempotencyKey = `idem_${typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : `${Date.now()}_${Math.random().toString(36).slice(2, 10)}`}`;
|
|
893
913
|
const patch = { kind: "add_item", tempItem, lineKey };
|
|
894
914
|
const useOptimistic = entry.optimisticEnabled;
|
|
@@ -998,12 +1018,12 @@ async function performReorder(entry, orderId) {
|
|
|
998
1018
|
return result.value;
|
|
999
1019
|
}
|
|
1000
1020
|
function useCart(options = {}) {
|
|
1001
|
-
const context =
|
|
1021
|
+
const context = useOptionalCimplify();
|
|
1002
1022
|
const client = options.client ?? context?.client;
|
|
1003
1023
|
if (!client) {
|
|
1004
1024
|
throw new Error("useCart must be used within CimplifyProvider or passed { client }.");
|
|
1005
1025
|
}
|
|
1006
|
-
const locationId = options.locationId ?? client.getLocationId();
|
|
1026
|
+
const locationId = options.locationId ?? (context?.client === client ? context.currentLocation?.id ?? (context.isReady ? null : client.getLocationId()) : client.getLocationId());
|
|
1007
1027
|
const currency = options.currency ?? context?.currency ?? "USD";
|
|
1008
1028
|
const optimisticEnabled = context?.optimistic ?? true;
|
|
1009
1029
|
const entry = useMemo(
|
|
@@ -1016,6 +1036,11 @@ function useCart(options = {}) {
|
|
|
1016
1036
|
[client, currency, locationId, optimisticEnabled]
|
|
1017
1037
|
);
|
|
1018
1038
|
const view = useCollectionStore(entry.collection);
|
|
1039
|
+
useEffect(() => {
|
|
1040
|
+
if (client.getLocationId() !== locationId) {
|
|
1041
|
+
client.setLocationId(locationId);
|
|
1042
|
+
}
|
|
1043
|
+
}, [client, locationId]);
|
|
1019
1044
|
useEffect(() => {
|
|
1020
1045
|
void ensureInitialized(entry);
|
|
1021
1046
|
}, [entry]);
|
|
@@ -4875,19 +4900,53 @@ function useSearch(options = {}) {
|
|
|
4875
4900
|
}
|
|
4876
4901
|
var quoteCache = /* @__PURE__ */ new Map();
|
|
4877
4902
|
var quoteInflight = /* @__PURE__ */ new Map();
|
|
4878
|
-
|
|
4879
|
-
|
|
4903
|
+
var quoteClientNamespaces = /* @__PURE__ */ new WeakMap();
|
|
4904
|
+
var nextQuoteClientNamespace = 0;
|
|
4905
|
+
var QUOTE_LOAD_DEBOUNCE_MS = 150;
|
|
4906
|
+
var MIN_AUTO_REFRESH_DELAY_MS = 1e3;
|
|
4907
|
+
function getQuoteClientNamespace(client) {
|
|
4908
|
+
const existing = quoteClientNamespaces.get(client);
|
|
4909
|
+
if (existing !== void 0) {
|
|
4910
|
+
return existing;
|
|
4911
|
+
}
|
|
4912
|
+
const namespace = nextQuoteClientNamespace++;
|
|
4913
|
+
quoteClientNamespaces.set(client, namespace);
|
|
4914
|
+
return namespace;
|
|
4915
|
+
}
|
|
4916
|
+
function buildQuoteCacheKey(client, sessionEpoch, locationId, inputSignature) {
|
|
4917
|
+
return JSON.stringify([
|
|
4918
|
+
getQuoteClientNamespace(client),
|
|
4919
|
+
client.getPublicKey(),
|
|
4920
|
+
sessionEpoch,
|
|
4921
|
+
locationId ?? "",
|
|
4922
|
+
inputSignature
|
|
4923
|
+
]);
|
|
4924
|
+
}
|
|
4925
|
+
function useClientSessionEpoch(client) {
|
|
4926
|
+
const subscribe = useCallback(
|
|
4927
|
+
(notify) => {
|
|
4928
|
+
const unsubscribe = [
|
|
4929
|
+
client.events.on(AUTH_TOKEN_CHANGED, notify),
|
|
4930
|
+
client.events.on(SESSION_CLAIMED, notify),
|
|
4931
|
+
client.events.on(SESSION_CLEARED, notify)
|
|
4932
|
+
];
|
|
4933
|
+
return () => {
|
|
4934
|
+
for (const stopListening of unsubscribe) {
|
|
4935
|
+
stopListening();
|
|
4936
|
+
}
|
|
4937
|
+
};
|
|
4938
|
+
},
|
|
4939
|
+
[client]
|
|
4940
|
+
);
|
|
4941
|
+
const getSnapshot = useCallback(() => client.getSessionEpoch(), [client]);
|
|
4942
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
4880
4943
|
}
|
|
4881
4944
|
function serializeQuoteBundleSelections(selections) {
|
|
4882
4945
|
if (!selections || selections.length === 0) {
|
|
4883
4946
|
return "";
|
|
4884
4947
|
}
|
|
4885
4948
|
return selections.map((selection) => {
|
|
4886
|
-
return [
|
|
4887
|
-
selection.component_id,
|
|
4888
|
-
selection.quantity,
|
|
4889
|
-
selection.variant_id ?? ""
|
|
4890
|
-
].join(":");
|
|
4949
|
+
return [selection.component_id, selection.quantity, selection.variant_id ?? ""].join(":");
|
|
4891
4950
|
}).join(";");
|
|
4892
4951
|
}
|
|
4893
4952
|
function serializeQuoteCompositeSelections(selections) {
|
|
@@ -4917,15 +4976,37 @@ function buildQuoteInputSignature(input) {
|
|
|
4917
4976
|
serializeQuoteCompositeSelections(input.compositeSelections)
|
|
4918
4977
|
].join("|");
|
|
4919
4978
|
}
|
|
4920
|
-
function
|
|
4979
|
+
function quoteExpiryTimestamp(quote) {
|
|
4921
4980
|
if (!quote?.expires_at) {
|
|
4922
|
-
return
|
|
4981
|
+
return Number.NaN;
|
|
4923
4982
|
}
|
|
4924
4983
|
const expiresAt = Date.parse(quote.expires_at);
|
|
4925
|
-
|
|
4926
|
-
|
|
4984
|
+
return Number.isFinite(expiresAt) ? expiresAt : Number.NaN;
|
|
4985
|
+
}
|
|
4986
|
+
function isQuoteExpired(quote, now = Date.now()) {
|
|
4987
|
+
const expiresAt = quoteExpiryTimestamp(quote);
|
|
4988
|
+
return Number.isFinite(expiresAt) && expiresAt <= now;
|
|
4989
|
+
}
|
|
4990
|
+
function readUsableCachedQuote(cacheKey2) {
|
|
4991
|
+
const entry = quoteCache.get(cacheKey2);
|
|
4992
|
+
if (!entry) {
|
|
4993
|
+
return null;
|
|
4927
4994
|
}
|
|
4928
|
-
|
|
4995
|
+
if (isQuoteExpired(entry.quote)) {
|
|
4996
|
+
quoteCache.delete(cacheKey2);
|
|
4997
|
+
return null;
|
|
4998
|
+
}
|
|
4999
|
+
return entry.quote;
|
|
5000
|
+
}
|
|
5001
|
+
function requestState(cacheKey2, quote, isLoading) {
|
|
5002
|
+
return {
|
|
5003
|
+
cacheKey: cacheKey2,
|
|
5004
|
+
quote,
|
|
5005
|
+
isLoading,
|
|
5006
|
+
error: null,
|
|
5007
|
+
isExpired: false,
|
|
5008
|
+
messages: quote?.ui_messages ?? []
|
|
5009
|
+
};
|
|
4929
5010
|
}
|
|
4930
5011
|
function normalizeInput(input, fallbackLocationId) {
|
|
4931
5012
|
const productId = input.productId.trim();
|
|
@@ -4942,7 +5023,7 @@ function normalizeInput(input, fallbackLocationId) {
|
|
|
4942
5023
|
};
|
|
4943
5024
|
}
|
|
4944
5025
|
function useQuote(input, options = {}) {
|
|
4945
|
-
const context =
|
|
5026
|
+
const context = useOptionalCimplify();
|
|
4946
5027
|
const client = options.client ?? context?.client;
|
|
4947
5028
|
if (!client) {
|
|
4948
5029
|
throw new Error("useQuote must be used within CimplifyProvider or passed { client }.");
|
|
@@ -4950,59 +5031,58 @@ function useQuote(input, options = {}) {
|
|
|
4950
5031
|
const enabled = options.enabled ?? true;
|
|
4951
5032
|
const autoRefresh = options.autoRefresh ?? true;
|
|
4952
5033
|
const refreshBeforeExpiryMs = Math.max(0, options.refreshBeforeExpiryMs ?? 3e4);
|
|
4953
|
-
const
|
|
5034
|
+
const sessionEpoch = useClientSessionEpoch(client);
|
|
5035
|
+
const fallbackLocationId = context?.client === client ? context.currentLocation?.id ?? (context.isReady ? null : client.getLocationId()) : client.getLocationId();
|
|
4954
5036
|
const requestIdRef = useRef(0);
|
|
4955
|
-
const debounceTimerRef = useRef(null);
|
|
4956
5037
|
const inputSignature = buildQuoteInputSignature(input);
|
|
4957
5038
|
const normalizedInput = useMemo(() => {
|
|
4958
5039
|
if (!input) {
|
|
4959
5040
|
return null;
|
|
4960
5041
|
}
|
|
4961
|
-
const normalized = normalizeInput(input,
|
|
5042
|
+
const normalized = normalizeInput(input, fallbackLocationId);
|
|
4962
5043
|
return normalized.product_id.length > 0 ? normalized : null;
|
|
4963
|
-
}, [inputSignature,
|
|
5044
|
+
}, [inputSignature, fallbackLocationId]);
|
|
4964
5045
|
const cacheKey2 = useMemo(
|
|
4965
|
-
() => buildQuoteCacheKey(
|
|
4966
|
-
|
|
5046
|
+
() => buildQuoteCacheKey(
|
|
5047
|
+
client,
|
|
5048
|
+
sessionEpoch,
|
|
5049
|
+
normalizedInput?.location_id ?? null,
|
|
5050
|
+
inputSignature
|
|
5051
|
+
),
|
|
5052
|
+
[client, inputSignature, normalizedInput?.location_id, sessionEpoch]
|
|
4967
5053
|
);
|
|
4968
|
-
const
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
const
|
|
4973
|
-
const
|
|
4974
|
-
const
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
5054
|
+
const [state, setState] = useState(() => {
|
|
5055
|
+
const cached = enabled && normalizedInput ? readUsableCachedQuote(cacheKey2) : null;
|
|
5056
|
+
return requestState(cacheKey2, cached, enabled && normalizedInput !== null && !cached);
|
|
5057
|
+
});
|
|
5058
|
+
const stateIsCurrent = state.cacheKey === cacheKey2 && enabled && normalizedInput !== null;
|
|
5059
|
+
const activeQuote = stateIsCurrent ? state.quote : null;
|
|
5060
|
+
const activeQuoteExpired = isQuoteExpired(activeQuote);
|
|
5061
|
+
const quote = activeQuoteExpired ? null : activeQuote;
|
|
5062
|
+
const isLoading = enabled && normalizedInput !== null && (!stateIsCurrent || state.isLoading);
|
|
5063
|
+
const error = stateIsCurrent ? state.error : null;
|
|
5064
|
+
const isExpired = stateIsCurrent ? state.isExpired || activeQuoteExpired : false;
|
|
5065
|
+
const messages = stateIsCurrent ? state.messages : [];
|
|
5066
|
+
const expiresAt = quoteExpiryTimestamp(activeQuote);
|
|
4981
5067
|
const load = useCallback(
|
|
4982
5068
|
async (force = false) => {
|
|
4983
5069
|
if (!enabled || !normalizedInput) {
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
setIsExpired(false);
|
|
4987
|
-
setError(null);
|
|
4988
|
-
setIsLoading(false);
|
|
5070
|
+
requestIdRef.current += 1;
|
|
5071
|
+
setState(requestState(cacheKey2, null, false));
|
|
4989
5072
|
return;
|
|
4990
5073
|
}
|
|
4991
5074
|
const nextRequestId = ++requestIdRef.current;
|
|
4992
|
-
setError(null);
|
|
4993
5075
|
if (!force) {
|
|
4994
|
-
const
|
|
4995
|
-
if (
|
|
4996
|
-
|
|
4997
|
-
setMessages(cacheEntry.quote?.ui_messages ?? []);
|
|
4998
|
-
setIsExpired(isQuoteExpired(cacheEntry.quote));
|
|
4999
|
-
setIsLoading(false);
|
|
5076
|
+
const cachedQuote = readUsableCachedQuote(cacheKey2);
|
|
5077
|
+
if (cachedQuote) {
|
|
5078
|
+
setState(requestState(cacheKey2, cachedQuote, false));
|
|
5000
5079
|
return;
|
|
5001
5080
|
}
|
|
5002
5081
|
}
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5082
|
+
setState((current) => ({
|
|
5083
|
+
...requestState(cacheKey2, null, true),
|
|
5084
|
+
isExpired: current.cacheKey === cacheKey2 && current.isExpired
|
|
5085
|
+
}));
|
|
5006
5086
|
try {
|
|
5007
5087
|
const existing = quoteInflight.get(cacheKey2);
|
|
5008
5088
|
const promise = existing ?? (async () => {
|
|
@@ -5019,55 +5099,58 @@ function useQuote(input, options = {}) {
|
|
|
5019
5099
|
}).catch(() => void 0);
|
|
5020
5100
|
}
|
|
5021
5101
|
const value = await promise;
|
|
5022
|
-
|
|
5023
|
-
if (
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
setError(null);
|
|
5102
|
+
const expired = isQuoteExpired(value);
|
|
5103
|
+
if (expired) {
|
|
5104
|
+
quoteCache.delete(cacheKey2);
|
|
5105
|
+
} else {
|
|
5106
|
+
quoteCache.set(cacheKey2, { quote: value });
|
|
5028
5107
|
}
|
|
5029
|
-
} catch (loadError) {
|
|
5030
5108
|
if (nextRequestId === requestIdRef.current) {
|
|
5031
|
-
|
|
5109
|
+
setState({
|
|
5110
|
+
...requestState(cacheKey2, expired ? null : value, false),
|
|
5111
|
+
isExpired: expired
|
|
5112
|
+
});
|
|
5032
5113
|
}
|
|
5033
|
-
}
|
|
5114
|
+
} catch (loadError) {
|
|
5034
5115
|
if (nextRequestId === requestIdRef.current) {
|
|
5035
|
-
|
|
5116
|
+
setState((current) => ({
|
|
5117
|
+
...requestState(cacheKey2, null, false),
|
|
5118
|
+
error: loadError,
|
|
5119
|
+
isExpired: current.cacheKey === cacheKey2 && current.isExpired
|
|
5120
|
+
}));
|
|
5036
5121
|
}
|
|
5037
5122
|
}
|
|
5038
5123
|
},
|
|
5039
5124
|
[cacheKey2, client, enabled, normalizedInput]
|
|
5040
5125
|
);
|
|
5041
5126
|
useEffect(() => {
|
|
5042
|
-
if (
|
|
5043
|
-
clearTimeout(debounceTimerRef.current);
|
|
5044
|
-
}
|
|
5045
|
-
const hasCached = quoteCache.has(cacheKey2);
|
|
5046
|
-
if (hasCached || !enabled || !normalizedInput) {
|
|
5127
|
+
if (!enabled || !normalizedInput || readUsableCachedQuote(cacheKey2)) {
|
|
5047
5128
|
void load(false);
|
|
5048
|
-
|
|
5049
|
-
debounceTimerRef.current = setTimeout(() => {
|
|
5050
|
-
void load(false);
|
|
5051
|
-
}, 150);
|
|
5129
|
+
return;
|
|
5052
5130
|
}
|
|
5131
|
+
const timer = setTimeout(() => {
|
|
5132
|
+
void load(false);
|
|
5133
|
+
}, QUOTE_LOAD_DEBOUNCE_MS);
|
|
5053
5134
|
return () => {
|
|
5054
|
-
|
|
5055
|
-
clearTimeout(debounceTimerRef.current);
|
|
5056
|
-
debounceTimerRef.current = null;
|
|
5057
|
-
}
|
|
5135
|
+
clearTimeout(timer);
|
|
5058
5136
|
};
|
|
5059
5137
|
}, [load, cacheKey2, enabled, normalizedInput]);
|
|
5060
5138
|
const refresh = useCallback(async () => {
|
|
5061
5139
|
if (!enabled || !normalizedInput) {
|
|
5062
5140
|
return;
|
|
5063
5141
|
}
|
|
5064
|
-
if (!quote?.quote_id) {
|
|
5142
|
+
if (!quote?.quote_id || isQuoteExpired(quote)) {
|
|
5143
|
+
quoteCache.delete(cacheKey2);
|
|
5065
5144
|
await load(true);
|
|
5066
5145
|
return;
|
|
5067
5146
|
}
|
|
5068
5147
|
const nextRequestId = ++requestIdRef.current;
|
|
5069
|
-
|
|
5070
|
-
|
|
5148
|
+
setState((current) => ({
|
|
5149
|
+
...current,
|
|
5150
|
+
cacheKey: cacheKey2,
|
|
5151
|
+
isLoading: true,
|
|
5152
|
+
error: null
|
|
5153
|
+
}));
|
|
5071
5154
|
try {
|
|
5072
5155
|
const result = await client.catalogue.refreshQuote({
|
|
5073
5156
|
quote_id: quote.quote_id,
|
|
@@ -5077,52 +5160,67 @@ function useQuote(input, options = {}) {
|
|
|
5077
5160
|
throw result.error;
|
|
5078
5161
|
}
|
|
5079
5162
|
const refreshed = result.value.quote;
|
|
5080
|
-
|
|
5081
|
-
if (
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
setError(null);
|
|
5163
|
+
const expired = isQuoteExpired(refreshed);
|
|
5164
|
+
if (expired) {
|
|
5165
|
+
quoteCache.delete(cacheKey2);
|
|
5166
|
+
} else {
|
|
5167
|
+
quoteCache.set(cacheKey2, { quote: refreshed });
|
|
5086
5168
|
}
|
|
5087
|
-
} catch (refreshError) {
|
|
5088
5169
|
if (nextRequestId === requestIdRef.current) {
|
|
5089
|
-
|
|
5170
|
+
setState({
|
|
5171
|
+
...requestState(cacheKey2, expired ? null : refreshed, false),
|
|
5172
|
+
isExpired: expired
|
|
5173
|
+
});
|
|
5090
5174
|
}
|
|
5091
|
-
}
|
|
5175
|
+
} catch (refreshError) {
|
|
5092
5176
|
if (nextRequestId === requestIdRef.current) {
|
|
5093
|
-
|
|
5177
|
+
setState((current) => ({
|
|
5178
|
+
...current,
|
|
5179
|
+
cacheKey: cacheKey2,
|
|
5180
|
+
isLoading: false,
|
|
5181
|
+
error: refreshError
|
|
5182
|
+
}));
|
|
5094
5183
|
}
|
|
5095
5184
|
}
|
|
5096
5185
|
}, [cacheKey2, client, enabled, load, normalizedInput, quote]);
|
|
5097
5186
|
useEffect(() => {
|
|
5098
|
-
if (!Number.isFinite(
|
|
5099
|
-
setIsExpired(false);
|
|
5187
|
+
if (!activeQuote || !Number.isFinite(expiresAt)) {
|
|
5100
5188
|
return;
|
|
5101
5189
|
}
|
|
5102
|
-
const
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
timers.push(
|
|
5108
|
-
setTimeout(() => {
|
|
5109
|
-
setIsExpired(true);
|
|
5110
|
-
}, Math.max(0, quoteExpiryTimestamp - now))
|
|
5111
|
-
);
|
|
5112
|
-
}
|
|
5113
|
-
if (autoRefresh && enabled && !isCurrentlyExpired) {
|
|
5114
|
-
timers.push(
|
|
5115
|
-
setTimeout(() => {
|
|
5116
|
-
void refresh();
|
|
5117
|
-
}, Math.max(0, quoteExpiryTimestamp - now - refreshBeforeExpiryMs))
|
|
5118
|
-
);
|
|
5190
|
+
const remainingMs = expiresAt - Date.now();
|
|
5191
|
+
if (remainingMs <= 0) {
|
|
5192
|
+
quoteCache.delete(cacheKey2);
|
|
5193
|
+
void load(true);
|
|
5194
|
+
return;
|
|
5119
5195
|
}
|
|
5196
|
+
const expiryTimer = setTimeout(() => {
|
|
5197
|
+
quoteCache.delete(cacheKey2);
|
|
5198
|
+
setState({
|
|
5199
|
+
...requestState(cacheKey2, null, true),
|
|
5200
|
+
isExpired: true
|
|
5201
|
+
});
|
|
5202
|
+
void load(true);
|
|
5203
|
+
}, remainingMs);
|
|
5204
|
+
const refreshDelayMs = remainingMs - refreshBeforeExpiryMs;
|
|
5205
|
+
const refreshTimer = autoRefresh && enabled && refreshDelayMs >= MIN_AUTO_REFRESH_DELAY_MS ? setTimeout(() => {
|
|
5206
|
+
void refresh();
|
|
5207
|
+
}, refreshDelayMs) : null;
|
|
5120
5208
|
return () => {
|
|
5121
|
-
|
|
5122
|
-
|
|
5209
|
+
clearTimeout(expiryTimer);
|
|
5210
|
+
if (refreshTimer) {
|
|
5211
|
+
clearTimeout(refreshTimer);
|
|
5123
5212
|
}
|
|
5124
5213
|
};
|
|
5125
|
-
}, [
|
|
5214
|
+
}, [
|
|
5215
|
+
activeQuote,
|
|
5216
|
+
autoRefresh,
|
|
5217
|
+
cacheKey2,
|
|
5218
|
+
enabled,
|
|
5219
|
+
expiresAt,
|
|
5220
|
+
load,
|
|
5221
|
+
refresh,
|
|
5222
|
+
refreshBeforeExpiryMs
|
|
5223
|
+
]);
|
|
5126
5224
|
return { quote, isLoading, error, refresh, isExpired, messages };
|
|
5127
5225
|
}
|
|
5128
5226
|
|
|
@@ -5311,14 +5409,7 @@ function useBundles(options = {}) {
|
|
|
5311
5409
|
return { bundles: data ?? [], isLoading, error, refetch };
|
|
5312
5410
|
}
|
|
5313
5411
|
function useProductPrice(input) {
|
|
5314
|
-
const {
|
|
5315
|
-
product,
|
|
5316
|
-
quantity = 1,
|
|
5317
|
-
variant,
|
|
5318
|
-
addOnOptions,
|
|
5319
|
-
compositePrice,
|
|
5320
|
-
bundleTotalPrice
|
|
5321
|
-
} = input;
|
|
5412
|
+
const { product, quantity = 1, variant, addOnOptions, compositePrice, bundleTotalPrice } = input;
|
|
5322
5413
|
return useMemo(() => {
|
|
5323
5414
|
let unitPrice;
|
|
5324
5415
|
if (bundleTotalPrice != null) {
|
|
@@ -5326,10 +5417,7 @@ function useProductPrice(input) {
|
|
|
5326
5417
|
} else if (compositePrice) {
|
|
5327
5418
|
unitPrice = parsePrice(compositePrice.final_price);
|
|
5328
5419
|
} else {
|
|
5329
|
-
unitPrice =
|
|
5330
|
-
if (variant?.price_adjustment) {
|
|
5331
|
-
unitPrice += parsePrice(variant.price_adjustment);
|
|
5332
|
-
}
|
|
5420
|
+
unitPrice = getVariantUnitPrice(product, variant);
|
|
5333
5421
|
if (addOnOptions) {
|
|
5334
5422
|
for (const option of addOnOptions) {
|
|
5335
5423
|
if (option.default_price) {
|
|
@@ -5345,7 +5433,15 @@ function useProductPrice(input) {
|
|
|
5345
5433
|
totalPrice,
|
|
5346
5434
|
displayTotalPrice: totalPrice
|
|
5347
5435
|
};
|
|
5348
|
-
}, [
|
|
5436
|
+
}, [
|
|
5437
|
+
product,
|
|
5438
|
+
quantity,
|
|
5439
|
+
variant?.price_adjustment,
|
|
5440
|
+
variant?.price_info,
|
|
5441
|
+
addOnOptions,
|
|
5442
|
+
compositePrice,
|
|
5443
|
+
bundleTotalPrice
|
|
5444
|
+
]);
|
|
5349
5445
|
}
|
|
5350
5446
|
|
|
5351
5447
|
// src/react/hooks/use-orders.ts
|
|
@@ -9597,7 +9693,18 @@ function DateSlotPicker({
|
|
|
9597
9693
|
}
|
|
9598
9694
|
);
|
|
9599
9695
|
}
|
|
9600
|
-
|
|
9696
|
+
var REQUIRED_OPTIONS_MESSAGE = "Please select all required options";
|
|
9697
|
+
var QUOTE_LOADING_MESSAGE = "Updating price\u2026";
|
|
9698
|
+
var QUOTE_UNAVAILABLE_MESSAGE = "Price is unavailable. Please try again.";
|
|
9699
|
+
var CUSTOMIZER_VALIDATION_ID = "cimplify-customizer-validation";
|
|
9700
|
+
function initialVariantSelection(product) {
|
|
9701
|
+
const variant = product.variants?.find((candidate) => candidate.is_default) ?? product.variants?.[0];
|
|
9702
|
+
return { id: variant?.id, variant };
|
|
9703
|
+
}
|
|
9704
|
+
function ProductCustomizer(props) {
|
|
9705
|
+
return /* @__PURE__ */ jsx(ProductCustomizerContent, { ...props }, props.product.id);
|
|
9706
|
+
}
|
|
9707
|
+
function ProductCustomizerContent({
|
|
9601
9708
|
product,
|
|
9602
9709
|
onAddToCart,
|
|
9603
9710
|
onVariantChange,
|
|
@@ -9609,8 +9716,11 @@ function ProductCustomizer({
|
|
|
9609
9716
|
const [quantity, setQuantity] = useState(product.min_order_quantity ?? 1);
|
|
9610
9717
|
const [isAdded, setIsAdded] = useState(false);
|
|
9611
9718
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
9612
|
-
const [
|
|
9613
|
-
|
|
9719
|
+
const [variantSelection, setVariantSelection] = useState(
|
|
9720
|
+
() => initialVariantSelection(product)
|
|
9721
|
+
);
|
|
9722
|
+
const selectedVariantId = variantSelection.id;
|
|
9723
|
+
const selectedVariant = variantSelection.variant;
|
|
9614
9724
|
const [selectedAddOnOptionIds, setSelectedAddOnOptionIds] = useState([]);
|
|
9615
9725
|
const [compositeSelections, setCompositeSelections] = useState([]);
|
|
9616
9726
|
const [compositePrice, setCompositePrice] = useState(null);
|
|
@@ -9625,7 +9735,6 @@ function ProductCustomizer({
|
|
|
9625
9735
|
const [selectedStaffId, setSelectedStaffId] = useState(null);
|
|
9626
9736
|
const [unitsCount, setUnitsCount] = useState(1);
|
|
9627
9737
|
const cart = useCart();
|
|
9628
|
-
const currency = getProductCurrency(product);
|
|
9629
9738
|
const productType = product.type || "product";
|
|
9630
9739
|
const isComposite = productType === "composite";
|
|
9631
9740
|
const isBundle = productType === "bundle";
|
|
@@ -9635,26 +9744,6 @@ function ProductCustomizer({
|
|
|
9635
9744
|
const isStandard = !isComposite && !isBundle;
|
|
9636
9745
|
const hasVariants = isStandard && product.variants && product.variants.length > 0;
|
|
9637
9746
|
const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
|
|
9638
|
-
useEffect(() => {
|
|
9639
|
-
setQuantity(product.min_order_quantity ?? 1);
|
|
9640
|
-
setIsAdded(false);
|
|
9641
|
-
setIsSubmitting(false);
|
|
9642
|
-
setSelectedVariantId(void 0);
|
|
9643
|
-
setSelectedVariant(void 0);
|
|
9644
|
-
setSelectedAddOnOptionIds([]);
|
|
9645
|
-
setCompositeSelections([]);
|
|
9646
|
-
setCompositePrice(null);
|
|
9647
|
-
setCompositeReady(false);
|
|
9648
|
-
setBundleSelections([]);
|
|
9649
|
-
setBundleTotalPrice(null);
|
|
9650
|
-
setBundleReady(false);
|
|
9651
|
-
setSelectedBillingPlan(null);
|
|
9652
|
-
setCustomerInputValues({});
|
|
9653
|
-
setSpecialInstructions("");
|
|
9654
|
-
setSelectedSlot(null);
|
|
9655
|
-
setSelectedStaffId(null);
|
|
9656
|
-
setUnitsCount(1);
|
|
9657
|
-
}, [product.id, product.min_order_quantity]);
|
|
9658
9747
|
const slotStaff = useMemo(
|
|
9659
9748
|
() => (selectedSlot?.available_staff ?? []).map((member) => ({
|
|
9660
9749
|
id: member.staff_id,
|
|
@@ -9677,7 +9766,9 @@ function ProductCustomizer({
|
|
|
9677
9766
|
}, [product.add_ons, selectedAddOnOptionIds]);
|
|
9678
9767
|
const normalizedAddOnOptionIds = useMemo(() => {
|
|
9679
9768
|
if (selectedAddOnOptionIds.length === 0) return [];
|
|
9680
|
-
return Array.from(
|
|
9769
|
+
return Array.from(
|
|
9770
|
+
new Set(selectedAddOnOptionIds.map((id) => id.trim()).filter(Boolean))
|
|
9771
|
+
).sort();
|
|
9681
9772
|
}, [selectedAddOnOptionIds]);
|
|
9682
9773
|
const localTotalPrice = useMemo(() => {
|
|
9683
9774
|
if (isComposite && compositePrice) {
|
|
@@ -9686,17 +9777,23 @@ function ProductCustomizer({
|
|
|
9686
9777
|
if (isBundle && bundleTotalPrice != null) {
|
|
9687
9778
|
return bundleTotalPrice * quantity;
|
|
9688
9779
|
}
|
|
9689
|
-
let price =
|
|
9690
|
-
if (selectedVariant?.price_adjustment) {
|
|
9691
|
-
price += parsePrice(selectedVariant.price_adjustment);
|
|
9692
|
-
}
|
|
9780
|
+
let price = getVariantUnitPrice(product, selectedVariant);
|
|
9693
9781
|
for (const option of selectedAddOnOptions) {
|
|
9694
9782
|
if (option.default_price) {
|
|
9695
9783
|
price += parsePrice(option.default_price);
|
|
9696
9784
|
}
|
|
9697
9785
|
}
|
|
9698
9786
|
return price * quantity;
|
|
9699
|
-
}, [
|
|
9787
|
+
}, [
|
|
9788
|
+
product.default_price,
|
|
9789
|
+
selectedVariant,
|
|
9790
|
+
selectedAddOnOptions,
|
|
9791
|
+
quantity,
|
|
9792
|
+
isComposite,
|
|
9793
|
+
compositePrice,
|
|
9794
|
+
isBundle,
|
|
9795
|
+
bundleTotalPrice
|
|
9796
|
+
]);
|
|
9700
9797
|
const requiredAddOnsSatisfied = useMemo(() => {
|
|
9701
9798
|
if (!product.add_ons) return true;
|
|
9702
9799
|
for (const addOn of product.add_ons) {
|
|
@@ -9721,7 +9818,16 @@ function ProductCustomizer({
|
|
|
9721
9818
|
bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0,
|
|
9722
9819
|
compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0
|
|
9723
9820
|
}),
|
|
9724
|
-
[
|
|
9821
|
+
[
|
|
9822
|
+
product.id,
|
|
9823
|
+
quantity,
|
|
9824
|
+
selectedVariantId,
|
|
9825
|
+
normalizedAddOnOptionIds,
|
|
9826
|
+
isBundle,
|
|
9827
|
+
bundleSelections,
|
|
9828
|
+
isComposite,
|
|
9829
|
+
compositeSelections
|
|
9830
|
+
]
|
|
9725
9831
|
);
|
|
9726
9832
|
const requiredInputsSatisfied = useMemo(() => {
|
|
9727
9833
|
if (!product.input_fields || product.input_fields.length === 0) return true;
|
|
@@ -9732,17 +9838,23 @@ function ProductCustomizer({
|
|
|
9732
9838
|
});
|
|
9733
9839
|
}, [product.input_fields, customerInputValues]);
|
|
9734
9840
|
const quoteEnabled = isComposite ? compositeReady && requiredInputsSatisfied : isBundle ? bundleReady && requiredInputsSatisfied : requiredAddOnsSatisfied && requiredInputsSatisfied;
|
|
9735
|
-
const {
|
|
9841
|
+
const {
|
|
9842
|
+
quote,
|
|
9843
|
+
isLoading: isQuoteLoading,
|
|
9844
|
+
error: quoteError,
|
|
9845
|
+
isExpired: isQuoteExpired2
|
|
9846
|
+
} = useQuote(quoteInput, {
|
|
9736
9847
|
enabled: quoteEnabled
|
|
9737
9848
|
});
|
|
9849
|
+
const currency = quote?.currency ?? getProductCurrency(product);
|
|
9738
9850
|
const quoteId = quote?.quote_id;
|
|
9851
|
+
const quotedUnitPrice = (quote?.quoted_total_price_info ?? quote?.final_price_info)?.final_price;
|
|
9739
9852
|
const quotedTotalPrice = useMemo(() => {
|
|
9740
|
-
if (
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
}, [quote, quantity]);
|
|
9853
|
+
if (quotedUnitPrice === void 0 || quotedUnitPrice === null) return void 0;
|
|
9854
|
+
return parsePrice(quotedUnitPrice) * quantity;
|
|
9855
|
+
}, [quotedUnitPrice, quantity]);
|
|
9856
|
+
const quoteIsReady = quoteEnabled && quote !== null && !isQuoteLoading && !quoteError && !isQuoteExpired2;
|
|
9857
|
+
const validationMessage = !quoteEnabled ? REQUIRED_OPTIONS_MESSAGE : quoteError ? QUOTE_UNAVAILABLE_MESSAGE : !quoteIsReady ? QUOTE_LOADING_MESSAGE : null;
|
|
9746
9858
|
const displayTotalPrice = useMemo(() => {
|
|
9747
9859
|
const total = quotedTotalPrice ?? localTotalPrice;
|
|
9748
9860
|
const multiplier = serviceBillingMultiplier(product, {
|
|
@@ -9756,8 +9868,7 @@ function ProductCustomizer({
|
|
|
9756
9868
|
}, [quotedTotalPrice, localTotalPrice, product, quantity, unitsCount, selectedSlot]);
|
|
9757
9869
|
const handleVariantChange = useCallback(
|
|
9758
9870
|
(variantId, variant) => {
|
|
9759
|
-
|
|
9760
|
-
setSelectedVariant(variant);
|
|
9871
|
+
setVariantSelection({ id: variantId, variant });
|
|
9761
9872
|
onVariantChange?.(variantId, variant);
|
|
9762
9873
|
},
|
|
9763
9874
|
[onVariantChange]
|
|
@@ -9765,12 +9876,21 @@ function ProductCustomizer({
|
|
|
9765
9876
|
const addedTimerRef = useRef(void 0);
|
|
9766
9877
|
useEffect(() => () => clearTimeout(addedTimerRef.current), []);
|
|
9767
9878
|
const handleAddToCart = useCallback(async () => {
|
|
9768
|
-
if (isSubmitting)
|
|
9879
|
+
if (isSubmitting || !quoteIsReady || !quote || quotedUnitPrice === void 0 || quotedUnitPrice === null) {
|
|
9880
|
+
return;
|
|
9881
|
+
}
|
|
9769
9882
|
setIsSubmitting(true);
|
|
9770
9883
|
const options = {
|
|
9884
|
+
locationId: quote.location_id ?? void 0,
|
|
9771
9885
|
variantId: selectedVariantId,
|
|
9772
|
-
variant: selectedVariant ? {
|
|
9886
|
+
variant: selectedVariant ? {
|
|
9887
|
+
id: selectedVariant.id,
|
|
9888
|
+
name: selectedVariant.name || "",
|
|
9889
|
+
price_adjustment: selectedVariant.price_adjustment,
|
|
9890
|
+
price_info: selectedVariant.price_info
|
|
9891
|
+
} : void 0,
|
|
9773
9892
|
quoteId,
|
|
9893
|
+
quotedUnitPrice,
|
|
9774
9894
|
addOnOptionIds: normalizedAddOnOptionIds.length > 0 ? normalizedAddOnOptionIds : void 0,
|
|
9775
9895
|
addOnOptions: selectedAddOnOptions.length > 0 ? selectedAddOnOptions.map((opt) => ({
|
|
9776
9896
|
id: opt.id,
|
|
@@ -9807,7 +9927,32 @@ function ProductCustomizer({
|
|
|
9807
9927
|
} finally {
|
|
9808
9928
|
setIsSubmitting(false);
|
|
9809
9929
|
}
|
|
9810
|
-
}, [
|
|
9930
|
+
}, [
|
|
9931
|
+
product,
|
|
9932
|
+
quantity,
|
|
9933
|
+
selectedVariantId,
|
|
9934
|
+
selectedVariant,
|
|
9935
|
+
quoteId,
|
|
9936
|
+
quotedUnitPrice,
|
|
9937
|
+
normalizedAddOnOptionIds,
|
|
9938
|
+
selectedAddOnOptions,
|
|
9939
|
+
isComposite,
|
|
9940
|
+
compositeSelections,
|
|
9941
|
+
isBundle,
|
|
9942
|
+
bundleSelections,
|
|
9943
|
+
selectedBillingPlan,
|
|
9944
|
+
customerInputValues,
|
|
9945
|
+
specialInstructions,
|
|
9946
|
+
isService,
|
|
9947
|
+
selectedSlot,
|
|
9948
|
+
selectedStaffId,
|
|
9949
|
+
unitsCount,
|
|
9950
|
+
isSubmitting,
|
|
9951
|
+
onAddToCart,
|
|
9952
|
+
cart,
|
|
9953
|
+
quoteIsReady,
|
|
9954
|
+
quote
|
|
9955
|
+
]);
|
|
9811
9956
|
return /* @__PURE__ */ jsxs("div", { "data-cimplify-customizer": true, className: cn("space-y-6", className, classNames?.root), children: [
|
|
9812
9957
|
isComposite && product.groups && product.composite_id && /* @__PURE__ */ jsx(
|
|
9813
9958
|
CompositeSelector,
|
|
@@ -9920,27 +10065,48 @@ function ProductCustomizer({
|
|
|
9920
10065
|
currency
|
|
9921
10066
|
}
|
|
9922
10067
|
),
|
|
9923
|
-
product.deposit_type && product.deposit_type !== "none" && product.deposit_amount && /* @__PURE__ */ jsx(
|
|
9924
|
-
"
|
|
9925
|
-
/* @__PURE__ */ jsx(Price, { amount: product.deposit_amount, currency })
|
|
9926
|
-
] }) : /* @__PURE__ */ jsxs("span", { children: [
|
|
9927
|
-
"Deposit required: ",
|
|
9928
|
-
parsePrice(product.deposit_amount),
|
|
9929
|
-
"%"
|
|
9930
|
-
] }) }),
|
|
9931
|
-
product.allergies && product.allergies.length > 0 && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-allergens": true, className: cn("flex flex-wrap gap-1.5", classNames?.allergens), children: product.allergies.map((allergen) => /* @__PURE__ */ jsx(
|
|
9932
|
-
"span",
|
|
10068
|
+
product.deposit_type && product.deposit_type !== "none" && product.deposit_amount && /* @__PURE__ */ jsx(
|
|
10069
|
+
"div",
|
|
9933
10070
|
{
|
|
9934
|
-
"data-cimplify-
|
|
9935
|
-
className: "
|
|
9936
|
-
children:
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
10071
|
+
"data-cimplify-customizer-deposit": true,
|
|
10072
|
+
className: cn("text-sm text-muted-foreground", classNames?.depositInfo),
|
|
10073
|
+
children: product.deposit_type === "fixed" ? /* @__PURE__ */ jsxs("span", { children: [
|
|
10074
|
+
"Deposit required: ",
|
|
10075
|
+
/* @__PURE__ */ jsx(Price, { amount: product.deposit_amount, currency })
|
|
10076
|
+
] }) : /* @__PURE__ */ jsxs("span", { children: [
|
|
10077
|
+
"Deposit required: ",
|
|
10078
|
+
parsePrice(product.deposit_amount),
|
|
10079
|
+
"%"
|
|
10080
|
+
] })
|
|
10081
|
+
}
|
|
10082
|
+
),
|
|
10083
|
+
product.allergies && product.allergies.length > 0 && /* @__PURE__ */ jsx(
|
|
10084
|
+
"div",
|
|
10085
|
+
{
|
|
10086
|
+
"data-cimplify-customizer-allergens": true,
|
|
10087
|
+
className: cn("flex flex-wrap gap-1.5", classNames?.allergens),
|
|
10088
|
+
children: product.allergies.map((allergen) => /* @__PURE__ */ jsx(
|
|
10089
|
+
"span",
|
|
10090
|
+
{
|
|
10091
|
+
"data-cimplify-allergen-tag": true,
|
|
10092
|
+
className: "inline-block text-xs px-2 py-0.5 rounded-full bg-muted text-muted-foreground",
|
|
10093
|
+
children: allergen
|
|
10094
|
+
},
|
|
10095
|
+
allergen
|
|
10096
|
+
))
|
|
10097
|
+
}
|
|
10098
|
+
),
|
|
10099
|
+
isService && product.duration_minutes != null && /* @__PURE__ */ jsxs(
|
|
10100
|
+
"div",
|
|
10101
|
+
{
|
|
10102
|
+
"data-cimplify-customizer-duration": true,
|
|
10103
|
+
className: cn("text-sm text-muted-foreground", classNames?.duration),
|
|
10104
|
+
children: [
|
|
10105
|
+
"Duration: ",
|
|
10106
|
+
formatDuration2(product.duration_minutes, product.duration_unit)
|
|
10107
|
+
]
|
|
10108
|
+
}
|
|
10109
|
+
),
|
|
9944
10110
|
showSpecialInstructions && !isDigital && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-special-instructions": true, children: /* @__PURE__ */ jsx(
|
|
9945
10111
|
"textarea",
|
|
9946
10112
|
{
|
|
@@ -9973,13 +10139,17 @@ function ProductCustomizer({
|
|
|
9973
10139
|
"data-cimplify-customizer-actions": true,
|
|
9974
10140
|
className: cn("pt-4 border-t border-border", classNames?.actions),
|
|
9975
10141
|
children: [
|
|
9976
|
-
|
|
10142
|
+
validationMessage && /* @__PURE__ */ jsx(
|
|
9977
10143
|
"p",
|
|
9978
10144
|
{
|
|
9979
|
-
id:
|
|
10145
|
+
id: CUSTOMIZER_VALIDATION_ID,
|
|
9980
10146
|
"data-cimplify-customizer-validation": true,
|
|
9981
|
-
className: cn(
|
|
9982
|
-
|
|
10147
|
+
className: cn(
|
|
10148
|
+
"text-sm mb-3",
|
|
10149
|
+
quoteError ? "text-destructive" : "text-muted-foreground",
|
|
10150
|
+
classNames?.validation
|
|
10151
|
+
),
|
|
10152
|
+
children: validationMessage
|
|
9983
10153
|
}
|
|
9984
10154
|
),
|
|
9985
10155
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
@@ -9992,28 +10162,54 @@ function ProductCustomizer({
|
|
|
9992
10162
|
min: product.min_order_quantity ?? 1
|
|
9993
10163
|
}
|
|
9994
10164
|
),
|
|
9995
|
-
product.min_order_quantity && product.min_order_quantity > 1 && /* @__PURE__ */ jsxs(
|
|
9996
|
-
"
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10165
|
+
product.min_order_quantity && product.min_order_quantity > 1 && /* @__PURE__ */ jsxs(
|
|
10166
|
+
"span",
|
|
10167
|
+
{
|
|
10168
|
+
"data-cimplify-customizer-min-hint": true,
|
|
10169
|
+
className: "text-xs text-muted-foreground text-center",
|
|
10170
|
+
children: [
|
|
10171
|
+
"Min. ",
|
|
10172
|
+
product.min_order_quantity
|
|
10173
|
+
]
|
|
10174
|
+
}
|
|
10175
|
+
)
|
|
10003
10176
|
] }),
|
|
10177
|
+
product.quantity_pricing && product.quantity_pricing.length > 0 && /* @__PURE__ */ jsxs(
|
|
10178
|
+
"div",
|
|
10179
|
+
{
|
|
10180
|
+
"data-cimplify-customizer-unit-price": true,
|
|
10181
|
+
className: "text-sm text-muted-foreground text-right shrink-0",
|
|
10182
|
+
children: [
|
|
10183
|
+
/* @__PURE__ */ jsx(
|
|
10184
|
+
Price,
|
|
10185
|
+
{
|
|
10186
|
+
amount: getUnitPriceAtQuantity(
|
|
10187
|
+
product.quantity_pricing,
|
|
10188
|
+
quantity,
|
|
10189
|
+
parsePrice(product.default_price)
|
|
10190
|
+
),
|
|
10191
|
+
currency,
|
|
10192
|
+
className: "font-medium text-foreground"
|
|
10193
|
+
}
|
|
10194
|
+
),
|
|
10195
|
+
" ",
|
|
10196
|
+
"ea."
|
|
10197
|
+
]
|
|
10198
|
+
}
|
|
10199
|
+
),
|
|
10004
10200
|
/* @__PURE__ */ jsx(
|
|
10005
10201
|
Button$1,
|
|
10006
10202
|
{
|
|
10007
10203
|
onClick: handleAddToCart,
|
|
10008
|
-
disabled: isAdded || isSubmitting || !
|
|
10009
|
-
"aria-describedby":
|
|
10204
|
+
disabled: isAdded || isSubmitting || !quoteIsReady,
|
|
10205
|
+
"aria-describedby": validationMessage ? CUSTOMIZER_VALIDATION_ID : void 0,
|
|
10010
10206
|
"data-cimplify-customizer-submit": true,
|
|
10011
10207
|
className: cn(
|
|
10012
10208
|
"flex-1 h-14 text-base bg-primary text-primary-foreground font-medium hover:bg-primary/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed rounded-full",
|
|
10013
10209
|
isAdded && classNames?.submitButtonAdded,
|
|
10014
10210
|
classNames?.submitButton
|
|
10015
10211
|
),
|
|
10016
|
-
children: isAdded ? "Added" : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10212
|
+
children: isAdded ? "Added" : !quoteEnabled ? submitLabel ?? "Add to Cart" : !quoteIsReady ? quoteError ? QUOTE_UNAVAILABLE_MESSAGE : QUOTE_LOADING_MESSAGE : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
10017
10213
|
submitLabel ?? "Add to Cart",
|
|
10018
10214
|
" \xB7",
|
|
10019
10215
|
" ",
|
|
@@ -10447,13 +10643,16 @@ function CartLineItemRow({
|
|
|
10447
10643
|
item,
|
|
10448
10644
|
onRemove,
|
|
10449
10645
|
onQuantityChange,
|
|
10646
|
+
currency,
|
|
10450
10647
|
classNames
|
|
10451
10648
|
}) {
|
|
10452
|
-
const { unitPrice } = useProductPrice({
|
|
10649
|
+
const { unitPrice: locallyResolvedUnitPrice } = useProductPrice({
|
|
10453
10650
|
product: item.product,
|
|
10454
10651
|
variant: item.variant,
|
|
10455
10652
|
addOnOptions: item.addOnOptions
|
|
10456
10653
|
});
|
|
10654
|
+
const pinnedUnitPrice = item._quotedUnitPrice;
|
|
10655
|
+
const unitPrice = pinnedUnitPrice === void 0 ? locallyResolvedUnitPrice : parsePrice(pinnedUnitPrice);
|
|
10457
10656
|
const hasComposite = item.compositeSelections && item.compositeSelections.length > 0;
|
|
10458
10657
|
const hasBundle = item.bundleSelections && item.bundleSelections.length > 0;
|
|
10459
10658
|
const isOptimistic2 = item.isOptimistic === true;
|
|
@@ -10476,15 +10675,25 @@ function CartLineItemRow({
|
|
|
10476
10675
|
{
|
|
10477
10676
|
"data-cimplify-cart-item-image": true,
|
|
10478
10677
|
className: "relative w-20 h-20 shrink-0 rounded-md overflow-hidden bg-muted",
|
|
10479
|
-
children: imageUrl ? /* @__PURE__ */ jsx(
|
|
10480
|
-
"
|
|
10678
|
+
children: imageUrl ? /* @__PURE__ */ jsx("img", { src: imageUrl, alt: "", className: "w-full h-full object-cover", loading: "lazy" }) : /* @__PURE__ */ jsx("div", { className: "w-full h-full grid place-items-center text-muted-foreground/40", children: /* @__PURE__ */ jsx(
|
|
10679
|
+
"svg",
|
|
10481
10680
|
{
|
|
10482
|
-
|
|
10483
|
-
|
|
10484
|
-
|
|
10485
|
-
|
|
10681
|
+
className: "w-6 h-6",
|
|
10682
|
+
fill: "none",
|
|
10683
|
+
stroke: "currentColor",
|
|
10684
|
+
strokeWidth: "1.5",
|
|
10685
|
+
viewBox: "0 0 24 24",
|
|
10686
|
+
"aria-hidden": true,
|
|
10687
|
+
children: /* @__PURE__ */ jsx(
|
|
10688
|
+
"path",
|
|
10689
|
+
{
|
|
10690
|
+
strokeLinecap: "round",
|
|
10691
|
+
strokeLinejoin: "round",
|
|
10692
|
+
d: "M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
|
10693
|
+
}
|
|
10694
|
+
)
|
|
10486
10695
|
}
|
|
10487
|
-
)
|
|
10696
|
+
) })
|
|
10488
10697
|
}
|
|
10489
10698
|
),
|
|
10490
10699
|
/* @__PURE__ */ jsxs("div", { "data-cimplify-cart-item-info": true, className: "flex-1 min-w-0 flex flex-col", children: [
|
|
@@ -10508,7 +10717,18 @@ function CartLineItemRow({
|
|
|
10508
10717
|
classNames?.removeButton
|
|
10509
10718
|
),
|
|
10510
10719
|
"aria-label": `Remove ${item.product.name}`,
|
|
10511
|
-
children: /* @__PURE__ */ jsx(
|
|
10720
|
+
children: /* @__PURE__ */ jsx(
|
|
10721
|
+
"svg",
|
|
10722
|
+
{
|
|
10723
|
+
className: "w-3.5 h-3.5",
|
|
10724
|
+
fill: "none",
|
|
10725
|
+
stroke: "currentColor",
|
|
10726
|
+
strokeWidth: "2",
|
|
10727
|
+
viewBox: "0 0 24 24",
|
|
10728
|
+
"aria-hidden": true,
|
|
10729
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
|
|
10730
|
+
}
|
|
10731
|
+
)
|
|
10512
10732
|
}
|
|
10513
10733
|
)
|
|
10514
10734
|
] }),
|
|
@@ -10554,43 +10774,124 @@ function CartLineItemRow({
|
|
|
10554
10774
|
]
|
|
10555
10775
|
}
|
|
10556
10776
|
),
|
|
10557
|
-
item.customerInputs && item.customerInputs.length > 0 && /* @__PURE__ */ jsx(
|
|
10558
|
-
|
|
10559
|
-
|
|
10560
|
-
":
|
|
10561
|
-
|
|
10562
|
-
|
|
10563
|
-
|
|
10564
|
-
|
|
10565
|
-
|
|
10566
|
-
|
|
10567
|
-
|
|
10568
|
-
|
|
10569
|
-
|
|
10570
|
-
|
|
10571
|
-
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10777
|
+
item.customerInputs && item.customerInputs.length > 0 && /* @__PURE__ */ jsx(
|
|
10778
|
+
"dl",
|
|
10779
|
+
{
|
|
10780
|
+
"data-cimplify-cart-customer-inputs": true,
|
|
10781
|
+
className: cn("mt-1.5 text-xs space-y-0.5", classNames?.customerInputs),
|
|
10782
|
+
children: item.customerInputs.map((input) => /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-input": true, className: "flex gap-1.5", children: [
|
|
10783
|
+
/* @__PURE__ */ jsxs("dt", { "data-cimplify-cart-input-label": true, className: "text-muted-foreground", children: [
|
|
10784
|
+
input.field_name,
|
|
10785
|
+
":"
|
|
10786
|
+
] }),
|
|
10787
|
+
/* @__PURE__ */ jsx("dd", { "data-cimplify-cart-input-value": true, className: "text-foreground m-0 truncate", children: input.field_type === INPUT_FIELD_TYPE.File || input.field_type === INPUT_FIELD_TYPE.Image ? String(input.value).split("/").pop() || "Uploaded file" : String(input.value) })
|
|
10788
|
+
] }, input.field_id))
|
|
10789
|
+
}
|
|
10790
|
+
),
|
|
10791
|
+
(item.lineType === "service" || item.product.type === "service") && item.scheduledStart && /* @__PURE__ */ jsxs(
|
|
10792
|
+
"div",
|
|
10793
|
+
{
|
|
10794
|
+
"data-cimplify-cart-service-info": true,
|
|
10795
|
+
className: cn(
|
|
10796
|
+
"mt-1.5 flex items-center gap-1.5 text-xs text-muted-foreground",
|
|
10797
|
+
classNames?.serviceInfo
|
|
10798
|
+
),
|
|
10799
|
+
children: [
|
|
10800
|
+
/* @__PURE__ */ jsx(
|
|
10801
|
+
"svg",
|
|
10802
|
+
{
|
|
10803
|
+
className: "w-3.5 h-3.5 shrink-0",
|
|
10804
|
+
fill: "none",
|
|
10805
|
+
stroke: "currentColor",
|
|
10806
|
+
strokeWidth: "2",
|
|
10807
|
+
viewBox: "0 0 24 24",
|
|
10808
|
+
"aria-hidden": true,
|
|
10809
|
+
children: /* @__PURE__ */ jsx(
|
|
10810
|
+
"path",
|
|
10811
|
+
{
|
|
10812
|
+
strokeLinecap: "round",
|
|
10813
|
+
strokeLinejoin: "round",
|
|
10814
|
+
d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
10815
|
+
}
|
|
10816
|
+
)
|
|
10817
|
+
}
|
|
10818
|
+
),
|
|
10819
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
10820
|
+
new Date(item.scheduledStart).toLocaleDateString(void 0, {
|
|
10821
|
+
month: "short",
|
|
10822
|
+
day: "numeric"
|
|
10823
|
+
}),
|
|
10824
|
+
" ",
|
|
10825
|
+
"at",
|
|
10826
|
+
" ",
|
|
10827
|
+
new Date(item.scheduledStart).toLocaleTimeString([], {
|
|
10828
|
+
hour: "2-digit",
|
|
10829
|
+
minute: "2-digit"
|
|
10830
|
+
})
|
|
10831
|
+
] }),
|
|
10832
|
+
item.serviceStatus && /* @__PURE__ */ jsx(
|
|
10833
|
+
"span",
|
|
10834
|
+
{
|
|
10835
|
+
"data-status": item.serviceStatus,
|
|
10836
|
+
className: "ml-auto px-1.5 py-0.5 rounded-full bg-muted text-[10px] uppercase tracking-wider",
|
|
10837
|
+
children: item.serviceStatus
|
|
10838
|
+
}
|
|
10839
|
+
)
|
|
10840
|
+
]
|
|
10841
|
+
}
|
|
10842
|
+
),
|
|
10843
|
+
(item.lineType === "digital" || item.product.type === "digital") && /* @__PURE__ */ jsxs(
|
|
10844
|
+
"div",
|
|
10845
|
+
{
|
|
10846
|
+
"data-cimplify-cart-digital-info": true,
|
|
10847
|
+
className: cn(
|
|
10848
|
+
"mt-1.5 flex items-center gap-1 text-xs text-muted-foreground",
|
|
10849
|
+
classNames?.digitalInfo
|
|
10850
|
+
),
|
|
10851
|
+
children: [
|
|
10852
|
+
/* @__PURE__ */ jsx(
|
|
10853
|
+
"svg",
|
|
10854
|
+
{
|
|
10855
|
+
className: "w-3.5 h-3.5 shrink-0",
|
|
10856
|
+
fill: "none",
|
|
10857
|
+
stroke: "currentColor",
|
|
10858
|
+
strokeWidth: "2",
|
|
10859
|
+
viewBox: "0 0 24 24",
|
|
10860
|
+
"aria-hidden": true,
|
|
10861
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M13 10V3L4 14h7v7l9-11h-7z" })
|
|
10862
|
+
}
|
|
10863
|
+
),
|
|
10864
|
+
/* @__PURE__ */ jsx("span", { children: "Instant digital delivery" })
|
|
10865
|
+
]
|
|
10866
|
+
}
|
|
10867
|
+
),
|
|
10578
10868
|
(item.bundleResolved || item.compositeResolved) && /* @__PURE__ */ jsx(
|
|
10579
10869
|
"ul",
|
|
10580
10870
|
{
|
|
10581
10871
|
"data-cimplify-cart-composite-breakdown": item.compositeResolved ? "" : void 0,
|
|
10582
10872
|
"data-cimplify-cart-bundle-breakdown": item.bundleResolved ? "" : void 0,
|
|
10583
|
-
className: cn(
|
|
10873
|
+
className: cn(
|
|
10874
|
+
"mt-1.5 pl-3 border-l border-border space-y-0.5 text-xs text-muted-foreground",
|
|
10875
|
+
item.compositeResolved ? classNames?.compositeBreakdown : classNames?.bundleBreakdown
|
|
10876
|
+
),
|
|
10584
10877
|
children: (item.bundleResolved?.selections ?? item.compositeResolved?.selections ?? []).map((sel) => {
|
|
10585
10878
|
const name = sel.product_name ?? sel.component_name ?? "";
|
|
10586
10879
|
const compId = sel.component_id ?? `${name}-${sel.quantity}`;
|
|
10587
|
-
return /* @__PURE__ */ jsxs(
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
"
|
|
10591
|
-
|
|
10592
|
-
|
|
10593
|
-
|
|
10880
|
+
return /* @__PURE__ */ jsxs(
|
|
10881
|
+
"li",
|
|
10882
|
+
{
|
|
10883
|
+
"data-product-type": sel.product_type,
|
|
10884
|
+
className: "flex items-baseline gap-1.5 m-0",
|
|
10885
|
+
children: [
|
|
10886
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium text-foreground/80", children: [
|
|
10887
|
+
sel.quantity,
|
|
10888
|
+
"\\u00D7"
|
|
10889
|
+
] }),
|
|
10890
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: name })
|
|
10891
|
+
]
|
|
10892
|
+
},
|
|
10893
|
+
compId
|
|
10894
|
+
);
|
|
10594
10895
|
})
|
|
10595
10896
|
}
|
|
10596
10897
|
),
|
|
@@ -10599,6 +10900,7 @@ function CartLineItemRow({
|
|
|
10599
10900
|
Price,
|
|
10600
10901
|
{
|
|
10601
10902
|
amount: lineTotal,
|
|
10903
|
+
currency,
|
|
10602
10904
|
className: cn("text-sm font-semibold tabular-nums", classNames?.itemPrice)
|
|
10603
10905
|
}
|
|
10604
10906
|
),
|
|
@@ -10636,9 +10938,11 @@ function CartSummary({
|
|
|
10636
10938
|
isEmpty,
|
|
10637
10939
|
isOptimistic: isOptimistic2,
|
|
10638
10940
|
pendingOpCount,
|
|
10941
|
+
currency,
|
|
10639
10942
|
removeItem,
|
|
10640
10943
|
updateQuantity
|
|
10641
10944
|
} = useCart();
|
|
10945
|
+
const displayCurrency = serverCart?.currency ?? currencyCode(currency);
|
|
10642
10946
|
const deliveryFee = serverCart?.delivery_fee;
|
|
10643
10947
|
const serviceCharge = serverCart?.service_charge;
|
|
10644
10948
|
const totalDiscounts = serverCart?.total_discounts;
|
|
@@ -10670,6 +10974,7 @@ function CartSummary({
|
|
|
10670
10974
|
item,
|
|
10671
10975
|
onRemove: handleRemove,
|
|
10672
10976
|
onQuantityChange: handleQuantityChange,
|
|
10977
|
+
currency: displayCurrency,
|
|
10673
10978
|
classNames
|
|
10674
10979
|
},
|
|
10675
10980
|
item.id
|
|
@@ -10678,38 +10983,115 @@ function CartSummary({
|
|
|
10678
10983
|
"div",
|
|
10679
10984
|
{
|
|
10680
10985
|
"data-cimplify-cart-totals": true,
|
|
10681
|
-
className: cn(
|
|
10986
|
+
className: cn(
|
|
10987
|
+
"mt-6 pt-4 border-t border-border space-y-2 text-sm",
|
|
10988
|
+
classNames?.totals
|
|
10989
|
+
),
|
|
10682
10990
|
children: [
|
|
10683
|
-
/* @__PURE__ */ jsxs(
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
" ",
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10991
|
+
/* @__PURE__ */ jsxs(
|
|
10992
|
+
"div",
|
|
10993
|
+
{
|
|
10994
|
+
"data-cimplify-cart-subtotal": true,
|
|
10995
|
+
className: cn("flex items-baseline justify-between", classNames?.subtotal),
|
|
10996
|
+
children: [
|
|
10997
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
10998
|
+
"Subtotal (",
|
|
10999
|
+
itemCount,
|
|
11000
|
+
" ",
|
|
11001
|
+
itemCount === 1 ? "item" : "items",
|
|
11002
|
+
")"
|
|
11003
|
+
] }),
|
|
11004
|
+
/* @__PURE__ */ jsx(Price, { amount: subtotal, currency: displayCurrency, className: "tabular-nums" })
|
|
11005
|
+
]
|
|
11006
|
+
}
|
|
11007
|
+
),
|
|
11008
|
+
totalDiscounts != null && parsePrice(totalDiscounts) > 0 && /* @__PURE__ */ jsxs(
|
|
11009
|
+
"div",
|
|
11010
|
+
{
|
|
11011
|
+
"data-cimplify-cart-discount": true,
|
|
11012
|
+
className: cn("flex items-baseline justify-between", classNames?.discount),
|
|
11013
|
+
children: [
|
|
11014
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Discount" }),
|
|
11015
|
+
/* @__PURE__ */ jsx(
|
|
11016
|
+
Price,
|
|
11017
|
+
{
|
|
11018
|
+
amount: totalDiscounts,
|
|
11019
|
+
currency: displayCurrency,
|
|
11020
|
+
prefix: "-",
|
|
11021
|
+
className: "tabular-nums text-primary"
|
|
11022
|
+
}
|
|
11023
|
+
)
|
|
11024
|
+
]
|
|
11025
|
+
}
|
|
11026
|
+
),
|
|
11027
|
+
deliveryFee != null && /* @__PURE__ */ jsxs(
|
|
11028
|
+
"div",
|
|
11029
|
+
{
|
|
11030
|
+
"data-cimplify-cart-delivery-fee": true,
|
|
11031
|
+
className: cn("flex items-baseline justify-between", classNames?.deliveryFee),
|
|
11032
|
+
children: [
|
|
11033
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Delivery" }),
|
|
11034
|
+
parsePrice(deliveryFee) > 0 ? /* @__PURE__ */ jsx(
|
|
11035
|
+
Price,
|
|
11036
|
+
{
|
|
11037
|
+
amount: deliveryFee,
|
|
11038
|
+
currency: displayCurrency,
|
|
11039
|
+
className: "tabular-nums"
|
|
11040
|
+
}
|
|
11041
|
+
) : /* @__PURE__ */ jsx("span", { className: "font-medium text-primary", children: "Free" })
|
|
11042
|
+
]
|
|
11043
|
+
}
|
|
11044
|
+
),
|
|
11045
|
+
serviceCharge != null && parsePrice(serviceCharge) > 0 && /* @__PURE__ */ jsxs(
|
|
11046
|
+
"div",
|
|
11047
|
+
{
|
|
11048
|
+
"data-cimplify-cart-service-charge": true,
|
|
11049
|
+
className: cn("flex items-baseline justify-between", classNames?.serviceCharge),
|
|
11050
|
+
children: [
|
|
11051
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Service charge" }),
|
|
11052
|
+
/* @__PURE__ */ jsx(
|
|
11053
|
+
Price,
|
|
11054
|
+
{
|
|
11055
|
+
amount: serviceCharge,
|
|
11056
|
+
currency: displayCurrency,
|
|
11057
|
+
className: "tabular-nums"
|
|
11058
|
+
}
|
|
11059
|
+
)
|
|
11060
|
+
]
|
|
11061
|
+
}
|
|
11062
|
+
),
|
|
11063
|
+
/* @__PURE__ */ jsxs(
|
|
11064
|
+
"div",
|
|
11065
|
+
{
|
|
11066
|
+
"data-cimplify-cart-tax": true,
|
|
11067
|
+
className: cn("flex items-baseline justify-between", classNames?.tax),
|
|
11068
|
+
children: [
|
|
11069
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Tax" }),
|
|
11070
|
+
/* @__PURE__ */ jsx(Price, { amount: tax, currency: displayCurrency, className: "tabular-nums" })
|
|
11071
|
+
]
|
|
11072
|
+
}
|
|
11073
|
+
),
|
|
11074
|
+
/* @__PURE__ */ jsxs(
|
|
11075
|
+
"div",
|
|
11076
|
+
{
|
|
11077
|
+
"data-cimplify-cart-total": true,
|
|
11078
|
+
className: cn(
|
|
11079
|
+
"flex items-baseline justify-between pt-3 mt-1 border-t border-border",
|
|
11080
|
+
classNames?.total
|
|
11081
|
+
),
|
|
11082
|
+
children: [
|
|
11083
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold", children: "Total" }),
|
|
11084
|
+
/* @__PURE__ */ jsx(
|
|
11085
|
+
Price,
|
|
11086
|
+
{
|
|
11087
|
+
amount: total,
|
|
11088
|
+
currency: displayCurrency,
|
|
11089
|
+
className: "text-base font-bold tabular-nums"
|
|
11090
|
+
}
|
|
11091
|
+
)
|
|
11092
|
+
]
|
|
11093
|
+
}
|
|
11094
|
+
)
|
|
10713
11095
|
]
|
|
10714
11096
|
}
|
|
10715
11097
|
),
|
|
@@ -10794,12 +11176,14 @@ function SaleBadge({
|
|
|
10794
11176
|
return null;
|
|
10795
11177
|
}
|
|
10796
11178
|
let percentage = null;
|
|
10797
|
-
if (
|
|
11179
|
+
if (product.sale) {
|
|
11180
|
+
percentage = parsePrice(product.sale.percent_off);
|
|
11181
|
+
} else if (hasDeal && dealInfo.benefit_type === "percentage") {
|
|
10798
11182
|
percentage = parsePrice(dealInfo.value);
|
|
10799
11183
|
} else if (onSale) {
|
|
10800
11184
|
percentage = getDiscountPercentage(product);
|
|
10801
11185
|
}
|
|
10802
|
-
const badgeText = label ?? dealInfo?.label ?? (percentage != null && percentage > 0 ? `${percentage}% off` : null);
|
|
11186
|
+
const badgeText = label ?? product.sale?.badge_text ?? dealInfo?.label ?? (percentage != null && percentage > 0 ? `${percentage}% off` : null);
|
|
10803
11187
|
if (!badgeText) {
|
|
10804
11188
|
return null;
|
|
10805
11189
|
}
|