@cimplify/sdk 0.18.0 → 0.20.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.
Files changed (40) hide show
  1. package/dist/advanced.d.mts +2 -2
  2. package/dist/advanced.d.ts +2 -2
  3. package/dist/advanced.js +21 -21
  4. package/dist/advanced.mjs +2 -2
  5. package/dist/{chunk-RYQ5IPWX.js → chunk-2BSYTQAY.js} +18 -28
  6. package/dist/{chunk-KTTQC5HG.mjs → chunk-676BJ3EU.mjs} +43 -8
  7. package/dist/{chunk-2JI47EYJ.mjs → chunk-7KH2XJIW.mjs} +67 -12
  8. package/dist/{chunk-MJECWMOY.js → chunk-AVVLN353.js} +76 -40
  9. package/dist/{chunk-FTL2SXCG.mjs → chunk-HG7GG3TT.mjs} +18 -28
  10. package/dist/{chunk-DYKFSV77.js → chunk-KSN3RJFL.js} +86 -30
  11. package/dist/{client-BFFfuzJr.d.mts → client-D4E9aJy7.d.mts} +141 -7
  12. package/dist/{client-B1UtuyOg.d.ts → client-VyO6Bqz2.d.ts} +141 -7
  13. package/dist/index.d.mts +38 -5
  14. package/dist/index.d.ts +38 -5
  15. package/dist/index.js +101 -97
  16. package/dist/index.mjs +3 -3
  17. package/dist/{payment-D9FTaOse.d.mts → payment-CKqMU4xT.d.mts} +1052 -934
  18. package/dist/{payment-D9FTaOse.d.ts → payment-CKqMU4xT.d.ts} +1052 -934
  19. package/dist/{price-BD1iioLh.d.ts → price-BqV_DjjQ.d.mts} +1 -1
  20. package/dist/{price-9JsPuknm.d.mts → price-e4beObLZ.d.ts} +1 -1
  21. package/dist/react.d.mts +463 -11
  22. package/dist/react.d.ts +463 -11
  23. package/dist/react.js +1630 -113
  24. package/dist/react.mjs +1566 -65
  25. package/dist/styles.css +1 -1
  26. package/dist/utils.d.mts +2 -2
  27. package/dist/utils.d.ts +2 -2
  28. package/dist/utils.js +28 -28
  29. package/dist/utils.mjs +1 -1
  30. package/package.json +2 -2
  31. package/registry/availability-badge.json +1 -1
  32. package/registry/booking-page.json +1 -1
  33. package/registry/bundle-selector.json +1 -1
  34. package/registry/cart-summary.json +1 -1
  35. package/registry/composite-selector.json +1 -1
  36. package/registry/order-summary.json +1 -1
  37. package/registry/product-customizer.json +1 -1
  38. package/registry/search-input.json +1 -1
  39. package/registry/service-card.json +1 -1
  40. package/registry/variant-selector.json +1 -1
package/dist/react.js CHANGED
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkMJECWMOY_js = require('./chunk-MJECWMOY.js');
5
- var chunkDYKFSV77_js = require('./chunk-DYKFSV77.js');
6
- var chunkRYQ5IPWX_js = require('./chunk-RYQ5IPWX.js');
4
+ var chunkAVVLN353_js = require('./chunk-AVVLN353.js');
5
+ var chunkKSN3RJFL_js = require('./chunk-KSN3RJFL.js');
6
+ var chunk2BSYTQAY_js = require('./chunk-2BSYTQAY.js');
7
7
  var React3 = require('react');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
9
  var numberField = require('@base-ui/react/number-field');
@@ -447,13 +447,13 @@ function buildLineKey(productId, options) {
447
447
  return parts.join("|");
448
448
  }
449
449
  function calculateLineSubtotal(item) {
450
- let unitPrice = chunkRYQ5IPWX_js.parsePrice(item.product.default_price);
450
+ let unitPrice = chunk2BSYTQAY_js.parsePrice(item.product.default_price);
451
451
  if (item.variant?.price_adjustment) {
452
- unitPrice += chunkRYQ5IPWX_js.parsePrice(item.variant.price_adjustment);
452
+ unitPrice += chunk2BSYTQAY_js.parsePrice(item.variant.price_adjustment);
453
453
  }
454
454
  for (const option of item.addOnOptions || []) {
455
455
  if (option.default_price) {
456
- unitPrice += chunkRYQ5IPWX_js.parsePrice(option.default_price);
456
+ unitPrice += chunk2BSYTQAY_js.parsePrice(option.default_price);
457
457
  }
458
458
  }
459
459
  return roundMoney(unitPrice * item.quantity);
@@ -537,7 +537,12 @@ function mapServerCart(serverCart) {
537
537
  specialInstructions: item.special_instructions,
538
538
  scheduledStart: item.scheduled_start || void 0,
539
539
  scheduledEnd: item.scheduled_end || void 0,
540
- staffId: item.staff_id || void 0
540
+ staffId: item.staff_id || void 0,
541
+ lineType: item.line_type,
542
+ confirmationCode: item.confirmation_code || void 0,
543
+ serviceStatus: item.service_status || void 0,
544
+ bundleResolved: item.bundle_resolved || void 0,
545
+ compositeResolved: item.composite_resolved || void 0
541
546
  });
542
547
  });
543
548
  return {
@@ -1011,7 +1016,7 @@ var DEFAULT_COUNTRY = "US";
1011
1016
  function createDefaultClient() {
1012
1017
  const processRef = globalThis.process;
1013
1018
  const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
1014
- return chunkMJECWMOY_js.createCimplifyClient({ publicKey: envPublicKey });
1019
+ return chunkAVVLN353_js.createCimplifyClient({ publicKey: envPublicKey });
1015
1020
  }
1016
1021
  function getStoredLocationId() {
1017
1022
  if (typeof window === "undefined" || !window.localStorage) {
@@ -1094,7 +1099,7 @@ function CimplifyProvider({
1094
1099
  const setDisplayCurrency = React3.useCallback(
1095
1100
  (currency) => {
1096
1101
  const normalized = currency?.trim().toUpperCase() || null;
1097
- if (normalized && !chunkRYQ5IPWX_js.isSupportedCurrency(normalized)) {
1102
+ if (normalized && !chunk2BSYTQAY_js.isSupportedCurrency(normalized)) {
1098
1103
  return;
1099
1104
  }
1100
1105
  setDisplayCurrencyOverride(normalized);
@@ -1656,7 +1661,7 @@ function Price({ amount, className, prefix }) {
1656
1661
  const { displayCurrency, convertPrice } = useCimplify();
1657
1662
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { className, children: [
1658
1663
  prefix,
1659
- chunkRYQ5IPWX_js.formatPrice(convertPrice(amount), displayCurrency)
1664
+ chunk2BSYTQAY_js.formatPrice(convertPrice(amount), displayCurrency)
1660
1665
  ] });
1661
1666
  }
1662
1667
  var productsCache = /* @__PURE__ */ new Map();
@@ -2094,7 +2099,7 @@ function useOrder(orderId, options = {}) {
2094
2099
  return () => {
2095
2100
  window.clearInterval(timer);
2096
2101
  };
2097
- }, [enabled, load, normalizedOrderId.length, poll, pollInterval]);
2102
+ }, [enabled, load, normalizedOrderId, poll, pollInterval]);
2098
2103
  const refetch = React3.useCallback(async () => {
2099
2104
  orderCache.delete(cacheKey);
2100
2105
  await load(true);
@@ -3499,16 +3504,16 @@ function useProductPrice(input) {
3499
3504
  if (bundleTotalPrice != null) {
3500
3505
  unitPrice = bundleTotalPrice;
3501
3506
  } else if (compositePrice) {
3502
- unitPrice = chunkRYQ5IPWX_js.parsePrice(compositePrice.final_price);
3507
+ unitPrice = chunk2BSYTQAY_js.parsePrice(compositePrice.final_price);
3503
3508
  } else {
3504
- unitPrice = chunkRYQ5IPWX_js.parsePrice(product.default_price);
3509
+ unitPrice = chunk2BSYTQAY_js.parsePrice(product.default_price);
3505
3510
  if (variant?.price_adjustment) {
3506
- unitPrice += chunkRYQ5IPWX_js.parsePrice(variant.price_adjustment);
3511
+ unitPrice += chunk2BSYTQAY_js.parsePrice(variant.price_adjustment);
3507
3512
  }
3508
3513
  if (addOnOptions) {
3509
3514
  for (const option of addOnOptions) {
3510
3515
  if (option.default_price) {
3511
- unitPrice += chunkRYQ5IPWX_js.parsePrice(option.default_price);
3516
+ unitPrice += chunk2BSYTQAY_js.parsePrice(option.default_price);
3512
3517
  }
3513
3518
  }
3514
3519
  }
@@ -3994,6 +3999,682 @@ function useBookings(options = {}) {
3994
3999
  );
3995
4000
  return { bookings, isLoading, error, refetch, cancelBooking };
3996
4001
  }
4002
+ var definitionsCache = /* @__PURE__ */ new Map();
4003
+ var definitionsInflight = /* @__PURE__ */ new Map();
4004
+ function buildCacheKey(client, namespace) {
4005
+ return `attr_defs_${client.getPublicKey() || "__demo__"}${namespace ? `_${namespace}` : ""}`;
4006
+ }
4007
+ function useAttributeDefinitions(options = {}) {
4008
+ const context = useOptionalCimplifyClient();
4009
+ const client = options.client ?? context?.client;
4010
+ if (!client) {
4011
+ throw new Error(
4012
+ "useAttributeDefinitions must be used within CimplifyProvider or passed { client }."
4013
+ );
4014
+ }
4015
+ const enabled = options.enabled ?? true;
4016
+ const namespace = options.namespace;
4017
+ const cacheKey = React3.useMemo(() => buildCacheKey(client, namespace), [client, namespace]);
4018
+ const cached = definitionsCache.get(cacheKey);
4019
+ const [definitions, setDefinitions] = React3.useState(cached ?? []);
4020
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4021
+ const [error, setError] = React3.useState(null);
4022
+ const load = React3.useCallback(
4023
+ async (force = false) => {
4024
+ if (!enabled) {
4025
+ setIsLoading(false);
4026
+ return;
4027
+ }
4028
+ setError(null);
4029
+ if (!force) {
4030
+ const cachedDefs = definitionsCache.get(cacheKey);
4031
+ if (cachedDefs) {
4032
+ setDefinitions(cachedDefs);
4033
+ setIsLoading(false);
4034
+ return;
4035
+ }
4036
+ }
4037
+ setIsLoading(true);
4038
+ try {
4039
+ const existing = definitionsInflight.get(cacheKey);
4040
+ const promise = existing ?? (async () => {
4041
+ const result = await client.catalogue.getAttributeDefinitions(namespace);
4042
+ if (!result.ok) {
4043
+ throw result.error;
4044
+ }
4045
+ return result.value;
4046
+ })();
4047
+ if (!existing) {
4048
+ definitionsInflight.set(
4049
+ cacheKey,
4050
+ promise.finally(() => {
4051
+ definitionsInflight.delete(cacheKey);
4052
+ })
4053
+ );
4054
+ }
4055
+ const value = await promise;
4056
+ definitionsCache.set(cacheKey, value);
4057
+ setDefinitions(value);
4058
+ } catch (loadError) {
4059
+ setError(loadError);
4060
+ } finally {
4061
+ setIsLoading(false);
4062
+ }
4063
+ },
4064
+ [cacheKey, client, enabled]
4065
+ );
4066
+ React3.useEffect(() => {
4067
+ void load(false);
4068
+ }, [load]);
4069
+ const refetch = React3.useCallback(async () => {
4070
+ definitionsCache.delete(cacheKey);
4071
+ await load(true);
4072
+ }, [cacheKey, load]);
4073
+ return { definitions, isLoading, error, refetch };
4074
+ }
4075
+ var facetsCache = /* @__PURE__ */ new Map();
4076
+ var facetsInflight = /* @__PURE__ */ new Map();
4077
+ function usePropertyFacets(options = {}) {
4078
+ const context = useOptionalCimplifyClient();
4079
+ const client = options.client ?? context?.client;
4080
+ if (!client) {
4081
+ throw new Error(
4082
+ "usePropertyFacets must be used within CimplifyProvider or passed { client }."
4083
+ );
4084
+ }
4085
+ const enabled = options.enabled ?? true;
4086
+ const cacheKey = React3.useMemo(
4087
+ () => `facets_${client.getPublicKey() || "__demo__"}_${options.category_id ?? ""}_${options.product_type ?? ""}`,
4088
+ [client, options.category_id, options.product_type]
4089
+ );
4090
+ const cached = facetsCache.get(cacheKey);
4091
+ const [facets, setFacets] = React3.useState(cached ?? []);
4092
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4093
+ const [error, setError] = React3.useState(null);
4094
+ const load = React3.useCallback(
4095
+ async (force = false) => {
4096
+ if (!enabled) {
4097
+ setIsLoading(false);
4098
+ return;
4099
+ }
4100
+ setError(null);
4101
+ if (!force) {
4102
+ const cachedFacets = facetsCache.get(cacheKey);
4103
+ if (cachedFacets) {
4104
+ setFacets(cachedFacets);
4105
+ setIsLoading(false);
4106
+ return;
4107
+ }
4108
+ }
4109
+ setIsLoading(true);
4110
+ try {
4111
+ const existing = facetsInflight.get(cacheKey);
4112
+ const promise = existing ?? (async () => {
4113
+ const result = await client.catalogue.getPropertyFacets({
4114
+ category_id: options.category_id,
4115
+ product_type: options.product_type
4116
+ });
4117
+ if (!result.ok) {
4118
+ throw result.error;
4119
+ }
4120
+ return result.value;
4121
+ })();
4122
+ if (!existing) {
4123
+ facetsInflight.set(
4124
+ cacheKey,
4125
+ promise.finally(() => {
4126
+ facetsInflight.delete(cacheKey);
4127
+ })
4128
+ );
4129
+ }
4130
+ const value = await promise;
4131
+ facetsCache.set(cacheKey, value);
4132
+ setFacets(value);
4133
+ } catch (loadError) {
4134
+ setError(loadError);
4135
+ } finally {
4136
+ setIsLoading(false);
4137
+ }
4138
+ },
4139
+ [cacheKey, client, enabled, options.category_id, options.product_type]
4140
+ );
4141
+ React3.useEffect(() => {
4142
+ void load(false);
4143
+ }, [load]);
4144
+ const refetch = React3.useCallback(async () => {
4145
+ facetsCache.delete(cacheKey);
4146
+ await load(true);
4147
+ }, [cacheKey, load]);
4148
+ return { facets, isLoading, error, refetch };
4149
+ }
4150
+ function useBillingPlans(productId, options = {}) {
4151
+ const context = useOptionalCimplifyClient();
4152
+ const client = options.client ?? context?.client;
4153
+ if (!client) {
4154
+ throw new Error("useBillingPlans must be used within CimplifyProvider or passed { client }.");
4155
+ }
4156
+ const enabled = options.enabled ?? true;
4157
+ const requestIdRef = React3.useRef(0);
4158
+ const [plans, setPlans] = React3.useState([]);
4159
+ const [isLoading, setIsLoading] = React3.useState(enabled && !!productId);
4160
+ const [error, setError] = React3.useState(null);
4161
+ const customerId = options.customerId;
4162
+ const quantity = options.quantity;
4163
+ const orderValue = options.orderValue;
4164
+ const load = React3.useCallback(
4165
+ async (force = false) => {
4166
+ if (!enabled || !productId) {
4167
+ setPlans([]);
4168
+ setIsLoading(false);
4169
+ return;
4170
+ }
4171
+ const nextRequestId = ++requestIdRef.current;
4172
+ setError(null);
4173
+ setIsLoading(true);
4174
+ try {
4175
+ const result = await client.catalogue.getEligibleBillingPlans(productId, {
4176
+ customer_id: customerId,
4177
+ quantity,
4178
+ order_value: orderValue
4179
+ });
4180
+ if (!result.ok) {
4181
+ throw result.error;
4182
+ }
4183
+ if (nextRequestId === requestIdRef.current) {
4184
+ setPlans(result.value);
4185
+ setError(null);
4186
+ }
4187
+ } catch (loadError) {
4188
+ if (nextRequestId === requestIdRef.current) {
4189
+ setError(loadError);
4190
+ }
4191
+ } finally {
4192
+ if (nextRequestId === requestIdRef.current) {
4193
+ setIsLoading(false);
4194
+ }
4195
+ }
4196
+ },
4197
+ [client, enabled, productId, customerId, quantity, orderValue]
4198
+ );
4199
+ React3.useEffect(() => {
4200
+ void load(false);
4201
+ }, [load]);
4202
+ const refetch = React3.useCallback(async () => {
4203
+ await load(true);
4204
+ }, [load]);
4205
+ const subscriptionPlans = React3.useMemo(
4206
+ () => plans.filter((p) => p.plan_type === "subscription"),
4207
+ [plans]
4208
+ );
4209
+ const installmentPlans = React3.useMemo(
4210
+ () => plans.filter((p) => p.plan_type === "installment"),
4211
+ [plans]
4212
+ );
4213
+ return { plans, subscriptionPlans, installmentPlans, isLoading, error, refetch };
4214
+ }
4215
+ function findMatchingVariant(variants, selections) {
4216
+ const axisCount = Object.keys(selections).length;
4217
+ if (axisCount === 0) return null;
4218
+ return variants.find((v) => {
4219
+ const sel = v.axis_selections;
4220
+ if (!sel) return false;
4221
+ return Object.entries(selections).every(([axisId, valueId]) => sel[axisId] === valueId);
4222
+ }) ?? null;
4223
+ }
4224
+ function computeAvailableValues(variants, axes, selections) {
4225
+ const result = {};
4226
+ for (const axis of axes) {
4227
+ const otherSelections = Object.entries(selections).filter(([id]) => id !== axis.id);
4228
+ const candidates = variants.filter((v) => {
4229
+ const sel = v.axis_selections;
4230
+ if (!sel) return false;
4231
+ return otherSelections.every(([axisId, valueId]) => sel[axisId] === valueId);
4232
+ });
4233
+ const available = /* @__PURE__ */ new Set();
4234
+ for (const v of candidates) {
4235
+ const val = v.axis_selections?.[axis.id];
4236
+ if (val) available.add(val);
4237
+ }
4238
+ result[axis.id] = available;
4239
+ }
4240
+ return result;
4241
+ }
4242
+ function useVariantSelector(options) {
4243
+ const { variants, axes } = options;
4244
+ const [selectedValues, setSelectedValues] = React3.useState({});
4245
+ const selectValue = React3.useCallback(
4246
+ (axisId, valueId) => {
4247
+ setSelectedValues((prev) => {
4248
+ if (prev[axisId] === valueId) {
4249
+ const next = { ...prev };
4250
+ delete next[axisId];
4251
+ return next;
4252
+ }
4253
+ return { ...prev, [axisId]: valueId };
4254
+ });
4255
+ },
4256
+ []
4257
+ );
4258
+ const reset = React3.useCallback(() => setSelectedValues({}), []);
4259
+ const selectedVariant = React3.useMemo(
4260
+ () => findMatchingVariant(variants, selectedValues),
4261
+ [variants, selectedValues]
4262
+ );
4263
+ const variantImage = React3.useMemo(
4264
+ () => selectedVariant?.images?.[0] ?? null,
4265
+ [selectedVariant]
4266
+ );
4267
+ const availableValues = React3.useMemo(
4268
+ () => computeAvailableValues(variants, axes, selectedValues),
4269
+ [variants, axes, selectedValues]
4270
+ );
4271
+ return {
4272
+ selectedValues,
4273
+ selectedVariant,
4274
+ variantImage,
4275
+ availableValues,
4276
+ selectValue,
4277
+ reset
4278
+ };
4279
+ }
4280
+ var activityStateCache = /* @__PURE__ */ new Map();
4281
+ var activityStateInflight = /* @__PURE__ */ new Map();
4282
+ function buildActivityStateCacheKey(client) {
4283
+ return JSON.stringify({ key: client.getPublicKey(), type: "activity_state" });
4284
+ }
4285
+ function useActivityState(options = {}) {
4286
+ const context = useOptionalCimplifyClient();
4287
+ const client = options.client ?? context?.client;
4288
+ if (!client) {
4289
+ throw new Error("useActivityState must be used within CimplifyProvider or passed { client }.");
4290
+ }
4291
+ const enabled = options.enabled ?? true;
4292
+ const cacheKey = React3.useMemo(() => buildActivityStateCacheKey(client), [client]);
4293
+ const cached = activityStateCache.get(cacheKey);
4294
+ const [state, setState] = React3.useState(cached ?? null);
4295
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4296
+ const [error, setError] = React3.useState(null);
4297
+ const load = React3.useCallback(
4298
+ async (force = false) => {
4299
+ if (!enabled) {
4300
+ setIsLoading(false);
4301
+ return;
4302
+ }
4303
+ setError(null);
4304
+ if (!force) {
4305
+ const cachedState = activityStateCache.get(cacheKey);
4306
+ if (cachedState) {
4307
+ setState(cachedState);
4308
+ setIsLoading(false);
4309
+ return;
4310
+ }
4311
+ }
4312
+ setIsLoading(true);
4313
+ try {
4314
+ const existing = activityStateInflight.get(cacheKey);
4315
+ const promise = existing ?? (async () => {
4316
+ const result = await client.activity.getState();
4317
+ if (!result.ok) {
4318
+ throw result.error;
4319
+ }
4320
+ return result.value;
4321
+ })();
4322
+ if (!existing) {
4323
+ activityStateInflight.set(
4324
+ cacheKey,
4325
+ promise.finally(() => {
4326
+ activityStateInflight.delete(cacheKey);
4327
+ })
4328
+ );
4329
+ }
4330
+ const value = await promise;
4331
+ activityStateCache.set(cacheKey, value);
4332
+ setState(value);
4333
+ } catch (loadError) {
4334
+ setError(loadError);
4335
+ } finally {
4336
+ setIsLoading(false);
4337
+ }
4338
+ },
4339
+ [cacheKey, client, enabled]
4340
+ );
4341
+ React3.useEffect(() => {
4342
+ void load(false);
4343
+ }, [load]);
4344
+ const refetch = React3.useCallback(async () => {
4345
+ activityStateCache.delete(cacheKey);
4346
+ await load(true);
4347
+ }, [cacheKey, load]);
4348
+ const dismissMessage = React3.useCallback(
4349
+ async (code) => {
4350
+ const result = await client.activity.dismissMessage(code);
4351
+ if (!result.ok) {
4352
+ setError(result.error);
4353
+ return;
4354
+ }
4355
+ setState((prev) => {
4356
+ if (!prev) return prev;
4357
+ return { ...prev, messages: result.value.messages };
4358
+ });
4359
+ activityStateCache.delete(cacheKey);
4360
+ await load(true);
4361
+ },
4362
+ [cacheKey, client, load]
4363
+ );
4364
+ const messages = state?.messages ?? [];
4365
+ const intent = state?.intent ?? "";
4366
+ return { state, messages, intent, isLoading, error, refetch, dismissMessage };
4367
+ }
4368
+ var recommendationsCache = /* @__PURE__ */ new Map();
4369
+ var recommendationsInflight = /* @__PURE__ */ new Map();
4370
+ function buildRecommendationsCacheKey(client, locationId, limit) {
4371
+ return JSON.stringify({
4372
+ key: client.getPublicKey(),
4373
+ type: "recommendations",
4374
+ location_id: locationId,
4375
+ limit
4376
+ });
4377
+ }
4378
+ function useRecommendations(options = {}) {
4379
+ const context = useOptionalCimplifyClient();
4380
+ const client = options.client ?? context?.client;
4381
+ if (!client) {
4382
+ throw new Error(
4383
+ "useRecommendations must be used within CimplifyProvider or passed { client }."
4384
+ );
4385
+ }
4386
+ const enabled = options.enabled ?? true;
4387
+ const locationId = options.locationId ?? client.getLocationId() ?? void 0;
4388
+ const limit = options.limit;
4389
+ const previousLocationIdRef = React3.useRef(locationId);
4390
+ const cacheKey = React3.useMemo(
4391
+ () => buildRecommendationsCacheKey(client, locationId, limit),
4392
+ [client, locationId, limit]
4393
+ );
4394
+ const cached = recommendationsCache.get(cacheKey);
4395
+ const [response, setResponse] = React3.useState(cached ?? null);
4396
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4397
+ const [error, setError] = React3.useState(null);
4398
+ React3.useEffect(() => {
4399
+ if (previousLocationIdRef.current !== locationId) {
4400
+ recommendationsCache.clear();
4401
+ recommendationsInflight.clear();
4402
+ previousLocationIdRef.current = locationId;
4403
+ }
4404
+ }, [locationId]);
4405
+ const load = React3.useCallback(
4406
+ async (force = false) => {
4407
+ if (!enabled) {
4408
+ setIsLoading(false);
4409
+ return;
4410
+ }
4411
+ setError(null);
4412
+ if (!force) {
4413
+ const cachedResponse = recommendationsCache.get(cacheKey);
4414
+ if (cachedResponse) {
4415
+ setResponse(cachedResponse);
4416
+ setIsLoading(false);
4417
+ return;
4418
+ }
4419
+ }
4420
+ setIsLoading(true);
4421
+ try {
4422
+ const existing = recommendationsInflight.get(cacheKey);
4423
+ const promise = existing ?? (async () => {
4424
+ const result = await client.activity.getRecommendations({
4425
+ location_id: locationId,
4426
+ limit
4427
+ });
4428
+ if (!result.ok) {
4429
+ throw result.error;
4430
+ }
4431
+ return result.value;
4432
+ })();
4433
+ if (!existing) {
4434
+ recommendationsInflight.set(
4435
+ cacheKey,
4436
+ promise.finally(() => {
4437
+ recommendationsInflight.delete(cacheKey);
4438
+ })
4439
+ );
4440
+ }
4441
+ const value = await promise;
4442
+ recommendationsCache.set(cacheKey, value);
4443
+ setResponse(value);
4444
+ } catch (loadError) {
4445
+ setError(loadError);
4446
+ } finally {
4447
+ setIsLoading(false);
4448
+ }
4449
+ },
4450
+ [cacheKey, client, enabled, locationId, limit]
4451
+ );
4452
+ React3.useEffect(() => {
4453
+ void load(false);
4454
+ }, [load]);
4455
+ const refetch = React3.useCallback(async () => {
4456
+ recommendationsCache.delete(cacheKey);
4457
+ await load(true);
4458
+ }, [cacheKey, load]);
4459
+ const recommendations = response?.recommendations ?? [];
4460
+ const intent = response?.intent ?? "";
4461
+ return { recommendations, intent, isLoading, error, refetch };
4462
+ }
4463
+ var deliveryFeeCache = /* @__PURE__ */ new Map();
4464
+ function buildDeliveryFeeCacheKey(client, latitude, longitude, country) {
4465
+ return JSON.stringify({
4466
+ key: client.getPublicKey(),
4467
+ lat: latitude,
4468
+ lng: longitude,
4469
+ country
4470
+ });
4471
+ }
4472
+ function useDeliveryFee(options) {
4473
+ const context = useOptionalCimplifyClient();
4474
+ const client = options.client ?? context?.client;
4475
+ if (!client) {
4476
+ throw new Error("useDeliveryFee must be used within CimplifyProvider or passed { client }.");
4477
+ }
4478
+ const enabled = options.enabled ?? true;
4479
+ const { latitude, longitude, country } = options;
4480
+ const cacheKey = React3.useMemo(
4481
+ () => buildDeliveryFeeCacheKey(client, latitude, longitude, country),
4482
+ [client, latitude, longitude, country]
4483
+ );
4484
+ const cached = deliveryFeeCache.get(cacheKey);
4485
+ const [fee, setFee] = React3.useState(cached ?? null);
4486
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4487
+ const [error, setError] = React3.useState(null);
4488
+ const requestIdRef = React3.useRef(0);
4489
+ const load = React3.useCallback(
4490
+ async (force = false) => {
4491
+ if (!enabled) {
4492
+ setIsLoading(false);
4493
+ return;
4494
+ }
4495
+ setError(null);
4496
+ if (!force) {
4497
+ const cachedFee = deliveryFeeCache.get(cacheKey);
4498
+ if (cachedFee) {
4499
+ setFee(cachedFee);
4500
+ setIsLoading(false);
4501
+ return;
4502
+ }
4503
+ }
4504
+ setIsLoading(true);
4505
+ const currentRequestId = ++requestIdRef.current;
4506
+ try {
4507
+ const result = await client.delivery.getFee(latitude, longitude, country);
4508
+ if (currentRequestId !== requestIdRef.current) return;
4509
+ if (!result.ok) {
4510
+ throw result.error;
4511
+ }
4512
+ deliveryFeeCache.set(cacheKey, result.value);
4513
+ setFee(result.value);
4514
+ } catch (loadError) {
4515
+ if (currentRequestId !== requestIdRef.current) return;
4516
+ setError(loadError);
4517
+ } finally {
4518
+ if (currentRequestId === requestIdRef.current) {
4519
+ setIsLoading(false);
4520
+ }
4521
+ }
4522
+ },
4523
+ [cacheKey, client, country, enabled, latitude, longitude]
4524
+ );
4525
+ React3.useEffect(() => {
4526
+ void load(false);
4527
+ }, [load]);
4528
+ const refetch = React3.useCallback(async () => {
4529
+ deliveryFeeCache.delete(cacheKey);
4530
+ await load(true);
4531
+ }, [cacheKey, load]);
4532
+ return { fee, isLoading, error, refetch };
4533
+ }
4534
+ var fxRateCache = /* @__PURE__ */ new Map();
4535
+ var fxRateInflight = /* @__PURE__ */ new Map();
4536
+ function buildFxRateCacheKey(client, from, to) {
4537
+ return JSON.stringify({ key: client.getPublicKey(), from, to });
4538
+ }
4539
+ function useFxRate(options) {
4540
+ const context = useOptionalCimplifyClient();
4541
+ const client = options.client ?? context?.client;
4542
+ if (!client) {
4543
+ throw new Error("useFxRate must be used within CimplifyProvider or passed { client }.");
4544
+ }
4545
+ const enabled = options.enabled ?? true;
4546
+ const { from, to } = options;
4547
+ const cacheKey = React3.useMemo(
4548
+ () => buildFxRateCacheKey(client, from, to),
4549
+ [client, from, to]
4550
+ );
4551
+ const cached = fxRateCache.get(cacheKey);
4552
+ const [rate, setRate] = React3.useState(cached ?? null);
4553
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4554
+ const [error, setError] = React3.useState(null);
4555
+ const load = React3.useCallback(
4556
+ async (force = false) => {
4557
+ if (!enabled) {
4558
+ setIsLoading(false);
4559
+ return;
4560
+ }
4561
+ setError(null);
4562
+ if (!force) {
4563
+ const cachedRate = fxRateCache.get(cacheKey);
4564
+ if (cachedRate) {
4565
+ setRate(cachedRate);
4566
+ setIsLoading(false);
4567
+ return;
4568
+ }
4569
+ }
4570
+ setIsLoading(true);
4571
+ try {
4572
+ const existing = fxRateInflight.get(cacheKey);
4573
+ const promise = existing ?? (async () => {
4574
+ const result = await client.fx.getRate(from, to);
4575
+ if (!result.ok) {
4576
+ throw result.error;
4577
+ }
4578
+ return result.value;
4579
+ })();
4580
+ if (!existing) {
4581
+ fxRateInflight.set(
4582
+ cacheKey,
4583
+ promise.finally(() => {
4584
+ fxRateInflight.delete(cacheKey);
4585
+ })
4586
+ );
4587
+ }
4588
+ const value = await promise;
4589
+ fxRateCache.set(cacheKey, value);
4590
+ setRate(value);
4591
+ } catch (loadError) {
4592
+ setError(loadError);
4593
+ } finally {
4594
+ setIsLoading(false);
4595
+ }
4596
+ },
4597
+ [cacheKey, client, enabled, from, to]
4598
+ );
4599
+ React3.useEffect(() => {
4600
+ void load(false);
4601
+ }, [load]);
4602
+ const refetch = React3.useCallback(async () => {
4603
+ fxRateCache.delete(cacheKey);
4604
+ await load(true);
4605
+ }, [cacheKey, load]);
4606
+ return { rate, isLoading, error, refetch };
4607
+ }
4608
+ var bootstrapCache = /* @__PURE__ */ new Map();
4609
+ var bootstrapInflight = /* @__PURE__ */ new Map();
4610
+ function buildBootstrapCacheKey(client) {
4611
+ return JSON.stringify({ key: client.getPublicKey(), type: "bootstrap" });
4612
+ }
4613
+ function useBootstrap(options = {}) {
4614
+ const context = useOptionalCimplifyClient();
4615
+ const client = options.client ?? context?.client;
4616
+ if (!client) {
4617
+ throw new Error("useBootstrap must be used within CimplifyProvider or passed { client }.");
4618
+ }
4619
+ const enabled = options.enabled ?? true;
4620
+ const cacheKey = React3.useMemo(() => buildBootstrapCacheKey(client), [client]);
4621
+ const cached = bootstrapCache.get(cacheKey);
4622
+ const [bootstrap, setBootstrap] = React3.useState(cached ?? null);
4623
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4624
+ const [error, setError] = React3.useState(null);
4625
+ const load = React3.useCallback(
4626
+ async (force = false) => {
4627
+ if (!enabled) {
4628
+ setIsLoading(false);
4629
+ return;
4630
+ }
4631
+ setError(null);
4632
+ if (!force) {
4633
+ const cachedBootstrap = bootstrapCache.get(cacheKey);
4634
+ if (cachedBootstrap) {
4635
+ setBootstrap(cachedBootstrap);
4636
+ setIsLoading(false);
4637
+ return;
4638
+ }
4639
+ }
4640
+ setIsLoading(true);
4641
+ try {
4642
+ const existing = bootstrapInflight.get(cacheKey);
4643
+ const promise = existing ?? (async () => {
4644
+ const result = await client.business.getBootstrap();
4645
+ if (!result.ok) {
4646
+ throw result.error;
4647
+ }
4648
+ return result.value;
4649
+ })();
4650
+ if (!existing) {
4651
+ bootstrapInflight.set(
4652
+ cacheKey,
4653
+ promise.finally(() => {
4654
+ bootstrapInflight.delete(cacheKey);
4655
+ })
4656
+ );
4657
+ }
4658
+ const value = await promise;
4659
+ bootstrapCache.set(cacheKey, value);
4660
+ setBootstrap(value);
4661
+ } catch (loadError) {
4662
+ setError(loadError);
4663
+ } finally {
4664
+ setIsLoading(false);
4665
+ }
4666
+ },
4667
+ [cacheKey, client, enabled]
4668
+ );
4669
+ React3.useEffect(() => {
4670
+ void load(false);
4671
+ }, [load]);
4672
+ const refetch = React3.useCallback(async () => {
4673
+ bootstrapCache.delete(cacheKey);
4674
+ await load(true);
4675
+ }, [cacheKey, load]);
4676
+ return { bootstrap, isLoading, error, refetch };
4677
+ }
3997
4678
  var ElementsContext = React3.createContext({
3998
4679
  elements: null,
3999
4680
  isReady: false
@@ -4069,19 +4750,19 @@ function AuthElement({
4069
4750
  }, [onReady, onAuthenticated, onRequiresOtp, onError]);
4070
4751
  React3.useEffect(() => {
4071
4752
  if (!elements || !containerRef.current) return;
4072
- const element = elements.create(chunkDYKFSV77_js.ELEMENT_TYPES.AUTH, { prefillEmail });
4753
+ const element = elements.create(chunkKSN3RJFL_js.ELEMENT_TYPES.AUTH, { prefillEmail });
4073
4754
  elementRef.current = element;
4074
- element.on(chunkDYKFSV77_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
4755
+ element.on(chunkKSN3RJFL_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
4075
4756
  element.on(
4076
- chunkDYKFSV77_js.EVENT_TYPES.AUTHENTICATED,
4757
+ chunkKSN3RJFL_js.EVENT_TYPES.AUTHENTICATED,
4077
4758
  (data) => onAuthenticatedRef.current?.(data)
4078
4759
  );
4079
4760
  element.on(
4080
- chunkDYKFSV77_js.EVENT_TYPES.REQUIRES_OTP,
4761
+ chunkKSN3RJFL_js.EVENT_TYPES.REQUIRES_OTP,
4081
4762
  (data) => onRequiresOtpRef.current?.(data)
4082
4763
  );
4083
4764
  element.on(
4084
- chunkDYKFSV77_js.EVENT_TYPES.ERROR,
4765
+ chunkKSN3RJFL_js.EVENT_TYPES.ERROR,
4085
4766
  (data) => onErrorRef.current?.(data)
4086
4767
  );
4087
4768
  element.mount(containerRef.current);
@@ -4110,15 +4791,15 @@ function AddressElement({
4110
4791
  }, [onReady, onChange, onError]);
4111
4792
  React3.useEffect(() => {
4112
4793
  if (!elements || !containerRef.current) return;
4113
- const element = elements.create(chunkDYKFSV77_js.ELEMENT_TYPES.ADDRESS, { mode });
4794
+ const element = elements.create(chunkKSN3RJFL_js.ELEMENT_TYPES.ADDRESS, { mode });
4114
4795
  elementRef.current = element;
4115
- element.on(chunkDYKFSV77_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
4796
+ element.on(chunkKSN3RJFL_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
4116
4797
  element.on(
4117
- chunkDYKFSV77_js.EVENT_TYPES.CHANGE,
4798
+ chunkKSN3RJFL_js.EVENT_TYPES.CHANGE,
4118
4799
  (data) => onChangeRef.current?.(data)
4119
4800
  );
4120
4801
  element.on(
4121
- chunkDYKFSV77_js.EVENT_TYPES.ERROR,
4802
+ chunkKSN3RJFL_js.EVENT_TYPES.ERROR,
4122
4803
  (data) => onErrorRef.current?.(data)
4123
4804
  );
4124
4805
  element.mount(containerRef.current);
@@ -4148,15 +4829,15 @@ function PaymentElement({
4148
4829
  }, [onReady, onChange, onError]);
4149
4830
  React3.useEffect(() => {
4150
4831
  if (!elements || !containerRef.current) return;
4151
- const element = elements.create(chunkDYKFSV77_js.ELEMENT_TYPES.PAYMENT, { amount, currency });
4832
+ const element = elements.create(chunkKSN3RJFL_js.ELEMENT_TYPES.PAYMENT, { amount, currency });
4152
4833
  elementRef.current = element;
4153
- element.on(chunkDYKFSV77_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
4834
+ element.on(chunkKSN3RJFL_js.EVENT_TYPES.READY, () => onReadyRef.current?.());
4154
4835
  element.on(
4155
- chunkDYKFSV77_js.EVENT_TYPES.CHANGE,
4836
+ chunkKSN3RJFL_js.EVENT_TYPES.CHANGE,
4156
4837
  (data) => onChangeRef.current?.(data)
4157
4838
  );
4158
4839
  element.on(
4159
- chunkDYKFSV77_js.EVENT_TYPES.ERROR,
4840
+ chunkKSN3RJFL_js.EVENT_TYPES.ERROR,
4160
4841
  (data) => onErrorRef.current?.(data)
4161
4842
  );
4162
4843
  element.mount(containerRef.current);
@@ -4315,7 +4996,7 @@ function VariantSelector({
4315
4996
  if (!variants || variants.length <= 1) {
4316
4997
  return null;
4317
4998
  }
4318
- basePrice != null ? chunkRYQ5IPWX_js.parsePrice(basePrice) : 0;
4999
+ basePrice != null ? chunk2BSYTQAY_js.parsePrice(basePrice) : 0;
4319
5000
  if (variantAxes && variantAxes.length > 0) {
4320
5001
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: variantAxes.map((axis) => {
4321
5002
  const labelId = `${idPrefix}-axis-${axis.id}`;
@@ -4391,7 +5072,7 @@ function VariantSelector({
4391
5072
  className: cn("divide-y divide-border", classNames?.list),
4392
5073
  children: variants.map((variant) => {
4393
5074
  const isSelected = selectedVariantId === variant.id;
4394
- const adjustment = chunkRYQ5IPWX_js.parsePrice(variant.price_adjustment);
5075
+ const adjustment = chunk2BSYTQAY_js.parsePrice(variant.price_adjustment);
4395
5076
  return /* @__PURE__ */ jsxRuntime.jsxs(
4396
5077
  radio.Radio.Root,
4397
5078
  {
@@ -4419,7 +5100,7 @@ function VariantSelector({
4419
5100
  {
4420
5101
  "data-cimplify-variant-name": true,
4421
5102
  className: cn("flex-1 min-w-0 text-sm", classNames?.name),
4422
- children: chunkMJECWMOY_js.getVariantDisplayName(variant, productName)
5103
+ children: chunkAVVLN353_js.getVariantDisplayName(variant, productName)
4423
5104
  }
4424
5105
  ),
4425
5106
  /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm text-muted-foreground", classNames?.pricing), children: [
@@ -4657,16 +5338,16 @@ function BundleSelector({
4657
5338
  }, [components, selections, onReady]);
4658
5339
  const totalPrice = React3.useMemo(() => {
4659
5340
  if (pricingType === "fixed" && bundlePrice) {
4660
- return chunkRYQ5IPWX_js.parsePrice(bundlePrice);
5341
+ return chunk2BSYTQAY_js.parsePrice(bundlePrice);
4661
5342
  }
4662
5343
  const componentsTotal = components.reduce((sum, comp) => {
4663
5344
  return sum + getComponentPrice(comp, variantChoices[comp.id]) * comp.quantity;
4664
5345
  }, 0);
4665
5346
  if (pricingType === "percentage_discount" && discountValue) {
4666
- return componentsTotal * (1 - chunkRYQ5IPWX_js.parsePrice(discountValue) / 100);
5347
+ return componentsTotal * (1 - chunk2BSYTQAY_js.parsePrice(discountValue) / 100);
4667
5348
  }
4668
5349
  if (pricingType === "fixed_discount" && discountValue) {
4669
- return componentsTotal - chunkRYQ5IPWX_js.parsePrice(discountValue);
5350
+ return componentsTotal - chunk2BSYTQAY_js.parsePrice(discountValue);
4670
5351
  }
4671
5352
  return componentsTotal;
4672
5353
  }, [components, variantChoices, pricingType, bundlePrice, discountValue]);
@@ -4727,15 +5408,26 @@ function BundleSelector({
4727
5408
  }
4728
5409
  function getComponentPrice(component, selectedVariantId) {
4729
5410
  if (!selectedVariantId || component.available_variants.length === 0) {
4730
- return chunkRYQ5IPWX_js.parsePrice(component.effective_price);
5411
+ return chunk2BSYTQAY_js.parsePrice(component.effective_price);
4731
5412
  }
4732
5413
  if (selectedVariantId === component.variant_id) {
4733
- return chunkRYQ5IPWX_js.parsePrice(component.effective_price);
5414
+ return chunk2BSYTQAY_js.parsePrice(component.effective_price);
4734
5415
  }
4735
5416
  const bakedAdj = component.variant_id ? component.available_variants.find((v) => v.id === component.variant_id) : void 0;
4736
5417
  const selectedAdj = component.available_variants.find((v) => v.id === selectedVariantId);
4737
- if (!selectedAdj) return chunkRYQ5IPWX_js.parsePrice(component.effective_price);
4738
- return chunkRYQ5IPWX_js.parsePrice(component.effective_price) - chunkRYQ5IPWX_js.parsePrice(bakedAdj?.price_adjustment ?? "0") + chunkRYQ5IPWX_js.parsePrice(selectedAdj.price_adjustment);
5418
+ if (!selectedAdj) return chunk2BSYTQAY_js.parsePrice(component.effective_price);
5419
+ return chunk2BSYTQAY_js.parsePrice(component.effective_price) - chunk2BSYTQAY_js.parsePrice(bakedAdj?.price_adjustment ?? "0") + chunk2BSYTQAY_js.parsePrice(selectedAdj.price_adjustment);
5420
+ }
5421
+ function formatDuration(minutes, unit) {
5422
+ if (unit === "hours" || !unit && minutes >= 60 && minutes % 60 === 0) {
5423
+ const h = Math.round(minutes / 60);
5424
+ return `${h}h`;
5425
+ }
5426
+ if (unit === "days" || unit === "nights") {
5427
+ const d = Math.round(minutes / 1440);
5428
+ return `${d}${unit === "nights" ? "n" : "d"}`;
5429
+ }
5430
+ return `${minutes}min`;
4739
5431
  }
4740
5432
  function BundleComponentCard({
4741
5433
  component,
@@ -4782,6 +5474,43 @@ function BundleComponentCard({
4782
5474
  className: cn("text-sm", classNames?.componentName),
4783
5475
  children: component.product_name
4784
5476
  }
5477
+ ),
5478
+ component.product_type === "service" && /* @__PURE__ */ jsxRuntime.jsxs(
5479
+ "span",
5480
+ {
5481
+ "data-cimplify-bundle-type-badge": "service",
5482
+ className: cn(
5483
+ "text-[10px] uppercase tracking-wider font-medium text-blue-600",
5484
+ classNames?.typeBadge,
5485
+ classNames?.serviceBadge
5486
+ ),
5487
+ children: [
5488
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", fill: "none", className: "inline-block w-3 h-3 mr-0.5 -mt-px", "aria-hidden": "true", children: [
5489
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "7", stroke: "currentColor", strokeWidth: "1.5" }),
5490
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 4v4l2.5 1.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
5491
+ ] }),
5492
+ "Service",
5493
+ component.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5494
+ " \xB7 ",
5495
+ formatDuration(component.duration_minutes, component.duration_unit)
5496
+ ] })
5497
+ ]
5498
+ }
5499
+ ),
5500
+ component.product_type === "digital" && /* @__PURE__ */ jsxRuntime.jsxs(
5501
+ "span",
5502
+ {
5503
+ "data-cimplify-bundle-type-badge": "digital",
5504
+ className: cn(
5505
+ "text-[10px] uppercase tracking-wider font-medium text-violet-600",
5506
+ classNames?.typeBadge,
5507
+ classNames?.digitalBadge
5508
+ ),
5509
+ children: [
5510
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", fill: "none", className: "inline-block w-3 h-3 mr-0.5 -mt-px", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 2L4 9h4l-1 5 5-7H8l1-5z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
5511
+ "Digital"
5512
+ ]
5513
+ }
4785
5514
  )
4786
5515
  ] }),
4787
5516
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: displayPrice }) })
@@ -4800,7 +5529,7 @@ function BundleComponentCard({
4800
5529
  className: cn("mt-3 divide-y divide-border", classNames?.variantPicker),
4801
5530
  children: component.available_variants.map((variant) => {
4802
5531
  const isSelected = selectedVariantId === variant.id;
4803
- const adjustment = chunkRYQ5IPWX_js.parsePrice(variant.price_adjustment);
5532
+ const adjustment = chunk2BSYTQAY_js.parsePrice(variant.price_adjustment);
4804
5533
  return /* @__PURE__ */ jsxRuntime.jsxs(
4805
5534
  radio.Radio.Root,
4806
5535
  {
@@ -5106,6 +5835,39 @@ function CompositeSelector({
5106
5835
  children: displayName
5107
5836
  }
5108
5837
  ),
5838
+ component.product_type === "service" && /* @__PURE__ */ jsxRuntime.jsxs(
5839
+ "span",
5840
+ {
5841
+ "data-cimplify-composite-type-badge": "service",
5842
+ className: cn(
5843
+ "text-[10px] uppercase tracking-wider font-medium text-blue-600",
5844
+ classNames?.typeBadge,
5845
+ classNames?.serviceBadge
5846
+ ),
5847
+ children: [
5848
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", fill: "none", className: "inline-block w-3 h-3 mr-0.5 -mt-px", "aria-hidden": "true", children: [
5849
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "7", stroke: "currentColor", strokeWidth: "1.5" }),
5850
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 4v4l2.5 1.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
5851
+ ] }),
5852
+ "Service"
5853
+ ]
5854
+ }
5855
+ ),
5856
+ component.product_type === "digital" && /* @__PURE__ */ jsxRuntime.jsxs(
5857
+ "span",
5858
+ {
5859
+ "data-cimplify-composite-type-badge": "digital",
5860
+ className: cn(
5861
+ "text-[10px] uppercase tracking-wider font-medium text-violet-600",
5862
+ classNames?.typeBadge,
5863
+ classNames?.digitalBadge
5864
+ ),
5865
+ children: [
5866
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", fill: "none", className: "inline-block w-3 h-3 mr-0.5 -mt-px", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 2L4 9h4l-1 5 5-7H8l1-5z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
5867
+ "Digital"
5868
+ ]
5869
+ }
5870
+ ),
5109
5871
  component.is_popular && /* @__PURE__ */ jsxRuntime.jsx(
5110
5872
  "span",
5111
5873
  {
@@ -5213,7 +5975,7 @@ function CompositeSelector({
5213
5975
  "data-cimplify-composite-summary": true,
5214
5976
  className: cn("border-t border-border pt-4 space-y-1 text-sm", classNames?.summary),
5215
5977
  children: [
5216
- chunkRYQ5IPWX_js.parsePrice(priceResult.base_price) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
5978
+ chunk2BSYTQAY_js.parsePrice(priceResult.base_price) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
5217
5979
  "div",
5218
5980
  {
5219
5981
  "data-cimplify-composite-summary-line": true,
@@ -5224,7 +5986,7 @@ function CompositeSelector({
5224
5986
  ]
5225
5987
  }
5226
5988
  ),
5227
- chunkRYQ5IPWX_js.parsePrice(priceResult.components_total) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
5989
+ chunk2BSYTQAY_js.parsePrice(priceResult.components_total) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
5228
5990
  "div",
5229
5991
  {
5230
5992
  "data-cimplify-composite-summary-line": true,
@@ -5270,6 +6032,7 @@ function CompositeSelector({
5270
6032
  function ProductCustomizer({
5271
6033
  product,
5272
6034
  onAddToCart,
6035
+ showSpecialInstructions = true,
5273
6036
  className,
5274
6037
  classNames
5275
6038
  }) {
@@ -5285,10 +6048,13 @@ function ProductCustomizer({
5285
6048
  const [bundleSelections, setBundleSelections] = React3.useState([]);
5286
6049
  const [bundleTotalPrice, setBundleTotalPrice] = React3.useState(null);
5287
6050
  const [bundleReady, setBundleReady] = React3.useState(false);
6051
+ const [specialInstructions, setSpecialInstructions] = React3.useState("");
5288
6052
  const cart = useCart();
5289
6053
  const productType = product.type || "product";
5290
6054
  const isComposite = productType === "composite";
5291
6055
  const isBundle = productType === "bundle";
6056
+ const isDigital = productType === "digital";
6057
+ const isService = productType === "service";
5292
6058
  const isStandard = !isComposite && !isBundle;
5293
6059
  const hasVariants = isStandard && product.variants && product.variants.length > 0;
5294
6060
  const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
@@ -5305,6 +6071,7 @@ function ProductCustomizer({
5305
6071
  setBundleSelections([]);
5306
6072
  setBundleTotalPrice(null);
5307
6073
  setBundleReady(false);
6074
+ setSpecialInstructions("");
5308
6075
  }, [product.id]);
5309
6076
  const selectedAddOnOptions = React3.useMemo(() => {
5310
6077
  if (!product.add_ons) return [];
@@ -5324,18 +6091,18 @@ function ProductCustomizer({
5324
6091
  }, [selectedAddOnOptionIds]);
5325
6092
  const localTotalPrice = React3.useMemo(() => {
5326
6093
  if (isComposite && compositePrice) {
5327
- return chunkRYQ5IPWX_js.parsePrice(compositePrice.final_price) * quantity;
6094
+ return chunk2BSYTQAY_js.parsePrice(compositePrice.final_price) * quantity;
5328
6095
  }
5329
6096
  if (isBundle && bundleTotalPrice != null) {
5330
6097
  return bundleTotalPrice * quantity;
5331
6098
  }
5332
- let price = chunkRYQ5IPWX_js.parsePrice(product.default_price);
6099
+ let price = chunk2BSYTQAY_js.parsePrice(product.default_price);
5333
6100
  if (selectedVariant?.price_adjustment) {
5334
- price += chunkRYQ5IPWX_js.parsePrice(selectedVariant.price_adjustment);
6101
+ price += chunk2BSYTQAY_js.parsePrice(selectedVariant.price_adjustment);
5335
6102
  }
5336
6103
  for (const option of selectedAddOnOptions) {
5337
6104
  if (option.default_price) {
5338
- price += chunkRYQ5IPWX_js.parsePrice(option.default_price);
6105
+ price += chunk2BSYTQAY_js.parsePrice(option.default_price);
5339
6106
  }
5340
6107
  }
5341
6108
  return price * quantity;
@@ -5376,7 +6143,7 @@ function ProductCustomizer({
5376
6143
  const priceInfo = quote.quoted_total_price_info ?? quote.final_price_info;
5377
6144
  const perUnit = priceInfo.pre_tax_price;
5378
6145
  if (perUnit === void 0 || perUnit === null) return void 0;
5379
- return chunkRYQ5IPWX_js.parsePrice(perUnit) * quantity;
6146
+ return chunk2BSYTQAY_js.parsePrice(perUnit) * quantity;
5380
6147
  }, [quote, quantity]);
5381
6148
  const displayTotalPrice = quotedTotalPrice ?? localTotalPrice;
5382
6149
  const handleVariantChange = React3.useCallback(
@@ -5401,7 +6168,8 @@ function ProductCustomizer({
5401
6168
  default_price: opt.default_price
5402
6169
  })) : void 0,
5403
6170
  compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
5404
- bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0
6171
+ bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0,
6172
+ specialInstructions: specialInstructions.trim() || void 0
5405
6173
  };
5406
6174
  try {
5407
6175
  if (onAddToCart) {
@@ -5462,6 +6230,43 @@ function ProductCustomizer({
5462
6230
  onOptionsChange: setSelectedAddOnOptionIds
5463
6231
  }
5464
6232
  ),
6233
+ 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: [
6234
+ "Deposit required: ",
6235
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: product.deposit_amount })
6236
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6237
+ "Deposit required: ",
6238
+ chunk2BSYTQAY_js.parsePrice(product.deposit_amount),
6239
+ "%"
6240
+ ] }) }),
6241
+ product.allergies && product.allergies.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customizer-allergens": true, className: cn("flex flex-wrap gap-1.5", classNames?.allergens), children: product.allergies.map((allergen) => /* @__PURE__ */ jsxRuntime.jsx(
6242
+ "span",
6243
+ {
6244
+ "data-cimplify-allergen-tag": true,
6245
+ className: "inline-block text-xs px-2 py-0.5 rounded-full bg-muted text-muted-foreground",
6246
+ children: allergen
6247
+ },
6248
+ allergen
6249
+ )) }),
6250
+ isService && product.duration_minutes != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-customizer-duration": true, className: cn("text-sm text-muted-foreground", classNames?.duration), children: [
6251
+ "Duration: ",
6252
+ product.duration_minutes,
6253
+ " ",
6254
+ product.duration_unit ?? "minutes"
6255
+ ] }),
6256
+ showSpecialInstructions && !isDigital && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-customizer-special-instructions": true, children: /* @__PURE__ */ jsxRuntime.jsx(
6257
+ "textarea",
6258
+ {
6259
+ value: specialInstructions,
6260
+ onChange: (e) => setSpecialInstructions(e.target.value),
6261
+ placeholder: "Special instructions (e.g., no onions, extra sauce)",
6262
+ rows: 2,
6263
+ "data-cimplify-customizer-textarea": true,
6264
+ className: cn(
6265
+ "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 resize-none",
6266
+ classNames?.specialInstructions
6267
+ )
6268
+ }
6269
+ ) }),
5465
6270
  /* @__PURE__ */ jsxRuntime.jsxs(
5466
6271
  "div",
5467
6272
  {
@@ -5596,7 +6401,8 @@ function ProductImageGallery({
5596
6401
  function CartLineItemRow({
5597
6402
  item,
5598
6403
  onRemove,
5599
- onQuantityChange
6404
+ onQuantityChange,
6405
+ classNames
5600
6406
  }) {
5601
6407
  const { unitPrice } = useProductPrice({
5602
6408
  product: item.product,
@@ -5605,18 +6411,60 @@ function CartLineItemRow({
5605
6411
  });
5606
6412
  const hasComposite = item.compositeSelections && item.compositeSelections.length > 0;
5607
6413
  const hasBundle = item.bundleSelections && item.bundleSelections.length > 0;
5608
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item": true, children: [
6414
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item": true, className: classNames?.item, children: [
5609
6415
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-info": true, children: [
5610
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-name": true, children: item.product.name }),
5611
- item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children: chunkMJECWMOY_js.getVariantDisplayName(item.variant, item.product.name) }),
6416
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-name": true, className: classNames?.itemName, children: item.product.name }),
6417
+ item.variant && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-variant": true, children: chunkAVVLN353_js.getVariantDisplayName(item.variant, item.product.name) }),
5612
6418
  item.addOnOptions && item.addOnOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-cart-item-addons": true, children: [
5613
6419
  "+ ",
5614
6420
  item.addOnOptions.map((opt) => opt.name).join(", ")
5615
6421
  ] }),
5616
6422
  (hasComposite || hasBundle) && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-badge": true, children: hasComposite ? "Custom" : "Bundle" }),
5617
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: unitPrice })
6423
+ item.specialInstructions && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-cart-item-instructions": true, className: "text-xs text-muted-foreground", children: item.specialInstructions }),
6424
+ (item.lineType === "service" || item.product.type === "service") && item.scheduledStart && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-service-info": true, className: classNames?.serviceInfo, children: [
6425
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6426
+ "\u{1F4C5}",
6427
+ " ",
6428
+ new Date(item.scheduledStart).toLocaleDateString(),
6429
+ " at ",
6430
+ new Date(item.scheduledStart).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
6431
+ ] }),
6432
+ item.confirmationCode && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6433
+ "Confirmation: ",
6434
+ item.confirmationCode
6435
+ ] }),
6436
+ item.serviceStatus && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-status": item.serviceStatus, children: item.serviceStatus })
6437
+ ] }),
6438
+ (item.lineType === "digital" || item.product.type === "digital") && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-digital-info": true, className: classNames?.digitalInfo, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6439
+ "\u26A1",
6440
+ " Instant digital delivery"
6441
+ ] }) }),
6442
+ item.bundleResolved && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-bundle-breakdown": true, className: classNames?.bundleBreakdown, children: item.bundleResolved.selections.map((sel) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-product-type": sel.product_type, children: [
6443
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6444
+ sel.quantity,
6445
+ "\xD7 ",
6446
+ sel.product_name
6447
+ ] }),
6448
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6449
+ " \u2014 ",
6450
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
6451
+ ] }),
6452
+ sel.product_type === "digital" && /* @__PURE__ */ jsxRuntime.jsx("span", { children: " \u2014 Digital" })
6453
+ ] }, sel.component_id)) }),
6454
+ item.compositeResolved && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-composite-breakdown": true, className: classNames?.compositeBreakdown, children: item.compositeResolved.selections.map((sel) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-product-type": sel.product_type, children: [
6455
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6456
+ sel.quantity,
6457
+ "\xD7 ",
6458
+ sel.component_name
6459
+ ] }),
6460
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
6461
+ " \u2014 ",
6462
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
6463
+ ] })
6464
+ ] }, sel.component_id)) }),
6465
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: unitPrice, className: classNames?.itemPrice })
5618
6466
  ] }),
5619
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-controls": true, children: [
6467
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-item-controls": true, className: classNames?.quantity, children: [
5620
6468
  /* @__PURE__ */ jsxRuntime.jsx(
5621
6469
  QuantitySelector,
5622
6470
  {
@@ -5631,6 +6479,7 @@ function CartLineItemRow({
5631
6479
  type: "button",
5632
6480
  onClick: () => onRemove(item.id),
5633
6481
  "data-cimplify-cart-item-remove": true,
6482
+ className: classNames?.removeButton,
5634
6483
  "aria-label": `Remove ${item.product.name}`,
5635
6484
  children: "Remove"
5636
6485
  }
@@ -5639,13 +6488,18 @@ function CartLineItemRow({
5639
6488
  ] });
5640
6489
  }
5641
6490
  function CartSummary({
6491
+ cart: serverCart,
5642
6492
  onCheckout,
5643
6493
  onItemRemove,
5644
6494
  onQuantityChange,
5645
6495
  emptyMessage = "Your cart is empty",
5646
- className
6496
+ className,
6497
+ classNames
5647
6498
  }) {
5648
6499
  const { items, itemCount, subtotal, tax, total, isEmpty, removeItem, updateQuantity } = useCart();
6500
+ const deliveryFee = serverCart?.delivery_fee;
6501
+ const serviceCharge = serverCart?.service_charge;
6502
+ const totalDiscounts = serverCart?.total_discounts;
5649
6503
  const handleRemove = (itemId) => {
5650
6504
  if (onItemRemove) {
5651
6505
  onItemRemove(itemId);
@@ -5660,18 +6514,19 @@ function CartSummary({
5660
6514
  void updateQuantity(itemId, qty);
5661
6515
  }
5662
6516
  };
5663
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-summary": true, className, children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-empty": true, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: emptyMessage }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6517
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-summary": true, className: cn(className, classNames?.root), children: isEmpty ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-empty": true, className: classNames?.empty, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: emptyMessage }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5664
6518
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-cart-items": true, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
5665
6519
  CartLineItemRow,
5666
6520
  {
5667
6521
  item,
5668
6522
  onRemove: handleRemove,
5669
- onQuantityChange: handleQuantityChange
6523
+ onQuantityChange: handleQuantityChange,
6524
+ classNames
5670
6525
  },
5671
6526
  item.id
5672
6527
  )) }),
5673
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-totals": true, children: [
5674
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-subtotal": true, children: [
6528
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-totals": true, className: classNames?.totals, children: [
6529
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-subtotal": true, className: classNames?.subtotal, children: [
5675
6530
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5676
6531
  "Subtotal (",
5677
6532
  itemCount,
@@ -5681,11 +6536,23 @@ function CartSummary({
5681
6536
  ] }),
5682
6537
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: subtotal })
5683
6538
  ] }),
5684
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-tax": true, children: [
6539
+ totalDiscounts != null && chunk2BSYTQAY_js.parsePrice(totalDiscounts) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-discount": true, className: classNames?.discount, children: [
6540
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Discount" }),
6541
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: totalDiscounts, prefix: "-" })
6542
+ ] }),
6543
+ deliveryFee != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-delivery-fee": true, className: classNames?.deliveryFee, children: [
6544
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delivery fee" }),
6545
+ chunk2BSYTQAY_js.parsePrice(deliveryFee) > 0 ? /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: deliveryFee }) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Free delivery" })
6546
+ ] }),
6547
+ serviceCharge != null && chunk2BSYTQAY_js.parsePrice(serviceCharge) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-service-charge": true, className: classNames?.serviceCharge, children: [
6548
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Service charge" }),
6549
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: serviceCharge })
6550
+ ] }),
6551
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-tax": true, className: classNames?.tax, children: [
5685
6552
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Tax" }),
5686
6553
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: tax })
5687
6554
  ] }),
5688
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-total": true, children: [
6555
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-cart-total": true, className: classNames?.total, children: [
5689
6556
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Total" }),
5690
6557
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: total })
5691
6558
  ] })
@@ -5696,6 +6563,7 @@ function CartSummary({
5696
6563
  type: "button",
5697
6564
  onClick: onCheckout,
5698
6565
  "data-cimplify-cart-checkout": true,
6566
+ className: classNames?.checkout,
5699
6567
  children: "Proceed to Checkout"
5700
6568
  }
5701
6569
  )
@@ -5705,21 +6573,26 @@ function AvailabilityBadge({
5705
6573
  product,
5706
6574
  isAvailable,
5707
6575
  isInStock,
6576
+ stockQuantity,
6577
+ lowStockThreshold = 5,
6578
+ locationId,
5708
6579
  className,
5709
6580
  classNames
5710
6581
  }) {
5711
6582
  if (product.is_tracked !== true) {
5712
6583
  return null;
5713
6584
  }
5714
- const outOfStock = isInStock === false || isAvailable === false;
5715
- const stockState = outOfStock ? "out_of_stock" : "in_stock";
6585
+ const outOfStock = isInStock === false || isAvailable === false || stockQuantity !== void 0 && stockQuantity <= 0;
6586
+ const isLowStock = !outOfStock && stockQuantity !== void 0 && stockQuantity > 0 && stockQuantity <= lowStockThreshold;
6587
+ const stockState = outOfStock ? "out_of_stock" : isLowStock ? "low_stock" : "in_stock";
5716
6588
  const label = outOfStock ? "Out of Stock" : "In Stock";
5717
6589
  return /* @__PURE__ */ jsxRuntime.jsxs(
5718
6590
  "span",
5719
6591
  {
5720
6592
  "data-cimplify-availability-badge": true,
5721
6593
  "data-stock-state": stockState,
5722
- className: cn(className, classNames?.root),
6594
+ ...locationId ? { "data-location-id": locationId } : void 0,
6595
+ className: cn(className, classNames?.root, isLowStock && classNames?.lowStock),
5723
6596
  style: { display: "inline-flex", alignItems: "center", gap: "0.375rem" },
5724
6597
  children: [
5725
6598
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5735,7 +6608,12 @@ function AvailabilityBadge({
5735
6608
  }
5736
6609
  }
5737
6610
  ),
5738
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-availability-label": true, className: classNames?.label, children: label })
6611
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-availability-label": true, className: classNames?.label, children: label }),
6612
+ stockQuantity !== void 0 && isLowStock && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-availability-stock-count": true, className: classNames?.stockCount, children: [
6613
+ "Only ",
6614
+ stockQuantity,
6615
+ " left"
6616
+ ] })
5739
6617
  ]
5740
6618
  }
5741
6619
  );
@@ -5749,16 +6627,16 @@ function SaleBadge({
5749
6627
  className,
5750
6628
  classNames
5751
6629
  }) {
5752
- const onSale = chunkRYQ5IPWX_js.isOnSale(product);
6630
+ const onSale = chunk2BSYTQAY_js.isOnSale(product);
5753
6631
  const hasDeal = dealInfo !== void 0;
5754
6632
  if (!hasDeal && !onSale && !label) {
5755
6633
  return null;
5756
6634
  }
5757
6635
  let percentage = null;
5758
6636
  if (hasDeal && dealInfo.benefit_type === "percentage") {
5759
- percentage = chunkRYQ5IPWX_js.parsePrice(dealInfo.value);
6637
+ percentage = chunk2BSYTQAY_js.parsePrice(dealInfo.value);
5760
6638
  } else if (onSale) {
5761
- percentage = chunkRYQ5IPWX_js.getDiscountPercentage(product);
6639
+ percentage = chunk2BSYTQAY_js.getDiscountPercentage(product);
5762
6640
  }
5763
6641
  const badgeText = label ?? dealInfo?.label ?? (percentage != null && percentage > 0 ? `${percentage}% off` : null);
5764
6642
  if (!badgeText) {
@@ -5777,7 +6655,7 @@ function SaleBadge({
5777
6655
  "%"
5778
6656
  ] }),
5779
6657
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-sale-label": true, className: classNames?.label, children: badgeText }),
5780
- showOriginalPrice && onSale && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-sale-original-price": true, className: classNames?.originalPrice, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: chunkRYQ5IPWX_js.getBasePrice(product) }) })
6658
+ showOriginalPrice && onSale && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-sale-original-price": true, className: classNames?.originalPrice, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: chunk2BSYTQAY_js.getBasePrice(product) }) })
5781
6659
  ]
5782
6660
  }
5783
6661
  );
@@ -6204,10 +7082,16 @@ function SearchInput({
6204
7082
  onResultClick,
6205
7083
  renderResult,
6206
7084
  showResults = true,
7085
+ categoryId,
7086
+ categoryName,
6207
7087
  className,
6208
7088
  classNames
6209
7089
  }) {
6210
- const { results, isLoading, query, setQuery, clear } = useSearch(searchOptions);
7090
+ const mergedOptions = React3.useMemo(
7091
+ () => categoryId ? { ...searchOptions, category: categoryId } : searchOptions ?? {},
7092
+ [searchOptions, categoryId]
7093
+ );
7094
+ const { results, isLoading, query, setQuery, clear } = useSearch(mergedOptions);
6211
7095
  const handleValueChange = React3.useCallback(
6212
7096
  (value) => {
6213
7097
  setQuery(value);
@@ -6260,6 +7144,10 @@ function SearchInput({
6260
7144
  }
6261
7145
  )
6262
7146
  ] }),
7147
+ categoryId && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-search-category-filter": true, className: classNames?.categoryFilter, children: [
7148
+ "Filtered by: ",
7149
+ categoryName || categoryId
7150
+ ] }),
6263
7151
  showResults && query.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-search-results": true, className: classNames?.results, children: [
6264
7152
  isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-search-loading": true, className: classNames?.loading, "aria-busy": "true", children: "Searching..." }),
6265
7153
  !isLoading && results.length === 0 && query.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-search-empty": true, className: classNames?.empty, children: "No results found" }),
@@ -6270,7 +7158,21 @@ function SearchInput({
6270
7158
  onClick: () => onResultClick?.(product),
6271
7159
  "data-cimplify-search-result": true,
6272
7160
  className: classNames?.resultItem,
6273
- children: renderResult ? renderResult(product) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-search-result-name": true, children: product.name }) })
7161
+ style: !renderResult ? { display: "flex", alignItems: "center", gap: "0.5rem", width: "100%" } : void 0,
7162
+ children: renderResult ? renderResult(product) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
7163
+ (product.images?.[0] || product.image_url) && /* @__PURE__ */ jsxRuntime.jsx(
7164
+ "img",
7165
+ {
7166
+ src: product.images?.[0] || product.image_url,
7167
+ alt: "",
7168
+ "data-cimplify-search-result-image": true,
7169
+ className: classNames?.resultImage,
7170
+ style: { width: "2rem", height: "2rem", objectFit: "cover", borderRadius: "0.25rem", flexShrink: 0 }
7171
+ }
7172
+ ),
7173
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-search-result-name": true, className: classNames?.resultName, style: { flex: 1, textAlign: "left" }, children: product.name }),
7174
+ product.default_price !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-search-result-price": true, className: classNames?.resultPrice, style: { flexShrink: 0 }, children: chunk2BSYTQAY_js.formatPrice(product.default_price) })
7175
+ ] })
6274
7176
  },
6275
7177
  product.id
6276
7178
  ))
@@ -6609,6 +7511,12 @@ var STATUS_LABELS = {
6609
7511
  cancelled: "Cancelled",
6610
7512
  refunded: "Refunded"
6611
7513
  };
7514
+ var PAYMENT_STATE_LABELS = {
7515
+ not_paid: "Not Paid",
7516
+ paid: "Paid",
7517
+ partially_refunded: "Partially Refunded",
7518
+ refunded: "Refunded"
7519
+ };
6612
7520
  function OrderSummary({
6613
7521
  order: orderProp,
6614
7522
  orderId,
@@ -6650,8 +7558,25 @@ function OrderSummary({
6650
7558
  className: classNames?.status,
6651
7559
  children: STATUS_LABELS[order.status] ?? order.status
6652
7560
  }
7561
+ ),
7562
+ order.payment_state && /* @__PURE__ */ jsxRuntime.jsx(
7563
+ "span",
7564
+ {
7565
+ "data-cimplify-order-payment-state": true,
7566
+ "data-payment-state": order.payment_state,
7567
+ className: classNames?.paymentState,
7568
+ children: PAYMENT_STATE_LABELS[order.payment_state] ?? order.payment_state
7569
+ }
6653
7570
  )
6654
7571
  ] }),
7572
+ order.order_type === "pickup" && order.pickup_time && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-fulfillment": true, className: classNames?.fulfillmentDetails, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7573
+ "Pickup time: ",
7574
+ new Date(order.pickup_time).toLocaleString()
7575
+ ] }) }),
7576
+ order.order_type === "dine-in" && order.table_number && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-fulfillment": true, className: classNames?.fulfillmentDetails, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7577
+ "Table: ",
7578
+ order.table_number
7579
+ ] }) }),
6655
7580
  /* @__PURE__ */ jsxRuntime.jsx("time", { "data-cimplify-order-date": true, dateTime: order.created_at, children: new Date(order.created_at).toLocaleDateString(void 0, {
6656
7581
  year: "numeric",
6657
7582
  month: "long",
@@ -6663,6 +7588,10 @@ function OrderSummary({
6663
7588
  order.customer_name && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-order-customer-name": true, children: order.customer_name }),
6664
7589
  order.customer_email && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-order-customer-email": true, children: order.customer_email })
6665
7590
  ] }),
7591
+ order.delivery_address && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-delivery-address": true, className: classNames?.deliveryAddress, children: [
7592
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delivery address" }),
7593
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: order.delivery_address })
7594
+ ] }),
6666
7595
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-items": true, className: classNames?.items, children: order.items.map(
6667
7596
  (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: [
6668
7597
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-line-info": true, children: [
@@ -6672,19 +7601,80 @@ function OrderSummary({
6672
7601
  ] }),
6673
7602
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-order-line-key": true, children: item.line_key })
6674
7603
  ] }),
6675
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: item.price })
7604
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: item.price }),
7605
+ item.fulfillment_type === "digital" && item.fulfillment_id && /* @__PURE__ */ jsxRuntime.jsx(
7606
+ "a",
7607
+ {
7608
+ href: item.fulfillment_id,
7609
+ target: "_blank",
7610
+ rel: "noopener noreferrer",
7611
+ "data-cimplify-order-line-download": true,
7612
+ className: "text-sm text-primary underline",
7613
+ children: "Download"
7614
+ }
7615
+ ),
7616
+ item.configuration.type === "service" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-service-info": true, className: classNames?.serviceInfo, children: [
7617
+ item.configuration.scheduled_start && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7618
+ "\u{1F4C5}",
7619
+ " ",
7620
+ new Date(item.configuration.scheduled_start).toLocaleDateString(),
7621
+ " at ",
7622
+ new Date(item.configuration.scheduled_start).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
7623
+ ] }),
7624
+ item.configuration.confirmation_code && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7625
+ "Confirmation: ",
7626
+ item.configuration.confirmation_code
7627
+ ] }),
7628
+ item.configuration.service_status && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-status": item.configuration.service_status, children: item.configuration.service_status })
7629
+ ] }),
7630
+ item.configuration.type === "digital" && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-digital-info": true, className: classNames?.digitalInfo, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7631
+ "\u26A1",
7632
+ " Instant digital delivery"
7633
+ ] }) }),
7634
+ item.configuration.type === "bundle" && item.configuration.resolved && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-bundle-breakdown": true, className: classNames?.bundleBreakdown, children: item.configuration.resolved.selections.map((sel) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-product-type": sel.product_type, children: [
7635
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7636
+ sel.quantity,
7637
+ "\xD7 ",
7638
+ sel.product_name
7639
+ ] }),
7640
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7641
+ " \u2014 ",
7642
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
7643
+ ] }),
7644
+ sel.product_type === "digital" && /* @__PURE__ */ jsxRuntime.jsx("span", { children: " \u2014 Digital" })
7645
+ ] }, sel.component_id)) }),
7646
+ item.configuration.type === "composite" && item.configuration.resolved && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-composite-breakdown": true, className: classNames?.compositeBreakdown, children: item.configuration.resolved.selections.map((sel) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-product-type": sel.product_type, children: [
7647
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7648
+ sel.quantity,
7649
+ "\xD7 ",
7650
+ sel.component_name
7651
+ ] }),
7652
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
7653
+ " \u2014 ",
7654
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
7655
+ ] }),
7656
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: sel.unit_price })
7657
+ ] }, sel.component_id)) })
6676
7658
  ] }, item.id)
6677
7659
  ) }),
7660
+ order.customer_notes && order.customer_notes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-notes": true, className: classNames?.notes, children: [
7661
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Notes" }),
7662
+ order.customer_notes.map((note, index) => /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-order-note": true, children: note }, index))
7663
+ ] }),
6678
7664
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-totals": true, className: classNames?.totals, children: [
6679
- order.total_discount != null && chunkRYQ5IPWX_js.parsePrice(order.total_discount) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-discount": true, children: [
7665
+ order.total_discount != null && chunk2BSYTQAY_js.parsePrice(order.total_discount) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-discount": true, children: [
6680
7666
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Discount" }),
6681
7667
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.total_discount, prefix: "-" })
6682
7668
  ] }),
6683
- order.service_charge != null && chunkRYQ5IPWX_js.parsePrice(order.service_charge) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-service-charge": true, children: [
7669
+ order.delivery_fee != null && chunk2BSYTQAY_js.parsePrice(order.delivery_fee) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-delivery-fee": true, children: [
7670
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delivery fee" }),
7671
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.delivery_fee })
7672
+ ] }),
7673
+ order.service_charge != null && chunk2BSYTQAY_js.parsePrice(order.service_charge) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-service-charge": true, children: [
6684
7674
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Service charge" }),
6685
7675
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.service_charge })
6686
7676
  ] }),
6687
- order.tax != null && chunkRYQ5IPWX_js.parsePrice(order.tax) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-tax": true, children: [
7677
+ order.tax != null && chunk2BSYTQAY_js.parsePrice(order.tax) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-tax": true, children: [
6688
7678
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Tax" }),
6689
7679
  /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: order.tax })
6690
7680
  ] }),
@@ -6700,6 +7690,7 @@ function OrderSummary({
6700
7690
  target: "_blank",
6701
7691
  rel: "noopener noreferrer",
6702
7692
  "data-cimplify-order-tracking": true,
7693
+ className: classNames?.trackingLink,
6703
7694
  children: "Track your order"
6704
7695
  }
6705
7696
  )
@@ -7365,6 +8356,23 @@ function BookingList({
7365
8356
  booking.order_id
7366
8357
  )) });
7367
8358
  }
8359
+
8360
+ // src/react/utils/format-duration.ts
8361
+ var UNIT_LABELS = {
8362
+ minutes: { singular: "min", plural: "min" },
8363
+ hours: { singular: "hr", plural: "hrs" },
8364
+ days: { singular: "day", plural: "days" },
8365
+ nights: { singular: "night", plural: "nights" },
8366
+ weeks: { singular: "week", plural: "weeks" },
8367
+ months: { singular: "month", plural: "months" },
8368
+ years: { singular: "year", plural: "years" }
8369
+ };
8370
+ function formatDuration2(value, unit) {
8371
+ const resolved = unit ?? "minutes";
8372
+ const labels = UNIT_LABELS[resolved];
8373
+ const label = value === 1 ? labels.singular : labels.plural;
8374
+ return `${value} ${label}`;
8375
+ }
7368
8376
  var ASPECT_STYLES3 = {
7369
8377
  square: { aspectRatio: "1/1" },
7370
8378
  "4/3": { aspectRatio: "4/3" },
@@ -7426,10 +8434,7 @@ function ServiceCard({
7426
8434
  }
7427
8435
  ),
7428
8436
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-service-card-meta": true, className: classNames?.meta, children: [
7429
- /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-service-card-duration": true, className: classNames?.duration, children: [
7430
- service.duration_minutes,
7431
- " min"
7432
- ] }),
8437
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-duration": true, className: classNames?.duration, children: formatDuration2(service.duration_minutes, service.duration_unit) }),
7433
8438
  service.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-price": true, className: classNames?.price, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: service.price }) })
7434
8439
  ] })
7435
8440
  ] }),
@@ -8199,16 +9204,21 @@ function DealsPage({
8199
9204
  }
8200
9205
  function BookingPage({
8201
9206
  service,
9207
+ product,
8202
9208
  staff,
8203
9209
  participantCount,
8204
9210
  title,
8205
9211
  onBooked,
8206
9212
  onBack,
9213
+ existingBooking,
9214
+ onRescheduled,
8207
9215
  showPrice = true,
8208
9216
  className,
8209
9217
  classNames
8210
9218
  }) {
8211
9219
  const { addItem } = useCart();
9220
+ const { client } = useCimplifyClient();
9221
+ const isReschedule = existingBooking !== void 0;
8212
9222
  const [step, setStep] = React3.useState("select-slot");
8213
9223
  const [selectedSlot, setSelectedSlot] = React3.useState(null);
8214
9224
  const [selectedDate, setSelectedDate] = React3.useState(null);
@@ -8216,6 +9226,11 @@ function BookingPage({
8216
9226
  const [isSubmitting, setIsSubmitting] = React3.useState(false);
8217
9227
  const [error, setError] = React3.useState(null);
8218
9228
  const hasStaffStep = staff && staff.length > 0;
9229
+ const depositType = product?.deposit_type;
9230
+ const depositAmount = product?.deposit_amount;
9231
+ const hasDeposit = depositType !== void 0 && depositType !== "none" && depositAmount !== void 0 && chunk2BSYTQAY_js.parsePrice(depositAmount) !== 0;
9232
+ const cancellationMinutes = product?.cancellation_window_minutes;
9233
+ const noShowFee = product?.no_show_fee;
8219
9234
  const handleSlotSelect = React3.useCallback(
8220
9235
  (slot, date) => {
8221
9236
  setSelectedSlot(slot);
@@ -8248,34 +9263,51 @@ function BookingPage({
8248
9263
  setIsSubmitting(true);
8249
9264
  setError(null);
8250
9265
  try {
8251
- const serviceProduct = {
8252
- id: service.product_id || service.id,
8253
- business_id: service.business_id || "",
8254
- category_id: service.category_id || void 0,
8255
- name: service.name,
8256
- slug: service.id,
8257
- description: service.description || void 0,
8258
- image_url: service.image_url || void 0,
8259
- default_price: service.price || "0",
8260
- type: "service",
8261
- inventory_type: "none",
8262
- variant_strategy: "fetch_all",
8263
- is_active: service.is_available,
8264
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
8265
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
8266
- };
8267
- await addItem(serviceProduct, 1, {
8268
- scheduledStart: selectedSlot.start_time,
8269
- scheduledEnd: selectedSlot.end_time,
8270
- staffId: selectedStaffId || void 0
8271
- });
8272
- onBooked?.(selectedSlot, selectedStaffId);
9266
+ if (isReschedule && existingBooking) {
9267
+ const serviceItem = existingBooking.service_items[0];
9268
+ const result = await client.scheduling.rescheduleBooking({
9269
+ order_id: existingBooking.order_id,
9270
+ line_item_id: serviceItem?.service_id ?? existingBooking.order_id,
9271
+ new_start_time: selectedSlot.start_time,
9272
+ new_end_time: selectedSlot.end_time,
9273
+ new_staff_id: selectedStaffId || void 0,
9274
+ reschedule_type: "customer"
9275
+ });
9276
+ if (!result.ok) {
9277
+ throw result.error;
9278
+ }
9279
+ onRescheduled?.(existingBooking, selectedSlot);
9280
+ } else {
9281
+ const serviceProduct = {
9282
+ id: service.product_id || service.id,
9283
+ business_id: service.business_id || "",
9284
+ category_id: service.category_id || void 0,
9285
+ name: service.name,
9286
+ slug: service.id,
9287
+ description: service.description || void 0,
9288
+ image_url: service.image_url || void 0,
9289
+ default_price: service.price || "0",
9290
+ type: "service",
9291
+ inventory_type: "none",
9292
+ variant_strategy: "fetch_all",
9293
+ is_active: service.is_available,
9294
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
9295
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
9296
+ };
9297
+ await addItem(serviceProduct, 1, {
9298
+ scheduledStart: selectedSlot.start_time,
9299
+ scheduledEnd: selectedSlot.end_time,
9300
+ staffId: selectedStaffId || void 0
9301
+ });
9302
+ onBooked?.(selectedSlot, selectedStaffId);
9303
+ }
8273
9304
  } catch (err) {
8274
- setError(err instanceof Error ? err.message : "Failed to add booking to cart");
9305
+ const fallbackMessage = isReschedule ? "Failed to reschedule booking" : "Failed to add booking to cart";
9306
+ setError(err instanceof Error ? err.message : fallbackMessage);
8275
9307
  } finally {
8276
9308
  setIsSubmitting(false);
8277
9309
  }
8278
- }, [selectedSlot, selectedDate, selectedStaffId, service, addItem, onBooked]);
9310
+ }, [selectedSlot, selectedDate, selectedStaffId, service, addItem, onBooked, isReschedule, existingBooking, client, onRescheduled]);
8279
9311
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-page": true, className: cn(className, classNames?.root), children: [
8280
9312
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-page-header": true, className: classNames?.header, children: [
8281
9313
  onBack && step === "select-slot" && /* @__PURE__ */ jsxRuntime.jsx(
@@ -8298,15 +9330,29 @@ function BookingPage({
8298
9330
  children: "Back"
8299
9331
  }
8300
9332
  ),
8301
- /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-booking-page-title": true, className: classNames?.title, children: title || `Book ${service.name}` })
9333
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-booking-page-title": true, className: classNames?.title, children: title || (isReschedule ? "Reschedule Booking" : `Book ${service.name}`) })
8302
9334
  ] }),
9335
+ isReschedule && existingBooking && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-booking-reschedule-info": true, className: classNames?.rescheduleInfo, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
9336
+ "Rescheduling booking from ",
9337
+ new Date(existingBooking.service_items[0]?.scheduled_start ?? existingBooking.created_at).toLocaleDateString()
9338
+ ] }) }),
8303
9339
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-service-info": true, className: classNames?.serviceInfo, children: [
8304
9340
  /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-service-name": true, children: service.name }),
8305
- /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-service-duration": true, children: [
8306
- service.duration_minutes,
8307
- " min"
9341
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-service-duration": true, children: formatDuration2(service.duration_minutes, service.duration_unit) }),
9342
+ service.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-service-price": true, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: service.price }) }),
9343
+ hasDeposit && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-deposit-info": true, className: classNames?.depositInfo, children: [
9344
+ "Deposit: ",
9345
+ depositType === "percentage" ? `${chunk2BSYTQAY_js.parsePrice(depositAmount)}%` : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount })
9346
+ ] }),
9347
+ cancellationMinutes !== void 0 && cancellationMinutes > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-cancellation-policy": true, className: classNames?.cancellationPolicy, children: [
9348
+ "Free cancellation up to ",
9349
+ cancellationMinutes >= 60 ? `${Math.floor(cancellationMinutes / 60)} hour${Math.floor(cancellationMinutes / 60) !== 1 ? "s" : ""}` : `${cancellationMinutes} minute${cancellationMinutes !== 1 ? "s" : ""}`,
9350
+ " before"
8308
9351
  ] }),
8309
- service.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-service-price": true, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: service.price }) })
9352
+ noShowFee !== void 0 && chunk2BSYTQAY_js.parsePrice(noShowFee) !== 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-no-show-fee": true, className: classNames?.cancellationPolicy, children: [
9353
+ "No-show fee: ",
9354
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: noShowFee })
9355
+ ] })
8310
9356
  ] }),
8311
9357
  error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-booking-error": true, className: classNames?.error, children: error }),
8312
9358
  step === "select-slot" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "select-slot", className: classNames?.step, children: [
@@ -8353,10 +9399,7 @@ function BookingPage({
8353
9399
  ] }),
8354
9400
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8355
9401
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Duration" }),
8356
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
8357
- service.duration_minutes,
8358
- " min"
8359
- ] })
9402
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDuration2(service.duration_minutes, service.duration_unit) })
8360
9403
  ] }),
8361
9404
  selectedStaffId && staff && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8362
9405
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Provider" }),
@@ -8365,6 +9408,10 @@ function BookingPage({
8365
9408
  (selectedSlot.price || service.price) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8366
9409
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Price" }),
8367
9410
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: selectedSlot.price || service.price }) })
9411
+ ] }),
9412
+ hasDeposit && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: cn(classNames?.summaryRow, classNames?.depositInfo), children: [
9413
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Deposit" }),
9414
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: depositType === "percentage" ? `${chunk2BSYTQAY_js.parsePrice(depositAmount)}%` : /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: depositAmount }) })
8368
9415
  ] })
8369
9416
  ] }),
8370
9417
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8375,7 +9422,7 @@ function BookingPage({
8375
9422
  disabled: isSubmitting,
8376
9423
  "data-cimplify-booking-confirm": true,
8377
9424
  className: classNames?.confirmButton,
8378
- children: isSubmitting ? "Adding to cart\u2026" : "Add to cart"
9425
+ children: isSubmitting ? isReschedule ? "Rescheduling\u2026" : "Adding to cart\u2026" : isReschedule ? "Reschedule" : "Confirm Booking"
8379
9426
  }
8380
9427
  )
8381
9428
  ] })
@@ -8467,10 +9514,464 @@ function BookingsPage({
8467
9514
  ) })
8468
9515
  ] });
8469
9516
  }
9517
+ function LocationPicker({
9518
+ locations: locationsProp,
9519
+ currentLocation: currentLocationProp,
9520
+ onLocationChange,
9521
+ renderLocation,
9522
+ emptyMessage,
9523
+ className,
9524
+ classNames
9525
+ }) {
9526
+ const {
9527
+ locations: fetched,
9528
+ currentLocation: fetchedCurrent,
9529
+ setCurrentLocation,
9530
+ isLoading
9531
+ } = useLocations();
9532
+ const locations = locationsProp ?? fetched;
9533
+ const currentLocation = currentLocationProp ?? fetchedCurrent;
9534
+ const handleSelect = (location) => {
9535
+ if (onLocationChange) {
9536
+ onLocationChange(location);
9537
+ } else {
9538
+ setCurrentLocation(location);
9539
+ }
9540
+ };
9541
+ if (isLoading && locations.length === 0) {
9542
+ return /* @__PURE__ */ jsxRuntime.jsx(
9543
+ "div",
9544
+ {
9545
+ "data-cimplify-location-picker": true,
9546
+ "aria-busy": "true",
9547
+ className: cn(className, classNames?.root, classNames?.loading)
9548
+ }
9549
+ );
9550
+ }
9551
+ if (locations.length <= 1) {
9552
+ return null;
9553
+ }
9554
+ if (locations.length === 0) {
9555
+ return /* @__PURE__ */ jsxRuntime.jsx(
9556
+ "div",
9557
+ {
9558
+ "data-cimplify-location-picker": true,
9559
+ "data-empty": true,
9560
+ className: cn(className, classNames?.root, classNames?.empty),
9561
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: emptyMessage ?? "No locations available" })
9562
+ }
9563
+ );
9564
+ }
9565
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-location-picker": true, className: cn(className, classNames?.root), children: locations.map((location) => {
9566
+ const isActive = currentLocation?.id === location.id;
9567
+ return /* @__PURE__ */ jsxRuntime.jsx(
9568
+ "button",
9569
+ {
9570
+ type: "button",
9571
+ onClick: () => handleSelect(location),
9572
+ "data-cimplify-location-item": true,
9573
+ "data-active": isActive || void 0,
9574
+ "aria-pressed": isActive,
9575
+ className: cn(classNames?.item, isActive && classNames?.activeItem),
9576
+ children: renderLocation ? renderLocation(location, isActive) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: location.name })
9577
+ },
9578
+ location.id
9579
+ );
9580
+ }) });
9581
+ }
9582
+ function RecommendationCarousel({
9583
+ recommendations: recommendationsProp,
9584
+ locationId,
9585
+ limit,
9586
+ onProductClick,
9587
+ renderProduct,
9588
+ emptyMessage,
9589
+ className,
9590
+ classNames
9591
+ }) {
9592
+ const { recommendations: fetched, isLoading } = useRecommendations({
9593
+ locationId,
9594
+ limit,
9595
+ enabled: recommendationsProp === void 0
9596
+ });
9597
+ const recommendations = recommendationsProp ?? fetched;
9598
+ if (isLoading && recommendations.length === 0) {
9599
+ return /* @__PURE__ */ jsxRuntime.jsx(
9600
+ "div",
9601
+ {
9602
+ "data-cimplify-recommendation-carousel": true,
9603
+ "aria-busy": "true",
9604
+ className: cn(className, classNames?.root, classNames?.loading)
9605
+ }
9606
+ );
9607
+ }
9608
+ if (recommendations.length === 0) {
9609
+ return null;
9610
+ }
9611
+ return /* @__PURE__ */ jsxRuntime.jsx(
9612
+ "div",
9613
+ {
9614
+ "data-cimplify-recommendation-carousel": true,
9615
+ className: cn(className, classNames?.root),
9616
+ style: { display: "flex", overflowX: "auto", gap: "1rem" },
9617
+ children: recommendations.map((rec, index) => {
9618
+ const productId = rec.product?.id ?? String(index);
9619
+ return /* @__PURE__ */ jsxRuntime.jsx(
9620
+ "button",
9621
+ {
9622
+ type: "button",
9623
+ onClick: () => onProductClick?.(rec),
9624
+ "data-cimplify-recommendation-item": true,
9625
+ className: classNames?.item,
9626
+ style: { flexShrink: 0 },
9627
+ children: renderProduct ? renderProduct(rec) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9628
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-recommendation-name": true, children: rec.product?.name ?? rec.product?.id ?? "Product" }),
9629
+ rec.reason && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-recommendation-reason": true, className: classNames?.reason, children: rec.reason })
9630
+ ] })
9631
+ },
9632
+ String(productId)
9633
+ );
9634
+ })
9635
+ }
9636
+ );
9637
+ }
9638
+ function SessionMessageBanner({
9639
+ messages: messagesProp,
9640
+ onDismiss,
9641
+ renderMessage,
9642
+ className,
9643
+ classNames
9644
+ }) {
9645
+ const { messages: fetched, isLoading, dismissMessage } = useActivityState({
9646
+ enabled: messagesProp === void 0
9647
+ });
9648
+ const messages = messagesProp ?? fetched;
9649
+ const handleDismiss = async (code) => {
9650
+ if (onDismiss) {
9651
+ onDismiss(code);
9652
+ } else {
9653
+ await dismissMessage(code);
9654
+ }
9655
+ };
9656
+ if (isLoading && messages.length === 0) {
9657
+ return /* @__PURE__ */ jsxRuntime.jsx(
9658
+ "div",
9659
+ {
9660
+ "data-cimplify-session-message-banner": true,
9661
+ "aria-busy": "true",
9662
+ className: cn(className, classNames?.root)
9663
+ }
9664
+ );
9665
+ }
9666
+ if (messages.length === 0) {
9667
+ return null;
9668
+ }
9669
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-session-message-banner": true, className: cn(className, classNames?.root), children: messages.map((msg) => /* @__PURE__ */ jsxRuntime.jsx(
9670
+ "div",
9671
+ {
9672
+ "data-cimplify-session-message": true,
9673
+ "data-level": msg.level,
9674
+ className: classNames?.message,
9675
+ children: renderMessage ? renderMessage(msg) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9676
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-session-message-text": true, className: classNames?.text, children: msg.text }),
9677
+ msg.dismissible && /* @__PURE__ */ jsxRuntime.jsx(
9678
+ "button",
9679
+ {
9680
+ type: "button",
9681
+ onClick: () => void handleDismiss(msg.code),
9682
+ "data-cimplify-session-message-dismiss": true,
9683
+ className: classNames?.dismissButton,
9684
+ "aria-label": "Dismiss message",
9685
+ children: "\xD7"
9686
+ }
9687
+ )
9688
+ ] })
9689
+ },
9690
+ msg.code
9691
+ )) });
9692
+ }
9693
+ function RecentlyViewed({
9694
+ limit,
9695
+ onProductClick,
9696
+ renderProduct,
9697
+ emptyMessage,
9698
+ className,
9699
+ classNames
9700
+ }) {
9701
+ const { state, isLoading } = useActivityState();
9702
+ const rawViewed = state?.activity?.viewed_products ?? [];
9703
+ const viewed = limit ? rawViewed.slice(0, limit) : rawViewed;
9704
+ if (isLoading && viewed.length === 0) {
9705
+ return /* @__PURE__ */ jsxRuntime.jsx(
9706
+ "div",
9707
+ {
9708
+ "data-cimplify-recently-viewed": true,
9709
+ "aria-busy": "true",
9710
+ className: cn(className, classNames?.root, classNames?.loading)
9711
+ }
9712
+ );
9713
+ }
9714
+ if (viewed.length === 0) {
9715
+ return null;
9716
+ }
9717
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-recently-viewed": true, className: cn(className, classNames?.root), children: viewed.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
9718
+ "button",
9719
+ {
9720
+ type: "button",
9721
+ onClick: () => onProductClick?.(product),
9722
+ "data-cimplify-recently-viewed-item": true,
9723
+ className: classNames?.item,
9724
+ children: renderProduct ? renderProduct(product) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: product.product_name ?? product.product_id })
9725
+ },
9726
+ product.product_id
9727
+ )) });
9728
+ }
9729
+ var FREQUENCY_LABELS = {
9730
+ weekly: "Weekly",
9731
+ monthly: "Monthly",
9732
+ quarterly: "Quarterly",
9733
+ annually: "Annually"
9734
+ };
9735
+ function formatMarkup(plan) {
9736
+ if (!plan.markup_type || plan.markup_amount == null) return null;
9737
+ if (plan.markup_type === "percentage") return `+${plan.markup_amount}%`;
9738
+ return null;
9739
+ }
9740
+ function BillingPlanSelector({
9741
+ productId,
9742
+ plans: plansProp,
9743
+ onPlanSelect,
9744
+ selectedPlanId,
9745
+ showOneTimePurchase = false,
9746
+ oneTimePurchaseLabel = "One-time purchase",
9747
+ renderPlan,
9748
+ className,
9749
+ classNames
9750
+ }) {
9751
+ const { plans: fetched, isLoading } = useBillingPlans(productId, {
9752
+ enabled: plansProp === void 0
9753
+ });
9754
+ const plans = plansProp ?? fetched;
9755
+ if (isLoading && plans.length === 0) {
9756
+ return /* @__PURE__ */ jsxRuntime.jsx(
9757
+ "div",
9758
+ {
9759
+ "data-cimplify-billing-plan-selector": true,
9760
+ "aria-busy": "true",
9761
+ className: cn(className, classNames?.root, classNames?.loading)
9762
+ }
9763
+ );
9764
+ }
9765
+ if (plans.length === 0 && !showOneTimePurchase) {
9766
+ return null;
9767
+ }
9768
+ const isOneTimePurchaseSelected = selectedPlanId === null;
9769
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-billing-plan-selector": true, className: cn(className, classNames?.root), children: [
9770
+ showOneTimePurchase && /* @__PURE__ */ jsxRuntime.jsx(
9771
+ "button",
9772
+ {
9773
+ type: "button",
9774
+ onClick: () => onPlanSelect?.(null),
9775
+ "data-cimplify-billing-plan": true,
9776
+ "data-plan-type": "one-time",
9777
+ "data-active": isOneTimePurchaseSelected || void 0,
9778
+ "aria-pressed": isOneTimePurchaseSelected,
9779
+ className: cn(
9780
+ classNames?.plan,
9781
+ isOneTimePurchaseSelected && classNames?.activePlan
9782
+ ),
9783
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: oneTimePurchaseLabel })
9784
+ }
9785
+ ),
9786
+ plans.map((plan) => {
9787
+ const isActive = selectedPlanId === plan.id;
9788
+ const markup = formatMarkup(plan);
9789
+ return /* @__PURE__ */ jsxRuntime.jsx(
9790
+ "button",
9791
+ {
9792
+ type: "button",
9793
+ onClick: () => onPlanSelect?.(plan),
9794
+ "data-cimplify-billing-plan": true,
9795
+ "data-plan-type": plan.plan_type,
9796
+ "data-active": isActive || void 0,
9797
+ "aria-pressed": isActive,
9798
+ className: cn(classNames?.plan, isActive && classNames?.activePlan),
9799
+ children: renderPlan ? renderPlan(plan, isActive) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9800
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: FREQUENCY_LABELS[plan.frequency] }),
9801
+ markup && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: markup }),
9802
+ plan.markup_type === "fixed" && plan.markup_amount != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: [
9803
+ "+",
9804
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: plan.markup_amount })
9805
+ ] }),
9806
+ plan.trial_days > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-trial": true, className: classNames?.trialBadge, children: [
9807
+ plan.trial_days,
9808
+ "-day trial"
9809
+ ] }),
9810
+ plan.setup_fee > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-setup-fee": true, className: classNames?.setupFee, children: [
9811
+ "Setup fee: ",
9812
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: plan.setup_fee })
9813
+ ] }),
9814
+ plan.plan_type === "installment" && plan.installment_periods != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-billing-periods": true, children: [
9815
+ plan.installment_periods,
9816
+ " payments"
9817
+ ] })
9818
+ ] })
9819
+ },
9820
+ plan.id
9821
+ );
9822
+ })
9823
+ ] });
9824
+ }
9825
+ function DeliveryEstimate({
9826
+ latitude,
9827
+ longitude,
9828
+ country,
9829
+ onFeeCalculated,
9830
+ className,
9831
+ classNames
9832
+ }) {
9833
+ const context = useOptionalCimplifyClient();
9834
+ const client = context?.client ?? null;
9835
+ const [result, setResult] = React3.useState(null);
9836
+ const [isLoading, setIsLoading] = React3.useState(true);
9837
+ const [error, setError] = React3.useState(null);
9838
+ const requestIdRef = React3.useRef(0);
9839
+ React3.useEffect(() => {
9840
+ if (!client) return;
9841
+ const nextRequestId = ++requestIdRef.current;
9842
+ setIsLoading(true);
9843
+ setError(null);
9844
+ void (async () => {
9845
+ const res = await client.delivery.getFee(latitude, longitude, country);
9846
+ if (nextRequestId !== requestIdRef.current) return;
9847
+ if (!res.ok) {
9848
+ setError(res.error);
9849
+ setResult(null);
9850
+ setIsLoading(false);
9851
+ return;
9852
+ }
9853
+ setResult(res.value);
9854
+ setError(null);
9855
+ setIsLoading(false);
9856
+ onFeeCalculated?.(res.value);
9857
+ })();
9858
+ }, [client, latitude, longitude, country]);
9859
+ if (!client) {
9860
+ return null;
9861
+ }
9862
+ if (isLoading) {
9863
+ return /* @__PURE__ */ jsxRuntime.jsx(
9864
+ "div",
9865
+ {
9866
+ "data-cimplify-delivery-estimate": true,
9867
+ "data-serviceable": "false",
9868
+ "aria-busy": "true",
9869
+ className: cn(className, classNames?.root, classNames?.loading)
9870
+ }
9871
+ );
9872
+ }
9873
+ if (error) {
9874
+ return /* @__PURE__ */ jsxRuntime.jsx(
9875
+ "div",
9876
+ {
9877
+ "data-cimplify-delivery-estimate": true,
9878
+ "data-serviceable": "false",
9879
+ className: cn(className, classNames?.root, classNames?.error),
9880
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: error.message })
9881
+ }
9882
+ );
9883
+ }
9884
+ if (!result || !result.serviceable) {
9885
+ return /* @__PURE__ */ jsxRuntime.jsx(
9886
+ "div",
9887
+ {
9888
+ "data-cimplify-delivery-estimate": true,
9889
+ "data-serviceable": "false",
9890
+ className: cn(className, classNames?.root, classNames?.notServiceable),
9891
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Not serviceable" })
9892
+ }
9893
+ );
9894
+ }
9895
+ return /* @__PURE__ */ jsxRuntime.jsxs(
9896
+ "div",
9897
+ {
9898
+ "data-cimplify-delivery-estimate": true,
9899
+ "data-serviceable": "true",
9900
+ className: cn(className, classNames?.root),
9901
+ children: [
9902
+ result.fee != null && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-delivery-fee": true, className: classNames?.fee, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: result.fee }) }),
9903
+ result.currency && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-delivery-currency": true, className: classNames?.currency, children: result.currency })
9904
+ ]
9905
+ }
9906
+ );
9907
+ }
9908
+ function CurrencySelector({
9909
+ currencies,
9910
+ currentCurrency,
9911
+ onCurrencyChange,
9912
+ showRate = false,
9913
+ baseCurrency,
9914
+ renderCurrency,
9915
+ className,
9916
+ classNames
9917
+ }) {
9918
+ const context = useOptionalCimplifyClient();
9919
+ const client = context?.client ?? null;
9920
+ const [rates, setRates] = React3.useState({});
9921
+ const [isLoadingRates, setIsLoadingRates] = React3.useState(false);
9922
+ const requestIdRef = React3.useRef(0);
9923
+ React3.useEffect(() => {
9924
+ if (!showRate || !baseCurrency || !client) return;
9925
+ const targets = currencies.filter((c) => c !== baseCurrency);
9926
+ if (targets.length === 0) return;
9927
+ const nextRequestId = ++requestIdRef.current;
9928
+ setIsLoadingRates(true);
9929
+ void (async () => {
9930
+ const fetched = {};
9931
+ await Promise.all(
9932
+ targets.map(async (currency) => {
9933
+ const res = await client.fx.getRate(baseCurrency, currency);
9934
+ if (res.ok) {
9935
+ fetched[currency] = res.value;
9936
+ }
9937
+ })
9938
+ );
9939
+ if (nextRequestId !== requestIdRef.current) return;
9940
+ setRates(fetched);
9941
+ setIsLoadingRates(false);
9942
+ })();
9943
+ }, [client, showRate, baseCurrency, currencies]);
9944
+ if (currencies.length <= 1) {
9945
+ return null;
9946
+ }
9947
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-currency-selector": true, className: cn(className, classNames?.root), children: currencies.map((currency) => {
9948
+ const isActive = currentCurrency === currency;
9949
+ const rate = rates[currency] ?? null;
9950
+ return /* @__PURE__ */ jsxRuntime.jsx(
9951
+ "button",
9952
+ {
9953
+ type: "button",
9954
+ onClick: () => onCurrencyChange?.(currency),
9955
+ "data-cimplify-currency-option": true,
9956
+ "data-active": isActive || void 0,
9957
+ "aria-pressed": isActive,
9958
+ className: cn(
9959
+ classNames?.option,
9960
+ isActive && classNames?.activeOption
9961
+ ),
9962
+ children: renderCurrency ? renderCurrency(currency, isActive, rate) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9963
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-currency-label": true, className: classNames?.label, children: currency }),
9964
+ showRate && baseCurrency && currency !== baseCurrency && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-currency-rate": true, className: classNames?.rate, children: isLoadingRates ? "..." : rate ? `1 ${baseCurrency} = ${rate.rate.toFixed(4)} ${currency}` : null })
9965
+ ] })
9966
+ },
9967
+ currency
9968
+ );
9969
+ }) });
9970
+ }
8470
9971
 
8471
9972
  Object.defineProperty(exports, "getVariantDisplayName", {
8472
9973
  enumerable: true,
8473
- get: function () { return chunkMJECWMOY_js.getVariantDisplayName; }
9974
+ get: function () { return chunkAVVLN353_js.getVariantDisplayName; }
8474
9975
  });
8475
9976
  exports.Ad = Ad;
8476
9977
  exports.AdProvider = AdProvider;
@@ -8478,6 +9979,7 @@ exports.AddOnSelector = AddOnSelector;
8478
9979
  exports.AddressElement = AddressElement;
8479
9980
  exports.AuthElement = AuthElement;
8480
9981
  exports.AvailabilityBadge = AvailabilityBadge;
9982
+ exports.BillingPlanSelector = BillingPlanSelector;
8481
9983
  exports.BookingCard = BookingCard;
8482
9984
  exports.BookingList = BookingList;
8483
9985
  exports.BookingPage = BookingPage;
@@ -8493,11 +9995,14 @@ exports.CimplifyCheckout = CimplifyCheckout;
8493
9995
  exports.CimplifyProvider = CimplifyProvider;
8494
9996
  exports.CollectionPage = CollectionPage;
8495
9997
  exports.CompositeSelector = CompositeSelector;
9998
+ exports.CurrencySelector = CurrencySelector;
8496
9999
  exports.DateSlotPicker = DateSlotPicker;
8497
10000
  exports.DealBanner = DealBanner;
8498
10001
  exports.DealsPage = DealsPage;
10002
+ exports.DeliveryEstimate = DeliveryEstimate;
8499
10003
  exports.DiscountInput = DiscountInput;
8500
10004
  exports.ElementsProvider = ElementsProvider;
10005
+ exports.LocationPicker = LocationPicker;
8501
10006
  exports.OrderDetailPage = OrderDetailPage;
8502
10007
  exports.OrderHistory = OrderHistory;
8503
10008
  exports.OrderHistoryPage = OrderHistoryPage;
@@ -8511,19 +10016,26 @@ exports.ProductImageGallery = ProductImageGallery;
8511
10016
  exports.ProductPage = ProductPage;
8512
10017
  exports.ProductSheet = ProductSheet;
8513
10018
  exports.QuantitySelector = QuantitySelector;
10019
+ exports.RecentlyViewed = RecentlyViewed;
10020
+ exports.RecommendationCarousel = RecommendationCarousel;
8514
10021
  exports.SaleBadge = SaleBadge;
8515
10022
  exports.SearchInput = SearchInput;
8516
10023
  exports.SearchPage = SearchPage;
8517
10024
  exports.ServiceCard = ServiceCard;
8518
10025
  exports.ServiceGrid = ServiceGrid;
10026
+ exports.SessionMessageBanner = SessionMessageBanner;
8519
10027
  exports.SlotPicker = SlotPicker;
8520
10028
  exports.StaffPicker = StaffPicker;
8521
10029
  exports.StoreNav = StoreNav;
8522
10030
  exports.VariantSelector = VariantSelector;
8523
10031
  exports.cn = cn;
10032
+ exports.useActivityState = useActivityState;
8524
10033
  exports.useAds = useAds;
10034
+ exports.useAttributeDefinitions = useAttributeDefinitions;
8525
10035
  exports.useAvailableSlots = useAvailableSlots;
10036
+ exports.useBillingPlans = useBillingPlans;
8526
10037
  exports.useBookings = useBookings;
10038
+ exports.useBootstrap = useBootstrap;
8527
10039
  exports.useBundles = useBundles;
8528
10040
  exports.useCart = useCart;
8529
10041
  exports.useCategories = useCategories;
@@ -8533,8 +10045,10 @@ exports.useCimplifyClient = useCimplifyClient;
8533
10045
  exports.useCollection = useCollection;
8534
10046
  exports.useCollections = useCollections;
8535
10047
  exports.useDeals = useDeals;
10048
+ exports.useDeliveryFee = useDeliveryFee;
8536
10049
  exports.useElements = useElements;
8537
10050
  exports.useElementsReady = useElementsReady;
10051
+ exports.useFxRate = useFxRate;
8538
10052
  exports.useLocations = useLocations;
8539
10053
  exports.useOptionalCimplify = useOptionalCimplify;
8540
10054
  exports.useOrder = useOrder;
@@ -8546,7 +10060,9 @@ exports.useProductPrice = useProductPrice;
8546
10060
  exports.useProductSchedules = useProductSchedules;
8547
10061
  exports.useProducts = useProducts;
8548
10062
  exports.useProductsOnSale = useProductsOnSale;
10063
+ exports.usePropertyFacets = usePropertyFacets;
8549
10064
  exports.useQuote = useQuote;
10065
+ exports.useRecommendations = useRecommendations;
8550
10066
  exports.useSearch = useSearch;
8551
10067
  exports.useServiceAvailability = useServiceAvailability;
8552
10068
  exports.useServices = useServices;
@@ -8554,3 +10070,4 @@ exports.useTaxonomies = useTaxonomies;
8554
10070
  exports.useTaxonomy = useTaxonomy;
8555
10071
  exports.useTaxonomyPath = useTaxonomyPath;
8556
10072
  exports.useValidateDiscount = useValidateDiscount;
10073
+ exports.useVariantSelector = useVariantSelector;