@cimplify/sdk 0.28.0 → 0.30.0
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/{chunk-GS7AX6B3.js → chunk-F47XFKYP.js} +152 -0
- package/dist/{chunk-FFUCCUG4.mjs → chunk-WGAVNFEQ.mjs} +149 -1
- package/dist/{index-EGhIxwfI.d.mts → index-BHVJgyqM.d.ts} +2 -2
- package/dist/{index-C2U1gHyP.d.ts → index-D4oNCc37.d.mts} +2 -2
- package/dist/{index-iHKILmG9.d.ts → index-DTdtu4OO.d.ts} +141 -15
- package/dist/{index-ClrQ0yTH.d.mts → index-DaXyvlxk.d.mts} +141 -15
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +26 -10
- package/dist/index.mjs +1 -1
- package/dist/{payment-k8feV7r8.d.ts → payment-DnU_eLuT.d.mts} +119 -3
- package/dist/{payment-k8feV7r8.d.mts → payment-DnU_eLuT.d.ts} +119 -3
- package/dist/{price-Den0zv61.d.mts → price-D-hso3np.d.mts} +1 -1
- package/dist/{price-4EK-0zF5.d.ts → price-DUVmRTaz.d.ts} +1 -1
- package/dist/react.d.mts +99 -4
- package/dist/react.d.ts +99 -4
- package/dist/react.js +1893 -381
- package/dist/react.mjs +1556 -47
- package/dist/styles.css +1 -1
- package/dist/utils.d.mts +3 -3
- package/dist/utils.d.ts +3 -3
- package/package.json +1 -1
- package/registry/cart-summary.json +1 -1
- package/registry/chat-widget.json +15 -0
- package/registry/index.json +9 -0
- package/registry/product-customizer.json +1 -1
- package/registry/schedule-service-card.json +1 -1
- package/registry/service-product-layout.json +1 -1
- package/registry/subscription-card.json +1 -1
package/dist/react.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkF47XFKYP_js = require('./chunk-F47XFKYP.js');
|
|
5
5
|
var chunk2CGA3MUW_js = require('./chunk-2CGA3MUW.js');
|
|
6
6
|
var chunkPEDLCL72_js = require('./chunk-PEDLCL72.js');
|
|
7
|
-
var
|
|
7
|
+
var React10 = require('react');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
var clsx = require('clsx');
|
|
10
10
|
var tailwindMerge = require('tailwind-merge');
|
|
@@ -20,7 +20,7 @@ var tabs = require('@base-ui/react/tabs');
|
|
|
20
20
|
|
|
21
21
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
22
|
|
|
23
|
-
var
|
|
23
|
+
var React10__default = /*#__PURE__*/_interopDefault(React10);
|
|
24
24
|
|
|
25
25
|
// src/ads/identity.ts
|
|
26
26
|
var COOKIE_NAME = "_cimplify_uid";
|
|
@@ -197,7 +197,7 @@ function deriveAdsApiUrl() {
|
|
|
197
197
|
}
|
|
198
198
|
return "https://api.cimplify.io";
|
|
199
199
|
}
|
|
200
|
-
var AdContext =
|
|
200
|
+
var AdContext = React10.createContext({
|
|
201
201
|
siteId: null,
|
|
202
202
|
config: null,
|
|
203
203
|
isLoading: true,
|
|
@@ -205,7 +205,7 @@ var AdContext = React3.createContext({
|
|
|
205
205
|
apiBase: "https://api.cimplify.io"
|
|
206
206
|
});
|
|
207
207
|
function useAds() {
|
|
208
|
-
return
|
|
208
|
+
return React10.useContext(AdContext);
|
|
209
209
|
}
|
|
210
210
|
function AdProvider({
|
|
211
211
|
siteId,
|
|
@@ -214,10 +214,10 @@ function AdProvider({
|
|
|
214
214
|
children
|
|
215
215
|
}) {
|
|
216
216
|
const resolvedApiBase = apiBase || deriveAdsApiUrl();
|
|
217
|
-
const [config, setConfig] =
|
|
218
|
-
const [isLoading, setIsLoading] =
|
|
219
|
-
const [identity, setIdentity] =
|
|
220
|
-
|
|
217
|
+
const [config, setConfig] = React10.useState(null);
|
|
218
|
+
const [isLoading, setIsLoading] = React10.useState(true);
|
|
219
|
+
const [identity, setIdentity] = React10.useState(null);
|
|
220
|
+
React10.useEffect(() => {
|
|
221
221
|
const userIdentity = getUserIdentity(authenticatedAccountId);
|
|
222
222
|
setIdentity(userIdentity);
|
|
223
223
|
fetch(`${resolvedApiBase}/ads/config/${siteId}`).then((r) => r.json()).then((data) => {
|
|
@@ -240,11 +240,11 @@ function Ad({
|
|
|
240
240
|
onClick
|
|
241
241
|
}) {
|
|
242
242
|
const { siteId, config, isLoading, identity, apiBase } = useAds();
|
|
243
|
-
const [ad, setAd] =
|
|
244
|
-
const [error, setError] =
|
|
245
|
-
const impressionTracked =
|
|
246
|
-
const containerRef =
|
|
247
|
-
|
|
243
|
+
const [ad, setAd] = React10.useState(null);
|
|
244
|
+
const [error, setError] = React10.useState(false);
|
|
245
|
+
const impressionTracked = React10.useRef(false);
|
|
246
|
+
const containerRef = React10.useRef(null);
|
|
247
|
+
React10.useEffect(() => {
|
|
248
248
|
if (isLoading || !config?.enabled || !siteId || !identity) return;
|
|
249
249
|
const path = typeof window !== "undefined" ? window.location.pathname : "/";
|
|
250
250
|
const referrer = typeof document !== "undefined" ? document.referrer : "";
|
|
@@ -287,7 +287,7 @@ function Ad({
|
|
|
287
287
|
}
|
|
288
288
|
}).catch(() => setError(true));
|
|
289
289
|
}, [siteId, config, isLoading, slot, identity, apiBase]);
|
|
290
|
-
|
|
290
|
+
React10.useEffect(() => {
|
|
291
291
|
if (!ad || impressionTracked.current || typeof window === "undefined" || !identity) return;
|
|
292
292
|
const observer = new IntersectionObserver(
|
|
293
293
|
([entry]) => {
|
|
@@ -570,7 +570,8 @@ function mapServerCart(serverCart) {
|
|
|
570
570
|
confirmationCode: item.confirmation_code || void 0,
|
|
571
571
|
serviceStatus: item.service_status || void 0,
|
|
572
572
|
bundleResolved: item.bundle_resolved || void 0,
|
|
573
|
-
compositeResolved: item.composite_resolved || void 0
|
|
573
|
+
compositeResolved: item.composite_resolved || void 0,
|
|
574
|
+
customerInputs: item.customer_inputs || void 0
|
|
574
575
|
});
|
|
575
576
|
});
|
|
576
577
|
return {
|
|
@@ -790,7 +791,8 @@ function createCartStore(params) {
|
|
|
790
791
|
scheduled_start: normalizedOptions.scheduledStart,
|
|
791
792
|
scheduled_end: normalizedOptions.scheduledEnd,
|
|
792
793
|
staff_id: normalizedOptions.staffId,
|
|
793
|
-
resource_id: normalizedOptions.resourceId
|
|
794
|
+
resource_id: normalizedOptions.resourceId,
|
|
795
|
+
customer_inputs: normalizedOptions.customerInputs
|
|
794
796
|
});
|
|
795
797
|
if (!result.ok) {
|
|
796
798
|
throw result.error;
|
|
@@ -981,7 +983,7 @@ function useCart(options = {}) {
|
|
|
981
983
|
const locationId = options.locationId ?? client.getLocationId();
|
|
982
984
|
const isDemoMode = options.demoMode ?? context?.isDemoMode ?? client.getPublicKey().trim().length === 0;
|
|
983
985
|
const currency = options.currency ?? context?.currency ?? "USD";
|
|
984
|
-
const store =
|
|
986
|
+
const store = React10.useMemo(
|
|
985
987
|
() => getOrCreateStore({
|
|
986
988
|
client,
|
|
987
989
|
locationId,
|
|
@@ -990,53 +992,53 @@ function useCart(options = {}) {
|
|
|
990
992
|
}),
|
|
991
993
|
[client, currency, isDemoMode, locationId]
|
|
992
994
|
);
|
|
993
|
-
const snapshot =
|
|
995
|
+
const snapshot = React10.useSyncExternalStore(
|
|
994
996
|
store.subscribe,
|
|
995
997
|
store.getSnapshot,
|
|
996
998
|
store.getSnapshot
|
|
997
999
|
);
|
|
998
|
-
|
|
1000
|
+
React10.useEffect(() => {
|
|
999
1001
|
void store.initialize();
|
|
1000
1002
|
}, [store]);
|
|
1001
|
-
const addItem =
|
|
1003
|
+
const addItem = React10.useCallback(
|
|
1002
1004
|
async (product, quantity, addOptions) => {
|
|
1003
1005
|
await store.addItem(product, quantity, addOptions);
|
|
1004
1006
|
},
|
|
1005
1007
|
[store]
|
|
1006
1008
|
);
|
|
1007
|
-
const removeItem =
|
|
1009
|
+
const removeItem = React10.useCallback(
|
|
1008
1010
|
async (itemId) => {
|
|
1009
1011
|
await store.removeItem(itemId);
|
|
1010
1012
|
},
|
|
1011
1013
|
[store]
|
|
1012
1014
|
);
|
|
1013
|
-
const updateQuantity =
|
|
1015
|
+
const updateQuantity = React10.useCallback(
|
|
1014
1016
|
async (itemId, quantity) => {
|
|
1015
1017
|
await store.updateQuantity(itemId, quantity);
|
|
1016
1018
|
},
|
|
1017
1019
|
[store]
|
|
1018
1020
|
);
|
|
1019
|
-
const clearCart =
|
|
1021
|
+
const clearCart = React10.useCallback(async () => {
|
|
1020
1022
|
await store.clearCart();
|
|
1021
1023
|
}, [store]);
|
|
1022
|
-
const sync =
|
|
1024
|
+
const sync = React10.useCallback(async () => {
|
|
1023
1025
|
try {
|
|
1024
1026
|
await store.sync();
|
|
1025
1027
|
} catch (syncError) {
|
|
1026
1028
|
throw syncError;
|
|
1027
1029
|
}
|
|
1028
1030
|
}, [store]);
|
|
1029
|
-
const reorder =
|
|
1031
|
+
const reorder = React10.useCallback(
|
|
1030
1032
|
async (orderId) => {
|
|
1031
1033
|
return store.reorder(orderId);
|
|
1032
1034
|
},
|
|
1033
1035
|
[store]
|
|
1034
1036
|
);
|
|
1035
|
-
const itemCount =
|
|
1037
|
+
const itemCount = React10.useMemo(
|
|
1036
1038
|
() => snapshot.items.reduce((sum, item) => sum + item.quantity, 0),
|
|
1037
1039
|
[snapshot.items]
|
|
1038
1040
|
);
|
|
1039
|
-
return
|
|
1041
|
+
return React10.useMemo(() => ({
|
|
1040
1042
|
items: snapshot.items,
|
|
1041
1043
|
itemCount,
|
|
1042
1044
|
subtotal: snapshot.subtotal,
|
|
@@ -1061,7 +1063,7 @@ var DEFAULT_COUNTRY = "US";
|
|
|
1061
1063
|
function createDefaultClient() {
|
|
1062
1064
|
const processRef = globalThis.process;
|
|
1063
1065
|
const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
|
|
1064
|
-
return
|
|
1066
|
+
return chunkF47XFKYP_js.createCimplifyClient({ publicKey: envPublicKey });
|
|
1065
1067
|
}
|
|
1066
1068
|
function getStoredLocationId() {
|
|
1067
1069
|
if (typeof window === "undefined" || !window.localStorage) {
|
|
@@ -1118,30 +1120,30 @@ function resolveInitialLocation(locations) {
|
|
|
1118
1120
|
}
|
|
1119
1121
|
return locations[0];
|
|
1120
1122
|
}
|
|
1121
|
-
var CimplifyClientContext =
|
|
1122
|
-
var CimplifyStateContext =
|
|
1123
|
+
var CimplifyClientContext = React10.createContext(null);
|
|
1124
|
+
var CimplifyStateContext = React10.createContext(null);
|
|
1123
1125
|
function CimplifyProvider({
|
|
1124
1126
|
client,
|
|
1125
1127
|
children,
|
|
1126
1128
|
onLocationChange
|
|
1127
1129
|
}) {
|
|
1128
|
-
const resolvedClient =
|
|
1129
|
-
const onLocationChangeRef =
|
|
1130
|
-
const [business, setBusiness] =
|
|
1131
|
-
const [locations, setLocations] =
|
|
1132
|
-
const [currentLocation, setCurrentLocationState] =
|
|
1133
|
-
const [isReady, setIsReady] =
|
|
1134
|
-
|
|
1130
|
+
const resolvedClient = React10.useMemo(() => client ?? createDefaultClient(), [client]);
|
|
1131
|
+
const onLocationChangeRef = React10.useRef(onLocationChange);
|
|
1132
|
+
const [business, setBusiness] = React10.useState(null);
|
|
1133
|
+
const [locations, setLocations] = React10.useState([]);
|
|
1134
|
+
const [currentLocation, setCurrentLocationState] = React10.useState(null);
|
|
1135
|
+
const [isReady, setIsReady] = React10.useState(false);
|
|
1136
|
+
React10.useEffect(() => {
|
|
1135
1137
|
onLocationChangeRef.current = onLocationChange;
|
|
1136
1138
|
}, [onLocationChange]);
|
|
1137
1139
|
const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
|
|
1138
1140
|
const baseCurrency = business?.default_currency || DEFAULT_CURRENCY;
|
|
1139
|
-
const [displayCurrencyOverride, setDisplayCurrencyOverride] =
|
|
1141
|
+
const [displayCurrencyOverride, setDisplayCurrencyOverride] = React10.useState(
|
|
1140
1142
|
() => getStoredDisplayCurrency()
|
|
1141
1143
|
);
|
|
1142
|
-
const [fxRate, setFxRate] =
|
|
1144
|
+
const [fxRate, setFxRate] = React10.useState(null);
|
|
1143
1145
|
const displayCurrency = displayCurrencyOverride && displayCurrencyOverride !== baseCurrency ? displayCurrencyOverride : baseCurrency;
|
|
1144
|
-
const setDisplayCurrency =
|
|
1146
|
+
const setDisplayCurrency = React10.useCallback(
|
|
1145
1147
|
(currency) => {
|
|
1146
1148
|
const normalized = currency?.trim().toUpperCase() || null;
|
|
1147
1149
|
if (normalized && !chunkPEDLCL72_js.isSupportedCurrency(normalized)) {
|
|
@@ -1155,7 +1157,7 @@ function CimplifyProvider({
|
|
|
1155
1157
|
},
|
|
1156
1158
|
[baseCurrency]
|
|
1157
1159
|
);
|
|
1158
|
-
|
|
1160
|
+
React10.useEffect(() => {
|
|
1159
1161
|
if (displayCurrency === baseCurrency || isDemoMode) {
|
|
1160
1162
|
setFxRate(null);
|
|
1161
1163
|
return;
|
|
@@ -1180,7 +1182,7 @@ function CimplifyProvider({
|
|
|
1180
1182
|
clearInterval(intervalId);
|
|
1181
1183
|
};
|
|
1182
1184
|
}, [resolvedClient, baseCurrency, displayCurrency, isDemoMode]);
|
|
1183
|
-
const convertPrice =
|
|
1185
|
+
const convertPrice = React10.useCallback(
|
|
1184
1186
|
(amount) => {
|
|
1185
1187
|
const num = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
1186
1188
|
if (isNaN(num)) return 0;
|
|
@@ -1189,7 +1191,7 @@ function CimplifyProvider({
|
|
|
1189
1191
|
},
|
|
1190
1192
|
[fxRate, displayCurrency, baseCurrency]
|
|
1191
1193
|
);
|
|
1192
|
-
const setCurrentLocation =
|
|
1194
|
+
const setCurrentLocation = React10.useCallback(
|
|
1193
1195
|
(location) => {
|
|
1194
1196
|
const previousLocationId = resolvedClient.getLocationId();
|
|
1195
1197
|
if (previousLocationId && previousLocationId !== location.id) {
|
|
@@ -1202,7 +1204,7 @@ function CimplifyProvider({
|
|
|
1202
1204
|
},
|
|
1203
1205
|
[resolvedClient]
|
|
1204
1206
|
);
|
|
1205
|
-
|
|
1207
|
+
React10.useEffect(() => {
|
|
1206
1208
|
let cancelled = false;
|
|
1207
1209
|
async function bootstrap() {
|
|
1208
1210
|
setIsReady(false);
|
|
@@ -1258,7 +1260,7 @@ function CimplifyProvider({
|
|
|
1258
1260
|
cancelled = true;
|
|
1259
1261
|
};
|
|
1260
1262
|
}, [resolvedClient, isDemoMode]);
|
|
1261
|
-
const clientContextValue =
|
|
1263
|
+
const clientContextValue = React10.useMemo(
|
|
1262
1264
|
() => ({
|
|
1263
1265
|
client: resolvedClient,
|
|
1264
1266
|
business,
|
|
@@ -1278,7 +1280,7 @@ function CimplifyProvider({
|
|
|
1278
1280
|
isDemoMode
|
|
1279
1281
|
]
|
|
1280
1282
|
);
|
|
1281
|
-
const stateContextValue =
|
|
1283
|
+
const stateContextValue = React10.useMemo(
|
|
1282
1284
|
() => ({
|
|
1283
1285
|
currentLocation,
|
|
1284
1286
|
setCurrentLocation,
|
|
@@ -1299,20 +1301,20 @@ function CimplifyProvider({
|
|
|
1299
1301
|
return /* @__PURE__ */ jsxRuntime.jsx(CimplifyClientContext.Provider, { value: clientContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(CimplifyStateContext.Provider, { value: stateContextValue, children }) });
|
|
1300
1302
|
}
|
|
1301
1303
|
function useCimplify() {
|
|
1302
|
-
const clientContext =
|
|
1303
|
-
const stateContext =
|
|
1304
|
+
const clientContext = React10.useContext(CimplifyClientContext);
|
|
1305
|
+
const stateContext = React10.useContext(CimplifyStateContext);
|
|
1304
1306
|
if (!clientContext || !stateContext) {
|
|
1305
1307
|
throw new Error("useCimplify must be used within CimplifyProvider");
|
|
1306
1308
|
}
|
|
1307
|
-
return
|
|
1309
|
+
return React10.useMemo(
|
|
1308
1310
|
() => ({ ...clientContext, ...stateContext }),
|
|
1309
1311
|
[clientContext, stateContext]
|
|
1310
1312
|
);
|
|
1311
1313
|
}
|
|
1312
1314
|
function useOptionalCimplify() {
|
|
1313
|
-
const clientContext =
|
|
1314
|
-
const stateContext =
|
|
1315
|
-
return
|
|
1315
|
+
const clientContext = React10.useContext(CimplifyClientContext);
|
|
1316
|
+
const stateContext = React10.useContext(CimplifyStateContext);
|
|
1317
|
+
return React10.useMemo(() => {
|
|
1316
1318
|
if (!clientContext || !stateContext) {
|
|
1317
1319
|
return null;
|
|
1318
1320
|
}
|
|
@@ -1320,14 +1322,14 @@ function useOptionalCimplify() {
|
|
|
1320
1322
|
}, [clientContext, stateContext]);
|
|
1321
1323
|
}
|
|
1322
1324
|
function useCimplifyClient() {
|
|
1323
|
-
const context =
|
|
1325
|
+
const context = React10.useContext(CimplifyClientContext);
|
|
1324
1326
|
if (!context) {
|
|
1325
1327
|
throw new Error("useCimplifyClient must be used within CimplifyProvider");
|
|
1326
1328
|
}
|
|
1327
1329
|
return context;
|
|
1328
1330
|
}
|
|
1329
1331
|
function useOptionalCimplifyClient() {
|
|
1330
|
-
return
|
|
1332
|
+
return React10.useContext(CimplifyClientContext);
|
|
1331
1333
|
}
|
|
1332
1334
|
var SPACE = { sm: 8};
|
|
1333
1335
|
function shellColors(isDark, primaryColor) {
|
|
@@ -1385,36 +1387,36 @@ function CimplifyCheckout({
|
|
|
1385
1387
|
demoMode,
|
|
1386
1388
|
className
|
|
1387
1389
|
}) {
|
|
1388
|
-
const resolvedOrderTypes =
|
|
1390
|
+
const resolvedOrderTypes = React10.useMemo(
|
|
1389
1391
|
() => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
|
|
1390
1392
|
[orderTypes]
|
|
1391
1393
|
);
|
|
1392
|
-
const resolvedDefaultOrderType =
|
|
1394
|
+
const resolvedDefaultOrderType = React10.useMemo(() => {
|
|
1393
1395
|
if (defaultOrderType && resolvedOrderTypes.includes(defaultOrderType)) {
|
|
1394
1396
|
return defaultOrderType;
|
|
1395
1397
|
}
|
|
1396
1398
|
return resolvedOrderTypes[0] || "pickup";
|
|
1397
1399
|
}, [defaultOrderType, resolvedOrderTypes]);
|
|
1398
|
-
const [orderType, setOrderType] =
|
|
1399
|
-
const [status, setStatus] =
|
|
1400
|
-
const [statusText, setStatusText] =
|
|
1401
|
-
const [isSubmitting, setIsSubmitting] =
|
|
1402
|
-
const [isInitializing, setIsInitializing] =
|
|
1403
|
-
const [errorMessage, setErrorMessage] =
|
|
1404
|
-
const [resolvedBusinessId, setResolvedBusinessId] =
|
|
1405
|
-
const [resolvedCartId, setResolvedCartId] =
|
|
1406
|
-
const [resolvedCart, setResolvedCart] =
|
|
1407
|
-
const checkoutMountRef =
|
|
1408
|
-
const elementsRef =
|
|
1409
|
-
const activeCheckoutRef =
|
|
1410
|
-
const initialAppearanceRef =
|
|
1411
|
-
const hasWarnedInlineAppearanceRef =
|
|
1412
|
-
const isMountedRef =
|
|
1413
|
-
const demoRunRef =
|
|
1400
|
+
const [orderType, setOrderType] = React10.useState(resolvedDefaultOrderType);
|
|
1401
|
+
const [status, setStatus] = React10.useState(null);
|
|
1402
|
+
const [statusText, setStatusText] = React10.useState("");
|
|
1403
|
+
const [isSubmitting, setIsSubmitting] = React10.useState(false);
|
|
1404
|
+
const [isInitializing, setIsInitializing] = React10.useState(false);
|
|
1405
|
+
const [errorMessage, setErrorMessage] = React10.useState(null);
|
|
1406
|
+
const [resolvedBusinessId, setResolvedBusinessId] = React10.useState(businessId ?? null);
|
|
1407
|
+
const [resolvedCartId, setResolvedCartId] = React10.useState(cartId ?? null);
|
|
1408
|
+
const [resolvedCart, setResolvedCart] = React10.useState(null);
|
|
1409
|
+
const checkoutMountRef = React10.useRef(null);
|
|
1410
|
+
const elementsRef = React10.useRef(null);
|
|
1411
|
+
const activeCheckoutRef = React10.useRef(null);
|
|
1412
|
+
const initialAppearanceRef = React10.useRef(appearance);
|
|
1413
|
+
const hasWarnedInlineAppearanceRef = React10.useRef(false);
|
|
1414
|
+
const isMountedRef = React10.useRef(true);
|
|
1415
|
+
const demoRunRef = React10.useRef(0);
|
|
1414
1416
|
const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
|
|
1415
1417
|
const isTestMode = client.isTestMode();
|
|
1416
1418
|
const cimplifyCtx = useOptionalCimplify();
|
|
1417
|
-
const fxOptions =
|
|
1419
|
+
const fxOptions = React10.useMemo(() => {
|
|
1418
1420
|
if (!cimplifyCtx?.fxRate) return void 0;
|
|
1419
1421
|
if (cimplifyCtx.displayCurrency === cimplifyCtx.baseCurrency) return void 0;
|
|
1420
1422
|
return {
|
|
@@ -1422,30 +1424,30 @@ function CimplifyCheckout({
|
|
|
1422
1424
|
convertPrice: cimplifyCtx.convertPrice
|
|
1423
1425
|
};
|
|
1424
1426
|
}, [cimplifyCtx?.fxRate, cimplifyCtx?.displayCurrency, cimplifyCtx?.baseCurrency, cimplifyCtx?.convertPrice]);
|
|
1425
|
-
const fxOptionsRef =
|
|
1427
|
+
const fxOptionsRef = React10.useRef(fxOptions);
|
|
1426
1428
|
fxOptionsRef.current = fxOptions;
|
|
1427
|
-
const resolvedCartRef =
|
|
1429
|
+
const resolvedCartRef = React10.useRef(resolvedCart);
|
|
1428
1430
|
resolvedCartRef.current = resolvedCart;
|
|
1429
1431
|
const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
|
|
1430
1432
|
const isDark = appearance?.theme === "dark";
|
|
1431
|
-
const emitStatus =
|
|
1433
|
+
const emitStatus = React10__default.default.useEffectEvent(
|
|
1432
1434
|
(nextStatus, context = {}) => {
|
|
1433
1435
|
setStatus(nextStatus);
|
|
1434
1436
|
setStatusText(context.display_text || "");
|
|
1435
1437
|
onStatusChange?.(nextStatus, context);
|
|
1436
1438
|
}
|
|
1437
1439
|
);
|
|
1438
|
-
const fireError =
|
|
1440
|
+
const fireError = React10__default.default.useEffectEvent(
|
|
1439
1441
|
(error) => {
|
|
1440
1442
|
onError?.(error);
|
|
1441
1443
|
}
|
|
1442
1444
|
);
|
|
1443
|
-
|
|
1445
|
+
React10.useEffect(() => {
|
|
1444
1446
|
if (!resolvedOrderTypes.includes(orderType)) {
|
|
1445
1447
|
setOrderType(resolvedDefaultOrderType);
|
|
1446
1448
|
}
|
|
1447
1449
|
}, [resolvedOrderTypes, resolvedDefaultOrderType, orderType]);
|
|
1448
|
-
|
|
1450
|
+
React10.useEffect(() => {
|
|
1449
1451
|
if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
|
|
1450
1452
|
hasWarnedInlineAppearanceRef.current = true;
|
|
1451
1453
|
console.warn(
|
|
@@ -1453,7 +1455,7 @@ function CimplifyCheckout({
|
|
|
1453
1455
|
);
|
|
1454
1456
|
}
|
|
1455
1457
|
}, [appearance]);
|
|
1456
|
-
|
|
1458
|
+
React10.useEffect(() => {
|
|
1457
1459
|
let cancelled = false;
|
|
1458
1460
|
async function bootstrap() {
|
|
1459
1461
|
if (isDemoCheckout) {
|
|
@@ -1533,7 +1535,7 @@ function CimplifyCheckout({
|
|
|
1533
1535
|
cancelled = true;
|
|
1534
1536
|
};
|
|
1535
1537
|
}, [businessId, cartId, client, isDemoCheckout]);
|
|
1536
|
-
|
|
1538
|
+
React10.useEffect(() => {
|
|
1537
1539
|
return () => {
|
|
1538
1540
|
isMountedRef.current = false;
|
|
1539
1541
|
demoRunRef.current += 1;
|
|
@@ -1541,7 +1543,7 @@ function CimplifyCheckout({
|
|
|
1541
1543
|
activeCheckoutRef.current = null;
|
|
1542
1544
|
};
|
|
1543
1545
|
}, []);
|
|
1544
|
-
const handleSubmit =
|
|
1546
|
+
const handleSubmit = React10__default.default.useEffectEvent(async () => {
|
|
1545
1547
|
if (isSubmitting || isInitializing || !resolvedCartId) {
|
|
1546
1548
|
if (!resolvedCartId && !isInitializing) {
|
|
1547
1549
|
const message = "Your cart is empty. Add items before checkout.";
|
|
@@ -1622,7 +1624,7 @@ function CimplifyCheckout({
|
|
|
1622
1624
|
}
|
|
1623
1625
|
}
|
|
1624
1626
|
});
|
|
1625
|
-
|
|
1627
|
+
React10.useEffect(() => {
|
|
1626
1628
|
if (isDemoCheckout || !resolvedBusinessId) {
|
|
1627
1629
|
elementsRef.current = null;
|
|
1628
1630
|
return;
|
|
@@ -1669,7 +1671,7 @@ function CimplifyCheckout({
|
|
|
1669
1671
|
resolvedDefaultOrderType,
|
|
1670
1672
|
submitLabel
|
|
1671
1673
|
]);
|
|
1672
|
-
|
|
1674
|
+
React10.useEffect(() => {
|
|
1673
1675
|
if (!resolvedCart || !elementsRef.current) return;
|
|
1674
1676
|
const checkoutElement = elementsRef.current.getElement("checkout");
|
|
1675
1677
|
if (checkoutElement) {
|
|
@@ -1717,10 +1719,10 @@ function CimplifyAccount({
|
|
|
1717
1719
|
const context = useOptionalCimplify();
|
|
1718
1720
|
const client = clientProp ?? context?.client;
|
|
1719
1721
|
const resolvedLinkUrl = linkUrl || DEFAULT_LINK_URL;
|
|
1720
|
-
const iframeRef =
|
|
1721
|
-
const [height, setHeight] =
|
|
1722
|
-
const [isReady, setIsReady] =
|
|
1723
|
-
const iframeSrc =
|
|
1722
|
+
const iframeRef = React10.useRef(null);
|
|
1723
|
+
const [height, setHeight] = React10.useState(400);
|
|
1724
|
+
const [isReady, setIsReady] = React10.useState(false);
|
|
1725
|
+
const iframeSrc = React10.useMemo(() => {
|
|
1724
1726
|
const path = section ? `/elements/account/${section}` : "/elements/account";
|
|
1725
1727
|
const url = new URL(path, resolvedLinkUrl);
|
|
1726
1728
|
if (client) {
|
|
@@ -1729,7 +1731,7 @@ function CimplifyAccount({
|
|
|
1729
1731
|
}
|
|
1730
1732
|
return url.toString();
|
|
1731
1733
|
}, [resolvedLinkUrl, section, client]);
|
|
1732
|
-
|
|
1734
|
+
React10.useEffect(() => {
|
|
1733
1735
|
function handleMessage(event) {
|
|
1734
1736
|
if (!event.data || typeof event.data !== "object") return;
|
|
1735
1737
|
if (iframeRef.current?.contentWindow && event.source !== iframeRef.current.contentWindow) {
|
|
@@ -1831,9 +1833,9 @@ function createCachedQuery(config) {
|
|
|
1831
1833
|
}
|
|
1832
1834
|
const enabled = options.enabled ?? true;
|
|
1833
1835
|
const locationId = client.getLocationId();
|
|
1834
|
-
const previousLocationRef =
|
|
1835
|
-
const requestIdRef =
|
|
1836
|
-
const optionsRef =
|
|
1836
|
+
const previousLocationRef = React10.useRef(locationId);
|
|
1837
|
+
const requestIdRef = React10.useRef(0);
|
|
1838
|
+
const optionsRef = React10.useRef(options);
|
|
1837
1839
|
optionsRef.current = options;
|
|
1838
1840
|
if (config.locationSensitive && previousLocationRef.current !== locationId) {
|
|
1839
1841
|
cache.clear();
|
|
@@ -1843,10 +1845,10 @@ function createCachedQuery(config) {
|
|
|
1843
1845
|
sweep();
|
|
1844
1846
|
const cacheKey2 = config.key(client, options);
|
|
1845
1847
|
const cached = cache.get(cacheKey2);
|
|
1846
|
-
const [data, setData] =
|
|
1847
|
-
const [isLoading, setIsLoading] =
|
|
1848
|
-
const [error, setError] =
|
|
1849
|
-
const load =
|
|
1848
|
+
const [data, setData] = React10.useState(cached?.data ?? null);
|
|
1849
|
+
const [isLoading, setIsLoading] = React10.useState(enabled && !cached);
|
|
1850
|
+
const [error, setError] = React10.useState(null);
|
|
1851
|
+
const load = React10.useCallback(
|
|
1850
1852
|
async (force = false) => {
|
|
1851
1853
|
if (!enabled) {
|
|
1852
1854
|
setIsLoading(false);
|
|
@@ -1889,10 +1891,10 @@ function createCachedQuery(config) {
|
|
|
1889
1891
|
},
|
|
1890
1892
|
[cacheKey2, client, enabled]
|
|
1891
1893
|
);
|
|
1892
|
-
|
|
1894
|
+
React10.useEffect(() => {
|
|
1893
1895
|
void load(false);
|
|
1894
1896
|
}, [load]);
|
|
1895
|
-
const refetch =
|
|
1897
|
+
const refetch = React10.useCallback(async () => {
|
|
1896
1898
|
cache.delete(cacheKey2);
|
|
1897
1899
|
await load(true);
|
|
1898
1900
|
}, [cacheKey2, load]);
|
|
@@ -2022,25 +2024,25 @@ function useOrder(orderId, options = {}) {
|
|
|
2022
2024
|
if (!client) {
|
|
2023
2025
|
throw new Error("useOrder must be used within CimplifyProvider or passed { client }.");
|
|
2024
2026
|
}
|
|
2025
|
-
const normalizedOrderId =
|
|
2027
|
+
const normalizedOrderId = React10.useMemo(() => (orderId || "").trim(), [orderId]);
|
|
2026
2028
|
const enabled = options.enabled ?? true;
|
|
2027
2029
|
const poll = options.poll ?? false;
|
|
2028
2030
|
const pollInterval = options.pollInterval ?? 5e3;
|
|
2029
|
-
const requestIdRef =
|
|
2030
|
-
const previousStatusRef =
|
|
2031
|
-
const onStatusChangeRef =
|
|
2031
|
+
const requestIdRef = React10.useRef(0);
|
|
2032
|
+
const previousStatusRef = React10.useRef(null);
|
|
2033
|
+
const onStatusChangeRef = React10.useRef(options.onStatusChange);
|
|
2032
2034
|
onStatusChangeRef.current = options.onStatusChange;
|
|
2033
|
-
const cacheKey2 =
|
|
2035
|
+
const cacheKey2 = React10.useMemo(
|
|
2034
2036
|
() => buildOrderCacheKey(client, normalizedOrderId),
|
|
2035
2037
|
[client, normalizedOrderId]
|
|
2036
2038
|
);
|
|
2037
2039
|
const cached = orderCache.get(cacheKey2);
|
|
2038
|
-
const [order, setOrder] =
|
|
2039
|
-
const [isLoading, setIsLoading] =
|
|
2040
|
+
const [order, setOrder] = React10.useState(cached?.order ?? null);
|
|
2041
|
+
const [isLoading, setIsLoading] = React10.useState(
|
|
2040
2042
|
enabled && normalizedOrderId.length > 0 && !cached
|
|
2041
2043
|
);
|
|
2042
|
-
const [error, setError] =
|
|
2043
|
-
const load =
|
|
2044
|
+
const [error, setError] = React10.useState(null);
|
|
2045
|
+
const load = React10.useCallback(
|
|
2044
2046
|
async (force = false) => {
|
|
2045
2047
|
if (!enabled || normalizedOrderId.length === 0) {
|
|
2046
2048
|
setOrder(null);
|
|
@@ -2099,11 +2101,11 @@ function useOrder(orderId, options = {}) {
|
|
|
2099
2101
|
},
|
|
2100
2102
|
[cacheKey2, client, enabled, normalizedOrderId]
|
|
2101
2103
|
);
|
|
2102
|
-
|
|
2104
|
+
React10.useEffect(() => {
|
|
2103
2105
|
void load(false);
|
|
2104
2106
|
}, [load]);
|
|
2105
2107
|
const isTerminal = order ? TERMINAL_STATUSES.has(order.status) : false;
|
|
2106
|
-
|
|
2108
|
+
React10.useEffect(() => {
|
|
2107
2109
|
if (!poll || !enabled || normalizedOrderId.length === 0 || isTerminal) {
|
|
2108
2110
|
return;
|
|
2109
2111
|
}
|
|
@@ -2114,7 +2116,7 @@ function useOrder(orderId, options = {}) {
|
|
|
2114
2116
|
window.clearInterval(timer);
|
|
2115
2117
|
};
|
|
2116
2118
|
}, [enabled, isTerminal, load, normalizedOrderId, poll, pollInterval]);
|
|
2117
|
-
const refetch =
|
|
2119
|
+
const refetch = React10.useCallback(async () => {
|
|
2118
2120
|
orderCache.delete(cacheKey2);
|
|
2119
2121
|
await load(true);
|
|
2120
2122
|
}, [cacheKey2, load]);
|
|
@@ -2165,10 +2167,10 @@ function useLocations(options = {}) {
|
|
|
2165
2167
|
};
|
|
2166
2168
|
}
|
|
2167
2169
|
const client = options.client;
|
|
2168
|
-
const [locations, setLocations] =
|
|
2169
|
-
const [currentLocation, setCurrentLocationState] =
|
|
2170
|
-
const [isLoading, setIsLoading] =
|
|
2171
|
-
const setCurrentLocation =
|
|
2170
|
+
const [locations, setLocations] = React10.useState([]);
|
|
2171
|
+
const [currentLocation, setCurrentLocationState] = React10.useState(null);
|
|
2172
|
+
const [isLoading, setIsLoading] = React10.useState(true);
|
|
2173
|
+
const setCurrentLocation = React10.useCallback(
|
|
2172
2174
|
(location) => {
|
|
2173
2175
|
setCurrentLocationState(location);
|
|
2174
2176
|
if (client) {
|
|
@@ -2178,7 +2180,7 @@ function useLocations(options = {}) {
|
|
|
2178
2180
|
},
|
|
2179
2181
|
[client]
|
|
2180
2182
|
);
|
|
2181
|
-
|
|
2183
|
+
React10.useEffect(() => {
|
|
2182
2184
|
if (!client) {
|
|
2183
2185
|
setLocations([]);
|
|
2184
2186
|
setCurrentLocationState(null);
|
|
@@ -2282,14 +2284,14 @@ function useSearch(options = {}) {
|
|
|
2282
2284
|
const minLength = Math.max(0, options.minLength ?? 2);
|
|
2283
2285
|
const debounceMs = Math.max(0, options.debounceMs ?? 300);
|
|
2284
2286
|
const limit = Math.max(1, options.limit ?? 20);
|
|
2285
|
-
const [query, setQueryState] =
|
|
2286
|
-
const [results, setResults] =
|
|
2287
|
-
const [isLoading, setIsLoading] =
|
|
2288
|
-
const [error, setError] =
|
|
2289
|
-
const requestIdRef =
|
|
2290
|
-
const timerRef =
|
|
2287
|
+
const [query, setQueryState] = React10.useState("");
|
|
2288
|
+
const [results, setResults] = React10.useState([]);
|
|
2289
|
+
const [isLoading, setIsLoading] = React10.useState(false);
|
|
2290
|
+
const [error, setError] = React10.useState(null);
|
|
2291
|
+
const requestIdRef = React10.useRef(0);
|
|
2292
|
+
const timerRef = React10.useRef(null);
|
|
2291
2293
|
const tagsSignature = options.tags?.join(",") ?? "";
|
|
2292
|
-
|
|
2294
|
+
React10.useEffect(() => {
|
|
2293
2295
|
if (timerRef.current) {
|
|
2294
2296
|
clearTimeout(timerRef.current);
|
|
2295
2297
|
timerRef.current = null;
|
|
@@ -2344,10 +2346,10 @@ function useSearch(options = {}) {
|
|
|
2344
2346
|
}
|
|
2345
2347
|
};
|
|
2346
2348
|
}, [client, debounceMs, limit, minLength, options.category, options.taxonomy, tagsSignature, options.featured, options.in_stock, options.min_price, options.max_price, options.sort_by, options.sort_order, query]);
|
|
2347
|
-
const setQuery =
|
|
2349
|
+
const setQuery = React10.useCallback((nextQuery) => {
|
|
2348
2350
|
setQueryState(nextQuery);
|
|
2349
2351
|
}, []);
|
|
2350
|
-
const clear =
|
|
2352
|
+
const clear = React10.useCallback(() => {
|
|
2351
2353
|
requestIdRef.current += 1;
|
|
2352
2354
|
if (timerRef.current) {
|
|
2353
2355
|
clearTimeout(timerRef.current);
|
|
@@ -2438,34 +2440,34 @@ function useQuote(input, options = {}) {
|
|
|
2438
2440
|
const autoRefresh = options.autoRefresh ?? true;
|
|
2439
2441
|
const refreshBeforeExpiryMs = Math.max(0, options.refreshBeforeExpiryMs ?? 3e4);
|
|
2440
2442
|
const locationId = client.getLocationId();
|
|
2441
|
-
const requestIdRef =
|
|
2442
|
-
const debounceTimerRef =
|
|
2443
|
+
const requestIdRef = React10.useRef(0);
|
|
2444
|
+
const debounceTimerRef = React10.useRef(null);
|
|
2443
2445
|
const inputSignature = buildQuoteInputSignature(input);
|
|
2444
|
-
const normalizedInput =
|
|
2446
|
+
const normalizedInput = React10.useMemo(() => {
|
|
2445
2447
|
if (!input) {
|
|
2446
2448
|
return null;
|
|
2447
2449
|
}
|
|
2448
2450
|
const normalized = normalizeInput(input, locationId);
|
|
2449
2451
|
return normalized.product_id.length > 0 ? normalized : null;
|
|
2450
2452
|
}, [inputSignature, locationId]);
|
|
2451
|
-
const cacheKey2 =
|
|
2453
|
+
const cacheKey2 = React10.useMemo(
|
|
2452
2454
|
() => buildQuoteCacheKey(client, locationId, inputSignature),
|
|
2453
2455
|
[client, inputSignature, locationId]
|
|
2454
2456
|
);
|
|
2455
2457
|
const cached = quoteCache.get(cacheKey2);
|
|
2456
|
-
const [quote, setQuote] =
|
|
2457
|
-
const [isLoading, setIsLoading] =
|
|
2458
|
-
const [error, setError] =
|
|
2459
|
-
const [isExpired, setIsExpired] =
|
|
2460
|
-
const [messages, setMessages] =
|
|
2461
|
-
const quoteExpiryTimestamp =
|
|
2458
|
+
const [quote, setQuote] = React10.useState(cached?.quote ?? null);
|
|
2459
|
+
const [isLoading, setIsLoading] = React10.useState(enabled && normalizedInput !== null && !cached);
|
|
2460
|
+
const [error, setError] = React10.useState(null);
|
|
2461
|
+
const [isExpired, setIsExpired] = React10.useState(isQuoteExpired(cached?.quote ?? null));
|
|
2462
|
+
const [messages, setMessages] = React10.useState(cached?.quote?.ui_messages ?? []);
|
|
2463
|
+
const quoteExpiryTimestamp = React10.useMemo(() => {
|
|
2462
2464
|
if (!quote?.expires_at) {
|
|
2463
2465
|
return Number.NaN;
|
|
2464
2466
|
}
|
|
2465
2467
|
const expiresAt = Date.parse(quote.expires_at);
|
|
2466
2468
|
return Number.isFinite(expiresAt) ? expiresAt : Number.NaN;
|
|
2467
2469
|
}, [quote?.expires_at]);
|
|
2468
|
-
const load =
|
|
2470
|
+
const load = React10.useCallback(
|
|
2469
2471
|
async (force = false) => {
|
|
2470
2472
|
if (!enabled || !normalizedInput) {
|
|
2471
2473
|
setQuote(null);
|
|
@@ -2525,7 +2527,7 @@ function useQuote(input, options = {}) {
|
|
|
2525
2527
|
},
|
|
2526
2528
|
[cacheKey2, client, enabled, normalizedInput]
|
|
2527
2529
|
);
|
|
2528
|
-
|
|
2530
|
+
React10.useEffect(() => {
|
|
2529
2531
|
if (debounceTimerRef.current) {
|
|
2530
2532
|
clearTimeout(debounceTimerRef.current);
|
|
2531
2533
|
}
|
|
@@ -2544,7 +2546,7 @@ function useQuote(input, options = {}) {
|
|
|
2544
2546
|
}
|
|
2545
2547
|
};
|
|
2546
2548
|
}, [load, cacheKey2, enabled, normalizedInput]);
|
|
2547
|
-
const refresh =
|
|
2549
|
+
const refresh = React10.useCallback(async () => {
|
|
2548
2550
|
if (!enabled || !normalizedInput) {
|
|
2549
2551
|
return;
|
|
2550
2552
|
}
|
|
@@ -2581,7 +2583,7 @@ function useQuote(input, options = {}) {
|
|
|
2581
2583
|
}
|
|
2582
2584
|
}
|
|
2583
2585
|
}, [cacheKey2, client, enabled, load, normalizedInput, quote]);
|
|
2584
|
-
|
|
2586
|
+
React10.useEffect(() => {
|
|
2585
2587
|
if (!Number.isFinite(quoteExpiryTimestamp)) {
|
|
2586
2588
|
setIsExpired(false);
|
|
2587
2589
|
return;
|
|
@@ -2757,9 +2759,9 @@ function useValidateDiscount(options = {}) {
|
|
|
2757
2759
|
if (!client) {
|
|
2758
2760
|
throw new Error("useValidateDiscount must be used within CimplifyProvider or passed { client }.");
|
|
2759
2761
|
}
|
|
2760
|
-
const [isValidating, setIsValidating] =
|
|
2761
|
-
const [error, setError] =
|
|
2762
|
-
const validate =
|
|
2762
|
+
const [isValidating, setIsValidating] = React10.useState(false);
|
|
2763
|
+
const [error, setError] = React10.useState(null);
|
|
2764
|
+
const validate = React10.useCallback(
|
|
2763
2765
|
async (code, orderSubtotal, locationId) => {
|
|
2764
2766
|
setError(null);
|
|
2765
2767
|
setIsValidating(true);
|
|
@@ -2806,7 +2808,7 @@ function useProductPrice(input) {
|
|
|
2806
2808
|
compositePrice,
|
|
2807
2809
|
bundleTotalPrice
|
|
2808
2810
|
} = input;
|
|
2809
|
-
return
|
|
2811
|
+
return React10.useMemo(() => {
|
|
2810
2812
|
let unitPrice;
|
|
2811
2813
|
if (bundleTotalPrice != null) {
|
|
2812
2814
|
unitPrice = bundleTotalPrice;
|
|
@@ -2855,10 +2857,10 @@ function useOrders(options = {}) {
|
|
|
2855
2857
|
function useSubscriptions(options = {}) {
|
|
2856
2858
|
const { client } = useCimplifyClient();
|
|
2857
2859
|
const { status, enabled = true } = options;
|
|
2858
|
-
const [subscriptions, setSubscriptions] =
|
|
2859
|
-
const [isLoading, setIsLoading] =
|
|
2860
|
-
const [error, setError] =
|
|
2861
|
-
const fetch2 =
|
|
2860
|
+
const [subscriptions, setSubscriptions] = React10.useState([]);
|
|
2861
|
+
const [isLoading, setIsLoading] = React10.useState(false);
|
|
2862
|
+
const [error, setError] = React10.useState(null);
|
|
2863
|
+
const fetch2 = React10.useCallback(async () => {
|
|
2862
2864
|
if (!enabled) return;
|
|
2863
2865
|
setIsLoading(true);
|
|
2864
2866
|
setError(null);
|
|
@@ -2876,7 +2878,7 @@ function useSubscriptions(options = {}) {
|
|
|
2876
2878
|
setIsLoading(false);
|
|
2877
2879
|
}
|
|
2878
2880
|
}, [client, enabled, status]);
|
|
2879
|
-
|
|
2881
|
+
React10.useEffect(() => {
|
|
2880
2882
|
void fetch2();
|
|
2881
2883
|
}, [fetch2]);
|
|
2882
2884
|
return { subscriptions, isLoading, error, refetch: fetch2 };
|
|
@@ -2885,10 +2887,10 @@ function useSubscription(id, options = {}) {
|
|
|
2885
2887
|
const { client } = useCimplifyClient();
|
|
2886
2888
|
const { enabled = true } = options;
|
|
2887
2889
|
const normalizedId = (id || "").trim();
|
|
2888
|
-
const [subscription, setSubscription] =
|
|
2889
|
-
const [isLoading, setIsLoading] =
|
|
2890
|
-
const [error, setError] =
|
|
2891
|
-
const fetch2 =
|
|
2890
|
+
const [subscription, setSubscription] = React10.useState(null);
|
|
2891
|
+
const [isLoading, setIsLoading] = React10.useState(false);
|
|
2892
|
+
const [error, setError] = React10.useState(null);
|
|
2893
|
+
const fetch2 = React10.useCallback(async () => {
|
|
2892
2894
|
if (!enabled || !normalizedId) return;
|
|
2893
2895
|
setIsLoading(true);
|
|
2894
2896
|
setError(null);
|
|
@@ -2905,25 +2907,25 @@ function useSubscription(id, options = {}) {
|
|
|
2905
2907
|
setIsLoading(false);
|
|
2906
2908
|
}
|
|
2907
2909
|
}, [client, enabled, normalizedId]);
|
|
2908
|
-
|
|
2910
|
+
React10.useEffect(() => {
|
|
2909
2911
|
void fetch2();
|
|
2910
2912
|
}, [fetch2]);
|
|
2911
|
-
const cancel =
|
|
2913
|
+
const cancel = React10.useCallback(async (reason) => {
|
|
2912
2914
|
if (!normalizedId) return;
|
|
2913
2915
|
await client.subscriptions.cancel(normalizedId, reason);
|
|
2914
2916
|
void fetch2();
|
|
2915
2917
|
}, [client, normalizedId, fetch2]);
|
|
2916
|
-
const pause =
|
|
2918
|
+
const pause = React10.useCallback(async () => {
|
|
2917
2919
|
if (!normalizedId) return;
|
|
2918
2920
|
await client.subscriptions.pause(normalizedId);
|
|
2919
2921
|
void fetch2();
|
|
2920
2922
|
}, [client, normalizedId, fetch2]);
|
|
2921
|
-
const resume =
|
|
2923
|
+
const resume = React10.useCallback(async () => {
|
|
2922
2924
|
if (!normalizedId) return;
|
|
2923
2925
|
await client.subscriptions.resume(normalizedId);
|
|
2924
2926
|
void fetch2();
|
|
2925
2927
|
}, [client, normalizedId, fetch2]);
|
|
2926
|
-
const skipNext =
|
|
2928
|
+
const skipNext = React10.useCallback(async () => {
|
|
2927
2929
|
if (!normalizedId) return;
|
|
2928
2930
|
await client.subscriptions.skipNextRenewal(normalizedId);
|
|
2929
2931
|
void fetch2();
|
|
@@ -3027,7 +3029,7 @@ function useBookings(options = {}) {
|
|
|
3027
3029
|
const context = useOptionalCimplifyClient();
|
|
3028
3030
|
const client = options.client ?? context?.client;
|
|
3029
3031
|
const { data, isLoading, error, refetch } = bookingsQuery(options);
|
|
3030
|
-
const cancelBooking =
|
|
3032
|
+
const cancelBooking = React10.useCallback(
|
|
3031
3033
|
async (bookingId, reason) => {
|
|
3032
3034
|
if (!client) throw new Error("useBookings must be used within CimplifyProvider or passed { client }.");
|
|
3033
3035
|
const result = await client.scheduling.cancelBooking({
|
|
@@ -3083,14 +3085,14 @@ function useBillingPlans(productId, options = {}) {
|
|
|
3083
3085
|
throw new Error("useBillingPlans must be used within CimplifyProvider or passed { client }.");
|
|
3084
3086
|
}
|
|
3085
3087
|
const enabled = options.enabled ?? true;
|
|
3086
|
-
const requestIdRef =
|
|
3087
|
-
const [plans, setPlans] =
|
|
3088
|
-
const [isLoading, setIsLoading] =
|
|
3089
|
-
const [error, setError] =
|
|
3088
|
+
const requestIdRef = React10.useRef(0);
|
|
3089
|
+
const [plans, setPlans] = React10.useState([]);
|
|
3090
|
+
const [isLoading, setIsLoading] = React10.useState(enabled && !!productId);
|
|
3091
|
+
const [error, setError] = React10.useState(null);
|
|
3090
3092
|
const customerId = options.customerId;
|
|
3091
3093
|
const quantity = options.quantity;
|
|
3092
3094
|
const orderValue = options.orderValue;
|
|
3093
|
-
const load =
|
|
3095
|
+
const load = React10.useCallback(
|
|
3094
3096
|
async (force = false) => {
|
|
3095
3097
|
if (!enabled || !productId) {
|
|
3096
3098
|
setPlans([]);
|
|
@@ -3125,17 +3127,17 @@ function useBillingPlans(productId, options = {}) {
|
|
|
3125
3127
|
},
|
|
3126
3128
|
[client, enabled, productId, customerId, quantity, orderValue]
|
|
3127
3129
|
);
|
|
3128
|
-
|
|
3130
|
+
React10.useEffect(() => {
|
|
3129
3131
|
void load(false);
|
|
3130
3132
|
}, [load]);
|
|
3131
|
-
const refetch =
|
|
3133
|
+
const refetch = React10.useCallback(async () => {
|
|
3132
3134
|
await load(true);
|
|
3133
3135
|
}, [load]);
|
|
3134
|
-
const subscriptionPlans =
|
|
3136
|
+
const subscriptionPlans = React10.useMemo(
|
|
3135
3137
|
() => plans.filter((p) => p.plan_type === "subscription"),
|
|
3136
3138
|
[plans]
|
|
3137
3139
|
);
|
|
3138
|
-
const installmentPlans =
|
|
3140
|
+
const installmentPlans = React10.useMemo(
|
|
3139
3141
|
() => plans.filter((p) => p.plan_type === "installment"),
|
|
3140
3142
|
[plans]
|
|
3141
3143
|
);
|
|
@@ -3170,8 +3172,8 @@ function computeAvailableValues(variants, axes, selections) {
|
|
|
3170
3172
|
}
|
|
3171
3173
|
function useVariantSelector(options) {
|
|
3172
3174
|
const { variants, axes } = options;
|
|
3173
|
-
const [selectedValues, setSelectedValues] =
|
|
3174
|
-
const selectValue =
|
|
3175
|
+
const [selectedValues, setSelectedValues] = React10.useState({});
|
|
3176
|
+
const selectValue = React10.useCallback(
|
|
3175
3177
|
(axisId, valueId) => {
|
|
3176
3178
|
setSelectedValues((prev) => {
|
|
3177
3179
|
if (prev[axisId] === valueId) {
|
|
@@ -3184,16 +3186,16 @@ function useVariantSelector(options) {
|
|
|
3184
3186
|
},
|
|
3185
3187
|
[]
|
|
3186
3188
|
);
|
|
3187
|
-
const reset =
|
|
3188
|
-
const selectedVariant =
|
|
3189
|
+
const reset = React10.useCallback(() => setSelectedValues({}), []);
|
|
3190
|
+
const selectedVariant = React10.useMemo(
|
|
3189
3191
|
() => findMatchingVariant(variants, selectedValues),
|
|
3190
3192
|
[variants, selectedValues]
|
|
3191
3193
|
);
|
|
3192
|
-
const variantImage =
|
|
3194
|
+
const variantImage = React10.useMemo(
|
|
3193
3195
|
() => selectedVariant?.images?.[0] ?? null,
|
|
3194
3196
|
[selectedVariant]
|
|
3195
3197
|
);
|
|
3196
|
-
const availableValues =
|
|
3198
|
+
const availableValues = React10.useMemo(
|
|
3197
3199
|
() => computeAvailableValues(variants, axes, selectedValues),
|
|
3198
3200
|
[variants, axes, selectedValues]
|
|
3199
3201
|
);
|
|
@@ -3219,7 +3221,7 @@ function useActivityState(options = {}) {
|
|
|
3219
3221
|
const context = useOptionalCimplifyClient();
|
|
3220
3222
|
const client = options.client ?? context?.client;
|
|
3221
3223
|
const { data, isLoading, error, refetch } = activityStateQuery(options);
|
|
3222
|
-
const dismissMessage =
|
|
3224
|
+
const dismissMessage = React10.useCallback(
|
|
3223
3225
|
async (code) => {
|
|
3224
3226
|
if (!client) return;
|
|
3225
3227
|
const result = await client.activity.dismissMessage(code);
|
|
@@ -3313,15 +3315,131 @@ function useBootstrap(options = {}) {
|
|
|
3313
3315
|
const { data, isLoading, error, refetch } = bootstrapQuery(options);
|
|
3314
3316
|
return { bootstrap: data, isLoading, error, refetch };
|
|
3315
3317
|
}
|
|
3316
|
-
var
|
|
3318
|
+
var POLL_INTERVAL_MS = 3e3;
|
|
3319
|
+
var POLL_IDLE_INTERVAL_MS = 15e3;
|
|
3320
|
+
var IDLE_TIMEOUT_MS = 6e4;
|
|
3321
|
+
function useChat(options = {}) {
|
|
3322
|
+
const context = useOptionalCimplifyClient();
|
|
3323
|
+
const client = options.client ?? context?.client;
|
|
3324
|
+
const [messages, setMessages] = React10.useState([]);
|
|
3325
|
+
const [isLoading, setIsLoading] = React10.useState(false);
|
|
3326
|
+
const [isSending, setIsSending] = React10.useState(false);
|
|
3327
|
+
const [error, setError] = React10.useState(null);
|
|
3328
|
+
const [conversationOpened, setConversationOpened] = React10.useState(false);
|
|
3329
|
+
const pollRef = React10.useRef(null);
|
|
3330
|
+
const lastActivityRef = React10.useRef(Date.now());
|
|
3331
|
+
const openedRef = React10.useRef(false);
|
|
3332
|
+
const messagesRef = React10.useRef([]);
|
|
3333
|
+
messagesRef.current = messages;
|
|
3334
|
+
const pollInterval = options.pollInterval ?? POLL_INTERVAL_MS;
|
|
3335
|
+
const pollIdleInterval = options.pollIdleInterval ?? POLL_IDLE_INTERVAL_MS;
|
|
3336
|
+
const pollMessages = React10.useCallback(async () => {
|
|
3337
|
+
if (!client) return;
|
|
3338
|
+
const isIdle = Date.now() - lastActivityRef.current > IDLE_TIMEOUT_MS;
|
|
3339
|
+
if (isIdle) return;
|
|
3340
|
+
const last = messagesRef.current[messagesRef.current.length - 1];
|
|
3341
|
+
const result = await client.support.getMessages({
|
|
3342
|
+
after: last?.created_at,
|
|
3343
|
+
limit: 50
|
|
3344
|
+
});
|
|
3345
|
+
if (result.ok && result.value.length > 0) {
|
|
3346
|
+
setMessages((prev) => {
|
|
3347
|
+
const ids = new Set(prev.map((m) => m.id));
|
|
3348
|
+
const fresh = result.value.filter((m) => !ids.has(m.id));
|
|
3349
|
+
return fresh.length > 0 ? [...prev, ...fresh] : prev;
|
|
3350
|
+
});
|
|
3351
|
+
}
|
|
3352
|
+
}, [client]);
|
|
3353
|
+
const startPolling = React10.useCallback(() => {
|
|
3354
|
+
if (pollRef.current) clearInterval(pollRef.current);
|
|
3355
|
+
const interval = Date.now() - lastActivityRef.current > IDLE_TIMEOUT_MS ? pollIdleInterval : pollInterval;
|
|
3356
|
+
pollRef.current = setInterval(pollMessages, interval);
|
|
3357
|
+
}, [pollMessages, pollInterval, pollIdleInterval]);
|
|
3358
|
+
const stopPolling = React10.useCallback(() => {
|
|
3359
|
+
if (pollRef.current) {
|
|
3360
|
+
clearInterval(pollRef.current);
|
|
3361
|
+
pollRef.current = null;
|
|
3362
|
+
}
|
|
3363
|
+
}, []);
|
|
3364
|
+
React10.useEffect(() => stopPolling, [stopPolling]);
|
|
3365
|
+
const openConversation = React10.useCallback(async () => {
|
|
3366
|
+
if (openedRef.current || !client) return;
|
|
3367
|
+
openedRef.current = true;
|
|
3368
|
+
setIsLoading(true);
|
|
3369
|
+
setError(null);
|
|
3370
|
+
const result = await client.support.openConversation();
|
|
3371
|
+
if (result.ok) {
|
|
3372
|
+
setMessages(result.value.messages);
|
|
3373
|
+
setConversationOpened(true);
|
|
3374
|
+
startPolling();
|
|
3375
|
+
} else {
|
|
3376
|
+
openedRef.current = false;
|
|
3377
|
+
setError(result.error);
|
|
3378
|
+
}
|
|
3379
|
+
setIsLoading(false);
|
|
3380
|
+
}, [client, startPolling]);
|
|
3381
|
+
const send = React10.useCallback(
|
|
3382
|
+
async (content) => {
|
|
3383
|
+
if (!client || !content.trim()) return;
|
|
3384
|
+
setError(null);
|
|
3385
|
+
lastActivityRef.current = Date.now();
|
|
3386
|
+
if (!openedRef.current) {
|
|
3387
|
+
await openConversation();
|
|
3388
|
+
if (!openedRef.current) return;
|
|
3389
|
+
}
|
|
3390
|
+
const optimisticId = `opt_${Date.now()}`;
|
|
3391
|
+
const optimistic = {
|
|
3392
|
+
id: optimisticId,
|
|
3393
|
+
sender_type: "customer",
|
|
3394
|
+
content: content.trim(),
|
|
3395
|
+
content_type: "text",
|
|
3396
|
+
attachments: [],
|
|
3397
|
+
metadata: {},
|
|
3398
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3399
|
+
};
|
|
3400
|
+
setMessages((prev) => [...prev, optimistic]);
|
|
3401
|
+
setIsSending(true);
|
|
3402
|
+
const result = await client.support.sendMessage(content.trim());
|
|
3403
|
+
if (result.ok) {
|
|
3404
|
+
setMessages(
|
|
3405
|
+
(prev) => prev.map((m) => m.id === optimisticId ? result.value : m)
|
|
3406
|
+
);
|
|
3407
|
+
} else {
|
|
3408
|
+
setMessages((prev) => prev.filter((m) => m.id !== optimisticId));
|
|
3409
|
+
setError(result.error);
|
|
3410
|
+
}
|
|
3411
|
+
setIsSending(false);
|
|
3412
|
+
},
|
|
3413
|
+
[client, openConversation]
|
|
3414
|
+
);
|
|
3415
|
+
const startConversation = React10.useCallback(
|
|
3416
|
+
async (starterText) => {
|
|
3417
|
+
await openConversation();
|
|
3418
|
+
if (starterText) {
|
|
3419
|
+
await send(starterText);
|
|
3420
|
+
}
|
|
3421
|
+
},
|
|
3422
|
+
[openConversation, send]
|
|
3423
|
+
);
|
|
3424
|
+
return {
|
|
3425
|
+
messages,
|
|
3426
|
+
isLoading,
|
|
3427
|
+
isSending,
|
|
3428
|
+
error,
|
|
3429
|
+
isActive: conversationOpened && messages.length > 0,
|
|
3430
|
+
send,
|
|
3431
|
+
startConversation
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
var ElementsContext = React10.createContext({
|
|
3317
3435
|
elements: null,
|
|
3318
3436
|
isReady: false
|
|
3319
3437
|
});
|
|
3320
3438
|
function useElements() {
|
|
3321
|
-
return
|
|
3439
|
+
return React10.useContext(ElementsContext).elements;
|
|
3322
3440
|
}
|
|
3323
3441
|
function useElementsReady() {
|
|
3324
|
-
return
|
|
3442
|
+
return React10.useContext(ElementsContext).isReady;
|
|
3325
3443
|
}
|
|
3326
3444
|
function ElementsProvider({
|
|
3327
3445
|
client,
|
|
@@ -3329,10 +3447,10 @@ function ElementsProvider({
|
|
|
3329
3447
|
options,
|
|
3330
3448
|
children
|
|
3331
3449
|
}) {
|
|
3332
|
-
const [elements, setElements] =
|
|
3333
|
-
const [isReady, setIsReady] =
|
|
3334
|
-
const initialOptionsRef =
|
|
3335
|
-
|
|
3450
|
+
const [elements, setElements] = React10.useState(null);
|
|
3451
|
+
const [isReady, setIsReady] = React10.useState(false);
|
|
3452
|
+
const initialOptionsRef = React10.useRef(options);
|
|
3453
|
+
React10.useEffect(() => {
|
|
3336
3454
|
let cancelled = false;
|
|
3337
3455
|
let instance = null;
|
|
3338
3456
|
setIsReady(false);
|
|
@@ -3373,20 +3491,20 @@ function AuthElement({
|
|
|
3373
3491
|
onRequiresOtp,
|
|
3374
3492
|
onError
|
|
3375
3493
|
}) {
|
|
3376
|
-
const containerRef =
|
|
3377
|
-
const elementRef =
|
|
3494
|
+
const containerRef = React10.useRef(null);
|
|
3495
|
+
const elementRef = React10.useRef(null);
|
|
3378
3496
|
const elements = useElements();
|
|
3379
|
-
const onReadyRef =
|
|
3380
|
-
const onAuthenticatedRef =
|
|
3381
|
-
const onRequiresOtpRef =
|
|
3382
|
-
const onErrorRef =
|
|
3383
|
-
|
|
3497
|
+
const onReadyRef = React10.useRef(onReady);
|
|
3498
|
+
const onAuthenticatedRef = React10.useRef(onAuthenticated);
|
|
3499
|
+
const onRequiresOtpRef = React10.useRef(onRequiresOtp);
|
|
3500
|
+
const onErrorRef = React10.useRef(onError);
|
|
3501
|
+
React10.useEffect(() => {
|
|
3384
3502
|
onReadyRef.current = onReady;
|
|
3385
3503
|
onAuthenticatedRef.current = onAuthenticated;
|
|
3386
3504
|
onRequiresOtpRef.current = onRequiresOtp;
|
|
3387
3505
|
onErrorRef.current = onError;
|
|
3388
3506
|
}, [onReady, onAuthenticated, onRequiresOtp, onError]);
|
|
3389
|
-
|
|
3507
|
+
React10.useEffect(() => {
|
|
3390
3508
|
if (!elements || !containerRef.current) return;
|
|
3391
3509
|
const element = elements.create(chunk2CGA3MUW_js.ELEMENT_TYPES.AUTH, { prefillEmail });
|
|
3392
3510
|
elementRef.current = element;
|
|
@@ -3416,18 +3534,18 @@ function AddressElement({
|
|
|
3416
3534
|
onChange,
|
|
3417
3535
|
onError
|
|
3418
3536
|
}) {
|
|
3419
|
-
const containerRef =
|
|
3420
|
-
const elementRef =
|
|
3537
|
+
const containerRef = React10.useRef(null);
|
|
3538
|
+
const elementRef = React10.useRef(null);
|
|
3421
3539
|
const elements = useElements();
|
|
3422
|
-
const onReadyRef =
|
|
3423
|
-
const onChangeRef =
|
|
3424
|
-
const onErrorRef =
|
|
3425
|
-
|
|
3540
|
+
const onReadyRef = React10.useRef(onReady);
|
|
3541
|
+
const onChangeRef = React10.useRef(onChange);
|
|
3542
|
+
const onErrorRef = React10.useRef(onError);
|
|
3543
|
+
React10.useEffect(() => {
|
|
3426
3544
|
onReadyRef.current = onReady;
|
|
3427
3545
|
onChangeRef.current = onChange;
|
|
3428
3546
|
onErrorRef.current = onError;
|
|
3429
3547
|
}, [onReady, onChange, onError]);
|
|
3430
|
-
|
|
3548
|
+
React10.useEffect(() => {
|
|
3431
3549
|
if (!elements || !containerRef.current) return;
|
|
3432
3550
|
const element = elements.create(chunk2CGA3MUW_js.ELEMENT_TYPES.ADDRESS, { mode });
|
|
3433
3551
|
elementRef.current = element;
|
|
@@ -3454,18 +3572,18 @@ function PaymentElement({
|
|
|
3454
3572
|
onChange,
|
|
3455
3573
|
onError
|
|
3456
3574
|
}) {
|
|
3457
|
-
const containerRef =
|
|
3458
|
-
const elementRef =
|
|
3575
|
+
const containerRef = React10.useRef(null);
|
|
3576
|
+
const elementRef = React10.useRef(null);
|
|
3459
3577
|
const elements = useElements();
|
|
3460
|
-
const onReadyRef =
|
|
3461
|
-
const onChangeRef =
|
|
3462
|
-
const onErrorRef =
|
|
3463
|
-
|
|
3578
|
+
const onReadyRef = React10.useRef(onReady);
|
|
3579
|
+
const onChangeRef = React10.useRef(onChange);
|
|
3580
|
+
const onErrorRef = React10.useRef(onError);
|
|
3581
|
+
React10.useEffect(() => {
|
|
3464
3582
|
onReadyRef.current = onReady;
|
|
3465
3583
|
onChangeRef.current = onChange;
|
|
3466
3584
|
onErrorRef.current = onError;
|
|
3467
3585
|
}, [onReady, onChange, onError]);
|
|
3468
|
-
|
|
3586
|
+
React10.useEffect(() => {
|
|
3469
3587
|
if (!elements || !containerRef.current) return;
|
|
3470
3588
|
const element = elements.create(chunk2CGA3MUW_js.ELEMENT_TYPES.PAYMENT, { amount, currency });
|
|
3471
3589
|
elementRef.current = element;
|
|
@@ -3485,8 +3603,8 @@ function PaymentElement({
|
|
|
3485
3603
|
}
|
|
3486
3604
|
function useCheckout() {
|
|
3487
3605
|
const elements = useElements();
|
|
3488
|
-
const [isLoading, setIsLoading] =
|
|
3489
|
-
const submit =
|
|
3606
|
+
const [isLoading, setIsLoading] = React10.useState(false);
|
|
3607
|
+
const submit = React10.useCallback(
|
|
3490
3608
|
async (data) => {
|
|
3491
3609
|
if (!elements) {
|
|
3492
3610
|
return { success: false, error: { code: "NO_ELEMENTS", message: "Elements not initialized" } };
|
|
@@ -3500,7 +3618,7 @@ function useCheckout() {
|
|
|
3500
3618
|
},
|
|
3501
3619
|
[elements]
|
|
3502
3620
|
);
|
|
3503
|
-
const process =
|
|
3621
|
+
const process = React10.useCallback(
|
|
3504
3622
|
async (options) => {
|
|
3505
3623
|
if (!elements) {
|
|
3506
3624
|
return {
|
|
@@ -3594,13 +3712,13 @@ function VariantSelector({
|
|
|
3594
3712
|
className,
|
|
3595
3713
|
classNames
|
|
3596
3714
|
}) {
|
|
3597
|
-
const [axisSelections, setAxisSelections] =
|
|
3598
|
-
const initialized =
|
|
3599
|
-
const idPrefix =
|
|
3600
|
-
|
|
3715
|
+
const [axisSelections, setAxisSelections] = React10.useState({});
|
|
3716
|
+
const initialized = React10.useRef(false);
|
|
3717
|
+
const idPrefix = React10.useId();
|
|
3718
|
+
React10.useEffect(() => {
|
|
3601
3719
|
initialized.current = false;
|
|
3602
3720
|
}, [variants]);
|
|
3603
|
-
|
|
3721
|
+
React10.useEffect(() => {
|
|
3604
3722
|
if (initialized.current) return;
|
|
3605
3723
|
if (!variants || variants.length === 0) return;
|
|
3606
3724
|
const defaultVariant = variants.find((v) => v.is_default) || variants[0];
|
|
@@ -3615,7 +3733,7 @@ function VariantSelector({
|
|
|
3615
3733
|
setAxisSelections(initial);
|
|
3616
3734
|
}
|
|
3617
3735
|
}, [variants, onVariantChange]);
|
|
3618
|
-
|
|
3736
|
+
React10.useEffect(() => {
|
|
3619
3737
|
if (!initialized.current) return;
|
|
3620
3738
|
if (!variantAxes || variantAxes.length === 0) return;
|
|
3621
3739
|
const match = variants.find((v) => {
|
|
@@ -3735,7 +3853,7 @@ function VariantSelector({
|
|
|
3735
3853
|
{
|
|
3736
3854
|
"data-cimplify-variant-name": true,
|
|
3737
3855
|
className: cn("flex-1 min-w-0 text-sm", classNames?.name),
|
|
3738
|
-
children:
|
|
3856
|
+
children: chunkF47XFKYP_js.getVariantDisplayName(variant, productName)
|
|
3739
3857
|
}
|
|
3740
3858
|
),
|
|
3741
3859
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm text-muted-foreground", classNames?.pricing), children: [
|
|
@@ -3758,12 +3876,12 @@ function AddOnSelector({
|
|
|
3758
3876
|
className,
|
|
3759
3877
|
classNames
|
|
3760
3878
|
}) {
|
|
3761
|
-
const selectedSet =
|
|
3762
|
-
const isOptionSelected =
|
|
3879
|
+
const selectedSet = React10.useMemo(() => new Set(selectedOptions), [selectedOptions]);
|
|
3880
|
+
const isOptionSelected = React10.useCallback(
|
|
3763
3881
|
(optionId) => selectedSet.has(optionId),
|
|
3764
3882
|
[selectedSet]
|
|
3765
3883
|
);
|
|
3766
|
-
const handleCheckedChange =
|
|
3884
|
+
const handleCheckedChange = React10.useCallback(
|
|
3767
3885
|
(addOn, optionId, checked) => {
|
|
3768
3886
|
const isSelected = selectedSet.has(optionId);
|
|
3769
3887
|
if (addOn.is_mutually_exclusive || !addOn.is_multiple_allowed) {
|
|
@@ -3939,9 +4057,9 @@ function BundleSelector({
|
|
|
3939
4057
|
className,
|
|
3940
4058
|
classNames
|
|
3941
4059
|
}) {
|
|
3942
|
-
const [variantChoices, setVariantChoices] =
|
|
3943
|
-
const lastComponentIds =
|
|
3944
|
-
|
|
4060
|
+
const [variantChoices, setVariantChoices] = React10.useState({});
|
|
4061
|
+
const lastComponentIds = React10.useRef("");
|
|
4062
|
+
React10.useEffect(() => {
|
|
3945
4063
|
const ids = components.map((c) => c.id).sort().join();
|
|
3946
4064
|
if (ids === lastComponentIds.current) return;
|
|
3947
4065
|
lastComponentIds.current = ids;
|
|
@@ -3958,20 +4076,20 @@ function BundleSelector({
|
|
|
3958
4076
|
}
|
|
3959
4077
|
setVariantChoices(defaults);
|
|
3960
4078
|
}, [components]);
|
|
3961
|
-
const selections =
|
|
4079
|
+
const selections = React10.useMemo(() => {
|
|
3962
4080
|
return components.map((comp) => ({
|
|
3963
4081
|
component_id: comp.id,
|
|
3964
4082
|
variant_id: variantChoices[comp.id],
|
|
3965
4083
|
quantity: comp.quantity
|
|
3966
4084
|
}));
|
|
3967
4085
|
}, [components, variantChoices]);
|
|
3968
|
-
|
|
4086
|
+
React10.useEffect(() => {
|
|
3969
4087
|
onSelectionsChange(selections);
|
|
3970
4088
|
}, [selections, onSelectionsChange]);
|
|
3971
|
-
|
|
4089
|
+
React10.useEffect(() => {
|
|
3972
4090
|
onReady?.(components.length > 0 && selections.length > 0);
|
|
3973
4091
|
}, [components, selections, onReady]);
|
|
3974
|
-
const totalPrice =
|
|
4092
|
+
const totalPrice = React10.useMemo(() => {
|
|
3975
4093
|
if (pricingType === "fixed" && bundlePrice) {
|
|
3976
4094
|
return chunkPEDLCL72_js.parsePrice(bundlePrice);
|
|
3977
4095
|
}
|
|
@@ -3986,10 +4104,10 @@ function BundleSelector({
|
|
|
3986
4104
|
}
|
|
3987
4105
|
return componentsTotal;
|
|
3988
4106
|
}, [components, variantChoices, pricingType, bundlePrice, discountValue]);
|
|
3989
|
-
|
|
4107
|
+
React10.useEffect(() => {
|
|
3990
4108
|
onPriceChange?.(totalPrice);
|
|
3991
4109
|
}, [totalPrice, onPriceChange]);
|
|
3992
|
-
const handleVariantChange =
|
|
4110
|
+
const handleVariantChange = React10.useCallback(
|
|
3993
4111
|
(componentId, variantId) => {
|
|
3994
4112
|
setVariantChoices((prev) => ({ ...prev, [componentId]: variantId }));
|
|
3995
4113
|
},
|
|
@@ -4070,9 +4188,9 @@ function BundleComponentCard({
|
|
|
4070
4188
|
onVariantChange,
|
|
4071
4189
|
classNames
|
|
4072
4190
|
}) {
|
|
4073
|
-
const idPrefix =
|
|
4191
|
+
const idPrefix = React10.useId();
|
|
4074
4192
|
const showVariantPicker = component.allow_variant_choice && component.available_variants.length > 1;
|
|
4075
|
-
const displayPrice =
|
|
4193
|
+
const displayPrice = React10.useMemo(
|
|
4076
4194
|
() => getComponentPrice(component, selectedVariantId),
|
|
4077
4195
|
[component, selectedVariantId]
|
|
4078
4196
|
);
|
|
@@ -4220,11 +4338,11 @@ function CompositeSelector({
|
|
|
4220
4338
|
classNames
|
|
4221
4339
|
}) {
|
|
4222
4340
|
const { client } = useCimplifyClient();
|
|
4223
|
-
const [groupSelections, setGroupSelections] =
|
|
4224
|
-
const [priceResult, setPriceResult] =
|
|
4225
|
-
const [isPriceLoading, setIsPriceLoading] =
|
|
4226
|
-
const [priceError, setPriceError] =
|
|
4227
|
-
const selections =
|
|
4341
|
+
const [groupSelections, setGroupSelections] = React10.useState({});
|
|
4342
|
+
const [priceResult, setPriceResult] = React10.useState(null);
|
|
4343
|
+
const [isPriceLoading, setIsPriceLoading] = React10.useState(false);
|
|
4344
|
+
const [priceError, setPriceError] = React10.useState(false);
|
|
4345
|
+
const selections = React10.useMemo(() => {
|
|
4228
4346
|
const result = [];
|
|
4229
4347
|
for (const groupSels of Object.values(groupSelections)) {
|
|
4230
4348
|
for (const [componentId, qty] of Object.entries(groupSels)) {
|
|
@@ -4235,13 +4353,13 @@ function CompositeSelector({
|
|
|
4235
4353
|
}
|
|
4236
4354
|
return result;
|
|
4237
4355
|
}, [groupSelections]);
|
|
4238
|
-
|
|
4356
|
+
React10.useEffect(() => {
|
|
4239
4357
|
onSelectionsChange(selections);
|
|
4240
4358
|
}, [selections, onSelectionsChange]);
|
|
4241
|
-
|
|
4359
|
+
React10.useEffect(() => {
|
|
4242
4360
|
onPriceChange?.(priceResult);
|
|
4243
4361
|
}, [priceResult, onPriceChange]);
|
|
4244
|
-
const allGroupsSatisfied =
|
|
4362
|
+
const allGroupsSatisfied = React10.useMemo(() => {
|
|
4245
4363
|
for (const group of groups) {
|
|
4246
4364
|
const groupSels = groupSelections[group.id] || {};
|
|
4247
4365
|
const totalSelected = Object.values(groupSels).reduce((sum, q) => sum + q, 0);
|
|
@@ -4249,17 +4367,17 @@ function CompositeSelector({
|
|
|
4249
4367
|
}
|
|
4250
4368
|
return true;
|
|
4251
4369
|
}, [groups, groupSelections]);
|
|
4252
|
-
const sortedGroups =
|
|
4370
|
+
const sortedGroups = React10.useMemo(
|
|
4253
4371
|
() => [...groups].sort((a, b) => a.display_order - b.display_order).map((group) => ({
|
|
4254
4372
|
...group,
|
|
4255
4373
|
_sortedComponents: group.components.filter((component) => component.is_available && !component.is_archived).sort((a, b) => a.display_order - b.display_order)
|
|
4256
4374
|
})),
|
|
4257
4375
|
[groups]
|
|
4258
4376
|
);
|
|
4259
|
-
|
|
4377
|
+
React10.useEffect(() => {
|
|
4260
4378
|
onReady?.(allGroupsSatisfied);
|
|
4261
4379
|
}, [allGroupsSatisfied, onReady]);
|
|
4262
|
-
|
|
4380
|
+
React10.useEffect(() => {
|
|
4263
4381
|
if (skipPriceFetch || !allGroupsSatisfied || selections.length === 0) return;
|
|
4264
4382
|
let cancelled = false;
|
|
4265
4383
|
const timer = setTimeout(() => {
|
|
@@ -4286,7 +4404,7 @@ function CompositeSelector({
|
|
|
4286
4404
|
clearTimeout(timer);
|
|
4287
4405
|
};
|
|
4288
4406
|
}, [selections, allGroupsSatisfied, compositeId, client, skipPriceFetch]);
|
|
4289
|
-
const toggleComponent =
|
|
4407
|
+
const toggleComponent = React10.useCallback(
|
|
4290
4408
|
(group, component) => {
|
|
4291
4409
|
setGroupSelections((prev) => {
|
|
4292
4410
|
const groupSels = { ...prev[group.id] || {} };
|
|
@@ -4314,7 +4432,7 @@ function CompositeSelector({
|
|
|
4314
4432
|
},
|
|
4315
4433
|
[]
|
|
4316
4434
|
);
|
|
4317
|
-
const updateQuantity =
|
|
4435
|
+
const updateQuantity = React10.useCallback(
|
|
4318
4436
|
(group, componentId, newValue) => {
|
|
4319
4437
|
setGroupSelections((prev) => {
|
|
4320
4438
|
const groupSels = { ...prev[group.id] || {} };
|
|
@@ -4664,8 +4782,26 @@ function CompositeSelector({
|
|
|
4664
4782
|
)
|
|
4665
4783
|
] });
|
|
4666
4784
|
}
|
|
4785
|
+
|
|
4786
|
+
// src/react/utils/format-duration.ts
|
|
4787
|
+
var UNIT_LABELS = {
|
|
4788
|
+
minutes: { singular: "min", plural: "min" },
|
|
4789
|
+
hours: { singular: "hr", plural: "hrs" },
|
|
4790
|
+
days: { singular: "day", plural: "days" },
|
|
4791
|
+
nights: { singular: "night", plural: "nights" },
|
|
4792
|
+
weeks: { singular: "week", plural: "weeks" },
|
|
4793
|
+
months: { singular: "month", plural: "months" },
|
|
4794
|
+
years: { singular: "year", plural: "years" }
|
|
4795
|
+
};
|
|
4796
|
+
function formatDuration2(value, unit) {
|
|
4797
|
+
const resolved = unit ?? "minutes";
|
|
4798
|
+
const labels = UNIT_LABELS[resolved];
|
|
4799
|
+
const label = value === 1 ? labels.singular : labels.plural;
|
|
4800
|
+
return `${value} ${label}`;
|
|
4801
|
+
}
|
|
4667
4802
|
var FREQUENCY_LABELS = {
|
|
4668
4803
|
weekly: "Weekly",
|
|
4804
|
+
biweekly: "Biweekly",
|
|
4669
4805
|
monthly: "Monthly",
|
|
4670
4806
|
quarterly: "Quarterly",
|
|
4671
4807
|
annually: "Annually"
|
|
@@ -4853,6 +4989,880 @@ function VolumePricing({
|
|
|
4853
4989
|
}
|
|
4854
4990
|
);
|
|
4855
4991
|
}
|
|
4992
|
+
function CustomerInputFields({
|
|
4993
|
+
fields,
|
|
4994
|
+
values,
|
|
4995
|
+
onChange,
|
|
4996
|
+
onFileUpload,
|
|
4997
|
+
className,
|
|
4998
|
+
classNames
|
|
4999
|
+
}) {
|
|
5000
|
+
const clientContext = useOptionalCimplifyClient();
|
|
5001
|
+
if (fields.length === 0) return null;
|
|
5002
|
+
const sorted = [...fields].sort((a, b) => a.display_order - b.display_order);
|
|
5003
|
+
const setValue = React10.useCallback(
|
|
5004
|
+
(fieldId, value) => {
|
|
5005
|
+
onChange({ ...values, [fieldId]: value });
|
|
5006
|
+
},
|
|
5007
|
+
[values, onChange]
|
|
5008
|
+
);
|
|
5009
|
+
const defaultFileUpload = React10.useCallback(
|
|
5010
|
+
async (file) => {
|
|
5011
|
+
if (onFileUpload) return onFileUpload(file, {});
|
|
5012
|
+
if (!clientContext?.client) throw new Error("No upload provider available");
|
|
5013
|
+
const result = await clientContext.client.uploads.upload(file);
|
|
5014
|
+
if (!result.ok) throw new Error(result.error.message);
|
|
5015
|
+
return result.value.url;
|
|
5016
|
+
},
|
|
5017
|
+
[onFileUpload, clientContext]
|
|
5018
|
+
);
|
|
5019
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customer-inputs": true, className: cn("space-y-4", className, classNames?.root), children: sorted.map((field) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5020
|
+
InputField,
|
|
5021
|
+
{
|
|
5022
|
+
field,
|
|
5023
|
+
value: values[field.id],
|
|
5024
|
+
onValueChange: (value) => setValue(field.id, value),
|
|
5025
|
+
onFileUpload: onFileUpload ?? (clientContext?.client ? (_file, _field) => defaultFileUpload(_file) : void 0),
|
|
5026
|
+
classNames
|
|
5027
|
+
},
|
|
5028
|
+
field.id
|
|
5029
|
+
)) });
|
|
5030
|
+
}
|
|
5031
|
+
function InputField({
|
|
5032
|
+
field,
|
|
5033
|
+
value,
|
|
5034
|
+
onValueChange,
|
|
5035
|
+
onFileUpload,
|
|
5036
|
+
classNames
|
|
5037
|
+
}) {
|
|
5038
|
+
const hasPriceAdjustment = field.price_adjustment != null && chunkPEDLCL72_js.parsePrice(field.price_adjustment) > 0;
|
|
5039
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customer-input": true, "data-field-type": field.field_type, className: classNames?.field, children: [
|
|
5040
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
|
|
5041
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: cn("text-sm font-semibold", classNames?.label), children: field.name }),
|
|
5042
|
+
field.is_required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs text-destructive", classNames?.required), children: "Required" }),
|
|
5043
|
+
hasPriceAdjustment && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn("text-xs text-muted-foreground", classNames?.priceAdjustment), children: [
|
|
5044
|
+
"+",
|
|
5045
|
+
/* @__PURE__ */ jsxRuntime.jsx(Price, { amount: field.price_adjustment })
|
|
5046
|
+
] })
|
|
5047
|
+
] }),
|
|
5048
|
+
field.help_text && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("text-xs text-muted-foreground mb-1.5", classNames?.helpText), children: field.help_text }),
|
|
5049
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5050
|
+
FieldInput,
|
|
5051
|
+
{
|
|
5052
|
+
field,
|
|
5053
|
+
value,
|
|
5054
|
+
onValueChange,
|
|
5055
|
+
onFileUpload,
|
|
5056
|
+
classNames
|
|
5057
|
+
}
|
|
5058
|
+
)
|
|
5059
|
+
] });
|
|
5060
|
+
}
|
|
5061
|
+
function FieldInput({
|
|
5062
|
+
field,
|
|
5063
|
+
value,
|
|
5064
|
+
onValueChange,
|
|
5065
|
+
onFileUpload,
|
|
5066
|
+
classNames
|
|
5067
|
+
}) {
|
|
5068
|
+
const inputClass = cn(
|
|
5069
|
+
"w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring",
|
|
5070
|
+
classNames?.input
|
|
5071
|
+
);
|
|
5072
|
+
switch (field.field_type) {
|
|
5073
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Text:
|
|
5074
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Url:
|
|
5075
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5076
|
+
"input",
|
|
5077
|
+
{
|
|
5078
|
+
type: field.field_type === chunkF47XFKYP_js.INPUT_FIELD_TYPE.Url ? "url" : "text",
|
|
5079
|
+
value: typeof value === "string" ? value : "",
|
|
5080
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5081
|
+
placeholder: field.placeholder,
|
|
5082
|
+
required: field.is_required,
|
|
5083
|
+
maxLength: field.validation?.max_length ?? void 0,
|
|
5084
|
+
className: inputClass
|
|
5085
|
+
}
|
|
5086
|
+
);
|
|
5087
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Textarea:
|
|
5088
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5089
|
+
"textarea",
|
|
5090
|
+
{
|
|
5091
|
+
value: typeof value === "string" ? value : "",
|
|
5092
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5093
|
+
placeholder: field.placeholder,
|
|
5094
|
+
required: field.is_required,
|
|
5095
|
+
maxLength: field.validation?.max_length ?? void 0,
|
|
5096
|
+
rows: 3,
|
|
5097
|
+
className: cn(inputClass, "resize-none", classNames?.textarea)
|
|
5098
|
+
}
|
|
5099
|
+
);
|
|
5100
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Number:
|
|
5101
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5102
|
+
"input",
|
|
5103
|
+
{
|
|
5104
|
+
type: "number",
|
|
5105
|
+
value: typeof value === "number" ? value : "",
|
|
5106
|
+
onChange: (e) => onValueChange(e.target.value ? parseFloat(e.target.value) : void 0),
|
|
5107
|
+
placeholder: field.placeholder,
|
|
5108
|
+
required: field.is_required,
|
|
5109
|
+
min: field.validation?.min_value ?? void 0,
|
|
5110
|
+
max: field.validation?.max_value ?? void 0,
|
|
5111
|
+
className: inputClass
|
|
5112
|
+
}
|
|
5113
|
+
);
|
|
5114
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Select:
|
|
5115
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5116
|
+
"select",
|
|
5117
|
+
{
|
|
5118
|
+
value: typeof value === "string" ? value : "",
|
|
5119
|
+
onChange: (e) => onValueChange(e.target.value || void 0),
|
|
5120
|
+
required: field.is_required,
|
|
5121
|
+
className: cn(inputClass, classNames?.select),
|
|
5122
|
+
children: [
|
|
5123
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: field.placeholder || "Select..." }),
|
|
5124
|
+
(field.options || []).map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt))
|
|
5125
|
+
]
|
|
5126
|
+
}
|
|
5127
|
+
);
|
|
5128
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Radio:
|
|
5129
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("space-y-2", classNames?.radioGroup), children: (field.options || []).map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5130
|
+
"label",
|
|
5131
|
+
{
|
|
5132
|
+
className: cn(
|
|
5133
|
+
"flex items-center gap-2 text-sm cursor-pointer",
|
|
5134
|
+
classNames?.radioOption
|
|
5135
|
+
),
|
|
5136
|
+
children: [
|
|
5137
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5138
|
+
"input",
|
|
5139
|
+
{
|
|
5140
|
+
type: "radio",
|
|
5141
|
+
name: field.id,
|
|
5142
|
+
value: opt,
|
|
5143
|
+
checked: value === opt,
|
|
5144
|
+
onChange: () => onValueChange(opt),
|
|
5145
|
+
className: "accent-primary"
|
|
5146
|
+
}
|
|
5147
|
+
),
|
|
5148
|
+
opt
|
|
5149
|
+
]
|
|
5150
|
+
},
|
|
5151
|
+
opt
|
|
5152
|
+
)) });
|
|
5153
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Checkbox:
|
|
5154
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: cn("flex items-center gap-2 text-sm cursor-pointer", classNames?.checkboxLabel), children: [
|
|
5155
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5156
|
+
"input",
|
|
5157
|
+
{
|
|
5158
|
+
type: "checkbox",
|
|
5159
|
+
checked: value === true,
|
|
5160
|
+
onChange: (e) => onValueChange(e.target.checked),
|
|
5161
|
+
className: "accent-primary w-4 h-4"
|
|
5162
|
+
}
|
|
5163
|
+
),
|
|
5164
|
+
field.placeholder || field.name
|
|
5165
|
+
] });
|
|
5166
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Color:
|
|
5167
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5168
|
+
"input",
|
|
5169
|
+
{
|
|
5170
|
+
type: "color",
|
|
5171
|
+
value: typeof value === "string" ? value : "#000000",
|
|
5172
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5173
|
+
className: cn("w-12 h-10 rounded-md border border-input cursor-pointer", classNames?.colorInput)
|
|
5174
|
+
}
|
|
5175
|
+
);
|
|
5176
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Date:
|
|
5177
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5178
|
+
"input",
|
|
5179
|
+
{
|
|
5180
|
+
type: "date",
|
|
5181
|
+
value: typeof value === "string" ? value : "",
|
|
5182
|
+
onChange: (e) => onValueChange(e.target.value || void 0),
|
|
5183
|
+
required: field.is_required,
|
|
5184
|
+
className: inputClass
|
|
5185
|
+
}
|
|
5186
|
+
);
|
|
5187
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.File:
|
|
5188
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Image:
|
|
5189
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5190
|
+
FileUploadInput,
|
|
5191
|
+
{
|
|
5192
|
+
field,
|
|
5193
|
+
value,
|
|
5194
|
+
onValueChange,
|
|
5195
|
+
onFileUpload,
|
|
5196
|
+
classNames
|
|
5197
|
+
}
|
|
5198
|
+
);
|
|
5199
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Email:
|
|
5200
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5201
|
+
"input",
|
|
5202
|
+
{
|
|
5203
|
+
type: "email",
|
|
5204
|
+
value: typeof value === "string" ? value : "",
|
|
5205
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5206
|
+
placeholder: field.placeholder || "email@example.com",
|
|
5207
|
+
required: field.is_required,
|
|
5208
|
+
className: inputClass
|
|
5209
|
+
}
|
|
5210
|
+
);
|
|
5211
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.DateTime: {
|
|
5212
|
+
const dtLocalValue = typeof value === "string" && value.includes("T") ? value.slice(0, 16) : typeof value === "string" ? value : "";
|
|
5213
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5214
|
+
"input",
|
|
5215
|
+
{
|
|
5216
|
+
type: "datetime-local",
|
|
5217
|
+
value: dtLocalValue,
|
|
5218
|
+
onChange: (e) => {
|
|
5219
|
+
if (!e.target.value) {
|
|
5220
|
+
onValueChange(void 0);
|
|
5221
|
+
return;
|
|
5222
|
+
}
|
|
5223
|
+
const date = new Date(e.target.value);
|
|
5224
|
+
onValueChange(Number.isNaN(date.getTime()) ? e.target.value : date.toISOString());
|
|
5225
|
+
},
|
|
5226
|
+
required: field.is_required,
|
|
5227
|
+
className: inputClass
|
|
5228
|
+
}
|
|
5229
|
+
);
|
|
5230
|
+
}
|
|
5231
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Time:
|
|
5232
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5233
|
+
"input",
|
|
5234
|
+
{
|
|
5235
|
+
type: "time",
|
|
5236
|
+
value: typeof value === "string" ? value : "",
|
|
5237
|
+
onChange: (e) => onValueChange(e.target.value || void 0),
|
|
5238
|
+
required: field.is_required,
|
|
5239
|
+
className: inputClass
|
|
5240
|
+
}
|
|
5241
|
+
);
|
|
5242
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.MultiSelect:
|
|
5243
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5244
|
+
MultiSelectInput,
|
|
5245
|
+
{
|
|
5246
|
+
field,
|
|
5247
|
+
value,
|
|
5248
|
+
onValueChange,
|
|
5249
|
+
classNames
|
|
5250
|
+
}
|
|
5251
|
+
);
|
|
5252
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.DateRange:
|
|
5253
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5254
|
+
DateRangeInput,
|
|
5255
|
+
{
|
|
5256
|
+
field,
|
|
5257
|
+
value,
|
|
5258
|
+
onValueChange,
|
|
5259
|
+
classNames,
|
|
5260
|
+
inputClass
|
|
5261
|
+
}
|
|
5262
|
+
);
|
|
5263
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Address:
|
|
5264
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5265
|
+
AddressInput,
|
|
5266
|
+
{
|
|
5267
|
+
field,
|
|
5268
|
+
value,
|
|
5269
|
+
onValueChange,
|
|
5270
|
+
classNames,
|
|
5271
|
+
inputClass
|
|
5272
|
+
}
|
|
5273
|
+
);
|
|
5274
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Location:
|
|
5275
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5276
|
+
LocationInput,
|
|
5277
|
+
{
|
|
5278
|
+
field,
|
|
5279
|
+
value,
|
|
5280
|
+
onValueChange,
|
|
5281
|
+
classNames,
|
|
5282
|
+
inputClass
|
|
5283
|
+
}
|
|
5284
|
+
);
|
|
5285
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Phone:
|
|
5286
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5287
|
+
PhoneInput,
|
|
5288
|
+
{
|
|
5289
|
+
field,
|
|
5290
|
+
value,
|
|
5291
|
+
onValueChange,
|
|
5292
|
+
classNames,
|
|
5293
|
+
inputClass
|
|
5294
|
+
}
|
|
5295
|
+
);
|
|
5296
|
+
case chunkF47XFKYP_js.INPUT_FIELD_TYPE.Signature:
|
|
5297
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5298
|
+
SignatureInput,
|
|
5299
|
+
{
|
|
5300
|
+
field,
|
|
5301
|
+
value,
|
|
5302
|
+
onValueChange,
|
|
5303
|
+
classNames
|
|
5304
|
+
}
|
|
5305
|
+
);
|
|
5306
|
+
default:
|
|
5307
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5308
|
+
"input",
|
|
5309
|
+
{
|
|
5310
|
+
type: "text",
|
|
5311
|
+
value: typeof value === "string" ? value : "",
|
|
5312
|
+
onChange: (e) => onValueChange(e.target.value),
|
|
5313
|
+
placeholder: field.placeholder,
|
|
5314
|
+
className: inputClass
|
|
5315
|
+
}
|
|
5316
|
+
);
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
function FileUploadInput({
|
|
5320
|
+
field,
|
|
5321
|
+
value,
|
|
5322
|
+
onValueChange,
|
|
5323
|
+
onFileUpload,
|
|
5324
|
+
classNames
|
|
5325
|
+
}) {
|
|
5326
|
+
const [isUploading, setIsUploading] = React10__default.default.useState(false);
|
|
5327
|
+
const fileUrl = typeof value === "string" ? value : void 0;
|
|
5328
|
+
const acceptedFormats = field.validation?.accepted_formats;
|
|
5329
|
+
const accept = acceptedFormats ? acceptedFormats.map((f) => `.${f}`).join(",") : field.field_type === chunkF47XFKYP_js.INPUT_FIELD_TYPE.Image ? "image/*" : void 0;
|
|
5330
|
+
const handleFile = async (file) => {
|
|
5331
|
+
if (!onFileUpload) return;
|
|
5332
|
+
if (field.validation?.max_size_mb) {
|
|
5333
|
+
const maxBytes = field.validation.max_size_mb * 1024 * 1024;
|
|
5334
|
+
if (file.size > maxBytes) {
|
|
5335
|
+
return;
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
setIsUploading(true);
|
|
5339
|
+
try {
|
|
5340
|
+
const url = await onFileUpload(file, field);
|
|
5341
|
+
onValueChange(url);
|
|
5342
|
+
} finally {
|
|
5343
|
+
setIsUploading(false);
|
|
5344
|
+
}
|
|
5345
|
+
};
|
|
5346
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("space-y-2", classNames?.fileInput), children: fileUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
5347
|
+
field.field_type === chunkF47XFKYP_js.INPUT_FIELD_TYPE.Image && /* @__PURE__ */ jsxRuntime.jsx("img", { src: fileUrl, alt: "Uploaded", className: "w-16 h-16 object-cover rounded-md border border-border" }),
|
|
5348
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground truncate", children: fileUrl.split("/").pop() }) }),
|
|
5349
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5350
|
+
"button",
|
|
5351
|
+
{
|
|
5352
|
+
type: "button",
|
|
5353
|
+
onClick: () => onValueChange(void 0),
|
|
5354
|
+
className: "text-xs text-muted-foreground hover:text-destructive transition-colors",
|
|
5355
|
+
children: "Remove"
|
|
5356
|
+
}
|
|
5357
|
+
)
|
|
5358
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col items-center justify-center w-full h-24 border-2 border-dashed border-border rounded-lg cursor-pointer hover:border-primary/40 transition-colors", children: [
|
|
5359
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5360
|
+
"input",
|
|
5361
|
+
{
|
|
5362
|
+
type: "file",
|
|
5363
|
+
accept,
|
|
5364
|
+
onChange: (e) => {
|
|
5365
|
+
const file = e.target.files?.[0];
|
|
5366
|
+
if (file) void handleFile(file);
|
|
5367
|
+
},
|
|
5368
|
+
className: "hidden",
|
|
5369
|
+
disabled: isUploading
|
|
5370
|
+
}
|
|
5371
|
+
),
|
|
5372
|
+
isUploading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Uploading..." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5373
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: field.placeholder || `Upload ${field.field_type === chunkF47XFKYP_js.INPUT_FIELD_TYPE.Image ? "image" : "file"}` }),
|
|
5374
|
+
acceptedFormats && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground/60 mt-1", children: [
|
|
5375
|
+
acceptedFormats.map((f) => f.toUpperCase()).join(", "),
|
|
5376
|
+
field.validation?.max_size_mb && ` \xB7 Max ${field.validation.max_size_mb}MB`
|
|
5377
|
+
] })
|
|
5378
|
+
] })
|
|
5379
|
+
] }) });
|
|
5380
|
+
}
|
|
5381
|
+
function MultiSelectInput({
|
|
5382
|
+
field,
|
|
5383
|
+
value,
|
|
5384
|
+
onValueChange,
|
|
5385
|
+
classNames
|
|
5386
|
+
}) {
|
|
5387
|
+
const selected = Array.isArray(value) ? value : [];
|
|
5388
|
+
const options = field.options || [];
|
|
5389
|
+
const maxSelections = field.validation?.max_selections;
|
|
5390
|
+
const toggle = (opt) => {
|
|
5391
|
+
const next = selected.includes(opt) ? selected.filter((s) => s !== opt) : maxSelections && selected.length >= maxSelections ? selected : [...selected, opt];
|
|
5392
|
+
onValueChange(next.length > 0 ? next : void 0);
|
|
5393
|
+
};
|
|
5394
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-2", classNames?.multiSelectGroup), children: [
|
|
5395
|
+
options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5396
|
+
"label",
|
|
5397
|
+
{
|
|
5398
|
+
className: cn(
|
|
5399
|
+
"flex items-center gap-2 text-sm cursor-pointer",
|
|
5400
|
+
classNames?.multiSelectOption
|
|
5401
|
+
),
|
|
5402
|
+
children: [
|
|
5403
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5404
|
+
"input",
|
|
5405
|
+
{
|
|
5406
|
+
type: "checkbox",
|
|
5407
|
+
checked: selected.includes(opt),
|
|
5408
|
+
onChange: () => toggle(opt),
|
|
5409
|
+
className: "accent-primary w-4 h-4"
|
|
5410
|
+
}
|
|
5411
|
+
),
|
|
5412
|
+
opt
|
|
5413
|
+
]
|
|
5414
|
+
},
|
|
5415
|
+
opt
|
|
5416
|
+
)),
|
|
5417
|
+
maxSelections && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
5418
|
+
selected.length,
|
|
5419
|
+
"/",
|
|
5420
|
+
maxSelections,
|
|
5421
|
+
" selected"
|
|
5422
|
+
] })
|
|
5423
|
+
] });
|
|
5424
|
+
}
|
|
5425
|
+
function DateRangeInput({
|
|
5426
|
+
field,
|
|
5427
|
+
value,
|
|
5428
|
+
onValueChange,
|
|
5429
|
+
classNames,
|
|
5430
|
+
inputClass
|
|
5431
|
+
}) {
|
|
5432
|
+
const range = value && typeof value === "object" ? value : {};
|
|
5433
|
+
const update = (key, v) => {
|
|
5434
|
+
const next = { ...range, [key]: v };
|
|
5435
|
+
onValueChange(next.start || next.end ? next : void 0);
|
|
5436
|
+
};
|
|
5437
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid grid-cols-2 gap-3", classNames?.dateRangeInput), children: [
|
|
5438
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5439
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs text-muted-foreground mb-1 block", children: "Start" }),
|
|
5440
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5441
|
+
"input",
|
|
5442
|
+
{
|
|
5443
|
+
type: "date",
|
|
5444
|
+
value: range.start || "",
|
|
5445
|
+
onChange: (e) => update("start", e.target.value),
|
|
5446
|
+
required: field.is_required,
|
|
5447
|
+
className: inputClass
|
|
5448
|
+
}
|
|
5449
|
+
)
|
|
5450
|
+
] }),
|
|
5451
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5452
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-xs text-muted-foreground mb-1 block", children: "End" }),
|
|
5453
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5454
|
+
"input",
|
|
5455
|
+
{
|
|
5456
|
+
type: "date",
|
|
5457
|
+
value: range.end || "",
|
|
5458
|
+
onChange: (e) => update("end", e.target.value),
|
|
5459
|
+
required: field.is_required,
|
|
5460
|
+
className: inputClass
|
|
5461
|
+
}
|
|
5462
|
+
)
|
|
5463
|
+
] })
|
|
5464
|
+
] });
|
|
5465
|
+
}
|
|
5466
|
+
function AddressInput({
|
|
5467
|
+
field,
|
|
5468
|
+
value,
|
|
5469
|
+
onValueChange,
|
|
5470
|
+
classNames,
|
|
5471
|
+
inputClass
|
|
5472
|
+
}) {
|
|
5473
|
+
const clientContext = useOptionalCimplifyClient();
|
|
5474
|
+
const addr = value && typeof value === "object" ? value : null;
|
|
5475
|
+
const [inputText, setInputText] = React10__default.default.useState(addr?.formatted_address ?? "");
|
|
5476
|
+
const [suggestions, setSuggestions] = React10__default.default.useState([]);
|
|
5477
|
+
const [isOpen, setIsOpen] = React10__default.default.useState(false);
|
|
5478
|
+
const [highlightedIndex, setHighlightedIndex] = React10__default.default.useState(-1);
|
|
5479
|
+
const debounceRef = React10__default.default.useRef(null);
|
|
5480
|
+
const seqRef = React10__default.default.useRef(0);
|
|
5481
|
+
const sessionTokenRef = React10__default.default.useRef(createSessionToken());
|
|
5482
|
+
const blurTimeoutRef = React10__default.default.useRef(null);
|
|
5483
|
+
React10__default.default.useEffect(() => {
|
|
5484
|
+
return () => {
|
|
5485
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5486
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5487
|
+
seqRef.current += 1;
|
|
5488
|
+
};
|
|
5489
|
+
}, []);
|
|
5490
|
+
const fetchSuggestions = React10__default.default.useCallback(async (query) => {
|
|
5491
|
+
const client = clientContext?.client;
|
|
5492
|
+
if (!client || query.length < 3) {
|
|
5493
|
+
setSuggestions([]);
|
|
5494
|
+
setIsOpen(false);
|
|
5495
|
+
return;
|
|
5496
|
+
}
|
|
5497
|
+
const seq = ++seqRef.current;
|
|
5498
|
+
const result = await client.places.autocomplete(query, sessionTokenRef.current);
|
|
5499
|
+
if (seqRef.current !== seq) return;
|
|
5500
|
+
if (result.ok && result.value.predictions.length > 0) {
|
|
5501
|
+
setSuggestions(result.value.predictions);
|
|
5502
|
+
setHighlightedIndex(0);
|
|
5503
|
+
setIsOpen(true);
|
|
5504
|
+
} else {
|
|
5505
|
+
setSuggestions([]);
|
|
5506
|
+
setIsOpen(false);
|
|
5507
|
+
}
|
|
5508
|
+
}, [clientContext]);
|
|
5509
|
+
const handleInputChange = (nextValue) => {
|
|
5510
|
+
setInputText(nextValue);
|
|
5511
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5512
|
+
debounceRef.current = setTimeout(() => void fetchSuggestions(nextValue.trim()), 300);
|
|
5513
|
+
};
|
|
5514
|
+
const selectSuggestion = React10__default.default.useCallback(async (suggestion) => {
|
|
5515
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5516
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5517
|
+
const fallback = suggestion.description.split(",")[0]?.trim() || suggestion.description;
|
|
5518
|
+
setInputText(fallback);
|
|
5519
|
+
setSuggestions([]);
|
|
5520
|
+
setIsOpen(false);
|
|
5521
|
+
const client = clientContext?.client;
|
|
5522
|
+
if (!client) return;
|
|
5523
|
+
const result = await client.places.details(suggestion.place_id, sessionTokenRef.current);
|
|
5524
|
+
sessionTokenRef.current = createSessionToken();
|
|
5525
|
+
if (result.ok) {
|
|
5526
|
+
const d = result.value;
|
|
5527
|
+
const addressValue = {
|
|
5528
|
+
formatted_address: d.formatted_address || fallback,
|
|
5529
|
+
street_address: d.street_address,
|
|
5530
|
+
apartment: d.apartment,
|
|
5531
|
+
city: d.city,
|
|
5532
|
+
region: d.region,
|
|
5533
|
+
postal_code: d.postal_code,
|
|
5534
|
+
country: d.country,
|
|
5535
|
+
latitude: d.latitude,
|
|
5536
|
+
longitude: d.longitude,
|
|
5537
|
+
place_id: d.place_id
|
|
5538
|
+
};
|
|
5539
|
+
setInputText(addressValue.formatted_address);
|
|
5540
|
+
onValueChange(addressValue);
|
|
5541
|
+
}
|
|
5542
|
+
}, [clientContext, onValueChange]);
|
|
5543
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-2 relative", classNames?.addressInput), children: [
|
|
5544
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5545
|
+
"input",
|
|
5546
|
+
{
|
|
5547
|
+
type: "text",
|
|
5548
|
+
value: inputText,
|
|
5549
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
5550
|
+
onFocus: () => {
|
|
5551
|
+
if (suggestions.length > 0) setIsOpen(true);
|
|
5552
|
+
},
|
|
5553
|
+
onBlur: () => {
|
|
5554
|
+
blurTimeoutRef.current = setTimeout(() => setIsOpen(false), 120);
|
|
5555
|
+
},
|
|
5556
|
+
onKeyDown: (e) => {
|
|
5557
|
+
if (e.key === "Escape") {
|
|
5558
|
+
setIsOpen(false);
|
|
5559
|
+
return;
|
|
5560
|
+
}
|
|
5561
|
+
if (!isOpen || suggestions.length === 0) return;
|
|
5562
|
+
if (e.key === "ArrowDown") {
|
|
5563
|
+
e.preventDefault();
|
|
5564
|
+
setHighlightedIndex((i) => i < suggestions.length - 1 ? i + 1 : 0);
|
|
5565
|
+
} else if (e.key === "ArrowUp") {
|
|
5566
|
+
e.preventDefault();
|
|
5567
|
+
setHighlightedIndex((i) => i > 0 ? i - 1 : suggestions.length - 1);
|
|
5568
|
+
} else if (e.key === "Enter" && highlightedIndex >= 0) {
|
|
5569
|
+
e.preventDefault();
|
|
5570
|
+
void selectSuggestion(suggestions[highlightedIndex]);
|
|
5571
|
+
}
|
|
5572
|
+
},
|
|
5573
|
+
placeholder: field.placeholder || "Search for an address...",
|
|
5574
|
+
required: field.is_required,
|
|
5575
|
+
autoComplete: "off",
|
|
5576
|
+
"aria-autocomplete": "list",
|
|
5577
|
+
"aria-expanded": isOpen && suggestions.length > 0,
|
|
5578
|
+
className: inputClass
|
|
5579
|
+
}
|
|
5580
|
+
),
|
|
5581
|
+
isOpen && suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", className: "absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-border bg-background shadow-lg", children: suggestions.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5582
|
+
"button",
|
|
5583
|
+
{
|
|
5584
|
+
type: "button",
|
|
5585
|
+
role: "option",
|
|
5586
|
+
"aria-selected": i === highlightedIndex,
|
|
5587
|
+
onMouseDown: (e) => {
|
|
5588
|
+
e.preventDefault();
|
|
5589
|
+
void selectSuggestion(s);
|
|
5590
|
+
},
|
|
5591
|
+
className: cn("block w-full px-3 py-2.5 text-left text-sm transition-colors", i === highlightedIndex ? "bg-muted text-foreground" : "text-foreground hover:bg-muted/70"),
|
|
5592
|
+
children: s.description
|
|
5593
|
+
},
|
|
5594
|
+
s.place_id
|
|
5595
|
+
)) }),
|
|
5596
|
+
addr && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5597
|
+
"input",
|
|
5598
|
+
{
|
|
5599
|
+
type: "text",
|
|
5600
|
+
value: addr.apartment || "",
|
|
5601
|
+
onChange: (e) => onValueChange({ ...addr, apartment: e.target.value || void 0 }),
|
|
5602
|
+
placeholder: "Apt, suite, unit (optional)",
|
|
5603
|
+
className: inputClass
|
|
5604
|
+
}
|
|
5605
|
+
)
|
|
5606
|
+
] });
|
|
5607
|
+
}
|
|
5608
|
+
function LocationInput({
|
|
5609
|
+
field,
|
|
5610
|
+
value,
|
|
5611
|
+
onValueChange,
|
|
5612
|
+
classNames,
|
|
5613
|
+
inputClass
|
|
5614
|
+
}) {
|
|
5615
|
+
const clientContext = useOptionalCimplifyClient();
|
|
5616
|
+
const loc = value && typeof value === "object" ? value : null;
|
|
5617
|
+
const [inputText, setInputText] = React10__default.default.useState(loc?.label ?? "");
|
|
5618
|
+
const [suggestions, setSuggestions] = React10__default.default.useState([]);
|
|
5619
|
+
const [isOpen, setIsOpen] = React10__default.default.useState(false);
|
|
5620
|
+
const [highlightedIndex, setHighlightedIndex] = React10__default.default.useState(-1);
|
|
5621
|
+
const debounceRef = React10__default.default.useRef(null);
|
|
5622
|
+
const seqRef = React10__default.default.useRef(0);
|
|
5623
|
+
const sessionTokenRef = React10__default.default.useRef(createSessionToken());
|
|
5624
|
+
const blurTimeoutRef = React10__default.default.useRef(null);
|
|
5625
|
+
React10__default.default.useEffect(() => {
|
|
5626
|
+
return () => {
|
|
5627
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5628
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5629
|
+
seqRef.current += 1;
|
|
5630
|
+
};
|
|
5631
|
+
}, []);
|
|
5632
|
+
const fetchSuggestions = React10__default.default.useCallback(async (query) => {
|
|
5633
|
+
const client = clientContext?.client;
|
|
5634
|
+
if (!client || query.length < 3) {
|
|
5635
|
+
setSuggestions([]);
|
|
5636
|
+
setIsOpen(false);
|
|
5637
|
+
return;
|
|
5638
|
+
}
|
|
5639
|
+
const seq = ++seqRef.current;
|
|
5640
|
+
const result = await client.places.autocomplete(query, sessionTokenRef.current);
|
|
5641
|
+
if (seqRef.current !== seq) return;
|
|
5642
|
+
if (result.ok && result.value.predictions.length > 0) {
|
|
5643
|
+
setSuggestions(result.value.predictions);
|
|
5644
|
+
setHighlightedIndex(0);
|
|
5645
|
+
setIsOpen(true);
|
|
5646
|
+
} else {
|
|
5647
|
+
setSuggestions([]);
|
|
5648
|
+
setIsOpen(false);
|
|
5649
|
+
}
|
|
5650
|
+
}, [clientContext]);
|
|
5651
|
+
const handleInputChange = (nextValue) => {
|
|
5652
|
+
setInputText(nextValue);
|
|
5653
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5654
|
+
debounceRef.current = setTimeout(() => void fetchSuggestions(nextValue.trim()), 300);
|
|
5655
|
+
};
|
|
5656
|
+
const selectSuggestion = React10__default.default.useCallback(async (suggestion) => {
|
|
5657
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
5658
|
+
if (blurTimeoutRef.current) clearTimeout(blurTimeoutRef.current);
|
|
5659
|
+
const label = suggestion.description.split(",")[0]?.trim() || suggestion.description;
|
|
5660
|
+
setInputText(label);
|
|
5661
|
+
setSuggestions([]);
|
|
5662
|
+
setIsOpen(false);
|
|
5663
|
+
const client = clientContext?.client;
|
|
5664
|
+
if (!client) return;
|
|
5665
|
+
const result = await client.places.details(suggestion.place_id, sessionTokenRef.current);
|
|
5666
|
+
sessionTokenRef.current = createSessionToken();
|
|
5667
|
+
if (result.ok) {
|
|
5668
|
+
const d = result.value;
|
|
5669
|
+
onValueChange({
|
|
5670
|
+
latitude: d.latitude,
|
|
5671
|
+
longitude: d.longitude,
|
|
5672
|
+
label: d.formatted_address || label
|
|
5673
|
+
});
|
|
5674
|
+
setInputText(d.formatted_address || label);
|
|
5675
|
+
}
|
|
5676
|
+
}, [clientContext, onValueChange]);
|
|
5677
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", classNames?.locationInput), children: [
|
|
5678
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5679
|
+
"input",
|
|
5680
|
+
{
|
|
5681
|
+
type: "text",
|
|
5682
|
+
value: inputText,
|
|
5683
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
5684
|
+
onFocus: () => {
|
|
5685
|
+
if (suggestions.length > 0) setIsOpen(true);
|
|
5686
|
+
},
|
|
5687
|
+
onBlur: () => {
|
|
5688
|
+
blurTimeoutRef.current = setTimeout(() => setIsOpen(false), 120);
|
|
5689
|
+
},
|
|
5690
|
+
onKeyDown: (e) => {
|
|
5691
|
+
if (e.key === "Escape") {
|
|
5692
|
+
setIsOpen(false);
|
|
5693
|
+
return;
|
|
5694
|
+
}
|
|
5695
|
+
if (!isOpen || suggestions.length === 0) return;
|
|
5696
|
+
if (e.key === "ArrowDown") {
|
|
5697
|
+
e.preventDefault();
|
|
5698
|
+
setHighlightedIndex((i) => i < suggestions.length - 1 ? i + 1 : 0);
|
|
5699
|
+
} else if (e.key === "ArrowUp") {
|
|
5700
|
+
e.preventDefault();
|
|
5701
|
+
setHighlightedIndex((i) => i > 0 ? i - 1 : suggestions.length - 1);
|
|
5702
|
+
} else if (e.key === "Enter" && highlightedIndex >= 0) {
|
|
5703
|
+
e.preventDefault();
|
|
5704
|
+
void selectSuggestion(suggestions[highlightedIndex]);
|
|
5705
|
+
}
|
|
5706
|
+
},
|
|
5707
|
+
placeholder: field.placeholder || "Search for a location...",
|
|
5708
|
+
required: field.is_required,
|
|
5709
|
+
autoComplete: "off",
|
|
5710
|
+
"aria-autocomplete": "list",
|
|
5711
|
+
"aria-expanded": isOpen && suggestions.length > 0,
|
|
5712
|
+
className: inputClass
|
|
5713
|
+
}
|
|
5714
|
+
),
|
|
5715
|
+
isOpen && suggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", className: "absolute left-0 right-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-border bg-background shadow-lg", children: suggestions.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5716
|
+
"button",
|
|
5717
|
+
{
|
|
5718
|
+
type: "button",
|
|
5719
|
+
role: "option",
|
|
5720
|
+
"aria-selected": i === highlightedIndex,
|
|
5721
|
+
onMouseDown: (e) => {
|
|
5722
|
+
e.preventDefault();
|
|
5723
|
+
void selectSuggestion(s);
|
|
5724
|
+
},
|
|
5725
|
+
className: cn("block w-full px-3 py-2.5 text-left text-sm transition-colors", i === highlightedIndex ? "bg-muted text-foreground" : "text-foreground hover:bg-muted/70"),
|
|
5726
|
+
children: s.description
|
|
5727
|
+
},
|
|
5728
|
+
s.place_id
|
|
5729
|
+
)) }),
|
|
5730
|
+
loc && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: [
|
|
5731
|
+
loc.latitude.toFixed(4),
|
|
5732
|
+
", ",
|
|
5733
|
+
loc.longitude.toFixed(4)
|
|
5734
|
+
] })
|
|
5735
|
+
] });
|
|
5736
|
+
}
|
|
5737
|
+
function PhoneInput({
|
|
5738
|
+
field,
|
|
5739
|
+
value,
|
|
5740
|
+
onValueChange,
|
|
5741
|
+
classNames,
|
|
5742
|
+
inputClass
|
|
5743
|
+
}) {
|
|
5744
|
+
const phone = value && typeof value === "object" ? value : null;
|
|
5745
|
+
const [code, setCode] = React10__default.default.useState(phone?.country_code ?? "+1");
|
|
5746
|
+
const [number, setNumber] = React10__default.default.useState(phone?.number ?? "");
|
|
5747
|
+
const update = (nextCode, nextNumber) => {
|
|
5748
|
+
setCode(nextCode);
|
|
5749
|
+
setNumber(nextNumber);
|
|
5750
|
+
if (nextNumber) {
|
|
5751
|
+
onValueChange({
|
|
5752
|
+
country_code: nextCode,
|
|
5753
|
+
number: nextNumber,
|
|
5754
|
+
formatted: `${nextCode} ${nextNumber}`
|
|
5755
|
+
});
|
|
5756
|
+
} else {
|
|
5757
|
+
onValueChange(void 0);
|
|
5758
|
+
}
|
|
5759
|
+
};
|
|
5760
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex gap-2", classNames?.phoneInput), children: [
|
|
5761
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5762
|
+
"input",
|
|
5763
|
+
{
|
|
5764
|
+
type: "text",
|
|
5765
|
+
value: code,
|
|
5766
|
+
onChange: (e) => update(e.target.value, number),
|
|
5767
|
+
placeholder: "+1",
|
|
5768
|
+
className: cn(inputClass, "w-20 shrink-0")
|
|
5769
|
+
}
|
|
5770
|
+
),
|
|
5771
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5772
|
+
"input",
|
|
5773
|
+
{
|
|
5774
|
+
type: "tel",
|
|
5775
|
+
value: number,
|
|
5776
|
+
onChange: (e) => update(code, e.target.value),
|
|
5777
|
+
placeholder: field.placeholder || "Phone number",
|
|
5778
|
+
required: field.is_required,
|
|
5779
|
+
className: inputClass
|
|
5780
|
+
}
|
|
5781
|
+
)
|
|
5782
|
+
] });
|
|
5783
|
+
}
|
|
5784
|
+
function SignatureInput({
|
|
5785
|
+
field,
|
|
5786
|
+
value,
|
|
5787
|
+
onValueChange,
|
|
5788
|
+
classNames
|
|
5789
|
+
}) {
|
|
5790
|
+
const sig = value && typeof value === "object" ? value : null;
|
|
5791
|
+
const canvasRef = React10__default.default.useRef(null);
|
|
5792
|
+
const isDrawing = React10__default.default.useRef(false);
|
|
5793
|
+
const getCtx = () => canvasRef.current?.getContext("2d") ?? null;
|
|
5794
|
+
const startDraw = (e) => {
|
|
5795
|
+
const ctx = getCtx();
|
|
5796
|
+
if (!ctx) return;
|
|
5797
|
+
isDrawing.current = true;
|
|
5798
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
5799
|
+
ctx.beginPath();
|
|
5800
|
+
ctx.moveTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
5801
|
+
canvasRef.current.setPointerCapture(e.pointerId);
|
|
5802
|
+
};
|
|
5803
|
+
const draw = (e) => {
|
|
5804
|
+
if (!isDrawing.current) return;
|
|
5805
|
+
const ctx = getCtx();
|
|
5806
|
+
if (!ctx) return;
|
|
5807
|
+
const rect = canvasRef.current.getBoundingClientRect();
|
|
5808
|
+
ctx.lineWidth = 2;
|
|
5809
|
+
ctx.lineCap = "round";
|
|
5810
|
+
const style = getComputedStyle(canvasRef.current);
|
|
5811
|
+
ctx.strokeStyle = style.color || "#000";
|
|
5812
|
+
ctx.lineTo(e.clientX - rect.left, e.clientY - rect.top);
|
|
5813
|
+
ctx.stroke();
|
|
5814
|
+
};
|
|
5815
|
+
const endDraw = () => {
|
|
5816
|
+
if (!isDrawing.current) return;
|
|
5817
|
+
isDrawing.current = false;
|
|
5818
|
+
const canvas = canvasRef.current;
|
|
5819
|
+
if (!canvas) return;
|
|
5820
|
+
onValueChange({
|
|
5821
|
+
data_url: canvas.toDataURL("image/png"),
|
|
5822
|
+
signer_name: sig?.signer_name
|
|
5823
|
+
});
|
|
5824
|
+
};
|
|
5825
|
+
const clear = () => {
|
|
5826
|
+
const canvas = canvasRef.current;
|
|
5827
|
+
if (!canvas) return;
|
|
5828
|
+
const ctx = canvas.getContext("2d");
|
|
5829
|
+
if (ctx) ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
5830
|
+
onValueChange(void 0);
|
|
5831
|
+
};
|
|
5832
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-2", classNames?.signatureCanvas), children: [
|
|
5833
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative rounded-md border border-input overflow-hidden", children: [
|
|
5834
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5835
|
+
"canvas",
|
|
5836
|
+
{
|
|
5837
|
+
ref: canvasRef,
|
|
5838
|
+
width: 400,
|
|
5839
|
+
height: 150,
|
|
5840
|
+
className: "w-full touch-none cursor-crosshair bg-background text-foreground",
|
|
5841
|
+
onPointerDown: startDraw,
|
|
5842
|
+
onPointerMove: draw,
|
|
5843
|
+
onPointerUp: endDraw,
|
|
5844
|
+
onPointerLeave: endDraw
|
|
5845
|
+
}
|
|
5846
|
+
),
|
|
5847
|
+
sig?.data_url && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5848
|
+
"button",
|
|
5849
|
+
{
|
|
5850
|
+
type: "button",
|
|
5851
|
+
onClick: clear,
|
|
5852
|
+
className: "absolute top-1.5 right-1.5 text-xs text-muted-foreground hover:text-destructive transition-colors",
|
|
5853
|
+
children: "Clear"
|
|
5854
|
+
}
|
|
5855
|
+
)
|
|
5856
|
+
] }),
|
|
5857
|
+
!sig?.data_url && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: field.placeholder || "Draw your signature above" })
|
|
5858
|
+
] });
|
|
5859
|
+
}
|
|
5860
|
+
function createSessionToken() {
|
|
5861
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
5862
|
+
return crypto.randomUUID();
|
|
5863
|
+
}
|
|
5864
|
+
return `places_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
5865
|
+
}
|
|
4856
5866
|
function ProductCustomizer({
|
|
4857
5867
|
product,
|
|
4858
5868
|
onAddToCart,
|
|
@@ -4860,20 +5870,21 @@ function ProductCustomizer({
|
|
|
4860
5870
|
className,
|
|
4861
5871
|
classNames
|
|
4862
5872
|
}) {
|
|
4863
|
-
const [quantity, setQuantity] =
|
|
4864
|
-
const [isAdded, setIsAdded] =
|
|
4865
|
-
const [isSubmitting, setIsSubmitting] =
|
|
4866
|
-
const [selectedVariantId, setSelectedVariantId] =
|
|
4867
|
-
const [selectedVariant, setSelectedVariant] =
|
|
4868
|
-
const [selectedAddOnOptionIds, setSelectedAddOnOptionIds] =
|
|
4869
|
-
const [compositeSelections, setCompositeSelections] =
|
|
4870
|
-
const [compositePrice, setCompositePrice] =
|
|
4871
|
-
const [compositeReady, setCompositeReady] =
|
|
4872
|
-
const [bundleSelections, setBundleSelections] =
|
|
4873
|
-
const [bundleTotalPrice, setBundleTotalPrice] =
|
|
4874
|
-
const [bundleReady, setBundleReady] =
|
|
4875
|
-
const [selectedBillingPlan, setSelectedBillingPlan] =
|
|
4876
|
-
const [
|
|
5873
|
+
const [quantity, setQuantity] = React10.useState(product.min_order_quantity ?? 1);
|
|
5874
|
+
const [isAdded, setIsAdded] = React10.useState(false);
|
|
5875
|
+
const [isSubmitting, setIsSubmitting] = React10.useState(false);
|
|
5876
|
+
const [selectedVariantId, setSelectedVariantId] = React10.useState();
|
|
5877
|
+
const [selectedVariant, setSelectedVariant] = React10.useState();
|
|
5878
|
+
const [selectedAddOnOptionIds, setSelectedAddOnOptionIds] = React10.useState([]);
|
|
5879
|
+
const [compositeSelections, setCompositeSelections] = React10.useState([]);
|
|
5880
|
+
const [compositePrice, setCompositePrice] = React10.useState(null);
|
|
5881
|
+
const [compositeReady, setCompositeReady] = React10.useState(false);
|
|
5882
|
+
const [bundleSelections, setBundleSelections] = React10.useState([]);
|
|
5883
|
+
const [bundleTotalPrice, setBundleTotalPrice] = React10.useState(null);
|
|
5884
|
+
const [bundleReady, setBundleReady] = React10.useState(false);
|
|
5885
|
+
const [selectedBillingPlan, setSelectedBillingPlan] = React10.useState(null);
|
|
5886
|
+
const [customerInputValues, setCustomerInputValues] = React10.useState({});
|
|
5887
|
+
const [specialInstructions, setSpecialInstructions] = React10.useState("");
|
|
4877
5888
|
const cart = useCart();
|
|
4878
5889
|
const productType = product.type || "product";
|
|
4879
5890
|
const isComposite = productType === "composite";
|
|
@@ -4883,7 +5894,7 @@ function ProductCustomizer({
|
|
|
4883
5894
|
const isStandard = !isComposite && !isBundle;
|
|
4884
5895
|
const hasVariants = isStandard && product.variants && product.variants.length > 0;
|
|
4885
5896
|
const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
|
|
4886
|
-
|
|
5897
|
+
React10.useEffect(() => {
|
|
4887
5898
|
setQuantity(product.min_order_quantity ?? 1);
|
|
4888
5899
|
setIsAdded(false);
|
|
4889
5900
|
setIsSubmitting(false);
|
|
@@ -4897,9 +5908,10 @@ function ProductCustomizer({
|
|
|
4897
5908
|
setBundleTotalPrice(null);
|
|
4898
5909
|
setBundleReady(false);
|
|
4899
5910
|
setSelectedBillingPlan(null);
|
|
5911
|
+
setCustomerInputValues({});
|
|
4900
5912
|
setSpecialInstructions("");
|
|
4901
5913
|
}, [product.id, product.min_order_quantity]);
|
|
4902
|
-
const selectedAddOnOptions =
|
|
5914
|
+
const selectedAddOnOptions = React10.useMemo(() => {
|
|
4903
5915
|
if (!product.add_ons) return [];
|
|
4904
5916
|
const options = [];
|
|
4905
5917
|
for (const addOn of product.add_ons) {
|
|
@@ -4911,11 +5923,11 @@ function ProductCustomizer({
|
|
|
4911
5923
|
}
|
|
4912
5924
|
return options;
|
|
4913
5925
|
}, [product.add_ons, selectedAddOnOptionIds]);
|
|
4914
|
-
const normalizedAddOnOptionIds =
|
|
5926
|
+
const normalizedAddOnOptionIds = React10.useMemo(() => {
|
|
4915
5927
|
if (selectedAddOnOptionIds.length === 0) return [];
|
|
4916
5928
|
return Array.from(new Set(selectedAddOnOptionIds.map((id) => id.trim()).filter(Boolean))).sort();
|
|
4917
5929
|
}, [selectedAddOnOptionIds]);
|
|
4918
|
-
const localTotalPrice =
|
|
5930
|
+
const localTotalPrice = React10.useMemo(() => {
|
|
4919
5931
|
if (isComposite && compositePrice) {
|
|
4920
5932
|
return chunkPEDLCL72_js.parsePrice(compositePrice.final_price) * quantity;
|
|
4921
5933
|
}
|
|
@@ -4933,7 +5945,7 @@ function ProductCustomizer({
|
|
|
4933
5945
|
}
|
|
4934
5946
|
return price * quantity;
|
|
4935
5947
|
}, [product.default_price, selectedVariant, selectedAddOnOptions, quantity, isComposite, compositePrice, isBundle, bundleTotalPrice]);
|
|
4936
|
-
const requiredAddOnsSatisfied =
|
|
5948
|
+
const requiredAddOnsSatisfied = React10.useMemo(() => {
|
|
4937
5949
|
if (!product.add_ons) return true;
|
|
4938
5950
|
for (const addOn of product.add_ons) {
|
|
4939
5951
|
if (addOn.is_required) {
|
|
@@ -4948,7 +5960,7 @@ function ProductCustomizer({
|
|
|
4948
5960
|
}
|
|
4949
5961
|
return true;
|
|
4950
5962
|
}, [product.add_ons, selectedAddOnOptionIds]);
|
|
4951
|
-
const quoteInput =
|
|
5963
|
+
const quoteInput = React10.useMemo(
|
|
4952
5964
|
() => ({
|
|
4953
5965
|
productId: product.id,
|
|
4954
5966
|
quantity,
|
|
@@ -4959,12 +5971,20 @@ function ProductCustomizer({
|
|
|
4959
5971
|
}),
|
|
4960
5972
|
[product.id, quantity, selectedVariantId, normalizedAddOnOptionIds, isBundle, bundleSelections, isComposite, compositeSelections]
|
|
4961
5973
|
);
|
|
4962
|
-
const
|
|
5974
|
+
const requiredInputsSatisfied = React10.useMemo(() => {
|
|
5975
|
+
if (!product.input_fields || product.input_fields.length === 0) return true;
|
|
5976
|
+
return product.input_fields.every((field) => {
|
|
5977
|
+
if (!field.is_required) return true;
|
|
5978
|
+
const val = customerInputValues[field.id];
|
|
5979
|
+
return val !== void 0 && val !== "" && val !== null;
|
|
5980
|
+
});
|
|
5981
|
+
}, [product.input_fields, customerInputValues]);
|
|
5982
|
+
const quoteEnabled = isComposite ? compositeReady && requiredInputsSatisfied : isBundle ? bundleReady && requiredInputsSatisfied : requiredAddOnsSatisfied && requiredInputsSatisfied;
|
|
4963
5983
|
const { quote } = useQuote(quoteInput, {
|
|
4964
5984
|
enabled: quoteEnabled
|
|
4965
5985
|
});
|
|
4966
5986
|
const quoteId = quote?.quote_id;
|
|
4967
|
-
const quotedTotalPrice =
|
|
5987
|
+
const quotedTotalPrice = React10.useMemo(() => {
|
|
4968
5988
|
if (!quote) return void 0;
|
|
4969
5989
|
const priceInfo = quote.quoted_total_price_info ?? quote.final_price_info;
|
|
4970
5990
|
const perUnit = priceInfo.pre_tax_price;
|
|
@@ -4972,16 +5992,16 @@ function ProductCustomizer({
|
|
|
4972
5992
|
return chunkPEDLCL72_js.parsePrice(perUnit) * quantity;
|
|
4973
5993
|
}, [quote, quantity]);
|
|
4974
5994
|
const displayTotalPrice = quotedTotalPrice ?? localTotalPrice;
|
|
4975
|
-
const handleVariantChange =
|
|
5995
|
+
const handleVariantChange = React10.useCallback(
|
|
4976
5996
|
(variantId, variant) => {
|
|
4977
5997
|
setSelectedVariantId(variantId);
|
|
4978
5998
|
setSelectedVariant(variant);
|
|
4979
5999
|
},
|
|
4980
6000
|
[]
|
|
4981
6001
|
);
|
|
4982
|
-
const addedTimerRef =
|
|
4983
|
-
|
|
4984
|
-
const handleAddToCart =
|
|
6002
|
+
const addedTimerRef = React10.useRef(void 0);
|
|
6003
|
+
React10.useEffect(() => () => clearTimeout(addedTimerRef.current), []);
|
|
6004
|
+
const handleAddToCart = React10.useCallback(async () => {
|
|
4985
6005
|
if (isSubmitting) return;
|
|
4986
6006
|
setIsSubmitting(true);
|
|
4987
6007
|
const options = {
|
|
@@ -4998,6 +6018,7 @@ function ProductCustomizer({
|
|
|
4998
6018
|
compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
|
|
4999
6019
|
bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0,
|
|
5000
6020
|
billingPlanId: selectedBillingPlan?.id,
|
|
6021
|
+
customerInputs: Object.keys(customerInputValues).length > 0 ? Object.entries(customerInputValues).filter(([, v]) => v !== void 0 && v !== "").map(([fieldId, value]) => ({ field_id: fieldId, value })) : void 0,
|
|
5001
6022
|
specialInstructions: specialInstructions.trim() || void 0
|
|
5002
6023
|
};
|
|
5003
6024
|
try {
|
|
@@ -5016,7 +6037,7 @@ function ProductCustomizer({
|
|
|
5016
6037
|
} finally {
|
|
5017
6038
|
setIsSubmitting(false);
|
|
5018
6039
|
}
|
|
5019
|
-
}, [product, quantity, selectedVariantId, selectedVariant, quoteId, normalizedAddOnOptionIds, selectedAddOnOptions, isComposite, compositeSelections, isBundle, bundleSelections, selectedBillingPlan, specialInstructions, isSubmitting, onAddToCart, cart]);
|
|
6040
|
+
}, [product, quantity, selectedVariantId, selectedVariant, quoteId, normalizedAddOnOptionIds, selectedAddOnOptions, isComposite, compositeSelections, isBundle, bundleSelections, selectedBillingPlan, customerInputValues, specialInstructions, isSubmitting, onAddToCart, cart]);
|
|
5020
6041
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer": true, className: cn("space-y-6", className, classNames?.root), children: [
|
|
5021
6042
|
isComposite && product.groups && product.composite_id && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5022
6043
|
CompositeSelector,
|
|
@@ -5077,6 +6098,14 @@ function ProductCustomizer({
|
|
|
5077
6098
|
currentQuantity: quantity
|
|
5078
6099
|
}
|
|
5079
6100
|
),
|
|
6101
|
+
product.input_fields && product.input_fields.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6102
|
+
CustomerInputFields,
|
|
6103
|
+
{
|
|
6104
|
+
fields: product.input_fields,
|
|
6105
|
+
values: customerInputValues,
|
|
6106
|
+
onChange: setCustomerInputValues
|
|
6107
|
+
}
|
|
6108
|
+
),
|
|
5080
6109
|
product.deposit_type && product.deposit_type !== "none" && product.deposit_amount && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customizer-deposit": true, className: cn("text-sm text-muted-foreground", classNames?.depositInfo), children: product.deposit_type === "fixed" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5081
6110
|
"Deposit required: ",
|
|
5082
6111
|
/* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.deposit_amount })
|
|
@@ -5096,9 +6125,7 @@ function ProductCustomizer({
|
|
|
5096
6125
|
)) }),
|
|
5097
6126
|
isService && product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer-duration": true, className: cn("text-sm text-muted-foreground", classNames?.duration), children: [
|
|
5098
6127
|
"Duration: ",
|
|
5099
|
-
product.duration_minutes,
|
|
5100
|
-
" ",
|
|
5101
|
-
product.duration_unit ?? "minutes"
|
|
6128
|
+
formatDuration2(product.duration_minutes, product.duration_unit)
|
|
5102
6129
|
] }),
|
|
5103
6130
|
showSpecialInstructions && !isDigital && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customizer-special-instructions": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5104
6131
|
"textarea",
|
|
@@ -5184,14 +6211,14 @@ function ProductImageGallery({
|
|
|
5184
6211
|
aspectRatio = "4/3",
|
|
5185
6212
|
className
|
|
5186
6213
|
}) {
|
|
5187
|
-
const normalizedImages =
|
|
6214
|
+
const normalizedImages = React10.useMemo(
|
|
5188
6215
|
() => images.filter(
|
|
5189
6216
|
(image) => typeof image === "string" && image.trim().length > 0
|
|
5190
6217
|
),
|
|
5191
6218
|
[images]
|
|
5192
6219
|
);
|
|
5193
|
-
const [selectedImage, setSelectedImage] =
|
|
5194
|
-
|
|
6220
|
+
const [selectedImage, setSelectedImage] = React10.useState(0);
|
|
6221
|
+
React10.useEffect(() => {
|
|
5195
6222
|
setSelectedImage(0);
|
|
5196
6223
|
}, [normalizedImages.length, productName]);
|
|
5197
6224
|
if (normalizedImages.length === 0) {
|
|
@@ -5271,13 +6298,17 @@ function CartLineItemRow({
|
|
|
5271
6298
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item": true, className: classNames?.item, children: [
|
|
5272
6299
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-info": true, children: [
|
|
5273
6300
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-name": true, className: classNames?.itemName, children: item.product.name }),
|
|
5274
|
-
item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children:
|
|
6301
|
+
item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children: chunkF47XFKYP_js.getVariantDisplayName(item.variant, item.product.name) }),
|
|
5275
6302
|
item.addOnOptions && item.addOnOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-cart-item-addons": true, children: [
|
|
5276
6303
|
"+ ",
|
|
5277
6304
|
item.addOnOptions.map((opt) => opt.name).join(", ")
|
|
5278
6305
|
] }),
|
|
5279
6306
|
(hasComposite || hasBundle) && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-badge": true, children: hasComposite ? "Custom" : "Bundle" }),
|
|
5280
6307
|
item.specialInstructions && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-instructions": true, className: "text-xs text-muted-foreground", children: item.specialInstructions }),
|
|
6308
|
+
item.customerInputs && item.customerInputs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-customer-inputs": true, className: classNames?.customerInputs, children: item.customerInputs.map((input) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-input": true, children: [
|
|
6309
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-input-label": true, children: input.field_name }),
|
|
6310
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-input-value": true, children: input.field_type === chunkF47XFKYP_js.INPUT_FIELD_TYPE.File || input.field_type === chunkF47XFKYP_js.INPUT_FIELD_TYPE.Image ? String(input.value).split("/").pop() || "Uploaded file" : String(input.value) })
|
|
6311
|
+
] }, input.field_id)) }),
|
|
5281
6312
|
(item.lineType === "service" || item.product.type === "service") && item.scheduledStart && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-service-info": true, className: classNames?.serviceInfo, children: [
|
|
5282
6313
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5283
6314
|
"\u{1F4C5}",
|
|
@@ -5796,7 +6827,7 @@ function FoodProductCard({
|
|
|
5796
6827
|
const tags = product.tags || [];
|
|
5797
6828
|
const isSignature = product.metadata?.is_signature === true;
|
|
5798
6829
|
const isNew = product.metadata?.is_new === true;
|
|
5799
|
-
const isComposite = product.type ===
|
|
6830
|
+
const isComposite = product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Composite;
|
|
5800
6831
|
return /* @__PURE__ */ jsxRuntime.jsxs(CardShell, { product, renderLink, className, children: [
|
|
5801
6832
|
/* @__PURE__ */ jsxRuntime.jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "square", renderImage, children: [
|
|
5802
6833
|
isSignature && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "absolute top-3 left-3 inline-flex items-center gap-1 text-[11px] font-semibold tracking-wide bg-amber-50 text-amber-700 border border-amber-200/60 px-2 py-0.5 rounded-md", children: [
|
|
@@ -6057,7 +7088,7 @@ function CompositeProductCard({
|
|
|
6057
7088
|
] })
|
|
6058
7089
|
] });
|
|
6059
7090
|
}
|
|
6060
|
-
function
|
|
7091
|
+
function formatDuration3(minutes, unit) {
|
|
6061
7092
|
if (unit && unit !== "minutes") return `${minutes} ${unit}`;
|
|
6062
7093
|
if (minutes >= 60) {
|
|
6063
7094
|
const h = Math.floor(minutes / 60);
|
|
@@ -6078,7 +7109,7 @@ function StandardServiceCard({
|
|
|
6078
7109
|
return /* @__PURE__ */ jsxRuntime.jsxs(CardShell, { product, renderLink, className, children: [
|
|
6079
7110
|
/* @__PURE__ */ jsxRuntime.jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "16/9", renderImage, children: [
|
|
6080
7111
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/50 to-transparent pointer-events-none" }),
|
|
6081
|
-
product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute bottom-3 left-3 inline-flex items-center gap-1 text-[12px] font-semibold px-2.5 py-1 rounded-lg bg-background/92 backdrop-blur-xl text-foreground shadow-sm", children:
|
|
7112
|
+
product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute bottom-3 left-3 inline-flex items-center gap-1 text-[12px] font-semibold px-2.5 py-1 rounded-lg bg-background/92 backdrop-blur-xl text-foreground shadow-sm", children: formatDuration3(product.duration_minutes, product.duration_unit) }),
|
|
6082
7113
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute bottom-3 right-3 text-white font-bold text-lg drop-shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price }) })
|
|
6083
7114
|
] }),
|
|
6084
7115
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
|
|
@@ -6112,7 +7143,7 @@ function StandardServiceCard({
|
|
|
6112
7143
|
] })
|
|
6113
7144
|
] });
|
|
6114
7145
|
}
|
|
6115
|
-
function
|
|
7146
|
+
function formatDuration4(minutes, unit) {
|
|
6116
7147
|
if (unit && unit !== "minutes") return `${minutes} ${unit}`;
|
|
6117
7148
|
if (minutes >= 60) {
|
|
6118
7149
|
const h = Math.floor(minutes / 60);
|
|
@@ -6137,7 +7168,7 @@ function CompactServiceCard({
|
|
|
6137
7168
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[14px] font-semibold text-foreground leading-tight truncate", children: product.name }),
|
|
6138
7169
|
product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[12px] text-muted-foreground mt-0.5 truncate", children: product.description }),
|
|
6139
7170
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-2 flex-wrap", children: [
|
|
6140
|
-
product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10.5px] font-medium text-muted-foreground px-1.5 py-0.5 bg-muted rounded", children:
|
|
7171
|
+
product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10.5px] font-medium text-muted-foreground px-1.5 py-0.5 bg-muted rounded", children: formatDuration4(product.duration_minutes, product.duration_unit) }),
|
|
6141
7172
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1 text-[10.5px] font-medium text-emerald-600", children: [
|
|
6142
7173
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[6px] h-[6px] rounded-full bg-emerald-500" }),
|
|
6143
7174
|
"Available"
|
|
@@ -6177,7 +7208,7 @@ function ScheduleServiceCard({
|
|
|
6177
7208
|
}) {
|
|
6178
7209
|
const image = product.image_url || product.images?.[0] || "";
|
|
6179
7210
|
const href = `/products/${product.slug}`;
|
|
6180
|
-
const durationLabel = product.duration_minutes != null ?
|
|
7211
|
+
const durationLabel = product.duration_minutes != null ? formatDuration2(product.duration_minutes, product.duration_unit) : null;
|
|
6181
7212
|
const displaySlots = (slots || []).slice(0, 3);
|
|
6182
7213
|
const shellClass = cn(
|
|
6183
7214
|
"group block text-left cursor-pointer bg-card rounded-[14px] overflow-hidden",
|
|
@@ -6230,7 +7261,7 @@ function ScheduleServiceCard({
|
|
|
6230
7261
|
}
|
|
6231
7262
|
return /* @__PURE__ */ jsxRuntime.jsx("a", { href, className: shellClass, "data-cimplify-card": true, children: inner });
|
|
6232
7263
|
}
|
|
6233
|
-
var
|
|
7264
|
+
var UNIT_LABELS2 = {
|
|
6234
7265
|
minutes: "min",
|
|
6235
7266
|
hours: "hr",
|
|
6236
7267
|
days: "day",
|
|
@@ -6248,7 +7279,7 @@ function RentalServiceCard({
|
|
|
6248
7279
|
}) {
|
|
6249
7280
|
const image = product.image_url || product.images?.[0] || "";
|
|
6250
7281
|
const hasDeposit = product.deposit_type && product.deposit_type !== "none" && product.deposit_amount;
|
|
6251
|
-
const unit = product.duration_unit ?
|
|
7282
|
+
const unit = product.duration_unit ? UNIT_LABELS2[product.duration_unit] || product.duration_unit : "day";
|
|
6252
7283
|
const status = product.inventory_status;
|
|
6253
7284
|
return /* @__PURE__ */ jsxRuntime.jsxs(CardShell, { product, renderLink, className, children: [
|
|
6254
7285
|
/* @__PURE__ */ jsxRuntime.jsxs(CardImage, { src: image, alt: product.name, aspectRatio: "16/9", renderImage, children: [
|
|
@@ -6368,7 +7399,7 @@ function AccommodationCard({
|
|
|
6368
7399
|
] })
|
|
6369
7400
|
] });
|
|
6370
7401
|
}
|
|
6371
|
-
var
|
|
7402
|
+
var UNIT_LABELS3 = {
|
|
6372
7403
|
weeks: "week",
|
|
6373
7404
|
months: "mo",
|
|
6374
7405
|
years: "yr"
|
|
@@ -6383,7 +7414,7 @@ function LeaseServiceCard({
|
|
|
6383
7414
|
const image = product.image_url || product.images?.[0] || "";
|
|
6384
7415
|
const hasDeposit = product.deposit_type && product.deposit_type !== "none" && product.deposit_amount;
|
|
6385
7416
|
const hasTiers = product.quantity_pricing && product.quantity_pricing.length > 1;
|
|
6386
|
-
const unit = product.duration_unit ?
|
|
7417
|
+
const unit = product.duration_unit ? UNIT_LABELS3[product.duration_unit] || product.duration_unit : "mo";
|
|
6387
7418
|
const tags = product.tags || [];
|
|
6388
7419
|
const cancellationHours = product.cancellation_window_minutes ? Math.floor(product.cancellation_window_minutes / 60) : null;
|
|
6389
7420
|
return /* @__PURE__ */ jsxRuntime.jsxs(CardShell, { product, renderLink, className, children: [
|
|
@@ -6441,6 +7472,7 @@ function LeaseServiceCard({
|
|
|
6441
7472
|
}
|
|
6442
7473
|
var FREQUENCY_LABELS2 = {
|
|
6443
7474
|
weekly: "/week",
|
|
7475
|
+
biweekly: "/2wk",
|
|
6444
7476
|
monthly: "/mo",
|
|
6445
7477
|
quarterly: "/qtr",
|
|
6446
7478
|
annually: "/yr"
|
|
@@ -6548,26 +7580,26 @@ var BUILT_IN_CARDS = {
|
|
|
6548
7580
|
["composite" /* Composite */]: CompositeProductCard,
|
|
6549
7581
|
["subscription" /* Subscription */]: SubscriptionCard
|
|
6550
7582
|
};
|
|
6551
|
-
var RENTAL_UNITS = /* @__PURE__ */ new Set([
|
|
6552
|
-
var LEASE_UNITS = /* @__PURE__ */ new Set([
|
|
7583
|
+
var RENTAL_UNITS = /* @__PURE__ */ new Set([chunkF47XFKYP_js.DURATION_UNIT.Days, chunkF47XFKYP_js.DURATION_UNIT.Hours]);
|
|
7584
|
+
var LEASE_UNITS = /* @__PURE__ */ new Set([chunkF47XFKYP_js.DURATION_UNIT.Weeks, chunkF47XFKYP_js.DURATION_UNIT.Months, chunkF47XFKYP_js.DURATION_UNIT.Years]);
|
|
6553
7585
|
function resolveCardVariant(product) {
|
|
6554
|
-
if (product.type ===
|
|
7586
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Bundle) {
|
|
6555
7587
|
return "bundle" /* Bundle */;
|
|
6556
7588
|
}
|
|
6557
|
-
if (product.type ===
|
|
7589
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Composite) {
|
|
6558
7590
|
return "composite" /* Composite */;
|
|
6559
7591
|
}
|
|
6560
7592
|
if (product.quantity_pricing && product.quantity_pricing.length > 1) {
|
|
6561
7593
|
return "wholesale" /* Wholesale */;
|
|
6562
7594
|
}
|
|
6563
|
-
if (product.type ===
|
|
7595
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Digital) {
|
|
6564
7596
|
return "digital" /* Digital */;
|
|
6565
7597
|
}
|
|
6566
|
-
if (product.type ===
|
|
7598
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Service) {
|
|
6567
7599
|
if (product.duration_unit && RENTAL_UNITS.has(product.duration_unit)) {
|
|
6568
7600
|
return "rental" /* Rental */;
|
|
6569
7601
|
}
|
|
6570
|
-
if (product.duration_unit ===
|
|
7602
|
+
if (product.duration_unit === chunkF47XFKYP_js.DURATION_UNIT.Nights) {
|
|
6571
7603
|
return "accommodation" /* Accommodation */;
|
|
6572
7604
|
}
|
|
6573
7605
|
if (product.duration_unit && LEASE_UNITS.has(product.duration_unit)) {
|
|
@@ -6578,10 +7610,10 @@ function resolveCardVariant(product) {
|
|
|
6578
7610
|
}
|
|
6579
7611
|
return "standard" /* Standard */;
|
|
6580
7612
|
}
|
|
6581
|
-
if (product.render_hint ===
|
|
7613
|
+
if (product.render_hint === chunkF47XFKYP_js.RENDER_HINT.Food) {
|
|
6582
7614
|
return "food" /* Food */;
|
|
6583
7615
|
}
|
|
6584
|
-
if (product.render_hint ===
|
|
7616
|
+
if (product.render_hint === chunkF47XFKYP_js.RENDER_HINT.Physical) {
|
|
6585
7617
|
return "retail" /* Retail */;
|
|
6586
7618
|
}
|
|
6587
7619
|
return "retail" /* Retail */;
|
|
@@ -6602,22 +7634,22 @@ function ProductCard({
|
|
|
6602
7634
|
classNames
|
|
6603
7635
|
}) {
|
|
6604
7636
|
const mode = displayMode ?? product.display_mode ?? "card";
|
|
6605
|
-
const [isOpen, setIsOpen] =
|
|
6606
|
-
const [shouldFetch, setShouldFetch] =
|
|
7637
|
+
const [isOpen, setIsOpen] = React10.useState(false);
|
|
7638
|
+
const [shouldFetch, setShouldFetch] = React10.useState(false);
|
|
6607
7639
|
const { product: productDetails } = useProduct(
|
|
6608
7640
|
product.slug ?? product.id,
|
|
6609
7641
|
{ enabled: shouldFetch || isOpen }
|
|
6610
7642
|
);
|
|
6611
|
-
const handlePrefetch =
|
|
7643
|
+
const handlePrefetch = React10.useCallback(() => {
|
|
6612
7644
|
setShouldFetch(true);
|
|
6613
7645
|
}, []);
|
|
6614
|
-
const handleOpenChange =
|
|
7646
|
+
const handleOpenChange = React10.useCallback((open) => {
|
|
6615
7647
|
setIsOpen(open);
|
|
6616
7648
|
if (open) {
|
|
6617
7649
|
setShouldFetch(true);
|
|
6618
7650
|
}
|
|
6619
7651
|
}, []);
|
|
6620
|
-
const handleClose =
|
|
7652
|
+
const handleClose = React10.useCallback(() => {
|
|
6621
7653
|
setIsOpen(false);
|
|
6622
7654
|
}, []);
|
|
6623
7655
|
const imageUrl = product.image_url || product.images?.[0];
|
|
@@ -6746,13 +7778,13 @@ function ProductGrid({
|
|
|
6746
7778
|
className,
|
|
6747
7779
|
classNames
|
|
6748
7780
|
}) {
|
|
6749
|
-
const rawId =
|
|
7781
|
+
const rawId = React10__default.default.useId();
|
|
6750
7782
|
const gridId = `cimplify-grid-${rawId.replace(/:/g, "")}`;
|
|
6751
7783
|
const sm = columns?.sm ?? 1;
|
|
6752
7784
|
const md = columns?.md ?? 2;
|
|
6753
7785
|
const lg = columns?.lg ?? 3;
|
|
6754
7786
|
const xl = columns?.xl ?? 4;
|
|
6755
|
-
const css =
|
|
7787
|
+
const css = React10__default.default.useMemo(
|
|
6756
7788
|
() => [
|
|
6757
7789
|
`#${gridId}{display:grid;grid-template-columns:repeat(${sm},1fr);gap:1rem}`,
|
|
6758
7790
|
`@media(min-width:768px){#${gridId}{grid-template-columns:repeat(${md},1fr)}}`,
|
|
@@ -6830,12 +7862,12 @@ function SearchInput({
|
|
|
6830
7862
|
className,
|
|
6831
7863
|
classNames
|
|
6832
7864
|
}) {
|
|
6833
|
-
const mergedOptions =
|
|
7865
|
+
const mergedOptions = React10.useMemo(
|
|
6834
7866
|
() => categoryId ? { ...searchOptions, category: categoryId } : searchOptions ?? {},
|
|
6835
7867
|
[searchOptions, categoryId]
|
|
6836
7868
|
);
|
|
6837
7869
|
const { results, isLoading, query, setQuery, clear } = useSearch(mergedOptions);
|
|
6838
|
-
const handleValueChange =
|
|
7870
|
+
const handleValueChange = React10.useCallback(
|
|
6839
7871
|
(value) => {
|
|
6840
7872
|
setQuery(value);
|
|
6841
7873
|
},
|
|
@@ -6934,7 +7966,7 @@ function CategoryFilter({
|
|
|
6934
7966
|
classNames
|
|
6935
7967
|
}) {
|
|
6936
7968
|
const { categories, isLoading } = useCategories();
|
|
6937
|
-
const handleValueChange =
|
|
7969
|
+
const handleValueChange = React10.useCallback(
|
|
6938
7970
|
(value) => {
|
|
6939
7971
|
onSelect(value === ALL_VALUE ? null : String(value));
|
|
6940
7972
|
},
|
|
@@ -7001,10 +8033,10 @@ function DiscountInput({
|
|
|
7001
8033
|
className,
|
|
7002
8034
|
classNames
|
|
7003
8035
|
}) {
|
|
7004
|
-
const [code, setCode] =
|
|
7005
|
-
const [appliedValidation, setAppliedValidation] =
|
|
8036
|
+
const [code, setCode] = React10.useState("");
|
|
8037
|
+
const [appliedValidation, setAppliedValidation] = React10.useState(null);
|
|
7006
8038
|
const { validate, isValidating, error } = useValidateDiscount();
|
|
7007
|
-
const handleApply =
|
|
8039
|
+
const handleApply = React10.useCallback(async () => {
|
|
7008
8040
|
const trimmed = code.trim();
|
|
7009
8041
|
if (!trimmed) return;
|
|
7010
8042
|
const result = await validate(trimmed, orderSubtotal, locationId);
|
|
@@ -7017,12 +8049,12 @@ function DiscountInput({
|
|
|
7017
8049
|
}
|
|
7018
8050
|
}
|
|
7019
8051
|
}, [code, validate, orderSubtotal, locationId, onApply]);
|
|
7020
|
-
const handleClear =
|
|
8052
|
+
const handleClear = React10.useCallback(() => {
|
|
7021
8053
|
setCode("");
|
|
7022
8054
|
setAppliedValidation(null);
|
|
7023
8055
|
onClear?.();
|
|
7024
8056
|
}, [onClear]);
|
|
7025
|
-
const handleKeyDown =
|
|
8057
|
+
const handleKeyDown = React10.useCallback(
|
|
7026
8058
|
(e) => {
|
|
7027
8059
|
if (e.key === "Enter") {
|
|
7028
8060
|
void handleApply();
|
|
@@ -7113,7 +8145,7 @@ function CategoryGrid({
|
|
|
7113
8145
|
enabled: categoriesProp === void 0
|
|
7114
8146
|
});
|
|
7115
8147
|
const categories = categoriesProp ?? fetched;
|
|
7116
|
-
const rawId =
|
|
8148
|
+
const rawId = React10__default.default.useId();
|
|
7117
8149
|
const gridId = `cimplify-cat-grid-${rawId.replace(/:/g, "")}`;
|
|
7118
8150
|
const sm = columns?.sm ?? 2;
|
|
7119
8151
|
const md = columns?.md ?? 3;
|
|
@@ -7339,7 +8371,7 @@ function OrderSummary({
|
|
|
7339
8371
|
/* @__PURE__ */ jsxRuntime.jsx("p", { children: order.delivery_address })
|
|
7340
8372
|
] }),
|
|
7341
8373
|
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-items": true, className: classNames?.items, children: order.items.map(
|
|
7342
|
-
(item) => renderLineItem ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8374
|
+
(item) => renderLineItem ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderLineItem(item) }, item.id) : /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-line-item": true, className: classNames?.lineItem, children: [
|
|
7343
8375
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-line-info": true, children: [
|
|
7344
8376
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-order-line-qty": true, children: [
|
|
7345
8377
|
item.quantity,
|
|
@@ -7774,9 +8806,9 @@ function DateSlotPicker({
|
|
|
7774
8806
|
className,
|
|
7775
8807
|
classNames
|
|
7776
8808
|
}) {
|
|
7777
|
-
const [offset, setOffset] =
|
|
7778
|
-
const [selectedDate, setSelectedDate] =
|
|
7779
|
-
const dateRange =
|
|
8809
|
+
const [offset, setOffset] = React10.useState(0);
|
|
8810
|
+
const [selectedDate, setSelectedDate] = React10.useState(toDateString(/* @__PURE__ */ new Date()));
|
|
8811
|
+
const dateRange = React10.useMemo(() => {
|
|
7780
8812
|
const today = /* @__PURE__ */ new Date();
|
|
7781
8813
|
const start = addDays(today, offset);
|
|
7782
8814
|
const dates = [];
|
|
@@ -7799,25 +8831,25 @@ function DateSlotPicker({
|
|
|
7799
8831
|
}
|
|
7800
8832
|
);
|
|
7801
8833
|
const days = availabilityProp ?? fetchedDays;
|
|
7802
|
-
const availabilityMap =
|
|
8834
|
+
const availabilityMap = React10.useMemo(() => {
|
|
7803
8835
|
const map = /* @__PURE__ */ new Map();
|
|
7804
8836
|
for (const day of days) {
|
|
7805
8837
|
map.set(day.date, day);
|
|
7806
8838
|
}
|
|
7807
8839
|
return map;
|
|
7808
8840
|
}, [days]);
|
|
7809
|
-
const handlePrev =
|
|
8841
|
+
const handlePrev = React10.useCallback(() => {
|
|
7810
8842
|
setOffset((prev) => Math.max(0, prev - daysToShow));
|
|
7811
8843
|
}, [daysToShow]);
|
|
7812
|
-
const handleNext =
|
|
8844
|
+
const handleNext = React10.useCallback(() => {
|
|
7813
8845
|
setOffset((prev) => prev + daysToShow);
|
|
7814
8846
|
}, [daysToShow]);
|
|
7815
|
-
const handleDateChange =
|
|
8847
|
+
const handleDateChange = React10.useCallback((value) => {
|
|
7816
8848
|
if (typeof value === "string") {
|
|
7817
8849
|
setSelectedDate(value);
|
|
7818
8850
|
}
|
|
7819
8851
|
}, []);
|
|
7820
|
-
const handleSlotSelect =
|
|
8852
|
+
const handleSlotSelect = React10.useCallback(
|
|
7821
8853
|
(slot) => {
|
|
7822
8854
|
onSlotSelect?.(slot, selectedDate);
|
|
7823
8855
|
},
|
|
@@ -8320,7 +9352,7 @@ function DefaultCatalogueLayout({
|
|
|
8320
9352
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-medium", children: "No products found" }),
|
|
8321
9353
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try adjusting your filters" })
|
|
8322
9354
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-4", children: products.map(
|
|
8323
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9355
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8324
9356
|
ProductCard,
|
|
8325
9357
|
{
|
|
8326
9358
|
product,
|
|
@@ -8427,7 +9459,7 @@ function CompactCatalogueLayout({
|
|
|
8427
9459
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg font-medium", children: "No items found" }),
|
|
8428
9460
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try a different category or search" })
|
|
8429
9461
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 lg:grid-cols-3 gap-5", children: products.map(
|
|
8430
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
9462
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8431
9463
|
ProductCard,
|
|
8432
9464
|
{
|
|
8433
9465
|
product,
|
|
@@ -8450,8 +9482,8 @@ var BUILT_IN_LAYOUTS = {
|
|
|
8450
9482
|
["compact" /* Compact */]: CompactCatalogueLayout
|
|
8451
9483
|
};
|
|
8452
9484
|
function useDebounce(value, delay) {
|
|
8453
|
-
const [debounced, setDebounced] =
|
|
8454
|
-
|
|
9485
|
+
const [debounced, setDebounced] = React10__default.default.useState(value);
|
|
9486
|
+
React10__default.default.useEffect(() => {
|
|
8455
9487
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
8456
9488
|
return () => clearTimeout(timer);
|
|
8457
9489
|
}, [value, delay]);
|
|
@@ -8475,15 +9507,15 @@ function CataloguePage({
|
|
|
8475
9507
|
className,
|
|
8476
9508
|
classNames
|
|
8477
9509
|
}) {
|
|
8478
|
-
const [selectedCategory, setSelectedCategory] =
|
|
8479
|
-
const [searchQuery, setSearchQuery] =
|
|
8480
|
-
const [sortBy, setSortBy] =
|
|
8481
|
-
const [sortOrder, setSortOrder] =
|
|
8482
|
-
const [inStockOnly, setInStockOnly] =
|
|
8483
|
-
const [selectedTags, setSelectedTags] =
|
|
8484
|
-
const [minPrice, setMinPrice] =
|
|
8485
|
-
const [maxPrice, setMaxPrice] =
|
|
8486
|
-
const [page, setPage] =
|
|
9510
|
+
const [selectedCategory, setSelectedCategory] = React10.useState(null);
|
|
9511
|
+
const [searchQuery, setSearchQuery] = React10.useState("");
|
|
9512
|
+
const [sortBy, setSortBy] = React10.useState(defaultSort?.by ?? "created_at");
|
|
9513
|
+
const [sortOrder, setSortOrder] = React10.useState(defaultSort?.order ?? "desc");
|
|
9514
|
+
const [inStockOnly, setInStockOnly] = React10.useState(false);
|
|
9515
|
+
const [selectedTags, setSelectedTags] = React10.useState([]);
|
|
9516
|
+
const [minPrice, setMinPrice] = React10.useState("");
|
|
9517
|
+
const [maxPrice, setMaxPrice] = React10.useState("");
|
|
9518
|
+
const [page, setPage] = React10.useState(1);
|
|
8487
9519
|
const debouncedSearch = useDebounce(searchQuery, 300);
|
|
8488
9520
|
const { products: fetchedProducts, isLoading, pagination } = useProducts({
|
|
8489
9521
|
enabled: productsProp === void 0,
|
|
@@ -8504,22 +9536,22 @@ function CataloguePage({
|
|
|
8504
9536
|
const products = productsProp ?? fetchedProducts;
|
|
8505
9537
|
const categories = categoriesProp ?? fetchedCategories;
|
|
8506
9538
|
const totalPages = pagination?.total_pages ?? 1;
|
|
8507
|
-
const handleCategoryChange =
|
|
9539
|
+
const handleCategoryChange = React10.useCallback((id) => {
|
|
8508
9540
|
setSelectedCategory(id);
|
|
8509
9541
|
setPage(1);
|
|
8510
9542
|
}, []);
|
|
8511
|
-
const handleSortChange =
|
|
9543
|
+
const handleSortChange = React10.useCallback((by, order) => {
|
|
8512
9544
|
setSortBy(by);
|
|
8513
9545
|
setSortOrder(order);
|
|
8514
9546
|
setPage(1);
|
|
8515
9547
|
}, []);
|
|
8516
|
-
const handleTagToggle =
|
|
9548
|
+
const handleTagToggle = React10.useCallback((tag) => {
|
|
8517
9549
|
setSelectedTags(
|
|
8518
9550
|
(prev) => prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
|
|
8519
9551
|
);
|
|
8520
9552
|
setPage(1);
|
|
8521
9553
|
}, []);
|
|
8522
|
-
const handlePriceRangeChange =
|
|
9554
|
+
const handlePriceRangeChange = React10.useCallback((min, max) => {
|
|
8523
9555
|
setMinPrice(min);
|
|
8524
9556
|
setMaxPrice(max);
|
|
8525
9557
|
setPage(1);
|
|
@@ -8943,15 +9975,6 @@ function WholesaleProductLayout({
|
|
|
8943
9975
|
)
|
|
8944
9976
|
] });
|
|
8945
9977
|
}
|
|
8946
|
-
function formatMinutes(minutes) {
|
|
8947
|
-
if (minutes >= 1440) return `${Math.floor(minutes / 1440)} day${minutes >= 2880 ? "s" : ""}`;
|
|
8948
|
-
if (minutes >= 60) {
|
|
8949
|
-
const h = Math.floor(minutes / 60);
|
|
8950
|
-
const m = minutes % 60;
|
|
8951
|
-
return m > 0 ? `${h}h ${m}min` : `${h} hour${h > 1 ? "s" : ""}`;
|
|
8952
|
-
}
|
|
8953
|
-
return `${minutes} min`;
|
|
8954
|
-
}
|
|
8955
9978
|
function ServiceProductLayout({
|
|
8956
9979
|
product,
|
|
8957
9980
|
onAddToCart,
|
|
@@ -8983,7 +10006,7 @@ function ServiceProductLayout({
|
|
|
8983
10006
|
/* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.default_price, className: "text-2xl font-bold text-primary mt-2 block" })
|
|
8984
10007
|
] }),
|
|
8985
10008
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-product-layout-service-info": true, className: "flex flex-wrap gap-2", children: [
|
|
8986
|
-
product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children:
|
|
10009
|
+
product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: formatDuration2(product.duration_minutes, product.duration_unit) }),
|
|
8987
10010
|
hasDeposit && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 bg-muted text-sm text-muted-foreground rounded-full", children: [
|
|
8988
10011
|
/* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount }),
|
|
8989
10012
|
" deposit"
|
|
@@ -9020,7 +10043,7 @@ function ServiceProductLayout({
|
|
|
9020
10043
|
cancellationHours,
|
|
9021
10044
|
" hours"
|
|
9022
10045
|
] }),
|
|
9023
|
-
" before the
|
|
10046
|
+
" before the booking"
|
|
9024
10047
|
] }),
|
|
9025
10048
|
product.no_show_fee && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
|
|
9026
10049
|
"No-show fee: ",
|
|
@@ -9351,25 +10374,25 @@ function resolveTemplateKey(product) {
|
|
|
9351
10374
|
if (typeof metaTemplate === "string" && metaTemplate.trim()) {
|
|
9352
10375
|
return metaTemplate.trim();
|
|
9353
10376
|
}
|
|
9354
|
-
if (product.type ===
|
|
10377
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Bundle) {
|
|
9355
10378
|
return "bundle" /* Bundle */;
|
|
9356
10379
|
}
|
|
9357
|
-
if (product.type ===
|
|
10380
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Composite) {
|
|
9358
10381
|
return "composite" /* Composite */;
|
|
9359
10382
|
}
|
|
9360
10383
|
if (product.quantity_pricing && product.quantity_pricing.length > 1) {
|
|
9361
10384
|
return "wholesale" /* Wholesale */;
|
|
9362
10385
|
}
|
|
9363
|
-
if (product.type ===
|
|
10386
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Service) {
|
|
9364
10387
|
return "service" /* Service */;
|
|
9365
10388
|
}
|
|
9366
|
-
if (product.type ===
|
|
10389
|
+
if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Digital) {
|
|
9367
10390
|
return "digital" /* Digital */;
|
|
9368
10391
|
}
|
|
9369
|
-
if (product.render_hint ===
|
|
10392
|
+
if (product.render_hint === chunkF47XFKYP_js.RENDER_HINT.Food) {
|
|
9370
10393
|
return "food" /* Food */;
|
|
9371
10394
|
}
|
|
9372
|
-
if (product.render_hint ===
|
|
10395
|
+
if (product.render_hint === chunkF47XFKYP_js.RENDER_HINT.Physical) {
|
|
9373
10396
|
return "physical" /* Physical */;
|
|
9374
10397
|
}
|
|
9375
10398
|
return "default" /* Default */;
|
|
@@ -9635,9 +10658,9 @@ function DefaultCollectionLayout({
|
|
|
9635
10658
|
onQuickAdd,
|
|
9636
10659
|
className
|
|
9637
10660
|
}) {
|
|
9638
|
-
const [searchQuery, setSearchQuery] =
|
|
9639
|
-
const [activeTag, setActiveTag] =
|
|
9640
|
-
const collectionTags =
|
|
10661
|
+
const [searchQuery, setSearchQuery] = React10.useState("");
|
|
10662
|
+
const [activeTag, setActiveTag] = React10.useState(null);
|
|
10663
|
+
const collectionTags = React10.useMemo(() => {
|
|
9641
10664
|
const tagSet = /* @__PURE__ */ new Set();
|
|
9642
10665
|
for (const p of products) {
|
|
9643
10666
|
if (p.tags) {
|
|
@@ -9646,7 +10669,7 @@ function DefaultCollectionLayout({
|
|
|
9646
10669
|
}
|
|
9647
10670
|
return Array.from(tagSet).slice(0, 6);
|
|
9648
10671
|
}, [products]);
|
|
9649
|
-
const filtered =
|
|
10672
|
+
const filtered = React10.useMemo(() => {
|
|
9650
10673
|
let result = products;
|
|
9651
10674
|
if (searchQuery.trim().length >= 2) {
|
|
9652
10675
|
const q = searchQuery.toLowerCase();
|
|
@@ -9721,7 +10744,7 @@ function DefaultCollectionLayout({
|
|
|
9721
10744
|
] })
|
|
9722
10745
|
] }),
|
|
9723
10746
|
filtered.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: filtered.map(
|
|
9724
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
10747
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9725
10748
|
ProductCard,
|
|
9726
10749
|
{
|
|
9727
10750
|
product,
|
|
@@ -9774,7 +10797,7 @@ function FeaturedCollectionLayout({
|
|
|
9774
10797
|
] })
|
|
9775
10798
|
] }),
|
|
9776
10799
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6", children: products.map(
|
|
9777
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
10800
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9778
10801
|
ProductCard,
|
|
9779
10802
|
{
|
|
9780
10803
|
product,
|
|
@@ -9796,10 +10819,10 @@ function CatalogueCollectionLayout({
|
|
|
9796
10819
|
onQuickAdd,
|
|
9797
10820
|
className
|
|
9798
10821
|
}) {
|
|
9799
|
-
const [searchQuery, setSearchQuery] =
|
|
9800
|
-
const [activeCategory, setActiveCategory] =
|
|
9801
|
-
const [sortBy, setSortBy] =
|
|
9802
|
-
const categories =
|
|
10822
|
+
const [searchQuery, setSearchQuery] = React10.useState("");
|
|
10823
|
+
const [activeCategory, setActiveCategory] = React10.useState(null);
|
|
10824
|
+
const [sortBy, setSortBy] = React10.useState("default");
|
|
10825
|
+
const categories = React10.useMemo(() => {
|
|
9803
10826
|
const cats = /* @__PURE__ */ new Map();
|
|
9804
10827
|
for (const p of products) {
|
|
9805
10828
|
if (p.category_id && p.tags) {
|
|
@@ -9810,7 +10833,7 @@ function CatalogueCollectionLayout({
|
|
|
9810
10833
|
}
|
|
9811
10834
|
return Array.from(cats.values()).slice(0, 8);
|
|
9812
10835
|
}, [products]);
|
|
9813
|
-
const filtered =
|
|
10836
|
+
const filtered = React10.useMemo(() => {
|
|
9814
10837
|
let result = products;
|
|
9815
10838
|
if (searchQuery.trim().length >= 2) {
|
|
9816
10839
|
const q = searchQuery.toLowerCase();
|
|
@@ -9898,7 +10921,7 @@ function CatalogueCollectionLayout({
|
|
|
9898
10921
|
] })
|
|
9899
10922
|
] }),
|
|
9900
10923
|
filtered.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4", children: filtered.map(
|
|
9901
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
10924
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
9902
10925
|
ProductCard,
|
|
9903
10926
|
{
|
|
9904
10927
|
product,
|
|
@@ -10077,13 +11100,13 @@ function OrderHistoryPage({
|
|
|
10077
11100
|
className,
|
|
10078
11101
|
classNames
|
|
10079
11102
|
}) {
|
|
10080
|
-
const [statusFilter, setStatusFilter] =
|
|
10081
|
-
const [selectedOrder, setSelectedOrder] =
|
|
10082
|
-
const handleTabChange =
|
|
11103
|
+
const [statusFilter, setStatusFilter] = React10.useState(void 0);
|
|
11104
|
+
const [selectedOrder, setSelectedOrder] = React10.useState(null);
|
|
11105
|
+
const handleTabChange = React10.useCallback((value) => {
|
|
10083
11106
|
const filter = STATUS_FILTERS.find((f) => f.tabValue === value);
|
|
10084
11107
|
setStatusFilter(filter?.value);
|
|
10085
11108
|
}, []);
|
|
10086
|
-
const handleOrderClick =
|
|
11109
|
+
const handleOrderClick = React10.useCallback(
|
|
10087
11110
|
(order) => {
|
|
10088
11111
|
if (onOrderNavigate) {
|
|
10089
11112
|
onOrderNavigate(order);
|
|
@@ -10093,7 +11116,7 @@ function OrderHistoryPage({
|
|
|
10093
11116
|
},
|
|
10094
11117
|
[onOrderNavigate]
|
|
10095
11118
|
);
|
|
10096
|
-
const handleBack =
|
|
11119
|
+
const handleBack = React10.useCallback(() => {
|
|
10097
11120
|
setSelectedOrder(null);
|
|
10098
11121
|
}, []);
|
|
10099
11122
|
const activeTabValue = STATUS_FILTERS.find((f) => f.value === statusFilter)?.tabValue ?? "all";
|
|
@@ -10278,7 +11301,7 @@ function DefaultSearchLayout({
|
|
|
10278
11301
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try a different search term" }),
|
|
10279
11302
|
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: clear, className: "text-sm font-medium text-primary mt-4 hover:underline", children: "Clear search" })
|
|
10280
11303
|
] }) : results.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-4", children: results.map(
|
|
10281
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11304
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
10282
11305
|
ProductCard,
|
|
10283
11306
|
{
|
|
10284
11307
|
product,
|
|
@@ -10380,7 +11403,7 @@ function CompactSearchLayout({
|
|
|
10380
11403
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try a different search term" }),
|
|
10381
11404
|
/* @__PURE__ */ jsxRuntime.jsx("button", { onClick: clear, className: "text-sm font-medium text-primary mt-4 hover:underline", children: "Clear search" })
|
|
10382
11405
|
] }) : results.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 lg:grid-cols-3 gap-5", children: results.map(
|
|
10383
|
-
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11406
|
+
(product) => renderCard ? /* @__PURE__ */ jsxRuntime.jsx(React10__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
10384
11407
|
ProductCard,
|
|
10385
11408
|
{
|
|
10386
11409
|
product,
|
|
@@ -10711,11 +11734,11 @@ function DeliveryEstimate({
|
|
|
10711
11734
|
}) {
|
|
10712
11735
|
const context = useOptionalCimplifyClient();
|
|
10713
11736
|
const client = context?.client ?? null;
|
|
10714
|
-
const [result, setResult] =
|
|
10715
|
-
const [isLoading, setIsLoading] =
|
|
10716
|
-
const [error, setError] =
|
|
10717
|
-
const requestIdRef =
|
|
10718
|
-
|
|
11737
|
+
const [result, setResult] = React10.useState(null);
|
|
11738
|
+
const [isLoading, setIsLoading] = React10.useState(true);
|
|
11739
|
+
const [error, setError] = React10.useState(null);
|
|
11740
|
+
const requestIdRef = React10.useRef(0);
|
|
11741
|
+
React10.useEffect(() => {
|
|
10719
11742
|
if (!client) return;
|
|
10720
11743
|
const nextRequestId = ++requestIdRef.current;
|
|
10721
11744
|
setIsLoading(true);
|
|
@@ -10796,10 +11819,10 @@ function CurrencySelector({
|
|
|
10796
11819
|
}) {
|
|
10797
11820
|
const context = useOptionalCimplifyClient();
|
|
10798
11821
|
const client = context?.client ?? null;
|
|
10799
|
-
const [rates, setRates] =
|
|
10800
|
-
const [isLoadingRates, setIsLoadingRates] =
|
|
10801
|
-
const requestIdRef =
|
|
10802
|
-
|
|
11822
|
+
const [rates, setRates] = React10.useState({});
|
|
11823
|
+
const [isLoadingRates, setIsLoadingRates] = React10.useState(false);
|
|
11824
|
+
const requestIdRef = React10.useRef(0);
|
|
11825
|
+
React10.useEffect(() => {
|
|
10803
11826
|
if (!showRate || !baseCurrency || !client) return;
|
|
10804
11827
|
const targets = currencies.filter((c) => c !== baseCurrency);
|
|
10805
11828
|
if (targets.length === 0) return;
|
|
@@ -10944,10 +11967,496 @@ function ResourcePicker({
|
|
|
10944
11967
|
}
|
|
10945
11968
|
);
|
|
10946
11969
|
}
|
|
11970
|
+
function ChatWidget({
|
|
11971
|
+
client: clientProp,
|
|
11972
|
+
businessName = "Support",
|
|
11973
|
+
greeting = "Hi there!",
|
|
11974
|
+
subtitle = "Ask us anything \u2014 we typically reply in a few seconds.",
|
|
11975
|
+
starters,
|
|
11976
|
+
placeholder = "Type a message\u2026",
|
|
11977
|
+
position = "bottom-right",
|
|
11978
|
+
defaultOpen = false,
|
|
11979
|
+
pollInterval,
|
|
11980
|
+
className,
|
|
11981
|
+
classNames
|
|
11982
|
+
}) {
|
|
11983
|
+
const context = useOptionalCimplifyClient();
|
|
11984
|
+
const client = clientProp ?? context?.client;
|
|
11985
|
+
const [open, setOpen] = React10.useState(defaultOpen);
|
|
11986
|
+
const [unread, setUnread] = React10.useState(0);
|
|
11987
|
+
const { messages, isLoading, isSending, error, isActive, send, startConversation } = useChat({ client, pollInterval });
|
|
11988
|
+
const prevCountRef = React10.useRef(messages.length);
|
|
11989
|
+
React10.useEffect(() => {
|
|
11990
|
+
if (!open && messages.length > prevCountRef.current) {
|
|
11991
|
+
const newMessages = messages.slice(prevCountRef.current);
|
|
11992
|
+
const incomingCount = newMessages.filter(
|
|
11993
|
+
(m) => m.sender_type !== "customer"
|
|
11994
|
+
).length;
|
|
11995
|
+
if (incomingCount > 0) setUnread((n) => n + incomingCount);
|
|
11996
|
+
}
|
|
11997
|
+
prevCountRef.current = messages.length;
|
|
11998
|
+
}, [messages, open]);
|
|
11999
|
+
const handleOpen = React10.useCallback(() => {
|
|
12000
|
+
setOpen(true);
|
|
12001
|
+
setUnread(0);
|
|
12002
|
+
}, []);
|
|
12003
|
+
const handleClose = React10.useCallback(() => setOpen(false), []);
|
|
12004
|
+
const isLeft = position === "bottom-left";
|
|
12005
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12006
|
+
"div",
|
|
12007
|
+
{
|
|
12008
|
+
className: cn(
|
|
12009
|
+
"fixed bottom-6 z-[9999]",
|
|
12010
|
+
isLeft ? "left-6" : "right-6",
|
|
12011
|
+
className,
|
|
12012
|
+
classNames?.root
|
|
12013
|
+
),
|
|
12014
|
+
children: [
|
|
12015
|
+
!open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12016
|
+
Bubble,
|
|
12017
|
+
{
|
|
12018
|
+
unread,
|
|
12019
|
+
onClick: handleOpen,
|
|
12020
|
+
className: classNames?.bubble
|
|
12021
|
+
}
|
|
12022
|
+
),
|
|
12023
|
+
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12024
|
+
Panel,
|
|
12025
|
+
{
|
|
12026
|
+
businessName,
|
|
12027
|
+
greeting,
|
|
12028
|
+
subtitle,
|
|
12029
|
+
starters,
|
|
12030
|
+
placeholder,
|
|
12031
|
+
messages,
|
|
12032
|
+
isLoading,
|
|
12033
|
+
isSending,
|
|
12034
|
+
error,
|
|
12035
|
+
isActive,
|
|
12036
|
+
isLeft,
|
|
12037
|
+
onClose: handleClose,
|
|
12038
|
+
onSend: send,
|
|
12039
|
+
onStartConversation: startConversation,
|
|
12040
|
+
classNames
|
|
12041
|
+
}
|
|
12042
|
+
)
|
|
12043
|
+
]
|
|
12044
|
+
}
|
|
12045
|
+
);
|
|
12046
|
+
}
|
|
12047
|
+
function Bubble({
|
|
12048
|
+
unread,
|
|
12049
|
+
onClick,
|
|
12050
|
+
className
|
|
12051
|
+
}) {
|
|
12052
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12053
|
+
"button",
|
|
12054
|
+
{
|
|
12055
|
+
type: "button",
|
|
12056
|
+
onClick,
|
|
12057
|
+
"aria-label": "Open chat",
|
|
12058
|
+
className: cn(
|
|
12059
|
+
"relative flex h-14 w-14 items-center justify-center rounded-full",
|
|
12060
|
+
"bg-foreground text-background shadow-lg",
|
|
12061
|
+
"transition-transform duration-300 ease-out",
|
|
12062
|
+
"hover:scale-[1.08] active:scale-95",
|
|
12063
|
+
className
|
|
12064
|
+
),
|
|
12065
|
+
children: [
|
|
12066
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChatIcon, { className: "h-6 w-6" }),
|
|
12067
|
+
unread > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12068
|
+
"span",
|
|
12069
|
+
{
|
|
12070
|
+
className: cn(
|
|
12071
|
+
"absolute -right-0.5 -top-0.5 flex h-5 w-5 items-center justify-center",
|
|
12072
|
+
"rounded-full bg-red-500 text-[10px] font-bold text-white",
|
|
12073
|
+
"ring-2 ring-background"
|
|
12074
|
+
),
|
|
12075
|
+
children: unread > 9 ? "9+" : unread
|
|
12076
|
+
}
|
|
12077
|
+
)
|
|
12078
|
+
]
|
|
12079
|
+
}
|
|
12080
|
+
);
|
|
12081
|
+
}
|
|
12082
|
+
function Panel({
|
|
12083
|
+
businessName,
|
|
12084
|
+
greeting,
|
|
12085
|
+
subtitle,
|
|
12086
|
+
starters,
|
|
12087
|
+
placeholder,
|
|
12088
|
+
messages,
|
|
12089
|
+
isLoading,
|
|
12090
|
+
isSending,
|
|
12091
|
+
error,
|
|
12092
|
+
isActive,
|
|
12093
|
+
isLeft,
|
|
12094
|
+
onClose,
|
|
12095
|
+
onSend,
|
|
12096
|
+
onStartConversation,
|
|
12097
|
+
classNames
|
|
12098
|
+
}) {
|
|
12099
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12100
|
+
"div",
|
|
12101
|
+
{
|
|
12102
|
+
className: cn(
|
|
12103
|
+
"flex flex-col overflow-hidden rounded-2xl bg-background shadow-2xl",
|
|
12104
|
+
"w-[400px] max-w-[calc(100vw-3rem)]",
|
|
12105
|
+
"h-[min(600px,calc(100vh-6rem))]",
|
|
12106
|
+
"animate-in fade-in slide-in-from-bottom-4 duration-300",
|
|
12107
|
+
isLeft ? "origin-bottom-left" : "origin-bottom-right",
|
|
12108
|
+
classNames?.panel
|
|
12109
|
+
),
|
|
12110
|
+
children: [
|
|
12111
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12112
|
+
Header,
|
|
12113
|
+
{
|
|
12114
|
+
businessName,
|
|
12115
|
+
onClose,
|
|
12116
|
+
className: classNames?.header
|
|
12117
|
+
}
|
|
12118
|
+
),
|
|
12119
|
+
!isActive && !isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12120
|
+
Welcome,
|
|
12121
|
+
{
|
|
12122
|
+
greeting,
|
|
12123
|
+
subtitle,
|
|
12124
|
+
starters,
|
|
12125
|
+
onStarter: onStartConversation,
|
|
12126
|
+
className: classNames?.welcome
|
|
12127
|
+
}
|
|
12128
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
12129
|
+
MessageList,
|
|
12130
|
+
{
|
|
12131
|
+
messages,
|
|
12132
|
+
isLoading,
|
|
12133
|
+
isSending,
|
|
12134
|
+
className: classNames?.messages
|
|
12135
|
+
}
|
|
12136
|
+
),
|
|
12137
|
+
error != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-red-200 bg-red-50 px-4 py-2 text-xs text-red-600", children: "Something went wrong. Please try again." }),
|
|
12138
|
+
(isActive || isLoading) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
12139
|
+
ChatInput,
|
|
12140
|
+
{
|
|
12141
|
+
placeholder,
|
|
12142
|
+
isSending,
|
|
12143
|
+
onSend,
|
|
12144
|
+
className: classNames?.input
|
|
12145
|
+
}
|
|
12146
|
+
),
|
|
12147
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 border-t border-border bg-background px-4 py-1.5 text-center text-[10px] text-muted-foreground", children: [
|
|
12148
|
+
"Powered by",
|
|
12149
|
+
" ",
|
|
12150
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "Cimplify" })
|
|
12151
|
+
] })
|
|
12152
|
+
]
|
|
12153
|
+
}
|
|
12154
|
+
);
|
|
12155
|
+
}
|
|
12156
|
+
function Header({
|
|
12157
|
+
businessName,
|
|
12158
|
+
onClose,
|
|
12159
|
+
className
|
|
12160
|
+
}) {
|
|
12161
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12162
|
+
"div",
|
|
12163
|
+
{
|
|
12164
|
+
className: cn(
|
|
12165
|
+
"flex flex-shrink-0 items-center gap-3 bg-foreground px-5 py-4 text-background",
|
|
12166
|
+
className
|
|
12167
|
+
),
|
|
12168
|
+
children: [
|
|
12169
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-[10px] bg-white/15", children: /* @__PURE__ */ jsxRuntime.jsx(ChatIcon, { className: "h-5 w-5" }) }),
|
|
12170
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
12171
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "truncate text-[15px] font-semibold leading-tight", children: businessName }),
|
|
12172
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs text-white/60", children: [
|
|
12173
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-[7px] w-[7px] flex-shrink-0 rounded-full bg-emerald-400" }),
|
|
12174
|
+
"Online"
|
|
12175
|
+
] })
|
|
12176
|
+
] }),
|
|
12177
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12178
|
+
"button",
|
|
12179
|
+
{
|
|
12180
|
+
type: "button",
|
|
12181
|
+
onClick: onClose,
|
|
12182
|
+
"aria-label": "Close chat",
|
|
12183
|
+
className: cn(
|
|
12184
|
+
"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg",
|
|
12185
|
+
"bg-white/10 text-white/70 transition-colors hover:bg-white/20 hover:text-white"
|
|
12186
|
+
),
|
|
12187
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, { className: "h-[18px] w-[18px]" })
|
|
12188
|
+
}
|
|
12189
|
+
)
|
|
12190
|
+
]
|
|
12191
|
+
}
|
|
12192
|
+
);
|
|
12193
|
+
}
|
|
12194
|
+
function Welcome({
|
|
12195
|
+
greeting,
|
|
12196
|
+
subtitle,
|
|
12197
|
+
starters,
|
|
12198
|
+
onStarter,
|
|
12199
|
+
className
|
|
12200
|
+
}) {
|
|
12201
|
+
const defaultStarters = [
|
|
12202
|
+
{ icon: "\u{1F50D}", text: "Help me find a product" },
|
|
12203
|
+
{ icon: "\u{1F6D2}", text: "Check my cart" },
|
|
12204
|
+
{ icon: "\u{1F4E6}", text: "Track my order" }
|
|
12205
|
+
];
|
|
12206
|
+
const items = starters ?? defaultStarters;
|
|
12207
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12208
|
+
"div",
|
|
12209
|
+
{
|
|
12210
|
+
className: cn(
|
|
12211
|
+
"flex flex-1 flex-col items-center justify-center overflow-y-auto bg-muted/50 px-8 py-10 text-center",
|
|
12212
|
+
className
|
|
12213
|
+
),
|
|
12214
|
+
children: [
|
|
12215
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-5 flex h-16 w-16 items-center justify-center rounded-2xl bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx(ChatIcon, { className: "h-7 w-7 text-muted-foreground" }) }),
|
|
12216
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-2 text-xl font-bold text-foreground", children: greeting }),
|
|
12217
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-6 max-w-[280px] text-sm leading-relaxed text-muted-foreground", children: subtitle }),
|
|
12218
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full max-w-[300px] flex-col gap-2", children: items.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12219
|
+
"button",
|
|
12220
|
+
{
|
|
12221
|
+
type: "button",
|
|
12222
|
+
onClick: () => onStarter(s.text),
|
|
12223
|
+
className: cn(
|
|
12224
|
+
"flex items-center gap-3 rounded-xl border border-border bg-background px-4 py-3",
|
|
12225
|
+
"text-left text-[13px] font-medium text-foreground",
|
|
12226
|
+
"transition-all hover:-translate-y-px hover:border-foreground hover:shadow-sm"
|
|
12227
|
+
),
|
|
12228
|
+
children: [
|
|
12229
|
+
s.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-muted text-[15px]", children: s.icon }),
|
|
12230
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: s.text })
|
|
12231
|
+
]
|
|
12232
|
+
},
|
|
12233
|
+
s.text
|
|
12234
|
+
)) })
|
|
12235
|
+
]
|
|
12236
|
+
}
|
|
12237
|
+
);
|
|
12238
|
+
}
|
|
12239
|
+
function MessageList({
|
|
12240
|
+
messages,
|
|
12241
|
+
isLoading,
|
|
12242
|
+
isSending,
|
|
12243
|
+
className
|
|
12244
|
+
}) {
|
|
12245
|
+
const bottomRef = React10.useRef(null);
|
|
12246
|
+
React10.useEffect(() => {
|
|
12247
|
+
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
12248
|
+
}, [messages.length, isSending]);
|
|
12249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12250
|
+
"div",
|
|
12251
|
+
{
|
|
12252
|
+
className: cn(
|
|
12253
|
+
"flex flex-1 flex-col gap-1 overflow-y-auto bg-muted/50 px-5 py-5",
|
|
12254
|
+
className
|
|
12255
|
+
),
|
|
12256
|
+
children: [
|
|
12257
|
+
isLoading && messages.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}) }),
|
|
12258
|
+
messages.map((msg, i) => {
|
|
12259
|
+
const isCustomer = msg.sender_type === "customer";
|
|
12260
|
+
const prev = messages[i - 1];
|
|
12261
|
+
const sameSenderAsPrev = prev?.sender_type === msg.sender_type;
|
|
12262
|
+
const isOptimistic = msg.id.startsWith("opt_");
|
|
12263
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
12264
|
+
!sameSenderAsPrev && i > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3" }),
|
|
12265
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12266
|
+
"div",
|
|
12267
|
+
{
|
|
12268
|
+
className: cn(
|
|
12269
|
+
"flex max-w-[85%]",
|
|
12270
|
+
isCustomer ? "ml-auto" : "mr-auto"
|
|
12271
|
+
),
|
|
12272
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12273
|
+
"div",
|
|
12274
|
+
{
|
|
12275
|
+
className: cn(
|
|
12276
|
+
"rounded-2xl px-3.5 py-2.5 text-sm leading-relaxed",
|
|
12277
|
+
isCustomer ? "bg-foreground text-background" : "border border-border bg-background text-foreground",
|
|
12278
|
+
isCustomer ? sameSenderAsPrev ? "rounded-tr" : "rounded-br" : sameSenderAsPrev ? "rounded-tl" : "rounded-bl",
|
|
12279
|
+
isOptimistic && "opacity-70"
|
|
12280
|
+
),
|
|
12281
|
+
children: [
|
|
12282
|
+
!isCustomer && !sameSenderAsPrev && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mb-1 inline-flex items-center gap-1 rounded bg-violet-100 px-1.5 py-0.5 text-[10px] font-semibold text-violet-600", children: [
|
|
12283
|
+
/* @__PURE__ */ jsxRuntime.jsx(SparkleIcon, { className: "h-[11px] w-[11px]" }),
|
|
12284
|
+
"AI"
|
|
12285
|
+
] }),
|
|
12286
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "whitespace-pre-wrap", children: msg.content })
|
|
12287
|
+
]
|
|
12288
|
+
}
|
|
12289
|
+
)
|
|
12290
|
+
}
|
|
12291
|
+
)
|
|
12292
|
+
] }, msg.id);
|
|
12293
|
+
}),
|
|
12294
|
+
isSending && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mr-auto mt-1", children: /* @__PURE__ */ jsxRuntime.jsx(TypingDots, {}) }),
|
|
12295
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: bottomRef })
|
|
12296
|
+
]
|
|
12297
|
+
}
|
|
12298
|
+
);
|
|
12299
|
+
}
|
|
12300
|
+
function ChatInput({
|
|
12301
|
+
placeholder,
|
|
12302
|
+
isSending,
|
|
12303
|
+
onSend,
|
|
12304
|
+
className
|
|
12305
|
+
}) {
|
|
12306
|
+
const [value, setValue] = React10.useState("");
|
|
12307
|
+
const textareaRef = React10.useRef(null);
|
|
12308
|
+
const handleSend = React10.useCallback(() => {
|
|
12309
|
+
const trimmed = value.trim();
|
|
12310
|
+
if (!trimmed || isSending) return;
|
|
12311
|
+
setValue("");
|
|
12312
|
+
if (textareaRef.current) {
|
|
12313
|
+
textareaRef.current.style.height = "auto";
|
|
12314
|
+
}
|
|
12315
|
+
onSend(trimmed);
|
|
12316
|
+
}, [value, isSending, onSend]);
|
|
12317
|
+
const handleKeyDown = React10.useCallback(
|
|
12318
|
+
(e) => {
|
|
12319
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
12320
|
+
e.preventDefault();
|
|
12321
|
+
handleSend();
|
|
12322
|
+
}
|
|
12323
|
+
},
|
|
12324
|
+
[handleSend]
|
|
12325
|
+
);
|
|
12326
|
+
const handleInput = React10.useCallback(() => {
|
|
12327
|
+
const el = textareaRef.current;
|
|
12328
|
+
if (!el) return;
|
|
12329
|
+
el.style.height = "auto";
|
|
12330
|
+
el.style.height = `${Math.min(el.scrollHeight, 100)}px`;
|
|
12331
|
+
}, []);
|
|
12332
|
+
const hasContent = value.trim().length > 0;
|
|
12333
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12334
|
+
"div",
|
|
12335
|
+
{
|
|
12336
|
+
className: cn(
|
|
12337
|
+
"flex flex-shrink-0 items-end gap-2 border-t border-border bg-background px-4 py-3",
|
|
12338
|
+
className
|
|
12339
|
+
),
|
|
12340
|
+
children: [
|
|
12341
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12342
|
+
"div",
|
|
12343
|
+
{
|
|
12344
|
+
className: cn(
|
|
12345
|
+
"flex flex-1 items-end rounded-xl border-[1.5px] border-transparent bg-muted px-1",
|
|
12346
|
+
"transition-colors focus-within:border-foreground focus-within:bg-background"
|
|
12347
|
+
),
|
|
12348
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12349
|
+
"textarea",
|
|
12350
|
+
{
|
|
12351
|
+
ref: textareaRef,
|
|
12352
|
+
value,
|
|
12353
|
+
onChange: (e) => setValue(e.target.value),
|
|
12354
|
+
onKeyDown: handleKeyDown,
|
|
12355
|
+
onInput: handleInput,
|
|
12356
|
+
placeholder,
|
|
12357
|
+
rows: 1,
|
|
12358
|
+
className: cn(
|
|
12359
|
+
"max-h-[100px] min-h-[20px] flex-1 resize-none bg-transparent px-2.5 py-2",
|
|
12360
|
+
"text-sm text-foreground outline-none placeholder:text-muted-foreground"
|
|
12361
|
+
)
|
|
12362
|
+
}
|
|
12363
|
+
)
|
|
12364
|
+
}
|
|
12365
|
+
),
|
|
12366
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12367
|
+
"button",
|
|
12368
|
+
{
|
|
12369
|
+
type: "button",
|
|
12370
|
+
onClick: handleSend,
|
|
12371
|
+
disabled: !hasContent || isSending,
|
|
12372
|
+
"aria-label": "Send message",
|
|
12373
|
+
className: cn(
|
|
12374
|
+
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-[10px]",
|
|
12375
|
+
"transition-all duration-200",
|
|
12376
|
+
hasContent && !isSending ? "bg-foreground text-background hover:scale-105 active:scale-95" : "bg-muted text-muted-foreground"
|
|
12377
|
+
),
|
|
12378
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SendIcon, { className: "h-[18px] w-[18px]" })
|
|
12379
|
+
}
|
|
12380
|
+
)
|
|
12381
|
+
]
|
|
12382
|
+
}
|
|
12383
|
+
);
|
|
12384
|
+
}
|
|
12385
|
+
function TypingDots() {
|
|
12386
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 px-4 py-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12387
|
+
"span",
|
|
12388
|
+
{
|
|
12389
|
+
className: "h-[7px] w-[7px] animate-bounce rounded-full bg-muted-foreground/40",
|
|
12390
|
+
style: { animationDelay: `${i * 160}ms` }
|
|
12391
|
+
},
|
|
12392
|
+
i
|
|
12393
|
+
)) });
|
|
12394
|
+
}
|
|
12395
|
+
function ChatIcon({ className }) {
|
|
12396
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12397
|
+
"svg",
|
|
12398
|
+
{
|
|
12399
|
+
className,
|
|
12400
|
+
viewBox: "0 0 24 24",
|
|
12401
|
+
fill: "none",
|
|
12402
|
+
stroke: "currentColor",
|
|
12403
|
+
strokeWidth: 2,
|
|
12404
|
+
strokeLinecap: "round",
|
|
12405
|
+
strokeLinejoin: "round",
|
|
12406
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z" })
|
|
12407
|
+
}
|
|
12408
|
+
);
|
|
12409
|
+
}
|
|
12410
|
+
function CloseIcon({ className }) {
|
|
12411
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12412
|
+
"svg",
|
|
12413
|
+
{
|
|
12414
|
+
className,
|
|
12415
|
+
viewBox: "0 0 24 24",
|
|
12416
|
+
fill: "none",
|
|
12417
|
+
stroke: "currentColor",
|
|
12418
|
+
strokeWidth: 2,
|
|
12419
|
+
strokeLinecap: "round",
|
|
12420
|
+
strokeLinejoin: "round",
|
|
12421
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
12422
|
+
}
|
|
12423
|
+
);
|
|
12424
|
+
}
|
|
12425
|
+
function SendIcon({ className }) {
|
|
12426
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
12427
|
+
"svg",
|
|
12428
|
+
{
|
|
12429
|
+
className,
|
|
12430
|
+
viewBox: "0 0 24 24",
|
|
12431
|
+
fill: "none",
|
|
12432
|
+
stroke: "currentColor",
|
|
12433
|
+
strokeWidth: 2,
|
|
12434
|
+
strokeLinecap: "round",
|
|
12435
|
+
strokeLinejoin: "round",
|
|
12436
|
+
children: [
|
|
12437
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
|
|
12438
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
|
|
12439
|
+
]
|
|
12440
|
+
}
|
|
12441
|
+
);
|
|
12442
|
+
}
|
|
12443
|
+
function SparkleIcon({ className }) {
|
|
12444
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12445
|
+
"svg",
|
|
12446
|
+
{
|
|
12447
|
+
className,
|
|
12448
|
+
viewBox: "0 0 24 24",
|
|
12449
|
+
fill: "none",
|
|
12450
|
+
stroke: "currentColor",
|
|
12451
|
+
strokeWidth: 2.5,
|
|
12452
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83" })
|
|
12453
|
+
}
|
|
12454
|
+
);
|
|
12455
|
+
}
|
|
10947
12456
|
|
|
10948
12457
|
Object.defineProperty(exports, "getVariantDisplayName", {
|
|
10949
12458
|
enumerable: true,
|
|
10950
|
-
get: function () { return
|
|
12459
|
+
get: function () { return chunkF47XFKYP_js.getVariantDisplayName; }
|
|
10951
12460
|
});
|
|
10952
12461
|
exports.AccommodationCard = AccommodationCard;
|
|
10953
12462
|
exports.Ad = Ad;
|
|
@@ -10973,6 +12482,7 @@ exports.CataloguePage = CataloguePage;
|
|
|
10973
12482
|
exports.CatalogueTemplate = CatalogueTemplate;
|
|
10974
12483
|
exports.CategoryFilter = CategoryFilter;
|
|
10975
12484
|
exports.CategoryGrid = CategoryGrid;
|
|
12485
|
+
exports.ChatWidget = ChatWidget;
|
|
10976
12486
|
exports.CheckoutPage = CheckoutPage;
|
|
10977
12487
|
exports.CimplifyAccount = CimplifyAccount;
|
|
10978
12488
|
exports.CimplifyCheckout = CimplifyCheckout;
|
|
@@ -10988,6 +12498,7 @@ exports.CompositeProductLayout = CompositeProductLayout;
|
|
|
10988
12498
|
exports.CompositeSelector = CompositeSelector;
|
|
10989
12499
|
exports.CurrencySelector = CurrencySelector;
|
|
10990
12500
|
exports.CustomAttributesTable = CustomAttributesTable;
|
|
12501
|
+
exports.CustomerInputFields = CustomerInputFields;
|
|
10991
12502
|
exports.DateSlotPicker = DateSlotPicker;
|
|
10992
12503
|
exports.DealBanner = DealBanner;
|
|
10993
12504
|
exports.DealsPage = DealsPage;
|
|
@@ -11063,6 +12574,7 @@ exports.useBootstrap = useBootstrap;
|
|
|
11063
12574
|
exports.useBundles = useBundles;
|
|
11064
12575
|
exports.useCart = useCart;
|
|
11065
12576
|
exports.useCategories = useCategories;
|
|
12577
|
+
exports.useChat = useChat;
|
|
11066
12578
|
exports.useCheckout = useCheckout;
|
|
11067
12579
|
exports.useCimplify = useCimplify;
|
|
11068
12580
|
exports.useCimplifyClient = useCimplifyClient;
|