@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/react.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkGS7AX6B3_js = require('./chunk-GS7AX6B3.js');
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 React3 = require('react');
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 React3__default = /*#__PURE__*/_interopDefault(React3);
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 = React3.createContext({
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 React3.useContext(AdContext);
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] = React3.useState(null);
218
- const [isLoading, setIsLoading] = React3.useState(true);
219
- const [identity, setIdentity] = React3.useState(null);
220
- React3.useEffect(() => {
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] = React3.useState(null);
244
- const [error, setError] = React3.useState(false);
245
- const impressionTracked = React3.useRef(false);
246
- const containerRef = React3.useRef(null);
247
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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 = React3.useMemo(
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 = React3.useSyncExternalStore(
995
+ const snapshot = React10.useSyncExternalStore(
994
996
  store.subscribe,
995
997
  store.getSnapshot,
996
998
  store.getSnapshot
997
999
  );
998
- React3.useEffect(() => {
1000
+ React10.useEffect(() => {
999
1001
  void store.initialize();
1000
1002
  }, [store]);
1001
- const addItem = React3.useCallback(
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 = React3.useCallback(
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 = React3.useCallback(
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 = React3.useCallback(async () => {
1021
+ const clearCart = React10.useCallback(async () => {
1020
1022
  await store.clearCart();
1021
1023
  }, [store]);
1022
- const sync = React3.useCallback(async () => {
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 = React3.useCallback(
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 = React3.useMemo(
1037
+ const itemCount = React10.useMemo(
1036
1038
  () => snapshot.items.reduce((sum, item) => sum + item.quantity, 0),
1037
1039
  [snapshot.items]
1038
1040
  );
1039
- return React3.useMemo(() => ({
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 chunkGS7AX6B3_js.createCimplifyClient({ publicKey: envPublicKey });
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 = React3.createContext(null);
1122
- var CimplifyStateContext = React3.createContext(null);
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 = React3.useMemo(() => client ?? createDefaultClient(), [client]);
1129
- const onLocationChangeRef = React3.useRef(onLocationChange);
1130
- const [business, setBusiness] = React3.useState(null);
1131
- const [locations, setLocations] = React3.useState([]);
1132
- const [currentLocation, setCurrentLocationState] = React3.useState(null);
1133
- const [isReady, setIsReady] = React3.useState(false);
1134
- React3.useEffect(() => {
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] = React3.useState(
1141
+ const [displayCurrencyOverride, setDisplayCurrencyOverride] = React10.useState(
1140
1142
  () => getStoredDisplayCurrency()
1141
1143
  );
1142
- const [fxRate, setFxRate] = React3.useState(null);
1144
+ const [fxRate, setFxRate] = React10.useState(null);
1143
1145
  const displayCurrency = displayCurrencyOverride && displayCurrencyOverride !== baseCurrency ? displayCurrencyOverride : baseCurrency;
1144
- const setDisplayCurrency = React3.useCallback(
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
- React3.useEffect(() => {
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 = React3.useCallback(
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 = React3.useCallback(
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
- React3.useEffect(() => {
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 = React3.useMemo(
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 = React3.useMemo(
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 = React3.useContext(CimplifyClientContext);
1303
- const stateContext = React3.useContext(CimplifyStateContext);
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 React3.useMemo(
1309
+ return React10.useMemo(
1308
1310
  () => ({ ...clientContext, ...stateContext }),
1309
1311
  [clientContext, stateContext]
1310
1312
  );
1311
1313
  }
1312
1314
  function useOptionalCimplify() {
1313
- const clientContext = React3.useContext(CimplifyClientContext);
1314
- const stateContext = React3.useContext(CimplifyStateContext);
1315
- return React3.useMemo(() => {
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 = React3.useContext(CimplifyClientContext);
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 React3.useContext(CimplifyClientContext);
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 = React3.useMemo(
1390
+ const resolvedOrderTypes = React10.useMemo(
1389
1391
  () => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
1390
1392
  [orderTypes]
1391
1393
  );
1392
- const resolvedDefaultOrderType = React3.useMemo(() => {
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] = React3.useState(resolvedDefaultOrderType);
1399
- const [status, setStatus] = React3.useState(null);
1400
- const [statusText, setStatusText] = React3.useState("");
1401
- const [isSubmitting, setIsSubmitting] = React3.useState(false);
1402
- const [isInitializing, setIsInitializing] = React3.useState(false);
1403
- const [errorMessage, setErrorMessage] = React3.useState(null);
1404
- const [resolvedBusinessId, setResolvedBusinessId] = React3.useState(businessId ?? null);
1405
- const [resolvedCartId, setResolvedCartId] = React3.useState(cartId ?? null);
1406
- const [resolvedCart, setResolvedCart] = React3.useState(null);
1407
- const checkoutMountRef = React3.useRef(null);
1408
- const elementsRef = React3.useRef(null);
1409
- const activeCheckoutRef = React3.useRef(null);
1410
- const initialAppearanceRef = React3.useRef(appearance);
1411
- const hasWarnedInlineAppearanceRef = React3.useRef(false);
1412
- const isMountedRef = React3.useRef(true);
1413
- const demoRunRef = React3.useRef(0);
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 = React3.useMemo(() => {
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 = React3.useRef(fxOptions);
1427
+ const fxOptionsRef = React10.useRef(fxOptions);
1426
1428
  fxOptionsRef.current = fxOptions;
1427
- const resolvedCartRef = React3.useRef(resolvedCart);
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 = React3__default.default.useEffectEvent(
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 = React3__default.default.useEffectEvent(
1440
+ const fireError = React10__default.default.useEffectEvent(
1439
1441
  (error) => {
1440
1442
  onError?.(error);
1441
1443
  }
1442
1444
  );
1443
- React3.useEffect(() => {
1445
+ React10.useEffect(() => {
1444
1446
  if (!resolvedOrderTypes.includes(orderType)) {
1445
1447
  setOrderType(resolvedDefaultOrderType);
1446
1448
  }
1447
1449
  }, [resolvedOrderTypes, resolvedDefaultOrderType, orderType]);
1448
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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 = React3__default.default.useEffectEvent(async () => {
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
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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 = React3.useRef(null);
1721
- const [height, setHeight] = React3.useState(400);
1722
- const [isReady, setIsReady] = React3.useState(false);
1723
- const iframeSrc = React3.useMemo(() => {
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
- React3.useEffect(() => {
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 = React3.useRef(locationId);
1835
- const requestIdRef = React3.useRef(0);
1836
- const optionsRef = React3.useRef(options);
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] = React3.useState(cached?.data ?? null);
1847
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
1848
- const [error, setError] = React3.useState(null);
1849
- const load = React3.useCallback(
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
- React3.useEffect(() => {
1894
+ React10.useEffect(() => {
1893
1895
  void load(false);
1894
1896
  }, [load]);
1895
- const refetch = React3.useCallback(async () => {
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 = React3.useMemo(() => (orderId || "").trim(), [orderId]);
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 = React3.useRef(0);
2030
- const previousStatusRef = React3.useRef(null);
2031
- const onStatusChangeRef = React3.useRef(options.onStatusChange);
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 = React3.useMemo(
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] = React3.useState(cached?.order ?? null);
2039
- const [isLoading, setIsLoading] = React3.useState(
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] = React3.useState(null);
2043
- const load = React3.useCallback(
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
- React3.useEffect(() => {
2104
+ React10.useEffect(() => {
2103
2105
  void load(false);
2104
2106
  }, [load]);
2105
2107
  const isTerminal = order ? TERMINAL_STATUSES.has(order.status) : false;
2106
- React3.useEffect(() => {
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 = React3.useCallback(async () => {
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] = React3.useState([]);
2169
- const [currentLocation, setCurrentLocationState] = React3.useState(null);
2170
- const [isLoading, setIsLoading] = React3.useState(true);
2171
- const setCurrentLocation = React3.useCallback(
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
- React3.useEffect(() => {
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] = React3.useState("");
2286
- const [results, setResults] = React3.useState([]);
2287
- const [isLoading, setIsLoading] = React3.useState(false);
2288
- const [error, setError] = React3.useState(null);
2289
- const requestIdRef = React3.useRef(0);
2290
- const timerRef = React3.useRef(null);
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
- React3.useEffect(() => {
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 = React3.useCallback((nextQuery) => {
2349
+ const setQuery = React10.useCallback((nextQuery) => {
2348
2350
  setQueryState(nextQuery);
2349
2351
  }, []);
2350
- const clear = React3.useCallback(() => {
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 = React3.useRef(0);
2442
- const debounceTimerRef = React3.useRef(null);
2443
+ const requestIdRef = React10.useRef(0);
2444
+ const debounceTimerRef = React10.useRef(null);
2443
2445
  const inputSignature = buildQuoteInputSignature(input);
2444
- const normalizedInput = React3.useMemo(() => {
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 = React3.useMemo(
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] = React3.useState(cached?.quote ?? null);
2457
- const [isLoading, setIsLoading] = React3.useState(enabled && normalizedInput !== null && !cached);
2458
- const [error, setError] = React3.useState(null);
2459
- const [isExpired, setIsExpired] = React3.useState(isQuoteExpired(cached?.quote ?? null));
2460
- const [messages, setMessages] = React3.useState(cached?.quote?.ui_messages ?? []);
2461
- const quoteExpiryTimestamp = React3.useMemo(() => {
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 = React3.useCallback(
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
- React3.useEffect(() => {
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 = React3.useCallback(async () => {
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
- React3.useEffect(() => {
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] = React3.useState(false);
2761
- const [error, setError] = React3.useState(null);
2762
- const validate = React3.useCallback(
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 React3.useMemo(() => {
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] = React3.useState([]);
2859
- const [isLoading, setIsLoading] = React3.useState(false);
2860
- const [error, setError] = React3.useState(null);
2861
- const fetch2 = React3.useCallback(async () => {
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
- React3.useEffect(() => {
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] = React3.useState(null);
2889
- const [isLoading, setIsLoading] = React3.useState(false);
2890
- const [error, setError] = React3.useState(null);
2891
- const fetch2 = React3.useCallback(async () => {
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
- React3.useEffect(() => {
2910
+ React10.useEffect(() => {
2909
2911
  void fetch2();
2910
2912
  }, [fetch2]);
2911
- const cancel = React3.useCallback(async (reason) => {
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 = React3.useCallback(async () => {
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 = React3.useCallback(async () => {
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 = React3.useCallback(async () => {
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 = React3.useCallback(
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 = React3.useRef(0);
3087
- const [plans, setPlans] = React3.useState([]);
3088
- const [isLoading, setIsLoading] = React3.useState(enabled && !!productId);
3089
- const [error, setError] = React3.useState(null);
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 = React3.useCallback(
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
- React3.useEffect(() => {
3130
+ React10.useEffect(() => {
3129
3131
  void load(false);
3130
3132
  }, [load]);
3131
- const refetch = React3.useCallback(async () => {
3133
+ const refetch = React10.useCallback(async () => {
3132
3134
  await load(true);
3133
3135
  }, [load]);
3134
- const subscriptionPlans = React3.useMemo(
3136
+ const subscriptionPlans = React10.useMemo(
3135
3137
  () => plans.filter((p) => p.plan_type === "subscription"),
3136
3138
  [plans]
3137
3139
  );
3138
- const installmentPlans = React3.useMemo(
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] = React3.useState({});
3174
- const selectValue = React3.useCallback(
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 = React3.useCallback(() => setSelectedValues({}), []);
3188
- const selectedVariant = React3.useMemo(
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 = React3.useMemo(
3194
+ const variantImage = React10.useMemo(
3193
3195
  () => selectedVariant?.images?.[0] ?? null,
3194
3196
  [selectedVariant]
3195
3197
  );
3196
- const availableValues = React3.useMemo(
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 = React3.useCallback(
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 ElementsContext = React3.createContext({
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 React3.useContext(ElementsContext).elements;
3439
+ return React10.useContext(ElementsContext).elements;
3322
3440
  }
3323
3441
  function useElementsReady() {
3324
- return React3.useContext(ElementsContext).isReady;
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] = React3.useState(null);
3333
- const [isReady, setIsReady] = React3.useState(false);
3334
- const initialOptionsRef = React3.useRef(options);
3335
- React3.useEffect(() => {
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 = React3.useRef(null);
3377
- const elementRef = React3.useRef(null);
3494
+ const containerRef = React10.useRef(null);
3495
+ const elementRef = React10.useRef(null);
3378
3496
  const elements = useElements();
3379
- const onReadyRef = React3.useRef(onReady);
3380
- const onAuthenticatedRef = React3.useRef(onAuthenticated);
3381
- const onRequiresOtpRef = React3.useRef(onRequiresOtp);
3382
- const onErrorRef = React3.useRef(onError);
3383
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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 = React3.useRef(null);
3420
- const elementRef = React3.useRef(null);
3537
+ const containerRef = React10.useRef(null);
3538
+ const elementRef = React10.useRef(null);
3421
3539
  const elements = useElements();
3422
- const onReadyRef = React3.useRef(onReady);
3423
- const onChangeRef = React3.useRef(onChange);
3424
- const onErrorRef = React3.useRef(onError);
3425
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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 = React3.useRef(null);
3458
- const elementRef = React3.useRef(null);
3575
+ const containerRef = React10.useRef(null);
3576
+ const elementRef = React10.useRef(null);
3459
3577
  const elements = useElements();
3460
- const onReadyRef = React3.useRef(onReady);
3461
- const onChangeRef = React3.useRef(onChange);
3462
- const onErrorRef = React3.useRef(onError);
3463
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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] = React3.useState(false);
3489
- const submit = React3.useCallback(
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 = React3.useCallback(
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] = React3.useState({});
3598
- const initialized = React3.useRef(false);
3599
- const idPrefix = React3.useId();
3600
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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
- React3.useEffect(() => {
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: chunkGS7AX6B3_js.getVariantDisplayName(variant, productName)
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 = React3.useMemo(() => new Set(selectedOptions), [selectedOptions]);
3762
- const isOptionSelected = React3.useCallback(
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 = React3.useCallback(
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] = React3.useState({});
3943
- const lastComponentIds = React3.useRef("");
3944
- React3.useEffect(() => {
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 = React3.useMemo(() => {
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
- React3.useEffect(() => {
4086
+ React10.useEffect(() => {
3969
4087
  onSelectionsChange(selections);
3970
4088
  }, [selections, onSelectionsChange]);
3971
- React3.useEffect(() => {
4089
+ React10.useEffect(() => {
3972
4090
  onReady?.(components.length > 0 && selections.length > 0);
3973
4091
  }, [components, selections, onReady]);
3974
- const totalPrice = React3.useMemo(() => {
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
- React3.useEffect(() => {
4107
+ React10.useEffect(() => {
3990
4108
  onPriceChange?.(totalPrice);
3991
4109
  }, [totalPrice, onPriceChange]);
3992
- const handleVariantChange = React3.useCallback(
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 = React3.useId();
4191
+ const idPrefix = React10.useId();
4074
4192
  const showVariantPicker = component.allow_variant_choice && component.available_variants.length > 1;
4075
- const displayPrice = React3.useMemo(
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] = React3.useState({});
4224
- const [priceResult, setPriceResult] = React3.useState(null);
4225
- const [isPriceLoading, setIsPriceLoading] = React3.useState(false);
4226
- const [priceError, setPriceError] = React3.useState(false);
4227
- const selections = React3.useMemo(() => {
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
- React3.useEffect(() => {
4356
+ React10.useEffect(() => {
4239
4357
  onSelectionsChange(selections);
4240
4358
  }, [selections, onSelectionsChange]);
4241
- React3.useEffect(() => {
4359
+ React10.useEffect(() => {
4242
4360
  onPriceChange?.(priceResult);
4243
4361
  }, [priceResult, onPriceChange]);
4244
- const allGroupsSatisfied = React3.useMemo(() => {
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 = React3.useMemo(
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
- React3.useEffect(() => {
4377
+ React10.useEffect(() => {
4260
4378
  onReady?.(allGroupsSatisfied);
4261
4379
  }, [allGroupsSatisfied, onReady]);
4262
- React3.useEffect(() => {
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 = React3.useCallback(
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 = React3.useCallback(
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] = React3.useState(product.min_order_quantity ?? 1);
4864
- const [isAdded, setIsAdded] = React3.useState(false);
4865
- const [isSubmitting, setIsSubmitting] = React3.useState(false);
4866
- const [selectedVariantId, setSelectedVariantId] = React3.useState();
4867
- const [selectedVariant, setSelectedVariant] = React3.useState();
4868
- const [selectedAddOnOptionIds, setSelectedAddOnOptionIds] = React3.useState([]);
4869
- const [compositeSelections, setCompositeSelections] = React3.useState([]);
4870
- const [compositePrice, setCompositePrice] = React3.useState(null);
4871
- const [compositeReady, setCompositeReady] = React3.useState(false);
4872
- const [bundleSelections, setBundleSelections] = React3.useState([]);
4873
- const [bundleTotalPrice, setBundleTotalPrice] = React3.useState(null);
4874
- const [bundleReady, setBundleReady] = React3.useState(false);
4875
- const [selectedBillingPlan, setSelectedBillingPlan] = React3.useState(null);
4876
- const [specialInstructions, setSpecialInstructions] = React3.useState("");
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
- React3.useEffect(() => {
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 = React3.useMemo(() => {
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 = React3.useMemo(() => {
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 = React3.useMemo(() => {
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 = React3.useMemo(() => {
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 = React3.useMemo(
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 quoteEnabled = isComposite ? compositeReady : isBundle ? bundleReady : requiredAddOnsSatisfied;
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 = React3.useMemo(() => {
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 = React3.useCallback(
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 = React3.useRef(void 0);
4983
- React3.useEffect(() => () => clearTimeout(addedTimerRef.current), []);
4984
- const handleAddToCart = React3.useCallback(async () => {
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 = React3.useMemo(
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] = React3.useState(0);
5194
- React3.useEffect(() => {
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: chunkGS7AX6B3_js.getVariantDisplayName(item.variant, item.product.name) }),
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 === chunkGS7AX6B3_js.PRODUCT_TYPE.Composite;
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 formatDuration2(minutes, unit) {
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: formatDuration2(product.duration_minutes, product.duration_unit) }),
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 formatDuration3(minutes, unit) {
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: formatDuration3(product.duration_minutes, product.duration_unit) }),
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 ? `${product.duration_minutes} ${product.duration_unit ?? "min"}` : 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 UNIT_LABELS = {
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 ? UNIT_LABELS[product.duration_unit] || product.duration_unit : "day";
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 UNIT_LABELS2 = {
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 ? UNIT_LABELS2[product.duration_unit] || product.duration_unit : "mo";
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([chunkGS7AX6B3_js.DURATION_UNIT.Days, chunkGS7AX6B3_js.DURATION_UNIT.Hours]);
6552
- var LEASE_UNITS = /* @__PURE__ */ new Set([chunkGS7AX6B3_js.DURATION_UNIT.Weeks, chunkGS7AX6B3_js.DURATION_UNIT.Months, chunkGS7AX6B3_js.DURATION_UNIT.Years]);
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 === chunkGS7AX6B3_js.PRODUCT_TYPE.Bundle) {
7586
+ if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Bundle) {
6555
7587
  return "bundle" /* Bundle */;
6556
7588
  }
6557
- if (product.type === chunkGS7AX6B3_js.PRODUCT_TYPE.Composite) {
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 === chunkGS7AX6B3_js.PRODUCT_TYPE.Digital) {
7595
+ if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Digital) {
6564
7596
  return "digital" /* Digital */;
6565
7597
  }
6566
- if (product.type === chunkGS7AX6B3_js.PRODUCT_TYPE.Service) {
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 === chunkGS7AX6B3_js.DURATION_UNIT.Nights) {
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 === chunkGS7AX6B3_js.RENDER_HINT.Food) {
7613
+ if (product.render_hint === chunkF47XFKYP_js.RENDER_HINT.Food) {
6582
7614
  return "food" /* Food */;
6583
7615
  }
6584
- if (product.render_hint === chunkGS7AX6B3_js.RENDER_HINT.Physical) {
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] = React3.useState(false);
6606
- const [shouldFetch, setShouldFetch] = React3.useState(false);
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 = React3.useCallback(() => {
7643
+ const handlePrefetch = React10.useCallback(() => {
6612
7644
  setShouldFetch(true);
6613
7645
  }, []);
6614
- const handleOpenChange = React3.useCallback((open) => {
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 = React3.useCallback(() => {
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 = React3__default.default.useId();
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 = React3__default.default.useMemo(
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 = React3.useMemo(
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 = React3.useCallback(
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 = React3.useCallback(
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] = React3.useState("");
7005
- const [appliedValidation, setAppliedValidation] = React3.useState(null);
8036
+ const [code, setCode] = React10.useState("");
8037
+ const [appliedValidation, setAppliedValidation] = React10.useState(null);
7006
8038
  const { validate, isValidating, error } = useValidateDiscount();
7007
- const handleApply = React3.useCallback(async () => {
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 = React3.useCallback(() => {
8052
+ const handleClear = React10.useCallback(() => {
7021
8053
  setCode("");
7022
8054
  setAppliedValidation(null);
7023
8055
  onClear?.();
7024
8056
  }, [onClear]);
7025
- const handleKeyDown = React3.useCallback(
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 = React3__default.default.useId();
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(React3__default.default.Fragment, { children: renderLineItem(item) }, item.id) : /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-line-item": true, className: classNames?.lineItem, children: [
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] = React3.useState(0);
7778
- const [selectedDate, setSelectedDate] = React3.useState(toDateString(/* @__PURE__ */ new Date()));
7779
- const dateRange = React3.useMemo(() => {
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 = React3.useMemo(() => {
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 = React3.useCallback(() => {
8841
+ const handlePrev = React10.useCallback(() => {
7810
8842
  setOffset((prev) => Math.max(0, prev - daysToShow));
7811
8843
  }, [daysToShow]);
7812
- const handleNext = React3.useCallback(() => {
8844
+ const handleNext = React10.useCallback(() => {
7813
8845
  setOffset((prev) => prev + daysToShow);
7814
8846
  }, [daysToShow]);
7815
- const handleDateChange = React3.useCallback((value) => {
8847
+ const handleDateChange = React10.useCallback((value) => {
7816
8848
  if (typeof value === "string") {
7817
8849
  setSelectedDate(value);
7818
8850
  }
7819
8851
  }, []);
7820
- const handleSlotSelect = React3.useCallback(
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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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] = React3__default.default.useState(value);
8454
- React3__default.default.useEffect(() => {
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] = React3.useState(null);
8479
- const [searchQuery, setSearchQuery] = React3.useState("");
8480
- const [sortBy, setSortBy] = React3.useState(defaultSort?.by ?? "created_at");
8481
- const [sortOrder, setSortOrder] = React3.useState(defaultSort?.order ?? "desc");
8482
- const [inStockOnly, setInStockOnly] = React3.useState(false);
8483
- const [selectedTags, setSelectedTags] = React3.useState([]);
8484
- const [minPrice, setMinPrice] = React3.useState("");
8485
- const [maxPrice, setMaxPrice] = React3.useState("");
8486
- const [page, setPage] = React3.useState(1);
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 = React3.useCallback((id) => {
9539
+ const handleCategoryChange = React10.useCallback((id) => {
8508
9540
  setSelectedCategory(id);
8509
9541
  setPage(1);
8510
9542
  }, []);
8511
- const handleSortChange = React3.useCallback((by, order) => {
9543
+ const handleSortChange = React10.useCallback((by, order) => {
8512
9544
  setSortBy(by);
8513
9545
  setSortOrder(order);
8514
9546
  setPage(1);
8515
9547
  }, []);
8516
- const handleTagToggle = React3.useCallback((tag) => {
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 = React3.useCallback((min, max) => {
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: formatMinutes(product.duration_minutes) }),
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 appointment"
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 === chunkGS7AX6B3_js.PRODUCT_TYPE.Bundle) {
10377
+ if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Bundle) {
9355
10378
  return "bundle" /* Bundle */;
9356
10379
  }
9357
- if (product.type === chunkGS7AX6B3_js.PRODUCT_TYPE.Composite) {
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 === chunkGS7AX6B3_js.PRODUCT_TYPE.Service) {
10386
+ if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Service) {
9364
10387
  return "service" /* Service */;
9365
10388
  }
9366
- if (product.type === chunkGS7AX6B3_js.PRODUCT_TYPE.Digital) {
10389
+ if (product.type === chunkF47XFKYP_js.PRODUCT_TYPE.Digital) {
9367
10390
  return "digital" /* Digital */;
9368
10391
  }
9369
- if (product.render_hint === chunkGS7AX6B3_js.RENDER_HINT.Food) {
10392
+ if (product.render_hint === chunkF47XFKYP_js.RENDER_HINT.Food) {
9370
10393
  return "food" /* Food */;
9371
10394
  }
9372
- if (product.render_hint === chunkGS7AX6B3_js.RENDER_HINT.Physical) {
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] = React3.useState("");
9639
- const [activeTag, setActiveTag] = React3.useState(null);
9640
- const collectionTags = React3.useMemo(() => {
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 = React3.useMemo(() => {
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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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] = React3.useState("");
9800
- const [activeCategory, setActiveCategory] = React3.useState(null);
9801
- const [sortBy, setSortBy] = React3.useState("default");
9802
- const categories = React3.useMemo(() => {
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 = React3.useMemo(() => {
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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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] = React3.useState(void 0);
10081
- const [selectedOrder, setSelectedOrder] = React3.useState(null);
10082
- const handleTabChange = React3.useCallback((value) => {
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 = React3.useCallback(
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 = React3.useCallback(() => {
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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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(React3__default.default.Fragment, { children: renderCard(product) }, product.id) : /* @__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] = React3.useState(null);
10715
- const [isLoading, setIsLoading] = React3.useState(true);
10716
- const [error, setError] = React3.useState(null);
10717
- const requestIdRef = React3.useRef(0);
10718
- React3.useEffect(() => {
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] = React3.useState({});
10800
- const [isLoadingRates, setIsLoadingRates] = React3.useState(false);
10801
- const requestIdRef = React3.useRef(0);
10802
- React3.useEffect(() => {
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 chunkGS7AX6B3_js.getVariantDisplayName; }
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;