@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.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { getVariantDisplayName, createCimplifyClient } from './chunk-KTTQC5HG.mjs';
3
- export { getVariantDisplayName } from './chunk-KTTQC5HG.mjs';
4
- import { ELEMENT_TYPES, EVENT_TYPES } from './chunk-2JI47EYJ.mjs';
5
- import { isSupportedCurrency, formatPrice, parsePrice, isOnSale, getDiscountPercentage, getBasePrice } from './chunk-FTL2SXCG.mjs';
2
+ import { getVariantDisplayName, createCimplifyClient } from './chunk-676BJ3EU.mjs';
3
+ export { getVariantDisplayName } from './chunk-676BJ3EU.mjs';
4
+ import { ELEMENT_TYPES, EVENT_TYPES } from './chunk-7KH2XJIW.mjs';
5
+ import { isSupportedCurrency, formatPrice, parsePrice, isOnSale, getDiscountPercentage, getBasePrice } from './chunk-HG7GG3TT.mjs';
6
6
  import React3, { createContext, useContext, useState, useEffect, useRef, useMemo, useSyncExternalStore, useCallback, useId } from 'react';
7
7
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
8
8
  import { NumberField } from '@base-ui/react/number-field';
@@ -532,7 +532,12 @@ function mapServerCart(serverCart) {
532
532
  specialInstructions: item.special_instructions,
533
533
  scheduledStart: item.scheduled_start || void 0,
534
534
  scheduledEnd: item.scheduled_end || void 0,
535
- staffId: item.staff_id || void 0
535
+ staffId: item.staff_id || void 0,
536
+ lineType: item.line_type,
537
+ confirmationCode: item.confirmation_code || void 0,
538
+ serviceStatus: item.service_status || void 0,
539
+ bundleResolved: item.bundle_resolved || void 0,
540
+ compositeResolved: item.composite_resolved || void 0
536
541
  });
537
542
  });
538
543
  return {
@@ -2089,7 +2094,7 @@ function useOrder(orderId, options = {}) {
2089
2094
  return () => {
2090
2095
  window.clearInterval(timer);
2091
2096
  };
2092
- }, [enabled, load, normalizedOrderId.length, poll, pollInterval]);
2097
+ }, [enabled, load, normalizedOrderId, poll, pollInterval]);
2093
2098
  const refetch = useCallback(async () => {
2094
2099
  orderCache.delete(cacheKey);
2095
2100
  await load(true);
@@ -3989,6 +3994,682 @@ function useBookings(options = {}) {
3989
3994
  );
3990
3995
  return { bookings, isLoading, error, refetch, cancelBooking };
3991
3996
  }
3997
+ var definitionsCache = /* @__PURE__ */ new Map();
3998
+ var definitionsInflight = /* @__PURE__ */ new Map();
3999
+ function buildCacheKey(client, namespace) {
4000
+ return `attr_defs_${client.getPublicKey() || "__demo__"}${namespace ? `_${namespace}` : ""}`;
4001
+ }
4002
+ function useAttributeDefinitions(options = {}) {
4003
+ const context = useOptionalCimplifyClient();
4004
+ const client = options.client ?? context?.client;
4005
+ if (!client) {
4006
+ throw new Error(
4007
+ "useAttributeDefinitions must be used within CimplifyProvider or passed { client }."
4008
+ );
4009
+ }
4010
+ const enabled = options.enabled ?? true;
4011
+ const namespace = options.namespace;
4012
+ const cacheKey = useMemo(() => buildCacheKey(client, namespace), [client, namespace]);
4013
+ const cached = definitionsCache.get(cacheKey);
4014
+ const [definitions, setDefinitions] = useState(cached ?? []);
4015
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4016
+ const [error, setError] = useState(null);
4017
+ const load = useCallback(
4018
+ async (force = false) => {
4019
+ if (!enabled) {
4020
+ setIsLoading(false);
4021
+ return;
4022
+ }
4023
+ setError(null);
4024
+ if (!force) {
4025
+ const cachedDefs = definitionsCache.get(cacheKey);
4026
+ if (cachedDefs) {
4027
+ setDefinitions(cachedDefs);
4028
+ setIsLoading(false);
4029
+ return;
4030
+ }
4031
+ }
4032
+ setIsLoading(true);
4033
+ try {
4034
+ const existing = definitionsInflight.get(cacheKey);
4035
+ const promise = existing ?? (async () => {
4036
+ const result = await client.catalogue.getAttributeDefinitions(namespace);
4037
+ if (!result.ok) {
4038
+ throw result.error;
4039
+ }
4040
+ return result.value;
4041
+ })();
4042
+ if (!existing) {
4043
+ definitionsInflight.set(
4044
+ cacheKey,
4045
+ promise.finally(() => {
4046
+ definitionsInflight.delete(cacheKey);
4047
+ })
4048
+ );
4049
+ }
4050
+ const value = await promise;
4051
+ definitionsCache.set(cacheKey, value);
4052
+ setDefinitions(value);
4053
+ } catch (loadError) {
4054
+ setError(loadError);
4055
+ } finally {
4056
+ setIsLoading(false);
4057
+ }
4058
+ },
4059
+ [cacheKey, client, enabled]
4060
+ );
4061
+ useEffect(() => {
4062
+ void load(false);
4063
+ }, [load]);
4064
+ const refetch = useCallback(async () => {
4065
+ definitionsCache.delete(cacheKey);
4066
+ await load(true);
4067
+ }, [cacheKey, load]);
4068
+ return { definitions, isLoading, error, refetch };
4069
+ }
4070
+ var facetsCache = /* @__PURE__ */ new Map();
4071
+ var facetsInflight = /* @__PURE__ */ new Map();
4072
+ function usePropertyFacets(options = {}) {
4073
+ const context = useOptionalCimplifyClient();
4074
+ const client = options.client ?? context?.client;
4075
+ if (!client) {
4076
+ throw new Error(
4077
+ "usePropertyFacets must be used within CimplifyProvider or passed { client }."
4078
+ );
4079
+ }
4080
+ const enabled = options.enabled ?? true;
4081
+ const cacheKey = useMemo(
4082
+ () => `facets_${client.getPublicKey() || "__demo__"}_${options.category_id ?? ""}_${options.product_type ?? ""}`,
4083
+ [client, options.category_id, options.product_type]
4084
+ );
4085
+ const cached = facetsCache.get(cacheKey);
4086
+ const [facets, setFacets] = useState(cached ?? []);
4087
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4088
+ const [error, setError] = useState(null);
4089
+ const load = useCallback(
4090
+ async (force = false) => {
4091
+ if (!enabled) {
4092
+ setIsLoading(false);
4093
+ return;
4094
+ }
4095
+ setError(null);
4096
+ if (!force) {
4097
+ const cachedFacets = facetsCache.get(cacheKey);
4098
+ if (cachedFacets) {
4099
+ setFacets(cachedFacets);
4100
+ setIsLoading(false);
4101
+ return;
4102
+ }
4103
+ }
4104
+ setIsLoading(true);
4105
+ try {
4106
+ const existing = facetsInflight.get(cacheKey);
4107
+ const promise = existing ?? (async () => {
4108
+ const result = await client.catalogue.getPropertyFacets({
4109
+ category_id: options.category_id,
4110
+ product_type: options.product_type
4111
+ });
4112
+ if (!result.ok) {
4113
+ throw result.error;
4114
+ }
4115
+ return result.value;
4116
+ })();
4117
+ if (!existing) {
4118
+ facetsInflight.set(
4119
+ cacheKey,
4120
+ promise.finally(() => {
4121
+ facetsInflight.delete(cacheKey);
4122
+ })
4123
+ );
4124
+ }
4125
+ const value = await promise;
4126
+ facetsCache.set(cacheKey, value);
4127
+ setFacets(value);
4128
+ } catch (loadError) {
4129
+ setError(loadError);
4130
+ } finally {
4131
+ setIsLoading(false);
4132
+ }
4133
+ },
4134
+ [cacheKey, client, enabled, options.category_id, options.product_type]
4135
+ );
4136
+ useEffect(() => {
4137
+ void load(false);
4138
+ }, [load]);
4139
+ const refetch = useCallback(async () => {
4140
+ facetsCache.delete(cacheKey);
4141
+ await load(true);
4142
+ }, [cacheKey, load]);
4143
+ return { facets, isLoading, error, refetch };
4144
+ }
4145
+ function useBillingPlans(productId, options = {}) {
4146
+ const context = useOptionalCimplifyClient();
4147
+ const client = options.client ?? context?.client;
4148
+ if (!client) {
4149
+ throw new Error("useBillingPlans must be used within CimplifyProvider or passed { client }.");
4150
+ }
4151
+ const enabled = options.enabled ?? true;
4152
+ const requestIdRef = useRef(0);
4153
+ const [plans, setPlans] = useState([]);
4154
+ const [isLoading, setIsLoading] = useState(enabled && !!productId);
4155
+ const [error, setError] = useState(null);
4156
+ const customerId = options.customerId;
4157
+ const quantity = options.quantity;
4158
+ const orderValue = options.orderValue;
4159
+ const load = useCallback(
4160
+ async (force = false) => {
4161
+ if (!enabled || !productId) {
4162
+ setPlans([]);
4163
+ setIsLoading(false);
4164
+ return;
4165
+ }
4166
+ const nextRequestId = ++requestIdRef.current;
4167
+ setError(null);
4168
+ setIsLoading(true);
4169
+ try {
4170
+ const result = await client.catalogue.getEligibleBillingPlans(productId, {
4171
+ customer_id: customerId,
4172
+ quantity,
4173
+ order_value: orderValue
4174
+ });
4175
+ if (!result.ok) {
4176
+ throw result.error;
4177
+ }
4178
+ if (nextRequestId === requestIdRef.current) {
4179
+ setPlans(result.value);
4180
+ setError(null);
4181
+ }
4182
+ } catch (loadError) {
4183
+ if (nextRequestId === requestIdRef.current) {
4184
+ setError(loadError);
4185
+ }
4186
+ } finally {
4187
+ if (nextRequestId === requestIdRef.current) {
4188
+ setIsLoading(false);
4189
+ }
4190
+ }
4191
+ },
4192
+ [client, enabled, productId, customerId, quantity, orderValue]
4193
+ );
4194
+ useEffect(() => {
4195
+ void load(false);
4196
+ }, [load]);
4197
+ const refetch = useCallback(async () => {
4198
+ await load(true);
4199
+ }, [load]);
4200
+ const subscriptionPlans = useMemo(
4201
+ () => plans.filter((p) => p.plan_type === "subscription"),
4202
+ [plans]
4203
+ );
4204
+ const installmentPlans = useMemo(
4205
+ () => plans.filter((p) => p.plan_type === "installment"),
4206
+ [plans]
4207
+ );
4208
+ return { plans, subscriptionPlans, installmentPlans, isLoading, error, refetch };
4209
+ }
4210
+ function findMatchingVariant(variants, selections) {
4211
+ const axisCount = Object.keys(selections).length;
4212
+ if (axisCount === 0) return null;
4213
+ return variants.find((v) => {
4214
+ const sel = v.axis_selections;
4215
+ if (!sel) return false;
4216
+ return Object.entries(selections).every(([axisId, valueId]) => sel[axisId] === valueId);
4217
+ }) ?? null;
4218
+ }
4219
+ function computeAvailableValues(variants, axes, selections) {
4220
+ const result = {};
4221
+ for (const axis of axes) {
4222
+ const otherSelections = Object.entries(selections).filter(([id]) => id !== axis.id);
4223
+ const candidates = variants.filter((v) => {
4224
+ const sel = v.axis_selections;
4225
+ if (!sel) return false;
4226
+ return otherSelections.every(([axisId, valueId]) => sel[axisId] === valueId);
4227
+ });
4228
+ const available = /* @__PURE__ */ new Set();
4229
+ for (const v of candidates) {
4230
+ const val = v.axis_selections?.[axis.id];
4231
+ if (val) available.add(val);
4232
+ }
4233
+ result[axis.id] = available;
4234
+ }
4235
+ return result;
4236
+ }
4237
+ function useVariantSelector(options) {
4238
+ const { variants, axes } = options;
4239
+ const [selectedValues, setSelectedValues] = useState({});
4240
+ const selectValue = useCallback(
4241
+ (axisId, valueId) => {
4242
+ setSelectedValues((prev) => {
4243
+ if (prev[axisId] === valueId) {
4244
+ const next = { ...prev };
4245
+ delete next[axisId];
4246
+ return next;
4247
+ }
4248
+ return { ...prev, [axisId]: valueId };
4249
+ });
4250
+ },
4251
+ []
4252
+ );
4253
+ const reset = useCallback(() => setSelectedValues({}), []);
4254
+ const selectedVariant = useMemo(
4255
+ () => findMatchingVariant(variants, selectedValues),
4256
+ [variants, selectedValues]
4257
+ );
4258
+ const variantImage = useMemo(
4259
+ () => selectedVariant?.images?.[0] ?? null,
4260
+ [selectedVariant]
4261
+ );
4262
+ const availableValues = useMemo(
4263
+ () => computeAvailableValues(variants, axes, selectedValues),
4264
+ [variants, axes, selectedValues]
4265
+ );
4266
+ return {
4267
+ selectedValues,
4268
+ selectedVariant,
4269
+ variantImage,
4270
+ availableValues,
4271
+ selectValue,
4272
+ reset
4273
+ };
4274
+ }
4275
+ var activityStateCache = /* @__PURE__ */ new Map();
4276
+ var activityStateInflight = /* @__PURE__ */ new Map();
4277
+ function buildActivityStateCacheKey(client) {
4278
+ return JSON.stringify({ key: client.getPublicKey(), type: "activity_state" });
4279
+ }
4280
+ function useActivityState(options = {}) {
4281
+ const context = useOptionalCimplifyClient();
4282
+ const client = options.client ?? context?.client;
4283
+ if (!client) {
4284
+ throw new Error("useActivityState must be used within CimplifyProvider or passed { client }.");
4285
+ }
4286
+ const enabled = options.enabled ?? true;
4287
+ const cacheKey = useMemo(() => buildActivityStateCacheKey(client), [client]);
4288
+ const cached = activityStateCache.get(cacheKey);
4289
+ const [state, setState] = useState(cached ?? null);
4290
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4291
+ const [error, setError] = useState(null);
4292
+ const load = useCallback(
4293
+ async (force = false) => {
4294
+ if (!enabled) {
4295
+ setIsLoading(false);
4296
+ return;
4297
+ }
4298
+ setError(null);
4299
+ if (!force) {
4300
+ const cachedState = activityStateCache.get(cacheKey);
4301
+ if (cachedState) {
4302
+ setState(cachedState);
4303
+ setIsLoading(false);
4304
+ return;
4305
+ }
4306
+ }
4307
+ setIsLoading(true);
4308
+ try {
4309
+ const existing = activityStateInflight.get(cacheKey);
4310
+ const promise = existing ?? (async () => {
4311
+ const result = await client.activity.getState();
4312
+ if (!result.ok) {
4313
+ throw result.error;
4314
+ }
4315
+ return result.value;
4316
+ })();
4317
+ if (!existing) {
4318
+ activityStateInflight.set(
4319
+ cacheKey,
4320
+ promise.finally(() => {
4321
+ activityStateInflight.delete(cacheKey);
4322
+ })
4323
+ );
4324
+ }
4325
+ const value = await promise;
4326
+ activityStateCache.set(cacheKey, value);
4327
+ setState(value);
4328
+ } catch (loadError) {
4329
+ setError(loadError);
4330
+ } finally {
4331
+ setIsLoading(false);
4332
+ }
4333
+ },
4334
+ [cacheKey, client, enabled]
4335
+ );
4336
+ useEffect(() => {
4337
+ void load(false);
4338
+ }, [load]);
4339
+ const refetch = useCallback(async () => {
4340
+ activityStateCache.delete(cacheKey);
4341
+ await load(true);
4342
+ }, [cacheKey, load]);
4343
+ const dismissMessage = useCallback(
4344
+ async (code) => {
4345
+ const result = await client.activity.dismissMessage(code);
4346
+ if (!result.ok) {
4347
+ setError(result.error);
4348
+ return;
4349
+ }
4350
+ setState((prev) => {
4351
+ if (!prev) return prev;
4352
+ return { ...prev, messages: result.value.messages };
4353
+ });
4354
+ activityStateCache.delete(cacheKey);
4355
+ await load(true);
4356
+ },
4357
+ [cacheKey, client, load]
4358
+ );
4359
+ const messages = state?.messages ?? [];
4360
+ const intent = state?.intent ?? "";
4361
+ return { state, messages, intent, isLoading, error, refetch, dismissMessage };
4362
+ }
4363
+ var recommendationsCache = /* @__PURE__ */ new Map();
4364
+ var recommendationsInflight = /* @__PURE__ */ new Map();
4365
+ function buildRecommendationsCacheKey(client, locationId, limit) {
4366
+ return JSON.stringify({
4367
+ key: client.getPublicKey(),
4368
+ type: "recommendations",
4369
+ location_id: locationId,
4370
+ limit
4371
+ });
4372
+ }
4373
+ function useRecommendations(options = {}) {
4374
+ const context = useOptionalCimplifyClient();
4375
+ const client = options.client ?? context?.client;
4376
+ if (!client) {
4377
+ throw new Error(
4378
+ "useRecommendations must be used within CimplifyProvider or passed { client }."
4379
+ );
4380
+ }
4381
+ const enabled = options.enabled ?? true;
4382
+ const locationId = options.locationId ?? client.getLocationId() ?? void 0;
4383
+ const limit = options.limit;
4384
+ const previousLocationIdRef = useRef(locationId);
4385
+ const cacheKey = useMemo(
4386
+ () => buildRecommendationsCacheKey(client, locationId, limit),
4387
+ [client, locationId, limit]
4388
+ );
4389
+ const cached = recommendationsCache.get(cacheKey);
4390
+ const [response, setResponse] = useState(cached ?? null);
4391
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4392
+ const [error, setError] = useState(null);
4393
+ useEffect(() => {
4394
+ if (previousLocationIdRef.current !== locationId) {
4395
+ recommendationsCache.clear();
4396
+ recommendationsInflight.clear();
4397
+ previousLocationIdRef.current = locationId;
4398
+ }
4399
+ }, [locationId]);
4400
+ const load = useCallback(
4401
+ async (force = false) => {
4402
+ if (!enabled) {
4403
+ setIsLoading(false);
4404
+ return;
4405
+ }
4406
+ setError(null);
4407
+ if (!force) {
4408
+ const cachedResponse = recommendationsCache.get(cacheKey);
4409
+ if (cachedResponse) {
4410
+ setResponse(cachedResponse);
4411
+ setIsLoading(false);
4412
+ return;
4413
+ }
4414
+ }
4415
+ setIsLoading(true);
4416
+ try {
4417
+ const existing = recommendationsInflight.get(cacheKey);
4418
+ const promise = existing ?? (async () => {
4419
+ const result = await client.activity.getRecommendations({
4420
+ location_id: locationId,
4421
+ limit
4422
+ });
4423
+ if (!result.ok) {
4424
+ throw result.error;
4425
+ }
4426
+ return result.value;
4427
+ })();
4428
+ if (!existing) {
4429
+ recommendationsInflight.set(
4430
+ cacheKey,
4431
+ promise.finally(() => {
4432
+ recommendationsInflight.delete(cacheKey);
4433
+ })
4434
+ );
4435
+ }
4436
+ const value = await promise;
4437
+ recommendationsCache.set(cacheKey, value);
4438
+ setResponse(value);
4439
+ } catch (loadError) {
4440
+ setError(loadError);
4441
+ } finally {
4442
+ setIsLoading(false);
4443
+ }
4444
+ },
4445
+ [cacheKey, client, enabled, locationId, limit]
4446
+ );
4447
+ useEffect(() => {
4448
+ void load(false);
4449
+ }, [load]);
4450
+ const refetch = useCallback(async () => {
4451
+ recommendationsCache.delete(cacheKey);
4452
+ await load(true);
4453
+ }, [cacheKey, load]);
4454
+ const recommendations = response?.recommendations ?? [];
4455
+ const intent = response?.intent ?? "";
4456
+ return { recommendations, intent, isLoading, error, refetch };
4457
+ }
4458
+ var deliveryFeeCache = /* @__PURE__ */ new Map();
4459
+ function buildDeliveryFeeCacheKey(client, latitude, longitude, country) {
4460
+ return JSON.stringify({
4461
+ key: client.getPublicKey(),
4462
+ lat: latitude,
4463
+ lng: longitude,
4464
+ country
4465
+ });
4466
+ }
4467
+ function useDeliveryFee(options) {
4468
+ const context = useOptionalCimplifyClient();
4469
+ const client = options.client ?? context?.client;
4470
+ if (!client) {
4471
+ throw new Error("useDeliveryFee must be used within CimplifyProvider or passed { client }.");
4472
+ }
4473
+ const enabled = options.enabled ?? true;
4474
+ const { latitude, longitude, country } = options;
4475
+ const cacheKey = useMemo(
4476
+ () => buildDeliveryFeeCacheKey(client, latitude, longitude, country),
4477
+ [client, latitude, longitude, country]
4478
+ );
4479
+ const cached = deliveryFeeCache.get(cacheKey);
4480
+ const [fee, setFee] = useState(cached ?? null);
4481
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4482
+ const [error, setError] = useState(null);
4483
+ const requestIdRef = useRef(0);
4484
+ const load = useCallback(
4485
+ async (force = false) => {
4486
+ if (!enabled) {
4487
+ setIsLoading(false);
4488
+ return;
4489
+ }
4490
+ setError(null);
4491
+ if (!force) {
4492
+ const cachedFee = deliveryFeeCache.get(cacheKey);
4493
+ if (cachedFee) {
4494
+ setFee(cachedFee);
4495
+ setIsLoading(false);
4496
+ return;
4497
+ }
4498
+ }
4499
+ setIsLoading(true);
4500
+ const currentRequestId = ++requestIdRef.current;
4501
+ try {
4502
+ const result = await client.delivery.getFee(latitude, longitude, country);
4503
+ if (currentRequestId !== requestIdRef.current) return;
4504
+ if (!result.ok) {
4505
+ throw result.error;
4506
+ }
4507
+ deliveryFeeCache.set(cacheKey, result.value);
4508
+ setFee(result.value);
4509
+ } catch (loadError) {
4510
+ if (currentRequestId !== requestIdRef.current) return;
4511
+ setError(loadError);
4512
+ } finally {
4513
+ if (currentRequestId === requestIdRef.current) {
4514
+ setIsLoading(false);
4515
+ }
4516
+ }
4517
+ },
4518
+ [cacheKey, client, country, enabled, latitude, longitude]
4519
+ );
4520
+ useEffect(() => {
4521
+ void load(false);
4522
+ }, [load]);
4523
+ const refetch = useCallback(async () => {
4524
+ deliveryFeeCache.delete(cacheKey);
4525
+ await load(true);
4526
+ }, [cacheKey, load]);
4527
+ return { fee, isLoading, error, refetch };
4528
+ }
4529
+ var fxRateCache = /* @__PURE__ */ new Map();
4530
+ var fxRateInflight = /* @__PURE__ */ new Map();
4531
+ function buildFxRateCacheKey(client, from, to) {
4532
+ return JSON.stringify({ key: client.getPublicKey(), from, to });
4533
+ }
4534
+ function useFxRate(options) {
4535
+ const context = useOptionalCimplifyClient();
4536
+ const client = options.client ?? context?.client;
4537
+ if (!client) {
4538
+ throw new Error("useFxRate must be used within CimplifyProvider or passed { client }.");
4539
+ }
4540
+ const enabled = options.enabled ?? true;
4541
+ const { from, to } = options;
4542
+ const cacheKey = useMemo(
4543
+ () => buildFxRateCacheKey(client, from, to),
4544
+ [client, from, to]
4545
+ );
4546
+ const cached = fxRateCache.get(cacheKey);
4547
+ const [rate, setRate] = useState(cached ?? null);
4548
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4549
+ const [error, setError] = useState(null);
4550
+ const load = useCallback(
4551
+ async (force = false) => {
4552
+ if (!enabled) {
4553
+ setIsLoading(false);
4554
+ return;
4555
+ }
4556
+ setError(null);
4557
+ if (!force) {
4558
+ const cachedRate = fxRateCache.get(cacheKey);
4559
+ if (cachedRate) {
4560
+ setRate(cachedRate);
4561
+ setIsLoading(false);
4562
+ return;
4563
+ }
4564
+ }
4565
+ setIsLoading(true);
4566
+ try {
4567
+ const existing = fxRateInflight.get(cacheKey);
4568
+ const promise = existing ?? (async () => {
4569
+ const result = await client.fx.getRate(from, to);
4570
+ if (!result.ok) {
4571
+ throw result.error;
4572
+ }
4573
+ return result.value;
4574
+ })();
4575
+ if (!existing) {
4576
+ fxRateInflight.set(
4577
+ cacheKey,
4578
+ promise.finally(() => {
4579
+ fxRateInflight.delete(cacheKey);
4580
+ })
4581
+ );
4582
+ }
4583
+ const value = await promise;
4584
+ fxRateCache.set(cacheKey, value);
4585
+ setRate(value);
4586
+ } catch (loadError) {
4587
+ setError(loadError);
4588
+ } finally {
4589
+ setIsLoading(false);
4590
+ }
4591
+ },
4592
+ [cacheKey, client, enabled, from, to]
4593
+ );
4594
+ useEffect(() => {
4595
+ void load(false);
4596
+ }, [load]);
4597
+ const refetch = useCallback(async () => {
4598
+ fxRateCache.delete(cacheKey);
4599
+ await load(true);
4600
+ }, [cacheKey, load]);
4601
+ return { rate, isLoading, error, refetch };
4602
+ }
4603
+ var bootstrapCache = /* @__PURE__ */ new Map();
4604
+ var bootstrapInflight = /* @__PURE__ */ new Map();
4605
+ function buildBootstrapCacheKey(client) {
4606
+ return JSON.stringify({ key: client.getPublicKey(), type: "bootstrap" });
4607
+ }
4608
+ function useBootstrap(options = {}) {
4609
+ const context = useOptionalCimplifyClient();
4610
+ const client = options.client ?? context?.client;
4611
+ if (!client) {
4612
+ throw new Error("useBootstrap must be used within CimplifyProvider or passed { client }.");
4613
+ }
4614
+ const enabled = options.enabled ?? true;
4615
+ const cacheKey = useMemo(() => buildBootstrapCacheKey(client), [client]);
4616
+ const cached = bootstrapCache.get(cacheKey);
4617
+ const [bootstrap, setBootstrap] = useState(cached ?? null);
4618
+ const [isLoading, setIsLoading] = useState(enabled && !cached);
4619
+ const [error, setError] = useState(null);
4620
+ const load = useCallback(
4621
+ async (force = false) => {
4622
+ if (!enabled) {
4623
+ setIsLoading(false);
4624
+ return;
4625
+ }
4626
+ setError(null);
4627
+ if (!force) {
4628
+ const cachedBootstrap = bootstrapCache.get(cacheKey);
4629
+ if (cachedBootstrap) {
4630
+ setBootstrap(cachedBootstrap);
4631
+ setIsLoading(false);
4632
+ return;
4633
+ }
4634
+ }
4635
+ setIsLoading(true);
4636
+ try {
4637
+ const existing = bootstrapInflight.get(cacheKey);
4638
+ const promise = existing ?? (async () => {
4639
+ const result = await client.business.getBootstrap();
4640
+ if (!result.ok) {
4641
+ throw result.error;
4642
+ }
4643
+ return result.value;
4644
+ })();
4645
+ if (!existing) {
4646
+ bootstrapInflight.set(
4647
+ cacheKey,
4648
+ promise.finally(() => {
4649
+ bootstrapInflight.delete(cacheKey);
4650
+ })
4651
+ );
4652
+ }
4653
+ const value = await promise;
4654
+ bootstrapCache.set(cacheKey, value);
4655
+ setBootstrap(value);
4656
+ } catch (loadError) {
4657
+ setError(loadError);
4658
+ } finally {
4659
+ setIsLoading(false);
4660
+ }
4661
+ },
4662
+ [cacheKey, client, enabled]
4663
+ );
4664
+ useEffect(() => {
4665
+ void load(false);
4666
+ }, [load]);
4667
+ const refetch = useCallback(async () => {
4668
+ bootstrapCache.delete(cacheKey);
4669
+ await load(true);
4670
+ }, [cacheKey, load]);
4671
+ return { bootstrap, isLoading, error, refetch };
4672
+ }
3992
4673
  var ElementsContext = createContext({
3993
4674
  elements: null,
3994
4675
  isReady: false
@@ -4732,6 +5413,17 @@ function getComponentPrice(component, selectedVariantId) {
4732
5413
  if (!selectedAdj) return parsePrice(component.effective_price);
4733
5414
  return parsePrice(component.effective_price) - parsePrice(bakedAdj?.price_adjustment ?? "0") + parsePrice(selectedAdj.price_adjustment);
4734
5415
  }
5416
+ function formatDuration(minutes, unit) {
5417
+ if (unit === "hours" || !unit && minutes >= 60 && minutes % 60 === 0) {
5418
+ const h = Math.round(minutes / 60);
5419
+ return `${h}h`;
5420
+ }
5421
+ if (unit === "days" || unit === "nights") {
5422
+ const d = Math.round(minutes / 1440);
5423
+ return `${d}${unit === "nights" ? "n" : "d"}`;
5424
+ }
5425
+ return `${minutes}min`;
5426
+ }
4735
5427
  function BundleComponentCard({
4736
5428
  component,
4737
5429
  selectedVariantId,
@@ -4777,6 +5469,43 @@ function BundleComponentCard({
4777
5469
  className: cn("text-sm", classNames?.componentName),
4778
5470
  children: component.product_name
4779
5471
  }
5472
+ ),
5473
+ component.product_type === "service" && /* @__PURE__ */ jsxs(
5474
+ "span",
5475
+ {
5476
+ "data-cimplify-bundle-type-badge": "service",
5477
+ className: cn(
5478
+ "text-[10px] uppercase tracking-wider font-medium text-blue-600",
5479
+ classNames?.typeBadge,
5480
+ classNames?.serviceBadge
5481
+ ),
5482
+ children: [
5483
+ /* @__PURE__ */ 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: [
5484
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "7", stroke: "currentColor", strokeWidth: "1.5" }),
5485
+ /* @__PURE__ */ jsx("path", { d: "M8 4v4l2.5 1.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
5486
+ ] }),
5487
+ "Service",
5488
+ component.duration_minutes != null && /* @__PURE__ */ jsxs(Fragment, { children: [
5489
+ " \xB7 ",
5490
+ formatDuration(component.duration_minutes, component.duration_unit)
5491
+ ] })
5492
+ ]
5493
+ }
5494
+ ),
5495
+ component.product_type === "digital" && /* @__PURE__ */ jsxs(
5496
+ "span",
5497
+ {
5498
+ "data-cimplify-bundle-type-badge": "digital",
5499
+ className: cn(
5500
+ "text-[10px] uppercase tracking-wider font-medium text-violet-600",
5501
+ classNames?.typeBadge,
5502
+ classNames?.digitalBadge
5503
+ ),
5504
+ children: [
5505
+ /* @__PURE__ */ 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__ */ jsx("path", { d: "M9 2L4 9h4l-1 5 5-7H8l1-5z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
5506
+ "Digital"
5507
+ ]
5508
+ }
4780
5509
  )
4781
5510
  ] }),
4782
5511
  /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: /* @__PURE__ */ jsx(Price, { amount: displayPrice }) })
@@ -5101,6 +5830,39 @@ function CompositeSelector({
5101
5830
  children: displayName
5102
5831
  }
5103
5832
  ),
5833
+ component.product_type === "service" && /* @__PURE__ */ jsxs(
5834
+ "span",
5835
+ {
5836
+ "data-cimplify-composite-type-badge": "service",
5837
+ className: cn(
5838
+ "text-[10px] uppercase tracking-wider font-medium text-blue-600",
5839
+ classNames?.typeBadge,
5840
+ classNames?.serviceBadge
5841
+ ),
5842
+ children: [
5843
+ /* @__PURE__ */ 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: [
5844
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "7", stroke: "currentColor", strokeWidth: "1.5" }),
5845
+ /* @__PURE__ */ jsx("path", { d: "M8 4v4l2.5 1.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
5846
+ ] }),
5847
+ "Service"
5848
+ ]
5849
+ }
5850
+ ),
5851
+ component.product_type === "digital" && /* @__PURE__ */ jsxs(
5852
+ "span",
5853
+ {
5854
+ "data-cimplify-composite-type-badge": "digital",
5855
+ className: cn(
5856
+ "text-[10px] uppercase tracking-wider font-medium text-violet-600",
5857
+ classNames?.typeBadge,
5858
+ classNames?.digitalBadge
5859
+ ),
5860
+ children: [
5861
+ /* @__PURE__ */ 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__ */ jsx("path", { d: "M9 2L4 9h4l-1 5 5-7H8l1-5z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
5862
+ "Digital"
5863
+ ]
5864
+ }
5865
+ ),
5104
5866
  component.is_popular && /* @__PURE__ */ jsx(
5105
5867
  "span",
5106
5868
  {
@@ -5265,6 +6027,7 @@ function CompositeSelector({
5265
6027
  function ProductCustomizer({
5266
6028
  product,
5267
6029
  onAddToCart,
6030
+ showSpecialInstructions = true,
5268
6031
  className,
5269
6032
  classNames
5270
6033
  }) {
@@ -5280,10 +6043,13 @@ function ProductCustomizer({
5280
6043
  const [bundleSelections, setBundleSelections] = useState([]);
5281
6044
  const [bundleTotalPrice, setBundleTotalPrice] = useState(null);
5282
6045
  const [bundleReady, setBundleReady] = useState(false);
6046
+ const [specialInstructions, setSpecialInstructions] = useState("");
5283
6047
  const cart = useCart();
5284
6048
  const productType = product.type || "product";
5285
6049
  const isComposite = productType === "composite";
5286
6050
  const isBundle = productType === "bundle";
6051
+ const isDigital = productType === "digital";
6052
+ const isService = productType === "service";
5287
6053
  const isStandard = !isComposite && !isBundle;
5288
6054
  const hasVariants = isStandard && product.variants && product.variants.length > 0;
5289
6055
  const hasAddOns = isStandard && product.add_ons && product.add_ons.length > 0;
@@ -5300,6 +6066,7 @@ function ProductCustomizer({
5300
6066
  setBundleSelections([]);
5301
6067
  setBundleTotalPrice(null);
5302
6068
  setBundleReady(false);
6069
+ setSpecialInstructions("");
5303
6070
  }, [product.id]);
5304
6071
  const selectedAddOnOptions = useMemo(() => {
5305
6072
  if (!product.add_ons) return [];
@@ -5396,7 +6163,8 @@ function ProductCustomizer({
5396
6163
  default_price: opt.default_price
5397
6164
  })) : void 0,
5398
6165
  compositeSelections: isComposite && compositeSelections.length > 0 ? compositeSelections : void 0,
5399
- bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0
6166
+ bundleSelections: isBundle && bundleSelections.length > 0 ? bundleSelections : void 0,
6167
+ specialInstructions: specialInstructions.trim() || void 0
5400
6168
  };
5401
6169
  try {
5402
6170
  if (onAddToCart) {
@@ -5457,6 +6225,43 @@ function ProductCustomizer({
5457
6225
  onOptionsChange: setSelectedAddOnOptionIds
5458
6226
  }
5459
6227
  ),
6228
+ product.deposit_type && product.deposit_type !== "none" && product.deposit_amount && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-deposit": true, className: cn("text-sm text-muted-foreground", classNames?.depositInfo), children: product.deposit_type === "fixed" ? /* @__PURE__ */ jsxs("span", { children: [
6229
+ "Deposit required: ",
6230
+ /* @__PURE__ */ jsx(Price, { amount: product.deposit_amount })
6231
+ ] }) : /* @__PURE__ */ jsxs("span", { children: [
6232
+ "Deposit required: ",
6233
+ parsePrice(product.deposit_amount),
6234
+ "%"
6235
+ ] }) }),
6236
+ product.allergies && product.allergies.length > 0 && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-allergens": true, className: cn("flex flex-wrap gap-1.5", classNames?.allergens), children: product.allergies.map((allergen) => /* @__PURE__ */ jsx(
6237
+ "span",
6238
+ {
6239
+ "data-cimplify-allergen-tag": true,
6240
+ className: "inline-block text-xs px-2 py-0.5 rounded-full bg-muted text-muted-foreground",
6241
+ children: allergen
6242
+ },
6243
+ allergen
6244
+ )) }),
6245
+ isService && product.duration_minutes != null && /* @__PURE__ */ jsxs("div", { "data-cimplify-customizer-duration": true, className: cn("text-sm text-muted-foreground", classNames?.duration), children: [
6246
+ "Duration: ",
6247
+ product.duration_minutes,
6248
+ " ",
6249
+ product.duration_unit ?? "minutes"
6250
+ ] }),
6251
+ showSpecialInstructions && !isDigital && /* @__PURE__ */ jsx("div", { "data-cimplify-customizer-special-instructions": true, children: /* @__PURE__ */ jsx(
6252
+ "textarea",
6253
+ {
6254
+ value: specialInstructions,
6255
+ onChange: (e) => setSpecialInstructions(e.target.value),
6256
+ placeholder: "Special instructions (e.g., no onions, extra sauce)",
6257
+ rows: 2,
6258
+ "data-cimplify-customizer-textarea": true,
6259
+ className: cn(
6260
+ "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",
6261
+ classNames?.specialInstructions
6262
+ )
6263
+ }
6264
+ ) }),
5460
6265
  /* @__PURE__ */ jsxs(
5461
6266
  "div",
5462
6267
  {
@@ -5591,7 +6396,8 @@ function ProductImageGallery({
5591
6396
  function CartLineItemRow({
5592
6397
  item,
5593
6398
  onRemove,
5594
- onQuantityChange
6399
+ onQuantityChange,
6400
+ classNames
5595
6401
  }) {
5596
6402
  const { unitPrice } = useProductPrice({
5597
6403
  product: item.product,
@@ -5600,18 +6406,60 @@ function CartLineItemRow({
5600
6406
  });
5601
6407
  const hasComposite = item.compositeSelections && item.compositeSelections.length > 0;
5602
6408
  const hasBundle = item.bundleSelections && item.bundleSelections.length > 0;
5603
- return /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-item": true, children: [
6409
+ return /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-item": true, className: classNames?.item, children: [
5604
6410
  /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-item-info": true, children: [
5605
- /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-name": true, children: item.product.name }),
6411
+ /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-name": true, className: classNames?.itemName, children: item.product.name }),
5606
6412
  item.variant && /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-variant": true, children: getVariantDisplayName(item.variant, item.product.name) }),
5607
6413
  item.addOnOptions && item.addOnOptions.length > 0 && /* @__PURE__ */ jsxs("span", { "data-cimplify-cart-item-addons": true, children: [
5608
6414
  "+ ",
5609
6415
  item.addOnOptions.map((opt) => opt.name).join(", ")
5610
6416
  ] }),
5611
6417
  (hasComposite || hasBundle) && /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-badge": true, children: hasComposite ? "Custom" : "Bundle" }),
5612
- /* @__PURE__ */ jsx(Price, { amount: unitPrice })
6418
+ item.specialInstructions && /* @__PURE__ */ jsx("span", { "data-cimplify-cart-item-instructions": true, className: "text-xs text-muted-foreground", children: item.specialInstructions }),
6419
+ (item.lineType === "service" || item.product.type === "service") && item.scheduledStart && /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-service-info": true, className: classNames?.serviceInfo, children: [
6420
+ /* @__PURE__ */ jsxs("span", { children: [
6421
+ "\u{1F4C5}",
6422
+ " ",
6423
+ new Date(item.scheduledStart).toLocaleDateString(),
6424
+ " at ",
6425
+ new Date(item.scheduledStart).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
6426
+ ] }),
6427
+ item.confirmationCode && /* @__PURE__ */ jsxs("span", { children: [
6428
+ "Confirmation: ",
6429
+ item.confirmationCode
6430
+ ] }),
6431
+ item.serviceStatus && /* @__PURE__ */ jsx("span", { "data-status": item.serviceStatus, children: item.serviceStatus })
6432
+ ] }),
6433
+ (item.lineType === "digital" || item.product.type === "digital") && /* @__PURE__ */ jsx("div", { "data-cimplify-cart-digital-info": true, className: classNames?.digitalInfo, children: /* @__PURE__ */ jsxs("span", { children: [
6434
+ "\u26A1",
6435
+ " Instant digital delivery"
6436
+ ] }) }),
6437
+ item.bundleResolved && /* @__PURE__ */ jsx("div", { "data-cimplify-cart-bundle-breakdown": true, className: classNames?.bundleBreakdown, children: item.bundleResolved.selections.map((sel) => /* @__PURE__ */ jsxs("div", { "data-product-type": sel.product_type, children: [
6438
+ /* @__PURE__ */ jsxs("span", { children: [
6439
+ sel.quantity,
6440
+ "\xD7 ",
6441
+ sel.product_name
6442
+ ] }),
6443
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxs("span", { children: [
6444
+ " \u2014 ",
6445
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
6446
+ ] }),
6447
+ sel.product_type === "digital" && /* @__PURE__ */ jsx("span", { children: " \u2014 Digital" })
6448
+ ] }, sel.component_id)) }),
6449
+ item.compositeResolved && /* @__PURE__ */ jsx("div", { "data-cimplify-cart-composite-breakdown": true, className: classNames?.compositeBreakdown, children: item.compositeResolved.selections.map((sel) => /* @__PURE__ */ jsxs("div", { "data-product-type": sel.product_type, children: [
6450
+ /* @__PURE__ */ jsxs("span", { children: [
6451
+ sel.quantity,
6452
+ "\xD7 ",
6453
+ sel.component_name
6454
+ ] }),
6455
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxs("span", { children: [
6456
+ " \u2014 ",
6457
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
6458
+ ] })
6459
+ ] }, sel.component_id)) }),
6460
+ /* @__PURE__ */ jsx(Price, { amount: unitPrice, className: classNames?.itemPrice })
5613
6461
  ] }),
5614
- /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-item-controls": true, children: [
6462
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-item-controls": true, className: classNames?.quantity, children: [
5615
6463
  /* @__PURE__ */ jsx(
5616
6464
  QuantitySelector,
5617
6465
  {
@@ -5626,6 +6474,7 @@ function CartLineItemRow({
5626
6474
  type: "button",
5627
6475
  onClick: () => onRemove(item.id),
5628
6476
  "data-cimplify-cart-item-remove": true,
6477
+ className: classNames?.removeButton,
5629
6478
  "aria-label": `Remove ${item.product.name}`,
5630
6479
  children: "Remove"
5631
6480
  }
@@ -5634,13 +6483,18 @@ function CartLineItemRow({
5634
6483
  ] });
5635
6484
  }
5636
6485
  function CartSummary({
6486
+ cart: serverCart,
5637
6487
  onCheckout,
5638
6488
  onItemRemove,
5639
6489
  onQuantityChange,
5640
6490
  emptyMessage = "Your cart is empty",
5641
- className
6491
+ className,
6492
+ classNames
5642
6493
  }) {
5643
6494
  const { items, itemCount, subtotal, tax, total, isEmpty, removeItem, updateQuantity } = useCart();
6495
+ const deliveryFee = serverCart?.delivery_fee;
6496
+ const serviceCharge = serverCart?.service_charge;
6497
+ const totalDiscounts = serverCart?.total_discounts;
5644
6498
  const handleRemove = (itemId) => {
5645
6499
  if (onItemRemove) {
5646
6500
  onItemRemove(itemId);
@@ -5655,18 +6509,19 @@ function CartSummary({
5655
6509
  void updateQuantity(itemId, qty);
5656
6510
  }
5657
6511
  };
5658
- return /* @__PURE__ */ jsx("div", { "data-cimplify-cart-summary": true, className, children: isEmpty ? /* @__PURE__ */ jsx("div", { "data-cimplify-cart-empty": true, children: /* @__PURE__ */ jsx("p", { children: emptyMessage }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
6512
+ return /* @__PURE__ */ jsx("div", { "data-cimplify-cart-summary": true, className: cn(className, classNames?.root), children: isEmpty ? /* @__PURE__ */ jsx("div", { "data-cimplify-cart-empty": true, className: classNames?.empty, children: /* @__PURE__ */ jsx("p", { children: emptyMessage }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5659
6513
  /* @__PURE__ */ jsx("div", { "data-cimplify-cart-items": true, children: items.map((item) => /* @__PURE__ */ jsx(
5660
6514
  CartLineItemRow,
5661
6515
  {
5662
6516
  item,
5663
6517
  onRemove: handleRemove,
5664
- onQuantityChange: handleQuantityChange
6518
+ onQuantityChange: handleQuantityChange,
6519
+ classNames
5665
6520
  },
5666
6521
  item.id
5667
6522
  )) }),
5668
- /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-totals": true, children: [
5669
- /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-subtotal": true, children: [
6523
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-totals": true, className: classNames?.totals, children: [
6524
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-subtotal": true, className: classNames?.subtotal, children: [
5670
6525
  /* @__PURE__ */ jsxs("span", { children: [
5671
6526
  "Subtotal (",
5672
6527
  itemCount,
@@ -5676,11 +6531,23 @@ function CartSummary({
5676
6531
  ] }),
5677
6532
  /* @__PURE__ */ jsx(Price, { amount: subtotal })
5678
6533
  ] }),
5679
- /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-tax": true, children: [
6534
+ totalDiscounts != null && parsePrice(totalDiscounts) > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-discount": true, className: classNames?.discount, children: [
6535
+ /* @__PURE__ */ jsx("span", { children: "Discount" }),
6536
+ /* @__PURE__ */ jsx(Price, { amount: totalDiscounts, prefix: "-" })
6537
+ ] }),
6538
+ deliveryFee != null && /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-delivery-fee": true, className: classNames?.deliveryFee, children: [
6539
+ /* @__PURE__ */ jsx("span", { children: "Delivery fee" }),
6540
+ parsePrice(deliveryFee) > 0 ? /* @__PURE__ */ jsx(Price, { amount: deliveryFee }) : /* @__PURE__ */ jsx("span", { children: "Free delivery" })
6541
+ ] }),
6542
+ serviceCharge != null && parsePrice(serviceCharge) > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-service-charge": true, className: classNames?.serviceCharge, children: [
6543
+ /* @__PURE__ */ jsx("span", { children: "Service charge" }),
6544
+ /* @__PURE__ */ jsx(Price, { amount: serviceCharge })
6545
+ ] }),
6546
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-tax": true, className: classNames?.tax, children: [
5680
6547
  /* @__PURE__ */ jsx("span", { children: "Tax" }),
5681
6548
  /* @__PURE__ */ jsx(Price, { amount: tax })
5682
6549
  ] }),
5683
- /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-total": true, children: [
6550
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-cart-total": true, className: classNames?.total, children: [
5684
6551
  /* @__PURE__ */ jsx("span", { children: "Total" }),
5685
6552
  /* @__PURE__ */ jsx(Price, { amount: total })
5686
6553
  ] })
@@ -5691,6 +6558,7 @@ function CartSummary({
5691
6558
  type: "button",
5692
6559
  onClick: onCheckout,
5693
6560
  "data-cimplify-cart-checkout": true,
6561
+ className: classNames?.checkout,
5694
6562
  children: "Proceed to Checkout"
5695
6563
  }
5696
6564
  )
@@ -5700,21 +6568,26 @@ function AvailabilityBadge({
5700
6568
  product,
5701
6569
  isAvailable,
5702
6570
  isInStock,
6571
+ stockQuantity,
6572
+ lowStockThreshold = 5,
6573
+ locationId,
5703
6574
  className,
5704
6575
  classNames
5705
6576
  }) {
5706
6577
  if (product.is_tracked !== true) {
5707
6578
  return null;
5708
6579
  }
5709
- const outOfStock = isInStock === false || isAvailable === false;
5710
- const stockState = outOfStock ? "out_of_stock" : "in_stock";
6580
+ const outOfStock = isInStock === false || isAvailable === false || stockQuantity !== void 0 && stockQuantity <= 0;
6581
+ const isLowStock = !outOfStock && stockQuantity !== void 0 && stockQuantity > 0 && stockQuantity <= lowStockThreshold;
6582
+ const stockState = outOfStock ? "out_of_stock" : isLowStock ? "low_stock" : "in_stock";
5711
6583
  const label = outOfStock ? "Out of Stock" : "In Stock";
5712
6584
  return /* @__PURE__ */ jsxs(
5713
6585
  "span",
5714
6586
  {
5715
6587
  "data-cimplify-availability-badge": true,
5716
6588
  "data-stock-state": stockState,
5717
- className: cn(className, classNames?.root),
6589
+ ...locationId ? { "data-location-id": locationId } : void 0,
6590
+ className: cn(className, classNames?.root, isLowStock && classNames?.lowStock),
5718
6591
  style: { display: "inline-flex", alignItems: "center", gap: "0.375rem" },
5719
6592
  children: [
5720
6593
  /* @__PURE__ */ jsx(
@@ -5730,7 +6603,12 @@ function AvailabilityBadge({
5730
6603
  }
5731
6604
  }
5732
6605
  ),
5733
- /* @__PURE__ */ jsx("span", { "data-cimplify-availability-label": true, className: classNames?.label, children: label })
6606
+ /* @__PURE__ */ jsx("span", { "data-cimplify-availability-label": true, className: classNames?.label, children: label }),
6607
+ stockQuantity !== void 0 && isLowStock && /* @__PURE__ */ jsxs("span", { "data-cimplify-availability-stock-count": true, className: classNames?.stockCount, children: [
6608
+ "Only ",
6609
+ stockQuantity,
6610
+ " left"
6611
+ ] })
5734
6612
  ]
5735
6613
  }
5736
6614
  );
@@ -6199,10 +7077,16 @@ function SearchInput({
6199
7077
  onResultClick,
6200
7078
  renderResult,
6201
7079
  showResults = true,
7080
+ categoryId,
7081
+ categoryName,
6202
7082
  className,
6203
7083
  classNames
6204
7084
  }) {
6205
- const { results, isLoading, query, setQuery, clear } = useSearch(searchOptions);
7085
+ const mergedOptions = useMemo(
7086
+ () => categoryId ? { ...searchOptions, category: categoryId } : searchOptions ?? {},
7087
+ [searchOptions, categoryId]
7088
+ );
7089
+ const { results, isLoading, query, setQuery, clear } = useSearch(mergedOptions);
6206
7090
  const handleValueChange = useCallback(
6207
7091
  (value) => {
6208
7092
  setQuery(value);
@@ -6255,6 +7139,10 @@ function SearchInput({
6255
7139
  }
6256
7140
  )
6257
7141
  ] }),
7142
+ categoryId && /* @__PURE__ */ jsxs("div", { "data-cimplify-search-category-filter": true, className: classNames?.categoryFilter, children: [
7143
+ "Filtered by: ",
7144
+ categoryName || categoryId
7145
+ ] }),
6258
7146
  showResults && query.length > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-search-results": true, className: classNames?.results, children: [
6259
7147
  isLoading && /* @__PURE__ */ jsx("div", { "data-cimplify-search-loading": true, className: classNames?.loading, "aria-busy": "true", children: "Searching..." }),
6260
7148
  !isLoading && results.length === 0 && query.length >= 2 && /* @__PURE__ */ jsx("div", { "data-cimplify-search-empty": true, className: classNames?.empty, children: "No results found" }),
@@ -6265,7 +7153,21 @@ function SearchInput({
6265
7153
  onClick: () => onResultClick?.(product),
6266
7154
  "data-cimplify-search-result": true,
6267
7155
  className: classNames?.resultItem,
6268
- children: renderResult ? renderResult(product) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("span", { "data-cimplify-search-result-name": true, children: product.name }) })
7156
+ style: !renderResult ? { display: "flex", alignItems: "center", gap: "0.5rem", width: "100%" } : void 0,
7157
+ children: renderResult ? renderResult(product) : /* @__PURE__ */ jsxs(Fragment, { children: [
7158
+ (product.images?.[0] || product.image_url) && /* @__PURE__ */ jsx(
7159
+ "img",
7160
+ {
7161
+ src: product.images?.[0] || product.image_url,
7162
+ alt: "",
7163
+ "data-cimplify-search-result-image": true,
7164
+ className: classNames?.resultImage,
7165
+ style: { width: "2rem", height: "2rem", objectFit: "cover", borderRadius: "0.25rem", flexShrink: 0 }
7166
+ }
7167
+ ),
7168
+ /* @__PURE__ */ jsx("span", { "data-cimplify-search-result-name": true, className: classNames?.resultName, style: { flex: 1, textAlign: "left" }, children: product.name }),
7169
+ product.default_price !== void 0 && /* @__PURE__ */ jsx("span", { "data-cimplify-search-result-price": true, className: classNames?.resultPrice, style: { flexShrink: 0 }, children: formatPrice(product.default_price) })
7170
+ ] })
6269
7171
  },
6270
7172
  product.id
6271
7173
  ))
@@ -6604,6 +7506,12 @@ var STATUS_LABELS = {
6604
7506
  cancelled: "Cancelled",
6605
7507
  refunded: "Refunded"
6606
7508
  };
7509
+ var PAYMENT_STATE_LABELS = {
7510
+ not_paid: "Not Paid",
7511
+ paid: "Paid",
7512
+ partially_refunded: "Partially Refunded",
7513
+ refunded: "Refunded"
7514
+ };
6607
7515
  function OrderSummary({
6608
7516
  order: orderProp,
6609
7517
  orderId,
@@ -6645,8 +7553,25 @@ function OrderSummary({
6645
7553
  className: classNames?.status,
6646
7554
  children: STATUS_LABELS[order.status] ?? order.status
6647
7555
  }
7556
+ ),
7557
+ order.payment_state && /* @__PURE__ */ jsx(
7558
+ "span",
7559
+ {
7560
+ "data-cimplify-order-payment-state": true,
7561
+ "data-payment-state": order.payment_state,
7562
+ className: classNames?.paymentState,
7563
+ children: PAYMENT_STATE_LABELS[order.payment_state] ?? order.payment_state
7564
+ }
6648
7565
  )
6649
7566
  ] }),
7567
+ order.order_type === "pickup" && order.pickup_time && /* @__PURE__ */ jsx("div", { "data-cimplify-order-fulfillment": true, className: classNames?.fulfillmentDetails, children: /* @__PURE__ */ jsxs("span", { children: [
7568
+ "Pickup time: ",
7569
+ new Date(order.pickup_time).toLocaleString()
7570
+ ] }) }),
7571
+ order.order_type === "dine-in" && order.table_number && /* @__PURE__ */ jsx("div", { "data-cimplify-order-fulfillment": true, className: classNames?.fulfillmentDetails, children: /* @__PURE__ */ jsxs("span", { children: [
7572
+ "Table: ",
7573
+ order.table_number
7574
+ ] }) }),
6650
7575
  /* @__PURE__ */ jsx("time", { "data-cimplify-order-date": true, dateTime: order.created_at, children: new Date(order.created_at).toLocaleDateString(void 0, {
6651
7576
  year: "numeric",
6652
7577
  month: "long",
@@ -6658,6 +7583,10 @@ function OrderSummary({
6658
7583
  order.customer_name && /* @__PURE__ */ jsx("span", { "data-cimplify-order-customer-name": true, children: order.customer_name }),
6659
7584
  order.customer_email && /* @__PURE__ */ jsx("span", { "data-cimplify-order-customer-email": true, children: order.customer_email })
6660
7585
  ] }),
7586
+ order.delivery_address && /* @__PURE__ */ jsxs("div", { "data-cimplify-order-delivery-address": true, className: classNames?.deliveryAddress, children: [
7587
+ /* @__PURE__ */ jsx("span", { children: "Delivery address" }),
7588
+ /* @__PURE__ */ jsx("p", { children: order.delivery_address })
7589
+ ] }),
6661
7590
  /* @__PURE__ */ jsx("div", { "data-cimplify-order-items": true, className: classNames?.items, children: order.items.map(
6662
7591
  (item) => renderLineItem ? /* @__PURE__ */ jsx(React3.Fragment, { children: renderLineItem(item) }, item.id) : /* @__PURE__ */ jsxs("div", { "data-cimplify-order-line-item": true, className: classNames?.lineItem, children: [
6663
7592
  /* @__PURE__ */ jsxs("div", { "data-cimplify-order-line-info": true, children: [
@@ -6667,14 +7596,75 @@ function OrderSummary({
6667
7596
  ] }),
6668
7597
  /* @__PURE__ */ jsx("span", { "data-cimplify-order-line-key": true, children: item.line_key })
6669
7598
  ] }),
6670
- /* @__PURE__ */ jsx(Price, { amount: item.price })
7599
+ /* @__PURE__ */ jsx(Price, { amount: item.price }),
7600
+ item.fulfillment_type === "digital" && item.fulfillment_id && /* @__PURE__ */ jsx(
7601
+ "a",
7602
+ {
7603
+ href: item.fulfillment_id,
7604
+ target: "_blank",
7605
+ rel: "noopener noreferrer",
7606
+ "data-cimplify-order-line-download": true,
7607
+ className: "text-sm text-primary underline",
7608
+ children: "Download"
7609
+ }
7610
+ ),
7611
+ item.configuration.type === "service" && /* @__PURE__ */ jsxs("div", { "data-cimplify-order-service-info": true, className: classNames?.serviceInfo, children: [
7612
+ item.configuration.scheduled_start && /* @__PURE__ */ jsxs("span", { children: [
7613
+ "\u{1F4C5}",
7614
+ " ",
7615
+ new Date(item.configuration.scheduled_start).toLocaleDateString(),
7616
+ " at ",
7617
+ new Date(item.configuration.scheduled_start).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })
7618
+ ] }),
7619
+ item.configuration.confirmation_code && /* @__PURE__ */ jsxs("span", { children: [
7620
+ "Confirmation: ",
7621
+ item.configuration.confirmation_code
7622
+ ] }),
7623
+ item.configuration.service_status && /* @__PURE__ */ jsx("span", { "data-status": item.configuration.service_status, children: item.configuration.service_status })
7624
+ ] }),
7625
+ item.configuration.type === "digital" && /* @__PURE__ */ jsx("div", { "data-cimplify-order-digital-info": true, className: classNames?.digitalInfo, children: /* @__PURE__ */ jsxs("span", { children: [
7626
+ "\u26A1",
7627
+ " Instant digital delivery"
7628
+ ] }) }),
7629
+ item.configuration.type === "bundle" && item.configuration.resolved && /* @__PURE__ */ jsx("div", { "data-cimplify-order-bundle-breakdown": true, className: classNames?.bundleBreakdown, children: item.configuration.resolved.selections.map((sel) => /* @__PURE__ */ jsxs("div", { "data-product-type": sel.product_type, children: [
7630
+ /* @__PURE__ */ jsxs("span", { children: [
7631
+ sel.quantity,
7632
+ "\xD7 ",
7633
+ sel.product_name
7634
+ ] }),
7635
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxs("span", { children: [
7636
+ " \u2014 ",
7637
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
7638
+ ] }),
7639
+ sel.product_type === "digital" && /* @__PURE__ */ jsx("span", { children: " \u2014 Digital" })
7640
+ ] }, sel.component_id)) }),
7641
+ item.configuration.type === "composite" && item.configuration.resolved && /* @__PURE__ */ jsx("div", { "data-cimplify-order-composite-breakdown": true, className: classNames?.compositeBreakdown, children: item.configuration.resolved.selections.map((sel) => /* @__PURE__ */ jsxs("div", { "data-product-type": sel.product_type, children: [
7642
+ /* @__PURE__ */ jsxs("span", { children: [
7643
+ sel.quantity,
7644
+ "\xD7 ",
7645
+ sel.component_name
7646
+ ] }),
7647
+ sel.product_type === "service" && sel.scheduling?.scheduled_start && /* @__PURE__ */ jsxs("span", { children: [
7648
+ " \u2014 ",
7649
+ new Date(sel.scheduling.scheduled_start).toLocaleDateString()
7650
+ ] }),
7651
+ /* @__PURE__ */ jsx(Price, { amount: sel.unit_price })
7652
+ ] }, sel.component_id)) })
6671
7653
  ] }, item.id)
6672
7654
  ) }),
7655
+ order.customer_notes && order.customer_notes.length > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-order-notes": true, className: classNames?.notes, children: [
7656
+ /* @__PURE__ */ jsx("span", { children: "Notes" }),
7657
+ order.customer_notes.map((note, index) => /* @__PURE__ */ jsx("p", { "data-cimplify-order-note": true, children: note }, index))
7658
+ ] }),
6673
7659
  /* @__PURE__ */ jsxs("div", { "data-cimplify-order-totals": true, className: classNames?.totals, children: [
6674
7660
  order.total_discount != null && parsePrice(order.total_discount) !== 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-order-discount": true, children: [
6675
7661
  /* @__PURE__ */ jsx("span", { children: "Discount" }),
6676
7662
  /* @__PURE__ */ jsx(Price, { amount: order.total_discount, prefix: "-" })
6677
7663
  ] }),
7664
+ order.delivery_fee != null && parsePrice(order.delivery_fee) > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-order-delivery-fee": true, children: [
7665
+ /* @__PURE__ */ jsx("span", { children: "Delivery fee" }),
7666
+ /* @__PURE__ */ jsx(Price, { amount: order.delivery_fee })
7667
+ ] }),
6678
7668
  order.service_charge != null && parsePrice(order.service_charge) !== 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-order-service-charge": true, children: [
6679
7669
  /* @__PURE__ */ jsx("span", { children: "Service charge" }),
6680
7670
  /* @__PURE__ */ jsx(Price, { amount: order.service_charge })
@@ -6695,6 +7685,7 @@ function OrderSummary({
6695
7685
  target: "_blank",
6696
7686
  rel: "noopener noreferrer",
6697
7687
  "data-cimplify-order-tracking": true,
7688
+ className: classNames?.trackingLink,
6698
7689
  children: "Track your order"
6699
7690
  }
6700
7691
  )
@@ -7360,6 +8351,23 @@ function BookingList({
7360
8351
  booking.order_id
7361
8352
  )) });
7362
8353
  }
8354
+
8355
+ // src/react/utils/format-duration.ts
8356
+ var UNIT_LABELS = {
8357
+ minutes: { singular: "min", plural: "min" },
8358
+ hours: { singular: "hr", plural: "hrs" },
8359
+ days: { singular: "day", plural: "days" },
8360
+ nights: { singular: "night", plural: "nights" },
8361
+ weeks: { singular: "week", plural: "weeks" },
8362
+ months: { singular: "month", plural: "months" },
8363
+ years: { singular: "year", plural: "years" }
8364
+ };
8365
+ function formatDuration2(value, unit) {
8366
+ const resolved = unit ?? "minutes";
8367
+ const labels = UNIT_LABELS[resolved];
8368
+ const label = value === 1 ? labels.singular : labels.plural;
8369
+ return `${value} ${label}`;
8370
+ }
7363
8371
  var ASPECT_STYLES3 = {
7364
8372
  square: { aspectRatio: "1/1" },
7365
8373
  "4/3": { aspectRatio: "4/3" },
@@ -7421,10 +8429,7 @@ function ServiceCard({
7421
8429
  }
7422
8430
  ),
7423
8431
  /* @__PURE__ */ jsxs("div", { "data-cimplify-service-card-meta": true, className: classNames?.meta, children: [
7424
- /* @__PURE__ */ jsxs("span", { "data-cimplify-service-card-duration": true, className: classNames?.duration, children: [
7425
- service.duration_minutes,
7426
- " min"
7427
- ] }),
8432
+ /* @__PURE__ */ jsx("span", { "data-cimplify-service-card-duration": true, className: classNames?.duration, children: formatDuration2(service.duration_minutes, service.duration_unit) }),
7428
8433
  service.price && /* @__PURE__ */ jsx("span", { "data-cimplify-service-card-price": true, className: classNames?.price, children: /* @__PURE__ */ jsx(Price, { amount: service.price }) })
7429
8434
  ] })
7430
8435
  ] }),
@@ -8194,16 +9199,21 @@ function DealsPage({
8194
9199
  }
8195
9200
  function BookingPage({
8196
9201
  service,
9202
+ product,
8197
9203
  staff,
8198
9204
  participantCount,
8199
9205
  title,
8200
9206
  onBooked,
8201
9207
  onBack,
9208
+ existingBooking,
9209
+ onRescheduled,
8202
9210
  showPrice = true,
8203
9211
  className,
8204
9212
  classNames
8205
9213
  }) {
8206
9214
  const { addItem } = useCart();
9215
+ const { client } = useCimplifyClient();
9216
+ const isReschedule = existingBooking !== void 0;
8207
9217
  const [step, setStep] = useState("select-slot");
8208
9218
  const [selectedSlot, setSelectedSlot] = useState(null);
8209
9219
  const [selectedDate, setSelectedDate] = useState(null);
@@ -8211,6 +9221,11 @@ function BookingPage({
8211
9221
  const [isSubmitting, setIsSubmitting] = useState(false);
8212
9222
  const [error, setError] = useState(null);
8213
9223
  const hasStaffStep = staff && staff.length > 0;
9224
+ const depositType = product?.deposit_type;
9225
+ const depositAmount = product?.deposit_amount;
9226
+ const hasDeposit = depositType !== void 0 && depositType !== "none" && depositAmount !== void 0 && parsePrice(depositAmount) !== 0;
9227
+ const cancellationMinutes = product?.cancellation_window_minutes;
9228
+ const noShowFee = product?.no_show_fee;
8214
9229
  const handleSlotSelect = useCallback(
8215
9230
  (slot, date) => {
8216
9231
  setSelectedSlot(slot);
@@ -8243,34 +9258,51 @@ function BookingPage({
8243
9258
  setIsSubmitting(true);
8244
9259
  setError(null);
8245
9260
  try {
8246
- const serviceProduct = {
8247
- id: service.product_id || service.id,
8248
- business_id: service.business_id || "",
8249
- category_id: service.category_id || void 0,
8250
- name: service.name,
8251
- slug: service.id,
8252
- description: service.description || void 0,
8253
- image_url: service.image_url || void 0,
8254
- default_price: service.price || "0",
8255
- type: "service",
8256
- inventory_type: "none",
8257
- variant_strategy: "fetch_all",
8258
- is_active: service.is_available,
8259
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
8260
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
8261
- };
8262
- await addItem(serviceProduct, 1, {
8263
- scheduledStart: selectedSlot.start_time,
8264
- scheduledEnd: selectedSlot.end_time,
8265
- staffId: selectedStaffId || void 0
8266
- });
8267
- onBooked?.(selectedSlot, selectedStaffId);
9261
+ if (isReschedule && existingBooking) {
9262
+ const serviceItem = existingBooking.service_items[0];
9263
+ const result = await client.scheduling.rescheduleBooking({
9264
+ order_id: existingBooking.order_id,
9265
+ line_item_id: serviceItem?.service_id ?? existingBooking.order_id,
9266
+ new_start_time: selectedSlot.start_time,
9267
+ new_end_time: selectedSlot.end_time,
9268
+ new_staff_id: selectedStaffId || void 0,
9269
+ reschedule_type: "customer"
9270
+ });
9271
+ if (!result.ok) {
9272
+ throw result.error;
9273
+ }
9274
+ onRescheduled?.(existingBooking, selectedSlot);
9275
+ } else {
9276
+ const serviceProduct = {
9277
+ id: service.product_id || service.id,
9278
+ business_id: service.business_id || "",
9279
+ category_id: service.category_id || void 0,
9280
+ name: service.name,
9281
+ slug: service.id,
9282
+ description: service.description || void 0,
9283
+ image_url: service.image_url || void 0,
9284
+ default_price: service.price || "0",
9285
+ type: "service",
9286
+ inventory_type: "none",
9287
+ variant_strategy: "fetch_all",
9288
+ is_active: service.is_available,
9289
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
9290
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
9291
+ };
9292
+ await addItem(serviceProduct, 1, {
9293
+ scheduledStart: selectedSlot.start_time,
9294
+ scheduledEnd: selectedSlot.end_time,
9295
+ staffId: selectedStaffId || void 0
9296
+ });
9297
+ onBooked?.(selectedSlot, selectedStaffId);
9298
+ }
8268
9299
  } catch (err) {
8269
- setError(err instanceof Error ? err.message : "Failed to add booking to cart");
9300
+ const fallbackMessage = isReschedule ? "Failed to reschedule booking" : "Failed to add booking to cart";
9301
+ setError(err instanceof Error ? err.message : fallbackMessage);
8270
9302
  } finally {
8271
9303
  setIsSubmitting(false);
8272
9304
  }
8273
- }, [selectedSlot, selectedDate, selectedStaffId, service, addItem, onBooked]);
9305
+ }, [selectedSlot, selectedDate, selectedStaffId, service, addItem, onBooked, isReschedule, existingBooking, client, onRescheduled]);
8274
9306
  return /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-page": true, className: cn(className, classNames?.root), children: [
8275
9307
  /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-page-header": true, className: classNames?.header, children: [
8276
9308
  onBack && step === "select-slot" && /* @__PURE__ */ jsx(
@@ -8293,15 +9325,29 @@ function BookingPage({
8293
9325
  children: "Back"
8294
9326
  }
8295
9327
  ),
8296
- /* @__PURE__ */ jsx("h1", { "data-cimplify-booking-page-title": true, className: classNames?.title, children: title || `Book ${service.name}` })
9328
+ /* @__PURE__ */ jsx("h1", { "data-cimplify-booking-page-title": true, className: classNames?.title, children: title || (isReschedule ? "Reschedule Booking" : `Book ${service.name}`) })
8297
9329
  ] }),
9330
+ isReschedule && existingBooking && /* @__PURE__ */ jsx("div", { "data-cimplify-booking-reschedule-info": true, className: classNames?.rescheduleInfo, children: /* @__PURE__ */ jsxs("span", { children: [
9331
+ "Rescheduling booking from ",
9332
+ new Date(existingBooking.service_items[0]?.scheduled_start ?? existingBooking.created_at).toLocaleDateString()
9333
+ ] }) }),
8298
9334
  /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-service-info": true, className: classNames?.serviceInfo, children: [
8299
9335
  /* @__PURE__ */ jsx("span", { "data-cimplify-booking-service-name": true, children: service.name }),
8300
- /* @__PURE__ */ jsxs("span", { "data-cimplify-booking-service-duration": true, children: [
8301
- service.duration_minutes,
8302
- " min"
9336
+ /* @__PURE__ */ jsx("span", { "data-cimplify-booking-service-duration": true, children: formatDuration2(service.duration_minutes, service.duration_unit) }),
9337
+ service.price && /* @__PURE__ */ jsx("span", { "data-cimplify-booking-service-price": true, children: /* @__PURE__ */ jsx(Price, { amount: service.price }) }),
9338
+ hasDeposit && /* @__PURE__ */ jsxs("span", { "data-cimplify-booking-deposit-info": true, className: classNames?.depositInfo, children: [
9339
+ "Deposit: ",
9340
+ depositType === "percentage" ? `${parsePrice(depositAmount)}%` : /* @__PURE__ */ jsx(Price, { amount: depositAmount })
9341
+ ] }),
9342
+ cancellationMinutes !== void 0 && cancellationMinutes > 0 && /* @__PURE__ */ jsxs("span", { "data-cimplify-booking-cancellation-policy": true, className: classNames?.cancellationPolicy, children: [
9343
+ "Free cancellation up to ",
9344
+ cancellationMinutes >= 60 ? `${Math.floor(cancellationMinutes / 60)} hour${Math.floor(cancellationMinutes / 60) !== 1 ? "s" : ""}` : `${cancellationMinutes} minute${cancellationMinutes !== 1 ? "s" : ""}`,
9345
+ " before"
8303
9346
  ] }),
8304
- service.price && /* @__PURE__ */ jsx("span", { "data-cimplify-booking-service-price": true, children: /* @__PURE__ */ jsx(Price, { amount: service.price }) })
9347
+ noShowFee !== void 0 && parsePrice(noShowFee) !== 0 && /* @__PURE__ */ jsxs("span", { "data-cimplify-booking-no-show-fee": true, className: classNames?.cancellationPolicy, children: [
9348
+ "No-show fee: ",
9349
+ /* @__PURE__ */ jsx(Price, { amount: noShowFee })
9350
+ ] })
8305
9351
  ] }),
8306
9352
  error && /* @__PURE__ */ jsx("div", { "data-cimplify-booking-error": true, className: classNames?.error, children: error }),
8307
9353
  step === "select-slot" && /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-step": "select-slot", className: classNames?.step, children: [
@@ -8348,10 +9394,7 @@ function BookingPage({
8348
9394
  ] }),
8349
9395
  /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8350
9396
  /* @__PURE__ */ jsx("span", { children: "Duration" }),
8351
- /* @__PURE__ */ jsxs("span", { children: [
8352
- service.duration_minutes,
8353
- " min"
8354
- ] })
9397
+ /* @__PURE__ */ jsx("span", { children: formatDuration2(service.duration_minutes, service.duration_unit) })
8355
9398
  ] }),
8356
9399
  selectedStaffId && staff && /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8357
9400
  /* @__PURE__ */ jsx("span", { children: "Provider" }),
@@ -8360,6 +9403,10 @@ function BookingPage({
8360
9403
  (selectedSlot.price || service.price) && /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8361
9404
  /* @__PURE__ */ jsx("span", { children: "Price" }),
8362
9405
  /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(Price, { amount: selectedSlot.price || service.price }) })
9406
+ ] }),
9407
+ hasDeposit && /* @__PURE__ */ jsxs("div", { "data-cimplify-booking-summary-row": true, className: cn(classNames?.summaryRow, classNames?.depositInfo), children: [
9408
+ /* @__PURE__ */ jsx("span", { children: "Deposit" }),
9409
+ /* @__PURE__ */ jsx("span", { children: depositType === "percentage" ? `${parsePrice(depositAmount)}%` : /* @__PURE__ */ jsx(Price, { amount: depositAmount }) })
8363
9410
  ] })
8364
9411
  ] }),
8365
9412
  /* @__PURE__ */ jsx(
@@ -8370,7 +9417,7 @@ function BookingPage({
8370
9417
  disabled: isSubmitting,
8371
9418
  "data-cimplify-booking-confirm": true,
8372
9419
  className: classNames?.confirmButton,
8373
- children: isSubmitting ? "Adding to cart\u2026" : "Add to cart"
9420
+ children: isSubmitting ? isReschedule ? "Rescheduling\u2026" : "Adding to cart\u2026" : isReschedule ? "Reschedule" : "Confirm Booking"
8374
9421
  }
8375
9422
  )
8376
9423
  ] })
@@ -8462,5 +9509,459 @@ function BookingsPage({
8462
9509
  ) })
8463
9510
  ] });
8464
9511
  }
9512
+ function LocationPicker({
9513
+ locations: locationsProp,
9514
+ currentLocation: currentLocationProp,
9515
+ onLocationChange,
9516
+ renderLocation,
9517
+ emptyMessage,
9518
+ className,
9519
+ classNames
9520
+ }) {
9521
+ const {
9522
+ locations: fetched,
9523
+ currentLocation: fetchedCurrent,
9524
+ setCurrentLocation,
9525
+ isLoading
9526
+ } = useLocations();
9527
+ const locations = locationsProp ?? fetched;
9528
+ const currentLocation = currentLocationProp ?? fetchedCurrent;
9529
+ const handleSelect = (location) => {
9530
+ if (onLocationChange) {
9531
+ onLocationChange(location);
9532
+ } else {
9533
+ setCurrentLocation(location);
9534
+ }
9535
+ };
9536
+ if (isLoading && locations.length === 0) {
9537
+ return /* @__PURE__ */ jsx(
9538
+ "div",
9539
+ {
9540
+ "data-cimplify-location-picker": true,
9541
+ "aria-busy": "true",
9542
+ className: cn(className, classNames?.root, classNames?.loading)
9543
+ }
9544
+ );
9545
+ }
9546
+ if (locations.length <= 1) {
9547
+ return null;
9548
+ }
9549
+ if (locations.length === 0) {
9550
+ return /* @__PURE__ */ jsx(
9551
+ "div",
9552
+ {
9553
+ "data-cimplify-location-picker": true,
9554
+ "data-empty": true,
9555
+ className: cn(className, classNames?.root, classNames?.empty),
9556
+ children: /* @__PURE__ */ jsx("p", { children: emptyMessage ?? "No locations available" })
9557
+ }
9558
+ );
9559
+ }
9560
+ return /* @__PURE__ */ jsx("div", { "data-cimplify-location-picker": true, className: cn(className, classNames?.root), children: locations.map((location) => {
9561
+ const isActive = currentLocation?.id === location.id;
9562
+ return /* @__PURE__ */ jsx(
9563
+ "button",
9564
+ {
9565
+ type: "button",
9566
+ onClick: () => handleSelect(location),
9567
+ "data-cimplify-location-item": true,
9568
+ "data-active": isActive || void 0,
9569
+ "aria-pressed": isActive,
9570
+ className: cn(classNames?.item, isActive && classNames?.activeItem),
9571
+ children: renderLocation ? renderLocation(location, isActive) : /* @__PURE__ */ jsx("span", { children: location.name })
9572
+ },
9573
+ location.id
9574
+ );
9575
+ }) });
9576
+ }
9577
+ function RecommendationCarousel({
9578
+ recommendations: recommendationsProp,
9579
+ locationId,
9580
+ limit,
9581
+ onProductClick,
9582
+ renderProduct,
9583
+ emptyMessage,
9584
+ className,
9585
+ classNames
9586
+ }) {
9587
+ const { recommendations: fetched, isLoading } = useRecommendations({
9588
+ locationId,
9589
+ limit,
9590
+ enabled: recommendationsProp === void 0
9591
+ });
9592
+ const recommendations = recommendationsProp ?? fetched;
9593
+ if (isLoading && recommendations.length === 0) {
9594
+ return /* @__PURE__ */ jsx(
9595
+ "div",
9596
+ {
9597
+ "data-cimplify-recommendation-carousel": true,
9598
+ "aria-busy": "true",
9599
+ className: cn(className, classNames?.root, classNames?.loading)
9600
+ }
9601
+ );
9602
+ }
9603
+ if (recommendations.length === 0) {
9604
+ return null;
9605
+ }
9606
+ return /* @__PURE__ */ jsx(
9607
+ "div",
9608
+ {
9609
+ "data-cimplify-recommendation-carousel": true,
9610
+ className: cn(className, classNames?.root),
9611
+ style: { display: "flex", overflowX: "auto", gap: "1rem" },
9612
+ children: recommendations.map((rec, index) => {
9613
+ const productId = rec.product?.id ?? String(index);
9614
+ return /* @__PURE__ */ jsx(
9615
+ "button",
9616
+ {
9617
+ type: "button",
9618
+ onClick: () => onProductClick?.(rec),
9619
+ "data-cimplify-recommendation-item": true,
9620
+ className: classNames?.item,
9621
+ style: { flexShrink: 0 },
9622
+ children: renderProduct ? renderProduct(rec) : /* @__PURE__ */ jsxs(Fragment, { children: [
9623
+ /* @__PURE__ */ jsx("span", { "data-cimplify-recommendation-name": true, children: rec.product?.name ?? rec.product?.id ?? "Product" }),
9624
+ rec.reason && /* @__PURE__ */ jsx("span", { "data-cimplify-recommendation-reason": true, className: classNames?.reason, children: rec.reason })
9625
+ ] })
9626
+ },
9627
+ String(productId)
9628
+ );
9629
+ })
9630
+ }
9631
+ );
9632
+ }
9633
+ function SessionMessageBanner({
9634
+ messages: messagesProp,
9635
+ onDismiss,
9636
+ renderMessage,
9637
+ className,
9638
+ classNames
9639
+ }) {
9640
+ const { messages: fetched, isLoading, dismissMessage } = useActivityState({
9641
+ enabled: messagesProp === void 0
9642
+ });
9643
+ const messages = messagesProp ?? fetched;
9644
+ const handleDismiss = async (code) => {
9645
+ if (onDismiss) {
9646
+ onDismiss(code);
9647
+ } else {
9648
+ await dismissMessage(code);
9649
+ }
9650
+ };
9651
+ if (isLoading && messages.length === 0) {
9652
+ return /* @__PURE__ */ jsx(
9653
+ "div",
9654
+ {
9655
+ "data-cimplify-session-message-banner": true,
9656
+ "aria-busy": "true",
9657
+ className: cn(className, classNames?.root)
9658
+ }
9659
+ );
9660
+ }
9661
+ if (messages.length === 0) {
9662
+ return null;
9663
+ }
9664
+ return /* @__PURE__ */ jsx("div", { "data-cimplify-session-message-banner": true, className: cn(className, classNames?.root), children: messages.map((msg) => /* @__PURE__ */ jsx(
9665
+ "div",
9666
+ {
9667
+ "data-cimplify-session-message": true,
9668
+ "data-level": msg.level,
9669
+ className: classNames?.message,
9670
+ children: renderMessage ? renderMessage(msg) : /* @__PURE__ */ jsxs(Fragment, { children: [
9671
+ /* @__PURE__ */ jsx("span", { "data-cimplify-session-message-text": true, className: classNames?.text, children: msg.text }),
9672
+ msg.dismissible && /* @__PURE__ */ jsx(
9673
+ "button",
9674
+ {
9675
+ type: "button",
9676
+ onClick: () => void handleDismiss(msg.code),
9677
+ "data-cimplify-session-message-dismiss": true,
9678
+ className: classNames?.dismissButton,
9679
+ "aria-label": "Dismiss message",
9680
+ children: "\xD7"
9681
+ }
9682
+ )
9683
+ ] })
9684
+ },
9685
+ msg.code
9686
+ )) });
9687
+ }
9688
+ function RecentlyViewed({
9689
+ limit,
9690
+ onProductClick,
9691
+ renderProduct,
9692
+ emptyMessage,
9693
+ className,
9694
+ classNames
9695
+ }) {
9696
+ const { state, isLoading } = useActivityState();
9697
+ const rawViewed = state?.activity?.viewed_products ?? [];
9698
+ const viewed = limit ? rawViewed.slice(0, limit) : rawViewed;
9699
+ if (isLoading && viewed.length === 0) {
9700
+ return /* @__PURE__ */ jsx(
9701
+ "div",
9702
+ {
9703
+ "data-cimplify-recently-viewed": true,
9704
+ "aria-busy": "true",
9705
+ className: cn(className, classNames?.root, classNames?.loading)
9706
+ }
9707
+ );
9708
+ }
9709
+ if (viewed.length === 0) {
9710
+ return null;
9711
+ }
9712
+ return /* @__PURE__ */ jsx("div", { "data-cimplify-recently-viewed": true, className: cn(className, classNames?.root), children: viewed.map((product) => /* @__PURE__ */ jsx(
9713
+ "button",
9714
+ {
9715
+ type: "button",
9716
+ onClick: () => onProductClick?.(product),
9717
+ "data-cimplify-recently-viewed-item": true,
9718
+ className: classNames?.item,
9719
+ children: renderProduct ? renderProduct(product) : /* @__PURE__ */ jsx("span", { children: product.product_name ?? product.product_id })
9720
+ },
9721
+ product.product_id
9722
+ )) });
9723
+ }
9724
+ var FREQUENCY_LABELS = {
9725
+ weekly: "Weekly",
9726
+ monthly: "Monthly",
9727
+ quarterly: "Quarterly",
9728
+ annually: "Annually"
9729
+ };
9730
+ function formatMarkup(plan) {
9731
+ if (!plan.markup_type || plan.markup_amount == null) return null;
9732
+ if (plan.markup_type === "percentage") return `+${plan.markup_amount}%`;
9733
+ return null;
9734
+ }
9735
+ function BillingPlanSelector({
9736
+ productId,
9737
+ plans: plansProp,
9738
+ onPlanSelect,
9739
+ selectedPlanId,
9740
+ showOneTimePurchase = false,
9741
+ oneTimePurchaseLabel = "One-time purchase",
9742
+ renderPlan,
9743
+ className,
9744
+ classNames
9745
+ }) {
9746
+ const { plans: fetched, isLoading } = useBillingPlans(productId, {
9747
+ enabled: plansProp === void 0
9748
+ });
9749
+ const plans = plansProp ?? fetched;
9750
+ if (isLoading && plans.length === 0) {
9751
+ return /* @__PURE__ */ jsx(
9752
+ "div",
9753
+ {
9754
+ "data-cimplify-billing-plan-selector": true,
9755
+ "aria-busy": "true",
9756
+ className: cn(className, classNames?.root, classNames?.loading)
9757
+ }
9758
+ );
9759
+ }
9760
+ if (plans.length === 0 && !showOneTimePurchase) {
9761
+ return null;
9762
+ }
9763
+ const isOneTimePurchaseSelected = selectedPlanId === null;
9764
+ return /* @__PURE__ */ jsxs("div", { "data-cimplify-billing-plan-selector": true, className: cn(className, classNames?.root), children: [
9765
+ showOneTimePurchase && /* @__PURE__ */ jsx(
9766
+ "button",
9767
+ {
9768
+ type: "button",
9769
+ onClick: () => onPlanSelect?.(null),
9770
+ "data-cimplify-billing-plan": true,
9771
+ "data-plan-type": "one-time",
9772
+ "data-active": isOneTimePurchaseSelected || void 0,
9773
+ "aria-pressed": isOneTimePurchaseSelected,
9774
+ className: cn(
9775
+ classNames?.plan,
9776
+ isOneTimePurchaseSelected && classNames?.activePlan
9777
+ ),
9778
+ children: /* @__PURE__ */ jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: oneTimePurchaseLabel })
9779
+ }
9780
+ ),
9781
+ plans.map((plan) => {
9782
+ const isActive = selectedPlanId === plan.id;
9783
+ const markup = formatMarkup(plan);
9784
+ return /* @__PURE__ */ jsx(
9785
+ "button",
9786
+ {
9787
+ type: "button",
9788
+ onClick: () => onPlanSelect?.(plan),
9789
+ "data-cimplify-billing-plan": true,
9790
+ "data-plan-type": plan.plan_type,
9791
+ "data-active": isActive || void 0,
9792
+ "aria-pressed": isActive,
9793
+ className: cn(classNames?.plan, isActive && classNames?.activePlan),
9794
+ children: renderPlan ? renderPlan(plan, isActive) : /* @__PURE__ */ jsxs(Fragment, { children: [
9795
+ /* @__PURE__ */ jsx("span", { "data-cimplify-billing-frequency": true, className: classNames?.frequency, children: FREQUENCY_LABELS[plan.frequency] }),
9796
+ markup && /* @__PURE__ */ jsx("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: markup }),
9797
+ plan.markup_type === "fixed" && plan.markup_amount != null && /* @__PURE__ */ jsxs("span", { "data-cimplify-billing-markup": true, className: classNames?.price, children: [
9798
+ "+",
9799
+ /* @__PURE__ */ jsx(Price, { amount: plan.markup_amount })
9800
+ ] }),
9801
+ plan.trial_days > 0 && /* @__PURE__ */ jsxs("span", { "data-cimplify-billing-trial": true, className: classNames?.trialBadge, children: [
9802
+ plan.trial_days,
9803
+ "-day trial"
9804
+ ] }),
9805
+ plan.setup_fee > 0 && /* @__PURE__ */ jsxs("span", { "data-cimplify-billing-setup-fee": true, className: classNames?.setupFee, children: [
9806
+ "Setup fee: ",
9807
+ /* @__PURE__ */ jsx(Price, { amount: plan.setup_fee })
9808
+ ] }),
9809
+ plan.plan_type === "installment" && plan.installment_periods != null && /* @__PURE__ */ jsxs("span", { "data-cimplify-billing-periods": true, children: [
9810
+ plan.installment_periods,
9811
+ " payments"
9812
+ ] })
9813
+ ] })
9814
+ },
9815
+ plan.id
9816
+ );
9817
+ })
9818
+ ] });
9819
+ }
9820
+ function DeliveryEstimate({
9821
+ latitude,
9822
+ longitude,
9823
+ country,
9824
+ onFeeCalculated,
9825
+ className,
9826
+ classNames
9827
+ }) {
9828
+ const context = useOptionalCimplifyClient();
9829
+ const client = context?.client ?? null;
9830
+ const [result, setResult] = useState(null);
9831
+ const [isLoading, setIsLoading] = useState(true);
9832
+ const [error, setError] = useState(null);
9833
+ const requestIdRef = useRef(0);
9834
+ useEffect(() => {
9835
+ if (!client) return;
9836
+ const nextRequestId = ++requestIdRef.current;
9837
+ setIsLoading(true);
9838
+ setError(null);
9839
+ void (async () => {
9840
+ const res = await client.delivery.getFee(latitude, longitude, country);
9841
+ if (nextRequestId !== requestIdRef.current) return;
9842
+ if (!res.ok) {
9843
+ setError(res.error);
9844
+ setResult(null);
9845
+ setIsLoading(false);
9846
+ return;
9847
+ }
9848
+ setResult(res.value);
9849
+ setError(null);
9850
+ setIsLoading(false);
9851
+ onFeeCalculated?.(res.value);
9852
+ })();
9853
+ }, [client, latitude, longitude, country]);
9854
+ if (!client) {
9855
+ return null;
9856
+ }
9857
+ if (isLoading) {
9858
+ return /* @__PURE__ */ jsx(
9859
+ "div",
9860
+ {
9861
+ "data-cimplify-delivery-estimate": true,
9862
+ "data-serviceable": "false",
9863
+ "aria-busy": "true",
9864
+ className: cn(className, classNames?.root, classNames?.loading)
9865
+ }
9866
+ );
9867
+ }
9868
+ if (error) {
9869
+ return /* @__PURE__ */ jsx(
9870
+ "div",
9871
+ {
9872
+ "data-cimplify-delivery-estimate": true,
9873
+ "data-serviceable": "false",
9874
+ className: cn(className, classNames?.root, classNames?.error),
9875
+ children: /* @__PURE__ */ jsx("span", { children: error.message })
9876
+ }
9877
+ );
9878
+ }
9879
+ if (!result || !result.serviceable) {
9880
+ return /* @__PURE__ */ jsx(
9881
+ "div",
9882
+ {
9883
+ "data-cimplify-delivery-estimate": true,
9884
+ "data-serviceable": "false",
9885
+ className: cn(className, classNames?.root, classNames?.notServiceable),
9886
+ children: /* @__PURE__ */ jsx("span", { children: "Not serviceable" })
9887
+ }
9888
+ );
9889
+ }
9890
+ return /* @__PURE__ */ jsxs(
9891
+ "div",
9892
+ {
9893
+ "data-cimplify-delivery-estimate": true,
9894
+ "data-serviceable": "true",
9895
+ className: cn(className, classNames?.root),
9896
+ children: [
9897
+ result.fee != null && /* @__PURE__ */ jsx("span", { "data-cimplify-delivery-fee": true, className: classNames?.fee, children: /* @__PURE__ */ jsx(Price, { amount: result.fee }) }),
9898
+ result.currency && /* @__PURE__ */ jsx("span", { "data-cimplify-delivery-currency": true, className: classNames?.currency, children: result.currency })
9899
+ ]
9900
+ }
9901
+ );
9902
+ }
9903
+ function CurrencySelector({
9904
+ currencies,
9905
+ currentCurrency,
9906
+ onCurrencyChange,
9907
+ showRate = false,
9908
+ baseCurrency,
9909
+ renderCurrency,
9910
+ className,
9911
+ classNames
9912
+ }) {
9913
+ const context = useOptionalCimplifyClient();
9914
+ const client = context?.client ?? null;
9915
+ const [rates, setRates] = useState({});
9916
+ const [isLoadingRates, setIsLoadingRates] = useState(false);
9917
+ const requestIdRef = useRef(0);
9918
+ useEffect(() => {
9919
+ if (!showRate || !baseCurrency || !client) return;
9920
+ const targets = currencies.filter((c) => c !== baseCurrency);
9921
+ if (targets.length === 0) return;
9922
+ const nextRequestId = ++requestIdRef.current;
9923
+ setIsLoadingRates(true);
9924
+ void (async () => {
9925
+ const fetched = {};
9926
+ await Promise.all(
9927
+ targets.map(async (currency) => {
9928
+ const res = await client.fx.getRate(baseCurrency, currency);
9929
+ if (res.ok) {
9930
+ fetched[currency] = res.value;
9931
+ }
9932
+ })
9933
+ );
9934
+ if (nextRequestId !== requestIdRef.current) return;
9935
+ setRates(fetched);
9936
+ setIsLoadingRates(false);
9937
+ })();
9938
+ }, [client, showRate, baseCurrency, currencies]);
9939
+ if (currencies.length <= 1) {
9940
+ return null;
9941
+ }
9942
+ return /* @__PURE__ */ jsx("div", { "data-cimplify-currency-selector": true, className: cn(className, classNames?.root), children: currencies.map((currency) => {
9943
+ const isActive = currentCurrency === currency;
9944
+ const rate = rates[currency] ?? null;
9945
+ return /* @__PURE__ */ jsx(
9946
+ "button",
9947
+ {
9948
+ type: "button",
9949
+ onClick: () => onCurrencyChange?.(currency),
9950
+ "data-cimplify-currency-option": true,
9951
+ "data-active": isActive || void 0,
9952
+ "aria-pressed": isActive,
9953
+ className: cn(
9954
+ classNames?.option,
9955
+ isActive && classNames?.activeOption
9956
+ ),
9957
+ children: renderCurrency ? renderCurrency(currency, isActive, rate) : /* @__PURE__ */ jsxs(Fragment, { children: [
9958
+ /* @__PURE__ */ jsx("span", { "data-cimplify-currency-label": true, className: classNames?.label, children: currency }),
9959
+ showRate && baseCurrency && currency !== baseCurrency && /* @__PURE__ */ jsx("span", { "data-cimplify-currency-rate": true, className: classNames?.rate, children: isLoadingRates ? "..." : rate ? `1 ${baseCurrency} = ${rate.rate.toFixed(4)} ${currency}` : null })
9960
+ ] })
9961
+ },
9962
+ currency
9963
+ );
9964
+ }) });
9965
+ }
8465
9966
 
8466
- export { Ad, AdProvider, AddOnSelector, AddressElement, AuthElement, AvailabilityBadge, BookingCard, BookingList, BookingPage, BookingsPage, BundleSelector, CartPage, CartSummary, CataloguePage, CategoryFilter, CategoryGrid, CheckoutPage, CimplifyCheckout, CimplifyProvider, CollectionPage, CompositeSelector, DateSlotPicker, DealBanner, DealsPage, DiscountInput, ElementsProvider, OrderDetailPage, OrderHistory, OrderHistoryPage, OrderSummary, PaymentElement, Price, ProductCard, ProductCustomizer, ProductGrid, ProductImageGallery, ProductPage, ProductSheet, QuantitySelector, SaleBadge, SearchInput, SearchPage, ServiceCard, ServiceGrid, SlotPicker, StaffPicker, StoreNav, VariantSelector, cn, useAds, useAvailableSlots, useBookings, useBundles, useCart, useCategories, useCheckout, useCimplify, useCimplifyClient, useCollection, useCollections, useDeals, useElements, useElementsReady, useLocations, useOptionalCimplify, useOrder, useOrders, useProduct, useProductAvailability, useProductDeals, useProductPrice, useProductSchedules, useProducts, useProductsOnSale, useQuote, useSearch, useServiceAvailability, useServices, useTaxonomies, useTaxonomy, useTaxonomyPath, useValidateDiscount };
9967
+ export { Ad, AdProvider, AddOnSelector, AddressElement, AuthElement, AvailabilityBadge, BillingPlanSelector, BookingCard, BookingList, BookingPage, BookingsPage, BundleSelector, CartPage, CartSummary, CataloguePage, CategoryFilter, CategoryGrid, CheckoutPage, CimplifyCheckout, CimplifyProvider, CollectionPage, CompositeSelector, CurrencySelector, DateSlotPicker, DealBanner, DealsPage, DeliveryEstimate, DiscountInput, ElementsProvider, LocationPicker, OrderDetailPage, OrderHistory, OrderHistoryPage, OrderSummary, PaymentElement, Price, ProductCard, ProductCustomizer, ProductGrid, ProductImageGallery, ProductPage, ProductSheet, QuantitySelector, RecentlyViewed, RecommendationCarousel, SaleBadge, SearchInput, SearchPage, ServiceCard, ServiceGrid, SessionMessageBanner, SlotPicker, StaffPicker, StoreNav, VariantSelector, cn, useActivityState, useAds, useAttributeDefinitions, useAvailableSlots, useBillingPlans, useBookings, useBootstrap, useBundles, useCart, useCategories, useCheckout, useCimplify, useCimplifyClient, useCollection, useCollections, useDeals, useDeliveryFee, useElements, useElementsReady, useFxRate, useLocations, useOptionalCimplify, useOrder, useOrders, useProduct, useProductAvailability, useProductDeals, useProductPrice, useProductSchedules, useProducts, useProductsOnSale, usePropertyFacets, useQuote, useRecommendations, useSearch, useServiceAvailability, useServices, useTaxonomies, useTaxonomy, useTaxonomyPath, useValidateDiscount, useVariantSelector };