@cimplify/sdk 0.21.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -444,6 +444,9 @@ function buildLineKey(productId, options) {
444
444
  if (options.staffId) {
445
445
  parts.push(`st:${options.staffId}`);
446
446
  }
447
+ if (options.resourceId) {
448
+ parts.push(`r:${options.resourceId}`);
449
+ }
447
450
  return parts.join("|");
448
451
  }
449
452
  function calculateLineSubtotal(item) {
@@ -761,7 +764,8 @@ function createCartStore(params) {
761
764
  composite_selections: normalizedOptions.compositeSelections,
762
765
  scheduled_start: normalizedOptions.scheduledStart,
763
766
  scheduled_end: normalizedOptions.scheduledEnd,
764
- staff_id: normalizedOptions.staffId
767
+ staff_id: normalizedOptions.staffId,
768
+ resource_id: normalizedOptions.resourceId
765
769
  });
766
770
  if (!result.ok) {
767
771
  throw result.error;
@@ -1680,41 +1684,130 @@ function Price({ amount, className, prefix }) {
1680
1684
  chunk64OCG2TJ_js.formatPrice(convertPrice(amount), displayCurrency)
1681
1685
  ] });
1682
1686
  }
1683
- var productsCache = /* @__PURE__ */ new Map();
1684
- var productsInflight = /* @__PURE__ */ new Map();
1685
- function buildProductsCacheKey(client, locationId, options) {
1686
- return [
1687
- client.getPublicKey(),
1688
- locationId ?? "",
1689
- options.category ?? "",
1690
- options.taxonomy ?? "",
1691
- options.search ?? "",
1692
- options.featured ?? "",
1693
- options.limit ?? "",
1694
- options.sort_by ?? "",
1695
- options.sort_order ?? "",
1696
- options.tags?.join(",") ?? "",
1697
- options.in_stock ?? "",
1698
- options.min_price ?? "",
1699
- options.max_price ?? "",
1700
- options.page ?? "",
1701
- options.properties ? JSON.stringify(options.properties) : ""
1702
- ].join("|");
1703
- }
1704
- function useProducts(options = {}) {
1705
- const context = useOptionalCimplifyClient();
1706
- const client = options.client ?? context?.client;
1707
- if (!client) {
1708
- throw new Error("useProducts must be used within CimplifyProvider or passed { client }.");
1687
+ function createCachedQuery(config) {
1688
+ const cache = /* @__PURE__ */ new Map();
1689
+ const inflight = /* @__PURE__ */ new Map();
1690
+ const gcMaxAge = config.gcMaxAge ?? 3e5;
1691
+ let lastSweep = 0;
1692
+ function sweep() {
1693
+ const now = Date.now();
1694
+ if (now - lastSweep < 6e4) return;
1695
+ lastSweep = now;
1696
+ const cutoff = now - gcMaxAge;
1697
+ for (const [key, entry] of cache) {
1698
+ if (entry.ts < cutoff) cache.delete(key);
1699
+ }
1709
1700
  }
1710
- const enabled = options.enabled ?? true;
1711
- const locationId = client.getLocationId();
1712
- const previousLocationIdRef = React3.useRef(locationId);
1713
- const requestIdRef = React3.useRef(0);
1714
- const tagsSignature = options.tags?.join(",") ?? "";
1715
- const propertiesSignature = options.properties ? JSON.stringify(options.properties) : "";
1716
- const queryOptions = React3.useMemo(
1717
- () => ({
1701
+ function useCachedQuery(options = {}) {
1702
+ const context = useOptionalCimplifyClient();
1703
+ const client = options.client ?? context?.client;
1704
+ if (!client) {
1705
+ throw new Error(
1706
+ `${config.name} must be used within CimplifyProvider or passed { client }.`
1707
+ );
1708
+ }
1709
+ const enabled = options.enabled ?? true;
1710
+ const locationId = client.getLocationId();
1711
+ const previousLocationRef = React3.useRef(locationId);
1712
+ const requestIdRef = React3.useRef(0);
1713
+ const optionsRef = React3.useRef(options);
1714
+ optionsRef.current = options;
1715
+ if (config.locationSensitive && previousLocationRef.current !== locationId) {
1716
+ cache.clear();
1717
+ inflight.clear();
1718
+ previousLocationRef.current = locationId;
1719
+ }
1720
+ sweep();
1721
+ const cacheKey2 = config.key(client, options);
1722
+ const cached = cache.get(cacheKey2);
1723
+ const [data, setData] = React3.useState(cached?.data ?? null);
1724
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
1725
+ const [error, setError] = React3.useState(null);
1726
+ const load = React3.useCallback(
1727
+ async (force = false) => {
1728
+ if (!enabled) {
1729
+ setIsLoading(false);
1730
+ return;
1731
+ }
1732
+ const nextRequestId = ++requestIdRef.current;
1733
+ setError(null);
1734
+ if (!force) {
1735
+ const hit = cache.get(cacheKey2);
1736
+ if (hit) {
1737
+ setData(hit.data);
1738
+ setIsLoading(false);
1739
+ return;
1740
+ }
1741
+ }
1742
+ setIsLoading(true);
1743
+ try {
1744
+ const existing = inflight.get(cacheKey2);
1745
+ const promise = existing ?? (async () => config.fetch(client, optionsRef.current))();
1746
+ if (!existing) {
1747
+ inflight.set(cacheKey2, promise);
1748
+ promise.finally(() => inflight.delete(cacheKey2)).catch(() => {
1749
+ });
1750
+ }
1751
+ const value = await promise;
1752
+ cache.set(cacheKey2, { data: value, ts: Date.now() });
1753
+ if (nextRequestId === requestIdRef.current) {
1754
+ setData(value);
1755
+ setError(null);
1756
+ }
1757
+ } catch (loadError) {
1758
+ if (nextRequestId === requestIdRef.current) {
1759
+ setError(loadError);
1760
+ }
1761
+ } finally {
1762
+ if (nextRequestId === requestIdRef.current) {
1763
+ setIsLoading(false);
1764
+ }
1765
+ }
1766
+ },
1767
+ [cacheKey2, client, enabled]
1768
+ );
1769
+ React3.useEffect(() => {
1770
+ void load(false);
1771
+ }, [load]);
1772
+ const refetch = React3.useCallback(async () => {
1773
+ cache.delete(cacheKey2);
1774
+ await load(true);
1775
+ }, [cacheKey2, load]);
1776
+ return { data, isLoading, error, refetch };
1777
+ }
1778
+ useCachedQuery.clear = () => {
1779
+ cache.clear();
1780
+ inflight.clear();
1781
+ };
1782
+ return useCachedQuery;
1783
+ }
1784
+ function cacheKey(...parts) {
1785
+ return parts.map((p) => String(p ?? "")).join("|");
1786
+ }
1787
+
1788
+ // src/react/hooks/use-products.ts
1789
+ var productsQuery = createCachedQuery({
1790
+ name: "useProducts",
1791
+ locationSensitive: true,
1792
+ key: (client, options) => cacheKey(
1793
+ client.getPublicKey(),
1794
+ client.getLocationId(),
1795
+ options.category,
1796
+ options.taxonomy,
1797
+ options.search,
1798
+ options.featured,
1799
+ options.limit,
1800
+ options.sort_by,
1801
+ options.sort_order,
1802
+ options.tags?.join(","),
1803
+ options.in_stock,
1804
+ options.min_price,
1805
+ options.max_price,
1806
+ options.page,
1807
+ options.properties ? JSON.stringify(options.properties) : void 0
1808
+ ),
1809
+ fetch: async (client, options) => {
1810
+ const result = await client.catalogue.getProducts({
1718
1811
  category: options.category,
1719
1812
  taxonomy: options.taxonomy,
1720
1813
  search: options.search,
@@ -1728,301 +1821,71 @@ function useProducts(options = {}) {
1728
1821
  max_price: options.max_price,
1729
1822
  page: options.page,
1730
1823
  properties: options.properties
1731
- }),
1732
- [
1733
- options.category,
1734
- options.taxonomy,
1735
- options.search,
1736
- options.featured,
1737
- options.limit,
1738
- options.sort_by,
1739
- options.sort_order,
1740
- tagsSignature,
1741
- options.in_stock,
1742
- options.min_price,
1743
- options.max_price,
1744
- options.page,
1745
- propertiesSignature
1746
- ]
1747
- );
1748
- const cacheKey = React3.useMemo(
1749
- () => buildProductsCacheKey(client, locationId, queryOptions),
1750
- [client, locationId, queryOptions]
1751
- );
1752
- const cached = productsCache.get(cacheKey);
1753
- const [products, setProducts] = React3.useState(cached?.products ?? []);
1754
- const [isComplete, setIsComplete] = React3.useState(cached?.is_complete ?? true);
1755
- const [totalAvailable, setTotalAvailable] = React3.useState(cached?.total_available);
1756
- const [pagination, setPagination] = React3.useState(cached?.pagination);
1757
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
1758
- const [error, setError] = React3.useState(null);
1759
- React3.useEffect(() => {
1760
- if (previousLocationIdRef.current !== locationId) {
1761
- productsCache.clear();
1762
- productsInflight.clear();
1763
- previousLocationIdRef.current = locationId;
1764
- }
1765
- }, [locationId]);
1766
- const load = React3.useCallback(
1767
- async (force = false) => {
1768
- if (!enabled) {
1769
- setIsLoading(false);
1770
- return;
1771
- }
1772
- const nextRequestId = ++requestIdRef.current;
1773
- setError(null);
1774
- if (!force) {
1775
- const cacheEntry = productsCache.get(cacheKey);
1776
- if (cacheEntry) {
1777
- setProducts(cacheEntry.products);
1778
- setIsComplete(cacheEntry.is_complete);
1779
- setTotalAvailable(cacheEntry.total_available);
1780
- setPagination(cacheEntry.pagination);
1781
- setIsLoading(false);
1782
- return;
1783
- }
1784
- }
1785
- setIsLoading(true);
1786
- try {
1787
- const existing = productsInflight.get(cacheKey);
1788
- const promise = existing ?? (async () => {
1789
- const result = await client.catalogue.getProducts(queryOptions);
1790
- if (!result.ok) {
1791
- throw result.error;
1792
- }
1793
- return result.value;
1794
- })();
1795
- if (!existing) {
1796
- productsInflight.set(
1797
- cacheKey,
1798
- promise.finally(() => {
1799
- productsInflight.delete(cacheKey);
1800
- })
1801
- );
1802
- }
1803
- const value = await promise;
1804
- productsCache.set(cacheKey, {
1805
- products: value.items,
1806
- is_complete: value.is_complete,
1807
- total_available: value.total_available,
1808
- pagination: value.pagination
1809
- });
1810
- if (nextRequestId === requestIdRef.current) {
1811
- setProducts(value.items);
1812
- setIsComplete(value.is_complete);
1813
- setTotalAvailable(value.total_available);
1814
- setPagination(value.pagination);
1815
- setError(null);
1816
- }
1817
- } catch (loadError) {
1818
- if (nextRequestId === requestIdRef.current) {
1819
- setError(loadError);
1820
- }
1821
- } finally {
1822
- if (nextRequestId === requestIdRef.current) {
1823
- setIsLoading(false);
1824
- }
1825
- }
1826
- },
1827
- [cacheKey, client, enabled, queryOptions]
1828
- );
1829
- React3.useEffect(() => {
1830
- void load(false);
1831
- }, [load]);
1832
- const refetch = React3.useCallback(async () => {
1833
- productsCache.delete(cacheKey);
1834
- await load(true);
1835
- }, [cacheKey, load]);
1824
+ });
1825
+ if (!result.ok) throw result.error;
1826
+ return {
1827
+ products: result.value.items,
1828
+ is_complete: result.value.is_complete,
1829
+ total_available: result.value.total_available,
1830
+ pagination: result.value.pagination
1831
+ };
1832
+ }
1833
+ });
1834
+ function useProducts(options = {}) {
1835
+ const { data, isLoading, error, refetch } = productsQuery(options);
1836
1836
  return {
1837
- products,
1838
- is_complete: isComplete,
1839
- total_available: totalAvailable,
1840
- pagination,
1837
+ products: data?.products ?? [],
1838
+ is_complete: data?.is_complete ?? true,
1839
+ total_available: data?.total_available,
1840
+ pagination: data?.pagination,
1841
1841
  isLoading,
1842
1842
  error,
1843
1843
  refetch
1844
1844
  };
1845
1845
  }
1846
- var productCache = /* @__PURE__ */ new Map();
1847
- var productInflight = /* @__PURE__ */ new Map();
1846
+
1847
+ // src/react/hooks/use-product.ts
1848
1848
  function isLikelySlug(value) {
1849
1849
  return /^[a-z0-9-]+$/.test(value);
1850
1850
  }
1851
- function buildProductCacheKey(client, locationId, slugOrId) {
1852
- return JSON.stringify({
1853
- key: client.getPublicKey(),
1854
- location_id: locationId || "__none__",
1855
- slug_or_id: slugOrId
1851
+ var productQuery = createCachedQuery({
1852
+ name: "useProduct",
1853
+ locationSensitive: true,
1854
+ key: (client, options) => cacheKey(client.getPublicKey(), client.getLocationId(), options.slugOrId),
1855
+ fetch: async (client, options) => {
1856
+ const result = isLikelySlug(options.slugOrId) ? await client.catalogue.getProductBySlug(options.slugOrId) : await client.catalogue.getProduct(options.slugOrId);
1857
+ if (!result.ok) throw result.error;
1858
+ client.activity.trackProductView(result.value.id, {
1859
+ productName: result.value.name,
1860
+ categoryId: result.value.category_id,
1861
+ price: String(result.value.default_price)
1862
+ });
1863
+ return result.value;
1864
+ }
1865
+ });
1866
+ function useProduct(slugOrId, options = {}) {
1867
+ const normalized = (slugOrId || "").trim();
1868
+ const { data, isLoading, error, refetch } = productQuery({
1869
+ ...options,
1870
+ slugOrId: normalized,
1871
+ enabled: (options.enabled ?? true) && normalized.length > 0
1856
1872
  });
1873
+ return { product: data, isLoading, error, refetch };
1857
1874
  }
1858
- function useProduct(slugOrId, options = {}) {
1859
- const context = useOptionalCimplifyClient();
1860
- const client = options.client ?? context?.client;
1861
- if (!client) {
1862
- throw new Error("useProduct must be used within CimplifyProvider or passed { client }.");
1875
+
1876
+ // src/react/hooks/use-categories.ts
1877
+ var categoriesQuery = createCachedQuery({
1878
+ name: "useCategories",
1879
+ key: (client) => client.getPublicKey() || "__demo__",
1880
+ fetch: async (client) => {
1881
+ const result = await client.catalogue.getCategories();
1882
+ if (!result.ok) throw result.error;
1883
+ return result.value;
1863
1884
  }
1864
- const enabled = options.enabled ?? true;
1865
- const locationId = client.getLocationId();
1866
- const previousLocationIdRef = React3.useRef(locationId);
1867
- const requestIdRef = React3.useRef(0);
1868
- const trackedProductRef = React3.useRef(null);
1869
- const normalizedSlugOrId = React3.useMemo(() => (slugOrId || "").trim(), [slugOrId]);
1870
- const cacheKey = React3.useMemo(
1871
- () => buildProductCacheKey(client, locationId, normalizedSlugOrId),
1872
- [client, locationId, normalizedSlugOrId]
1873
- );
1874
- const cached = productCache.get(cacheKey);
1875
- const [product, setProduct] = React3.useState(cached?.product ?? null);
1876
- const [isLoading, setIsLoading] = React3.useState(
1877
- enabled && normalizedSlugOrId.length > 0 && !cached
1878
- );
1879
- const [error, setError] = React3.useState(null);
1880
- React3.useEffect(() => {
1881
- if (previousLocationIdRef.current !== locationId) {
1882
- productCache.clear();
1883
- productInflight.clear();
1884
- previousLocationIdRef.current = locationId;
1885
- }
1886
- }, [locationId]);
1887
- const load = React3.useCallback(
1888
- async (force = false) => {
1889
- if (!enabled || normalizedSlugOrId.length === 0) {
1890
- setProduct(null);
1891
- setIsLoading(false);
1892
- return;
1893
- }
1894
- const nextRequestId = ++requestIdRef.current;
1895
- setError(null);
1896
- if (!force) {
1897
- const cacheEntry = productCache.get(cacheKey);
1898
- if (cacheEntry) {
1899
- setProduct(cacheEntry.product);
1900
- setIsLoading(false);
1901
- return;
1902
- }
1903
- }
1904
- setIsLoading(true);
1905
- try {
1906
- const existing = productInflight.get(cacheKey);
1907
- const promise = existing ?? (async () => {
1908
- const result = isLikelySlug(normalizedSlugOrId) ? await client.catalogue.getProductBySlug(normalizedSlugOrId) : await client.catalogue.getProduct(normalizedSlugOrId);
1909
- if (!result.ok) {
1910
- throw result.error;
1911
- }
1912
- return result.value;
1913
- })();
1914
- if (!existing) {
1915
- productInflight.set(
1916
- cacheKey,
1917
- promise.finally(() => {
1918
- productInflight.delete(cacheKey);
1919
- })
1920
- );
1921
- }
1922
- const value = await promise;
1923
- productCache.set(cacheKey, { product: value });
1924
- if (nextRequestId === requestIdRef.current) {
1925
- setProduct(value);
1926
- setError(null);
1927
- if (value && trackedProductRef.current !== value.id) {
1928
- trackedProductRef.current = value.id;
1929
- client.activity.trackProductView(value.id, {
1930
- productName: value.name,
1931
- categoryId: value.category_id,
1932
- price: String(value.default_price)
1933
- });
1934
- }
1935
- }
1936
- } catch (loadError) {
1937
- if (nextRequestId === requestIdRef.current) {
1938
- setError(loadError);
1939
- }
1940
- } finally {
1941
- if (nextRequestId === requestIdRef.current) {
1942
- setIsLoading(false);
1943
- }
1944
- }
1945
- },
1946
- [cacheKey, client, enabled, normalizedSlugOrId]
1947
- );
1948
- React3.useEffect(() => {
1949
- void load(false);
1950
- }, [load]);
1951
- const refetch = React3.useCallback(async () => {
1952
- productCache.delete(cacheKey);
1953
- await load(true);
1954
- }, [cacheKey, load]);
1955
- return { product, isLoading, error, refetch };
1956
- }
1957
- var categoriesCache = /* @__PURE__ */ new Map();
1958
- var categoriesInflight = /* @__PURE__ */ new Map();
1959
- function buildCategoriesCacheKey(client) {
1960
- return client.getPublicKey() || "__demo__";
1961
- }
1885
+ });
1962
1886
  function useCategories(options = {}) {
1963
- const context = useOptionalCimplifyClient();
1964
- const client = options.client ?? context?.client;
1965
- if (!client) {
1966
- throw new Error("useCategories must be used within CimplifyProvider or passed { client }.");
1967
- }
1968
- const enabled = options.enabled ?? true;
1969
- const cacheKey = React3.useMemo(() => buildCategoriesCacheKey(client), [client]);
1970
- const cached = categoriesCache.get(cacheKey);
1971
- const [categories, setCategories] = React3.useState(cached ?? []);
1972
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
1973
- const [error, setError] = React3.useState(null);
1974
- const load = React3.useCallback(
1975
- async (force = false) => {
1976
- if (!enabled) {
1977
- setIsLoading(false);
1978
- return;
1979
- }
1980
- setError(null);
1981
- if (!force) {
1982
- const cachedCategories = categoriesCache.get(cacheKey);
1983
- if (cachedCategories) {
1984
- setCategories(cachedCategories);
1985
- setIsLoading(false);
1986
- return;
1987
- }
1988
- }
1989
- setIsLoading(true);
1990
- try {
1991
- const existing = categoriesInflight.get(cacheKey);
1992
- const promise = existing ?? (async () => {
1993
- const result = await client.catalogue.getCategories();
1994
- if (!result.ok) {
1995
- throw result.error;
1996
- }
1997
- return result.value;
1998
- })();
1999
- if (!existing) {
2000
- categoriesInflight.set(
2001
- cacheKey,
2002
- promise.finally(() => {
2003
- categoriesInflight.delete(cacheKey);
2004
- })
2005
- );
2006
- }
2007
- const value = await promise;
2008
- categoriesCache.set(cacheKey, value);
2009
- setCategories(value);
2010
- } catch (loadError) {
2011
- setError(loadError);
2012
- } finally {
2013
- setIsLoading(false);
2014
- }
2015
- },
2016
- [cacheKey, client, enabled]
2017
- );
2018
- React3.useEffect(() => {
2019
- void load(false);
2020
- }, [load]);
2021
- const refetch = React3.useCallback(async () => {
2022
- categoriesCache.delete(cacheKey);
2023
- await load(true);
2024
- }, [cacheKey, load]);
2025
- return { categories, isLoading, error, refetch };
1887
+ const { data, isLoading, error, refetch } = categoriesQuery(options);
1888
+ return { categories: data ?? [], isLoading, error, refetch };
2026
1889
  }
2027
1890
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "cancelled", "refunded"]);
2028
1891
  var orderCache = /* @__PURE__ */ new Map();
@@ -2044,11 +1907,11 @@ function useOrder(orderId, options = {}) {
2044
1907
  const previousStatusRef = React3.useRef(null);
2045
1908
  const onStatusChangeRef = React3.useRef(options.onStatusChange);
2046
1909
  onStatusChangeRef.current = options.onStatusChange;
2047
- const cacheKey = React3.useMemo(
1910
+ const cacheKey2 = React3.useMemo(
2048
1911
  () => buildOrderCacheKey(client, normalizedOrderId),
2049
1912
  [client, normalizedOrderId]
2050
1913
  );
2051
- const cached = orderCache.get(cacheKey);
1914
+ const cached = orderCache.get(cacheKey2);
2052
1915
  const [order, setOrder] = React3.useState(cached?.order ?? null);
2053
1916
  const [isLoading, setIsLoading] = React3.useState(
2054
1917
  enabled && normalizedOrderId.length > 0 && !cached
@@ -2064,7 +1927,7 @@ function useOrder(orderId, options = {}) {
2064
1927
  const nextRequestId = ++requestIdRef.current;
2065
1928
  setError(null);
2066
1929
  if (!force) {
2067
- const cacheEntry = orderCache.get(cacheKey);
1930
+ const cacheEntry = orderCache.get(cacheKey2);
2068
1931
  if (cacheEntry) {
2069
1932
  setOrder(cacheEntry.order);
2070
1933
  setIsLoading(false);
@@ -2073,7 +1936,7 @@ function useOrder(orderId, options = {}) {
2073
1936
  }
2074
1937
  setIsLoading(true);
2075
1938
  try {
2076
- const existing = orderInflight.get(cacheKey);
1939
+ const existing = orderInflight.get(cacheKey2);
2077
1940
  const promise = existing ?? (async () => {
2078
1941
  const result = await client.orders.get(normalizedOrderId);
2079
1942
  if (!result.ok) {
@@ -2083,14 +1946,14 @@ function useOrder(orderId, options = {}) {
2083
1946
  })();
2084
1947
  if (!existing) {
2085
1948
  orderInflight.set(
2086
- cacheKey,
1949
+ cacheKey2,
2087
1950
  promise.finally(() => {
2088
- orderInflight.delete(cacheKey);
1951
+ orderInflight.delete(cacheKey2);
2089
1952
  })
2090
1953
  );
2091
1954
  }
2092
1955
  const value = await promise;
2093
- orderCache.set(cacheKey, { order: value });
1956
+ orderCache.set(cacheKey2, { order: value });
2094
1957
  if (nextRequestId === requestIdRef.current) {
2095
1958
  setOrder(value);
2096
1959
  setError(null);
@@ -2111,7 +1974,7 @@ function useOrder(orderId, options = {}) {
2111
1974
  }
2112
1975
  }
2113
1976
  },
2114
- [cacheKey, client, enabled, normalizedOrderId]
1977
+ [cacheKey2, client, enabled, normalizedOrderId]
2115
1978
  );
2116
1979
  React3.useEffect(() => {
2117
1980
  void load(false);
@@ -2129,9 +1992,9 @@ function useOrder(orderId, options = {}) {
2129
1992
  };
2130
1993
  }, [enabled, isTerminal, load, normalizedOrderId, poll, pollInterval]);
2131
1994
  const refetch = React3.useCallback(async () => {
2132
- orderCache.delete(cacheKey);
1995
+ orderCache.delete(cacheKey2);
2133
1996
  await load(true);
2134
- }, [cacheKey, load]);
1997
+ }, [cacheKey2, load]);
2135
1998
  return { order, isLoading, error, refetch, isTerminal };
2136
1999
  }
2137
2000
  var LOCATION_STORAGE_KEY2 = "cimplify_location_id";
@@ -2234,216 +2097,64 @@ function useLocations(options = {}) {
2234
2097
  isLoading
2235
2098
  };
2236
2099
  }
2237
- var collectionsCache = /* @__PURE__ */ new Map();
2238
- var collectionsInflight = /* @__PURE__ */ new Map();
2239
- function buildCollectionsCacheKey(client, locationId) {
2240
- return JSON.stringify({
2241
- key: client.getPublicKey(),
2242
- location_id: locationId || "__none__"
2100
+
2101
+ // src/react/hooks/use-collections.ts
2102
+ var collectionsQuery = createCachedQuery({
2103
+ name: "useCollections",
2104
+ locationSensitive: true,
2105
+ key: (client) => cacheKey(client.getPublicKey(), client.getLocationId()),
2106
+ fetch: async (client) => {
2107
+ const result = await client.catalogue.getCollections();
2108
+ if (!result.ok) throw result.error;
2109
+ return result.value;
2110
+ }
2111
+ });
2112
+ function useCollections(options = {}) {
2113
+ const { data, isLoading, error, refetch } = collectionsQuery(options);
2114
+ return { collections: data ?? [], isLoading, error, refetch };
2115
+ }
2116
+
2117
+ // src/react/hooks/use-collection.ts
2118
+ function isLikelySlug2(value) {
2119
+ return /^[a-z0-9-]+$/.test(value);
2120
+ }
2121
+ var collectionQuery = createCachedQuery({
2122
+ name: "useCollection",
2123
+ locationSensitive: true,
2124
+ key: (client, options) => cacheKey(client.getPublicKey(), client.getLocationId(), options.idOrSlug),
2125
+ fetch: async (client, options) => {
2126
+ const collectionResult = isLikelySlug2(options.idOrSlug) ? await client.catalogue.getCollectionBySlug(options.idOrSlug) : await client.catalogue.getCollection(options.idOrSlug);
2127
+ if (!collectionResult.ok) throw collectionResult.error;
2128
+ const productsResult = await client.catalogue.getCollectionProducts(
2129
+ collectionResult.value.id
2130
+ );
2131
+ if (!productsResult.ok) throw productsResult.error;
2132
+ return {
2133
+ collection: collectionResult.value,
2134
+ products: productsResult.value
2135
+ };
2136
+ }
2137
+ });
2138
+ function useCollection(idOrSlug, options = {}) {
2139
+ const normalized = (idOrSlug || "").trim();
2140
+ const { data, isLoading, error, refetch } = collectionQuery({
2141
+ ...options,
2142
+ idOrSlug: normalized,
2143
+ enabled: (options.enabled ?? true) && normalized.length > 0
2243
2144
  });
2145
+ return {
2146
+ collection: data?.collection ?? null,
2147
+ products: data?.products ?? [],
2148
+ isLoading,
2149
+ error,
2150
+ refetch
2151
+ };
2244
2152
  }
2245
- function useCollections(options = {}) {
2153
+ function useSearch(options = {}) {
2246
2154
  const context = useOptionalCimplifyClient();
2247
2155
  const client = options.client ?? context?.client;
2248
2156
  if (!client) {
2249
- throw new Error("useCollections must be used within CimplifyProvider or passed { client }.");
2250
- }
2251
- const enabled = options.enabled ?? true;
2252
- const locationId = client.getLocationId();
2253
- const previousLocationIdRef = React3.useRef(locationId);
2254
- const requestIdRef = React3.useRef(0);
2255
- const cacheKey = React3.useMemo(
2256
- () => buildCollectionsCacheKey(client, locationId),
2257
- [client, locationId]
2258
- );
2259
- const cached = collectionsCache.get(cacheKey);
2260
- const [collections, setCollections] = React3.useState(cached?.collections ?? []);
2261
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
2262
- const [error, setError] = React3.useState(null);
2263
- React3.useEffect(() => {
2264
- if (previousLocationIdRef.current !== locationId) {
2265
- collectionsCache.clear();
2266
- collectionsInflight.clear();
2267
- previousLocationIdRef.current = locationId;
2268
- }
2269
- }, [locationId]);
2270
- const load = React3.useCallback(
2271
- async (force = false) => {
2272
- if (!enabled) {
2273
- setIsLoading(false);
2274
- return;
2275
- }
2276
- const nextRequestId = ++requestIdRef.current;
2277
- setError(null);
2278
- if (!force) {
2279
- const cacheEntry = collectionsCache.get(cacheKey);
2280
- if (cacheEntry) {
2281
- setCollections(cacheEntry.collections);
2282
- setIsLoading(false);
2283
- return;
2284
- }
2285
- }
2286
- setIsLoading(true);
2287
- try {
2288
- const existing = collectionsInflight.get(cacheKey);
2289
- const promise = existing ?? (async () => {
2290
- const result = await client.catalogue.getCollections();
2291
- if (!result.ok) {
2292
- throw result.error;
2293
- }
2294
- return result.value;
2295
- })();
2296
- if (!existing) {
2297
- collectionsInflight.set(cacheKey, promise);
2298
- promise.finally(() => {
2299
- collectionsInflight.delete(cacheKey);
2300
- }).catch(() => void 0);
2301
- }
2302
- const value = await promise;
2303
- collectionsCache.set(cacheKey, { collections: value });
2304
- if (nextRequestId === requestIdRef.current) {
2305
- setCollections(value);
2306
- setError(null);
2307
- }
2308
- } catch (loadError) {
2309
- if (nextRequestId === requestIdRef.current) {
2310
- setError(loadError);
2311
- }
2312
- } finally {
2313
- if (nextRequestId === requestIdRef.current) {
2314
- setIsLoading(false);
2315
- }
2316
- }
2317
- },
2318
- [cacheKey, client, enabled]
2319
- );
2320
- React3.useEffect(() => {
2321
- void load(false);
2322
- }, [load]);
2323
- const refetch = React3.useCallback(async () => {
2324
- collectionsCache.delete(cacheKey);
2325
- await load(true);
2326
- }, [cacheKey, load]);
2327
- return { collections, isLoading, error, refetch };
2328
- }
2329
- var collectionCache = /* @__PURE__ */ new Map();
2330
- var collectionInflight = /* @__PURE__ */ new Map();
2331
- function isLikelySlug2(value) {
2332
- return /^[a-z0-9-]+$/.test(value);
2333
- }
2334
- function buildCollectionCacheKey(client, locationId, idOrSlug) {
2335
- return JSON.stringify({
2336
- key: client.getPublicKey(),
2337
- location_id: locationId || "__none__",
2338
- collection: idOrSlug
2339
- });
2340
- }
2341
- function useCollection(idOrSlug, options = {}) {
2342
- const context = useOptionalCimplifyClient();
2343
- const client = options.client ?? context?.client;
2344
- if (!client) {
2345
- throw new Error("useCollection must be used within CimplifyProvider or passed { client }.");
2346
- }
2347
- const enabled = options.enabled ?? true;
2348
- const locationId = client.getLocationId();
2349
- const previousLocationIdRef = React3.useRef(locationId);
2350
- const requestIdRef = React3.useRef(0);
2351
- const normalizedIdOrSlug = React3.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
2352
- const cacheKey = React3.useMemo(
2353
- () => buildCollectionCacheKey(client, locationId, normalizedIdOrSlug),
2354
- [client, locationId, normalizedIdOrSlug]
2355
- );
2356
- const cached = collectionCache.get(cacheKey);
2357
- const [collection, setCollection] = React3.useState(cached?.collection ?? null);
2358
- const [products, setProducts] = React3.useState(cached?.products ?? []);
2359
- const [isLoading, setIsLoading] = React3.useState(
2360
- enabled && normalizedIdOrSlug.length > 0 && !cached
2361
- );
2362
- const [error, setError] = React3.useState(null);
2363
- React3.useEffect(() => {
2364
- if (previousLocationIdRef.current !== locationId) {
2365
- collectionCache.clear();
2366
- collectionInflight.clear();
2367
- previousLocationIdRef.current = locationId;
2368
- }
2369
- }, [locationId]);
2370
- const load = React3.useCallback(
2371
- async (force = false) => {
2372
- if (!enabled || normalizedIdOrSlug.length === 0) {
2373
- setCollection(null);
2374
- setProducts([]);
2375
- setIsLoading(false);
2376
- return;
2377
- }
2378
- const nextRequestId = ++requestIdRef.current;
2379
- setError(null);
2380
- if (!force) {
2381
- const cacheEntry = collectionCache.get(cacheKey);
2382
- if (cacheEntry) {
2383
- setCollection(cacheEntry.collection);
2384
- setProducts(cacheEntry.products);
2385
- setIsLoading(false);
2386
- return;
2387
- }
2388
- }
2389
- setIsLoading(true);
2390
- try {
2391
- const existing = collectionInflight.get(cacheKey);
2392
- const promise = existing ?? (async () => {
2393
- const collectionResult = isLikelySlug2(normalizedIdOrSlug) ? await client.catalogue.getCollectionBySlug(normalizedIdOrSlug) : await client.catalogue.getCollection(normalizedIdOrSlug);
2394
- if (!collectionResult.ok) {
2395
- throw collectionResult.error;
2396
- }
2397
- const productsResult = await client.catalogue.getCollectionProducts(
2398
- collectionResult.value.id
2399
- );
2400
- if (!productsResult.ok) {
2401
- throw productsResult.error;
2402
- }
2403
- return {
2404
- collection: collectionResult.value,
2405
- products: productsResult.value
2406
- };
2407
- })();
2408
- if (!existing) {
2409
- collectionInflight.set(cacheKey, promise);
2410
- promise.finally(() => {
2411
- collectionInflight.delete(cacheKey);
2412
- }).catch(() => void 0);
2413
- }
2414
- const value = await promise;
2415
- collectionCache.set(cacheKey, value);
2416
- if (nextRequestId === requestIdRef.current) {
2417
- setCollection(value.collection);
2418
- setProducts(value.products);
2419
- setError(null);
2420
- }
2421
- } catch (loadError) {
2422
- if (nextRequestId === requestIdRef.current) {
2423
- setError(loadError);
2424
- }
2425
- } finally {
2426
- if (nextRequestId === requestIdRef.current) {
2427
- setIsLoading(false);
2428
- }
2429
- }
2430
- },
2431
- [cacheKey, client, enabled, normalizedIdOrSlug]
2432
- );
2433
- React3.useEffect(() => {
2434
- void load(false);
2435
- }, [load]);
2436
- const refetch = React3.useCallback(async () => {
2437
- collectionCache.delete(cacheKey);
2438
- await load(true);
2439
- }, [cacheKey, load]);
2440
- return { collection, products, isLoading, error, refetch };
2441
- }
2442
- function useSearch(options = {}) {
2443
- const context = useOptionalCimplifyClient();
2444
- const client = options.client ?? context?.client;
2445
- if (!client) {
2446
- throw new Error("useSearch must be used within CimplifyProvider or passed { client }.");
2157
+ throw new Error("useSearch must be used within CimplifyProvider or passed { client }.");
2447
2158
  }
2448
2159
  const minLength = Math.max(0, options.minLength ?? 2);
2449
2160
  const debounceMs = Math.max(0, options.debounceMs ?? 300);
@@ -2614,11 +2325,11 @@ function useQuote(input, options = {}) {
2614
2325
  const normalized = normalizeInput(input, locationId);
2615
2326
  return normalized.product_id.length > 0 ? normalized : null;
2616
2327
  }, [inputSignature, locationId]);
2617
- const cacheKey = React3.useMemo(
2328
+ const cacheKey2 = React3.useMemo(
2618
2329
  () => buildQuoteCacheKey(client, locationId, inputSignature),
2619
2330
  [client, inputSignature, locationId]
2620
2331
  );
2621
- const cached = quoteCache.get(cacheKey);
2332
+ const cached = quoteCache.get(cacheKey2);
2622
2333
  const [quote, setQuote] = React3.useState(cached?.quote ?? null);
2623
2334
  const [isLoading, setIsLoading] = React3.useState(enabled && normalizedInput !== null && !cached);
2624
2335
  const [error, setError] = React3.useState(null);
@@ -2644,7 +2355,7 @@ function useQuote(input, options = {}) {
2644
2355
  const nextRequestId = ++requestIdRef.current;
2645
2356
  setError(null);
2646
2357
  if (!force) {
2647
- const cacheEntry = quoteCache.get(cacheKey);
2358
+ const cacheEntry = quoteCache.get(cacheKey2);
2648
2359
  if (cacheEntry) {
2649
2360
  setQuote(cacheEntry.quote);
2650
2361
  setMessages(cacheEntry.quote?.ui_messages ?? []);
@@ -2657,7 +2368,7 @@ function useQuote(input, options = {}) {
2657
2368
  setQuote(null);
2658
2369
  setMessages([]);
2659
2370
  try {
2660
- const existing = quoteInflight.get(cacheKey);
2371
+ const existing = quoteInflight.get(cacheKey2);
2661
2372
  const promise = existing ?? (async () => {
2662
2373
  const result = await client.catalogue.fetchQuote(normalizedInput);
2663
2374
  if (!result.ok) {
@@ -2666,13 +2377,13 @@ function useQuote(input, options = {}) {
2666
2377
  return result.value;
2667
2378
  })();
2668
2379
  if (!existing) {
2669
- quoteInflight.set(cacheKey, promise);
2380
+ quoteInflight.set(cacheKey2, promise);
2670
2381
  promise.finally(() => {
2671
- quoteInflight.delete(cacheKey);
2382
+ quoteInflight.delete(cacheKey2);
2672
2383
  }).catch(() => void 0);
2673
2384
  }
2674
2385
  const value = await promise;
2675
- quoteCache.set(cacheKey, { quote: value });
2386
+ quoteCache.set(cacheKey2, { quote: value });
2676
2387
  if (nextRequestId === requestIdRef.current) {
2677
2388
  setQuote(value);
2678
2389
  setMessages(value.ui_messages ?? []);
@@ -2689,13 +2400,13 @@ function useQuote(input, options = {}) {
2689
2400
  }
2690
2401
  }
2691
2402
  },
2692
- [cacheKey, client, enabled, normalizedInput]
2403
+ [cacheKey2, client, enabled, normalizedInput]
2693
2404
  );
2694
2405
  React3.useEffect(() => {
2695
2406
  if (debounceTimerRef.current) {
2696
2407
  clearTimeout(debounceTimerRef.current);
2697
2408
  }
2698
- const hasCached = quoteCache.has(cacheKey);
2409
+ const hasCached = quoteCache.has(cacheKey2);
2699
2410
  if (hasCached || !enabled || !normalizedInput) {
2700
2411
  void load(false);
2701
2412
  } else {
@@ -2709,7 +2420,7 @@ function useQuote(input, options = {}) {
2709
2420
  debounceTimerRef.current = null;
2710
2421
  }
2711
2422
  };
2712
- }, [load, cacheKey, enabled, normalizedInput]);
2423
+ }, [load, cacheKey2, enabled, normalizedInput]);
2713
2424
  const refresh = React3.useCallback(async () => {
2714
2425
  if (!enabled || !normalizedInput) {
2715
2426
  return;
@@ -2730,7 +2441,7 @@ function useQuote(input, options = {}) {
2730
2441
  throw result.error;
2731
2442
  }
2732
2443
  const refreshed = result.value.quote;
2733
- quoteCache.set(cacheKey, { quote: refreshed });
2444
+ quoteCache.set(cacheKey2, { quote: refreshed });
2734
2445
  if (nextRequestId === requestIdRef.current) {
2735
2446
  setQuote(refreshed);
2736
2447
  setMessages(refreshed.ui_messages ?? []);
@@ -2746,7 +2457,7 @@ function useQuote(input, options = {}) {
2746
2457
  setIsLoading(false);
2747
2458
  }
2748
2459
  }
2749
- }, [cacheKey, client, enabled, load, normalizedInput, quote]);
2460
+ }, [cacheKey2, client, enabled, load, normalizedInput, quote]);
2750
2461
  React3.useEffect(() => {
2751
2462
  if (!Number.isFinite(quoteExpiryTimestamp)) {
2752
2463
  setIsExpired(false);
@@ -2778,1930 +2489,628 @@ function useQuote(input, options = {}) {
2778
2489
  }, [autoRefresh, enabled, quoteExpiryTimestamp, refresh, refreshBeforeExpiryMs]);
2779
2490
  return { quote, isLoading, error, refresh, isExpired, messages };
2780
2491
  }
2781
- var taxonomiesCache = /* @__PURE__ */ new Map();
2782
- var taxonomiesInflight = /* @__PURE__ */ new Map();
2783
- function buildTaxonomiesCacheKey(client, parentId) {
2784
- return JSON.stringify({
2785
- key: client.getPublicKey(),
2786
- parent_id: parentId || "__root__"
2787
- });
2788
- }
2492
+
2493
+ // src/react/hooks/use-taxonomies.ts
2494
+ var taxonomiesQuery = createCachedQuery({
2495
+ name: "useTaxonomies",
2496
+ key: (client, options) => cacheKey(client.getPublicKey(), options.parentId ?? "__root__"),
2497
+ fetch: async (client, options) => {
2498
+ const result = await client.catalogue.getTaxonomies(options.parentId);
2499
+ if (!result.ok) throw result.error;
2500
+ return result.value;
2501
+ }
2502
+ });
2789
2503
  function useTaxonomies(options = {}) {
2504
+ const { data, isLoading, error, refetch } = taxonomiesQuery(options);
2505
+ return { taxonomies: data ?? [], isLoading, error, refetch };
2506
+ }
2507
+
2508
+ // src/react/hooks/use-taxonomy.ts
2509
+ var taxonomyQuery = createCachedQuery({
2510
+ name: "useTaxonomy",
2511
+ key: (client, options) => cacheKey(client.getPublicKey(), options.id),
2512
+ fetch: async (client, options) => {
2513
+ const result = await client.catalogue.getTaxonomy(options.id);
2514
+ if (!result.ok) throw result.error;
2515
+ client.activity.trackCategoryView(result.value.id, {
2516
+ categoryName: result.value.name
2517
+ });
2518
+ return result.value;
2519
+ }
2520
+ });
2521
+ function useTaxonomy(id, options = {}) {
2522
+ const { data, isLoading, error, refetch } = taxonomyQuery({ ...options, id });
2523
+ return { taxonomy: data, isLoading, error, refetch };
2524
+ }
2525
+
2526
+ // src/react/hooks/use-taxonomy-path.ts
2527
+ var taxonomyPathQuery = createCachedQuery({
2528
+ name: "useTaxonomyPath",
2529
+ key: (client, options) => cacheKey(client.getPublicKey(), options.id),
2530
+ fetch: async (client, options) => {
2531
+ const result = await client.catalogue.getTaxonomyPath(options.id);
2532
+ if (!result.ok) throw result.error;
2533
+ return result.value;
2534
+ }
2535
+ });
2536
+ function useTaxonomyPath(id, options = {}) {
2537
+ const { data, isLoading, error, refetch } = taxonomyPathQuery({ ...options, id });
2538
+ return { path: data ?? [], isLoading, error, refetch };
2539
+ }
2540
+
2541
+ // src/react/hooks/use-product-schedules.ts
2542
+ var productSchedulesQuery = createCachedQuery({
2543
+ name: "useProductSchedules",
2544
+ key: (client, options) => cacheKey(client.getPublicKey(), options.productId),
2545
+ fetch: async (client, options) => {
2546
+ const result = await client.catalogue.getProductSchedules(options.productId);
2547
+ if (!result.ok) throw result.error;
2548
+ return result.value;
2549
+ }
2550
+ });
2551
+ function useProductSchedules(productId, options = {}) {
2552
+ const { data, isLoading, error, refetch } = productSchedulesQuery({ ...options, productId });
2553
+ return { schedules: data ?? [], isLoading, error, refetch };
2554
+ }
2555
+
2556
+ // src/react/hooks/use-product-availability.ts
2557
+ var productAvailabilityQuery = createCachedQuery({
2558
+ name: "useProductAvailability",
2559
+ locationSensitive: true,
2560
+ key: (client, options) => {
2561
+ const locationId = options.locationId ?? client.getLocationId();
2562
+ return cacheKey(client.getPublicKey(), options.productId, locationId);
2563
+ },
2564
+ fetch: async (client, options) => {
2565
+ const locationId = options.locationId ?? client.getLocationId();
2566
+ if (!locationId) return null;
2567
+ const result = await client.catalogue.checkProductAvailableNow(options.productId, locationId);
2568
+ if (!result.ok) throw result.error;
2569
+ return result.value;
2570
+ }
2571
+ });
2572
+ function useProductAvailability(productId, options = {}) {
2573
+ const { data, isLoading, error, refetch } = productAvailabilityQuery({ ...options, productId });
2574
+ return {
2575
+ isAvailable: data?.is_available ?? null,
2576
+ schedulesToday: data?.schedules_today ?? [],
2577
+ isLoading,
2578
+ error,
2579
+ refetch
2580
+ };
2581
+ }
2582
+
2583
+ // src/react/hooks/use-deals.ts
2584
+ function resolveLocationId(client, options) {
2585
+ return options.locationId ?? client.getLocationId() ?? void 0;
2586
+ }
2587
+ var dealsQuery = createCachedQuery({
2588
+ name: "useDeals",
2589
+ locationSensitive: true,
2590
+ key: (client, options) => cacheKey(client.getPublicKey(), resolveLocationId(client, options)),
2591
+ fetch: async (client, options) => {
2592
+ const result = await client.catalogue.getDeals(resolveLocationId(client, options));
2593
+ if (!result.ok) throw result.error;
2594
+ return result.value;
2595
+ }
2596
+ });
2597
+ function useDeals(options = {}) {
2598
+ const { data, isLoading, error, refetch } = dealsQuery(options);
2599
+ return { deals: data ?? [], isLoading, error, refetch };
2600
+ }
2601
+
2602
+ // src/react/hooks/use-products-on-sale.ts
2603
+ var productsOnSaleQuery = createCachedQuery({
2604
+ name: "useProductsOnSale",
2605
+ key: (client) => client.getPublicKey() || "__demo__",
2606
+ fetch: async (client) => {
2607
+ const result = await client.catalogue.getProductsOnSale();
2608
+ if (!result.ok) throw result.error;
2609
+ return result.value;
2610
+ }
2611
+ });
2612
+ function useProductsOnSale(options = {}) {
2613
+ const { data, isLoading, error, refetch } = productsOnSaleQuery(options);
2614
+ return { products: data ?? [], isLoading, error, refetch };
2615
+ }
2616
+
2617
+ // src/react/hooks/use-product-deals.ts
2618
+ var productDealsQuery = createCachedQuery({
2619
+ name: "useProductDeals",
2620
+ key: (client, options) => cacheKey(client.getPublicKey(), options.productId),
2621
+ fetch: async (client, options) => {
2622
+ const result = await client.catalogue.getProductDeals(options.productId);
2623
+ if (!result.ok) throw result.error;
2624
+ return result.value;
2625
+ }
2626
+ });
2627
+ function useProductDeals(productId, options = {}) {
2628
+ const { data, isLoading, error, refetch } = productDealsQuery({ ...options, productId });
2629
+ return { deals: data ?? [], isLoading, error, refetch };
2630
+ }
2631
+ function useValidateDiscount(options = {}) {
2790
2632
  const context = useOptionalCimplifyClient();
2791
2633
  const client = options.client ?? context?.client;
2792
2634
  if (!client) {
2793
- throw new Error("useTaxonomies must be used within CimplifyProvider or passed { client }.");
2635
+ throw new Error("useValidateDiscount must be used within CimplifyProvider or passed { client }.");
2794
2636
  }
2795
- const enabled = options.enabled ?? true;
2796
- const cacheKey = React3.useMemo(
2797
- () => buildTaxonomiesCacheKey(client, options.parentId),
2798
- [client, options.parentId]
2799
- );
2800
- const cached = taxonomiesCache.get(cacheKey);
2801
- const [taxonomies, setTaxonomies] = React3.useState(cached ?? []);
2802
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
2637
+ const [isValidating, setIsValidating] = React3.useState(false);
2803
2638
  const [error, setError] = React3.useState(null);
2804
- const parentId = options.parentId;
2805
- const load = React3.useCallback(
2806
- async (force = false) => {
2807
- if (!enabled) {
2808
- setIsLoading(false);
2809
- return;
2810
- }
2639
+ const validate = React3.useCallback(
2640
+ async (code, orderSubtotal, locationId) => {
2811
2641
  setError(null);
2812
- if (!force) {
2813
- const cachedTaxonomies = taxonomiesCache.get(cacheKey);
2814
- if (cachedTaxonomies) {
2815
- setTaxonomies(cachedTaxonomies);
2816
- setIsLoading(false);
2817
- return;
2818
- }
2819
- }
2820
- setIsLoading(true);
2642
+ setIsValidating(true);
2821
2643
  try {
2822
- const existing = taxonomiesInflight.get(cacheKey);
2823
- const promise = existing ?? (async () => {
2824
- const result = await client.catalogue.getTaxonomies(parentId);
2825
- if (!result.ok) {
2826
- throw result.error;
2827
- }
2828
- return result.value;
2829
- })();
2830
- if (!existing) {
2831
- taxonomiesInflight.set(
2832
- cacheKey,
2833
- promise.finally(() => {
2834
- taxonomiesInflight.delete(cacheKey);
2835
- })
2836
- );
2644
+ const result = await client.catalogue.validateDiscountCode(code, orderSubtotal, locationId);
2645
+ if (!result.ok) {
2646
+ setError(result.error);
2647
+ return null;
2837
2648
  }
2838
- const value = await promise;
2839
- taxonomiesCache.set(cacheKey, value);
2840
- setTaxonomies(value);
2841
- } catch (loadError) {
2842
- setError(loadError);
2649
+ return result.value;
2650
+ } catch (validateError) {
2651
+ setError(validateError);
2652
+ return null;
2843
2653
  } finally {
2844
- setIsLoading(false);
2654
+ setIsValidating(false);
2845
2655
  }
2846
2656
  },
2847
- [cacheKey, client, enabled, parentId]
2657
+ [client]
2848
2658
  );
2849
- React3.useEffect(() => {
2850
- void load(false);
2851
- }, [load]);
2852
- const refetch = React3.useCallback(async () => {
2853
- taxonomiesCache.delete(cacheKey);
2854
- await load(true);
2855
- }, [cacheKey, load]);
2856
- return { taxonomies, isLoading, error, refetch };
2857
- }
2858
- var taxonomyCache = /* @__PURE__ */ new Map();
2859
- var taxonomyInflight = /* @__PURE__ */ new Map();
2860
- function buildTaxonomyCacheKey(client, id) {
2861
- return JSON.stringify({
2862
- key: client.getPublicKey(),
2863
- id
2864
- });
2659
+ return { validate, isValidating, error };
2865
2660
  }
2866
- function useTaxonomy(id, options = {}) {
2867
- const context = useOptionalCimplifyClient();
2868
- const client = options.client ?? context?.client;
2869
- if (!client) {
2870
- throw new Error("useTaxonomy must be used within CimplifyProvider or passed { client }.");
2661
+
2662
+ // src/react/hooks/use-bundles.ts
2663
+ var bundlesQuery = createCachedQuery({
2664
+ name: "useBundles",
2665
+ locationSensitive: true,
2666
+ key: (client) => cacheKey(client.getPublicKey(), client.getLocationId()),
2667
+ fetch: async (client) => {
2668
+ const result = await client.catalogue.getBundles();
2669
+ if (!result.ok) throw result.error;
2670
+ return result.value;
2871
2671
  }
2872
- const enabled = options.enabled ?? true;
2873
- const cacheKey = React3.useMemo(() => buildTaxonomyCacheKey(client, id), [client, id]);
2874
- const cached = taxonomyCache.get(cacheKey);
2875
- const [taxonomy, setTaxonomy] = React3.useState(cached ?? null);
2876
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
2877
- const [error, setError] = React3.useState(null);
2878
- const trackedTaxonomyRef = React3.useRef(null);
2879
- const load = React3.useCallback(
2880
- async (force = false) => {
2881
- if (!enabled) {
2882
- setIsLoading(false);
2883
- return;
2884
- }
2885
- setError(null);
2886
- if (!force) {
2887
- const cachedTaxonomy = taxonomyCache.get(cacheKey);
2888
- if (cachedTaxonomy) {
2889
- setTaxonomy(cachedTaxonomy);
2890
- setIsLoading(false);
2891
- return;
2892
- }
2893
- }
2894
- setIsLoading(true);
2895
- try {
2896
- const existing = taxonomyInflight.get(cacheKey);
2897
- const promise = existing ?? (async () => {
2898
- const result = await client.catalogue.getTaxonomy(id);
2899
- if (!result.ok) {
2900
- throw result.error;
2901
- }
2902
- return result.value;
2903
- })();
2904
- if (!existing) {
2905
- taxonomyInflight.set(
2906
- cacheKey,
2907
- promise.finally(() => {
2908
- taxonomyInflight.delete(cacheKey);
2909
- })
2910
- );
2911
- }
2912
- const value = await promise;
2913
- taxonomyCache.set(cacheKey, value);
2914
- setTaxonomy(value);
2915
- if (value && trackedTaxonomyRef.current !== value.id) {
2916
- trackedTaxonomyRef.current = value.id;
2917
- client.activity.trackCategoryView(value.id, {
2918
- categoryName: value.name
2919
- });
2920
- }
2921
- } catch (loadError) {
2922
- setError(loadError);
2923
- } finally {
2924
- setIsLoading(false);
2925
- }
2926
- },
2927
- [cacheKey, client, enabled, id]
2928
- );
2929
- React3.useEffect(() => {
2930
- void load(false);
2931
- }, [load]);
2932
- const refetch = React3.useCallback(async () => {
2933
- taxonomyCache.delete(cacheKey);
2934
- await load(true);
2935
- }, [cacheKey, load]);
2936
- return { taxonomy, isLoading, error, refetch };
2937
- }
2938
- var taxonomyPathCache = /* @__PURE__ */ new Map();
2939
- var taxonomyPathInflight = /* @__PURE__ */ new Map();
2940
- function buildTaxonomyPathCacheKey(client, id) {
2941
- return JSON.stringify({
2942
- key: client.getPublicKey(),
2943
- id
2944
- });
2945
- }
2946
- function useTaxonomyPath(id, options = {}) {
2947
- const context = useOptionalCimplifyClient();
2948
- const client = options.client ?? context?.client;
2949
- if (!client) {
2950
- throw new Error("useTaxonomyPath must be used within CimplifyProvider or passed { client }.");
2951
- }
2952
- const enabled = options.enabled ?? true;
2953
- const cacheKey = React3.useMemo(() => buildTaxonomyPathCacheKey(client, id), [client, id]);
2954
- const cached = taxonomyPathCache.get(cacheKey);
2955
- const [path, setPath] = React3.useState(cached ?? []);
2956
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
2957
- const [error, setError] = React3.useState(null);
2958
- const load = React3.useCallback(
2959
- async (force = false) => {
2960
- if (!enabled) {
2961
- setIsLoading(false);
2962
- return;
2963
- }
2964
- setError(null);
2965
- if (!force) {
2966
- const cachedPath = taxonomyPathCache.get(cacheKey);
2967
- if (cachedPath) {
2968
- setPath(cachedPath);
2969
- setIsLoading(false);
2970
- return;
2971
- }
2972
- }
2973
- setIsLoading(true);
2974
- try {
2975
- const existing = taxonomyPathInflight.get(cacheKey);
2976
- const promise = existing ?? (async () => {
2977
- const result = await client.catalogue.getTaxonomyPath(id);
2978
- if (!result.ok) {
2979
- throw result.error;
2980
- }
2981
- return result.value;
2982
- })();
2983
- if (!existing) {
2984
- taxonomyPathInflight.set(
2985
- cacheKey,
2986
- promise.finally(() => {
2987
- taxonomyPathInflight.delete(cacheKey);
2988
- })
2989
- );
2990
- }
2991
- const value = await promise;
2992
- taxonomyPathCache.set(cacheKey, value);
2993
- setPath(value);
2994
- } catch (loadError) {
2995
- setError(loadError);
2996
- } finally {
2997
- setIsLoading(false);
2998
- }
2999
- },
3000
- [cacheKey, client, enabled, id]
3001
- );
3002
- React3.useEffect(() => {
3003
- void load(false);
3004
- }, [load]);
3005
- const refetch = React3.useCallback(async () => {
3006
- taxonomyPathCache.delete(cacheKey);
3007
- await load(true);
3008
- }, [cacheKey, load]);
3009
- return { path, isLoading, error, refetch };
3010
- }
3011
- var schedulesCache = /* @__PURE__ */ new Map();
3012
- var schedulesInflight = /* @__PURE__ */ new Map();
3013
- function buildSchedulesCacheKey(client, productId) {
3014
- return JSON.stringify({
3015
- key: client.getPublicKey(),
3016
- product_id: productId
3017
- });
3018
- }
3019
- function useProductSchedules(productId, options = {}) {
3020
- const context = useOptionalCimplifyClient();
3021
- const client = options.client ?? context?.client;
3022
- if (!client) {
3023
- throw new Error("useProductSchedules must be used within CimplifyProvider or passed { client }.");
3024
- }
3025
- const enabled = options.enabled ?? true;
3026
- const cacheKey = React3.useMemo(() => buildSchedulesCacheKey(client, productId), [client, productId]);
3027
- const cached = schedulesCache.get(cacheKey);
3028
- const [schedules, setSchedules] = React3.useState(cached ?? []);
3029
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3030
- const [error, setError] = React3.useState(null);
3031
- const load = React3.useCallback(
3032
- async (force = false) => {
3033
- if (!enabled) {
3034
- setIsLoading(false);
3035
- return;
3036
- }
3037
- setError(null);
3038
- if (!force) {
3039
- const cachedSchedules = schedulesCache.get(cacheKey);
3040
- if (cachedSchedules) {
3041
- setSchedules(cachedSchedules);
3042
- setIsLoading(false);
3043
- return;
3044
- }
3045
- }
3046
- setIsLoading(true);
3047
- try {
3048
- const existing = schedulesInflight.get(cacheKey);
3049
- const promise = existing ?? (async () => {
3050
- const result = await client.catalogue.getProductSchedules(productId);
3051
- if (!result.ok) {
3052
- throw result.error;
3053
- }
3054
- return result.value;
3055
- })();
3056
- if (!existing) {
3057
- schedulesInflight.set(
3058
- cacheKey,
3059
- promise.finally(() => {
3060
- schedulesInflight.delete(cacheKey);
3061
- })
3062
- );
3063
- }
3064
- const value = await promise;
3065
- schedulesCache.set(cacheKey, value);
3066
- setSchedules(value);
3067
- } catch (loadError) {
3068
- setError(loadError);
3069
- } finally {
3070
- setIsLoading(false);
3071
- }
3072
- },
3073
- [cacheKey, client, enabled, productId]
3074
- );
3075
- React3.useEffect(() => {
3076
- void load(false);
3077
- }, [load]);
3078
- const refetch = React3.useCallback(async () => {
3079
- schedulesCache.delete(cacheKey);
3080
- await load(true);
3081
- }, [cacheKey, load]);
3082
- return { schedules, isLoading, error, refetch };
3083
- }
3084
- var availabilityCache = /* @__PURE__ */ new Map();
3085
- var availabilityInflight = /* @__PURE__ */ new Map();
3086
- function buildAvailabilityCacheKey(client, productId, locationId) {
3087
- return JSON.stringify({
3088
- key: client.getPublicKey(),
3089
- product_id: productId,
3090
- location_id: locationId
3091
- });
3092
- }
3093
- function useProductAvailability(productId, options = {}) {
3094
- const context = useOptionalCimplifyClient();
3095
- const client = options.client ?? context?.client;
3096
- if (!client) {
3097
- throw new Error("useProductAvailability must be used within CimplifyProvider or passed { client }.");
3098
- }
3099
- const enabled = options.enabled ?? true;
3100
- const locationId = options.locationId ?? client.getLocationId();
3101
- const previousLocationIdRef = React3.useRef(locationId);
3102
- const cacheKey = React3.useMemo(
3103
- () => locationId ? buildAvailabilityCacheKey(client, productId, locationId) : null,
3104
- [client, productId, locationId]
3105
- );
3106
- const cached = cacheKey ? availabilityCache.get(cacheKey) : void 0;
3107
- const [isAvailable, setIsAvailable] = React3.useState(cached?.is_available ?? null);
3108
- const [schedulesToday, setSchedulesToday] = React3.useState(
3109
- cached?.schedules_today ?? []
3110
- );
3111
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached && !!locationId);
3112
- const [error, setError] = React3.useState(null);
3113
- React3.useEffect(() => {
3114
- if (previousLocationIdRef.current !== locationId) {
3115
- availabilityCache.clear();
3116
- availabilityInflight.clear();
3117
- previousLocationIdRef.current = locationId;
3118
- }
3119
- }, [locationId]);
3120
- const load = React3.useCallback(
3121
- async (force = false) => {
3122
- if (!enabled || !locationId || !cacheKey) {
3123
- setIsLoading(false);
3124
- return;
3125
- }
3126
- setError(null);
3127
- if (!force) {
3128
- const cachedAvailability = availabilityCache.get(cacheKey);
3129
- if (cachedAvailability) {
3130
- setIsAvailable(cachedAvailability.is_available);
3131
- setSchedulesToday(cachedAvailability.schedules_today);
3132
- setIsLoading(false);
3133
- return;
3134
- }
3135
- }
3136
- setIsLoading(true);
3137
- try {
3138
- const existing = availabilityInflight.get(cacheKey);
3139
- const promise = existing ?? (async () => {
3140
- const result = await client.catalogue.checkProductAvailableNow(productId, locationId);
3141
- if (!result.ok) {
3142
- throw result.error;
3143
- }
3144
- return result.value;
3145
- })();
3146
- if (!existing) {
3147
- availabilityInflight.set(
3148
- cacheKey,
3149
- promise.finally(() => {
3150
- availabilityInflight.delete(cacheKey);
3151
- })
3152
- );
3153
- }
3154
- const value = await promise;
3155
- availabilityCache.set(cacheKey, value);
3156
- setIsAvailable(value.is_available);
3157
- setSchedulesToday(value.schedules_today);
3158
- } catch (loadError) {
3159
- setError(loadError);
3160
- } finally {
3161
- setIsLoading(false);
3162
- }
3163
- },
3164
- [cacheKey, client, enabled, locationId, productId]
3165
- );
3166
- React3.useEffect(() => {
3167
- void load(false);
3168
- }, [load]);
3169
- const refetch = React3.useCallback(async () => {
3170
- if (cacheKey) {
3171
- availabilityCache.delete(cacheKey);
3172
- }
3173
- await load(true);
3174
- }, [cacheKey, load]);
3175
- return { isAvailable, schedulesToday, isLoading, error, refetch };
3176
- }
3177
- var dealsCache = /* @__PURE__ */ new Map();
3178
- var dealsInflight = /* @__PURE__ */ new Map();
3179
- function buildDealsCacheKey(client, locationId) {
3180
- return JSON.stringify({ key: client.getPublicKey(), location_id: locationId });
3181
- }
3182
- function useDeals(options = {}) {
3183
- const context = useOptionalCimplifyClient();
3184
- const client = options.client ?? context?.client;
3185
- if (!client) {
3186
- throw new Error("useDeals must be used within CimplifyProvider or passed { client }.");
3187
- }
3188
- const enabled = options.enabled ?? true;
3189
- const locationId = options.locationId ?? client.getLocationId() ?? void 0;
3190
- const previousLocationIdRef = React3.useRef(locationId);
3191
- const cacheKey = React3.useMemo(() => buildDealsCacheKey(client, locationId), [client, locationId]);
3192
- const cached = dealsCache.get(cacheKey);
3193
- const [deals, setDeals] = React3.useState(cached ?? []);
3194
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3195
- const [error, setError] = React3.useState(null);
3196
- React3.useEffect(() => {
3197
- if (previousLocationIdRef.current !== locationId) {
3198
- dealsCache.clear();
3199
- dealsInflight.clear();
3200
- previousLocationIdRef.current = locationId;
3201
- }
3202
- }, [locationId]);
3203
- const load = React3.useCallback(
3204
- async (force = false) => {
3205
- if (!enabled) {
3206
- setIsLoading(false);
3207
- return;
3208
- }
3209
- setError(null);
3210
- if (!force) {
3211
- const cachedDeals = dealsCache.get(cacheKey);
3212
- if (cachedDeals) {
3213
- setDeals(cachedDeals);
3214
- setIsLoading(false);
3215
- return;
3216
- }
3217
- }
3218
- setIsLoading(true);
3219
- try {
3220
- const existing = dealsInflight.get(cacheKey);
3221
- const promise = existing ?? (async () => {
3222
- const result = await client.catalogue.getDeals(locationId);
3223
- if (!result.ok) {
3224
- throw result.error;
3225
- }
3226
- return result.value;
3227
- })();
3228
- if (!existing) {
3229
- dealsInflight.set(
3230
- cacheKey,
3231
- promise.finally(() => {
3232
- dealsInflight.delete(cacheKey);
3233
- })
3234
- );
3235
- }
3236
- const value = await promise;
3237
- dealsCache.set(cacheKey, value);
3238
- setDeals(value);
3239
- } catch (loadError) {
3240
- setError(loadError);
3241
- } finally {
3242
- setIsLoading(false);
3243
- }
3244
- },
3245
- [cacheKey, client, enabled, locationId]
3246
- );
3247
- React3.useEffect(() => {
3248
- void load(false);
3249
- }, [load]);
3250
- const refetch = React3.useCallback(async () => {
3251
- dealsCache.delete(cacheKey);
3252
- await load(true);
3253
- }, [cacheKey, load]);
3254
- return { deals, isLoading, error, refetch };
3255
- }
3256
- var onSaleCache = /* @__PURE__ */ new Map();
3257
- var onSaleInflight = /* @__PURE__ */ new Map();
3258
- function buildOnSaleCacheKey(client) {
3259
- return client.getPublicKey() || "__demo__";
3260
- }
3261
- function useProductsOnSale(options = {}) {
3262
- const context = useOptionalCimplifyClient();
3263
- const client = options.client ?? context?.client;
3264
- if (!client) {
3265
- throw new Error("useProductsOnSale must be used within CimplifyProvider or passed { client }.");
3266
- }
3267
- const enabled = options.enabled ?? true;
3268
- const cacheKey = React3.useMemo(() => buildOnSaleCacheKey(client), [client]);
3269
- const cached = onSaleCache.get(cacheKey);
3270
- const [products, setProducts] = React3.useState(cached ?? []);
3271
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3272
- const [error, setError] = React3.useState(null);
3273
- const load = React3.useCallback(
3274
- async (force = false) => {
3275
- if (!enabled) {
3276
- setIsLoading(false);
3277
- return;
3278
- }
3279
- setError(null);
3280
- if (!force) {
3281
- const cachedProducts = onSaleCache.get(cacheKey);
3282
- if (cachedProducts) {
3283
- setProducts(cachedProducts);
3284
- setIsLoading(false);
3285
- return;
3286
- }
3287
- }
3288
- setIsLoading(true);
3289
- try {
3290
- const existing = onSaleInflight.get(cacheKey);
3291
- const promise = existing ?? (async () => {
3292
- const result = await client.catalogue.getProductsOnSale();
3293
- if (!result.ok) {
3294
- throw result.error;
3295
- }
3296
- return result.value;
3297
- })();
3298
- if (!existing) {
3299
- onSaleInflight.set(
3300
- cacheKey,
3301
- promise.finally(() => {
3302
- onSaleInflight.delete(cacheKey);
3303
- })
3304
- );
3305
- }
3306
- const value = await promise;
3307
- onSaleCache.set(cacheKey, value);
3308
- setProducts(value);
3309
- } catch (loadError) {
3310
- setError(loadError);
3311
- } finally {
3312
- setIsLoading(false);
3313
- }
3314
- },
3315
- [cacheKey, client, enabled]
3316
- );
3317
- React3.useEffect(() => {
3318
- void load(false);
3319
- }, [load]);
3320
- const refetch = React3.useCallback(async () => {
3321
- onSaleCache.delete(cacheKey);
3322
- await load(true);
3323
- }, [cacheKey, load]);
3324
- return { products, isLoading, error, refetch };
3325
- }
3326
- var productDealsCache = /* @__PURE__ */ new Map();
3327
- var productDealsInflight = /* @__PURE__ */ new Map();
3328
- function buildProductDealsCacheKey(client, productId) {
3329
- return JSON.stringify({ key: client.getPublicKey(), product_id: productId });
3330
- }
3331
- function useProductDeals(productId, options = {}) {
3332
- const context = useOptionalCimplifyClient();
3333
- const client = options.client ?? context?.client;
3334
- if (!client) {
3335
- throw new Error("useProductDeals must be used within CimplifyProvider or passed { client }.");
3336
- }
3337
- const enabled = options.enabled ?? true;
3338
- const cacheKey = React3.useMemo(
3339
- () => buildProductDealsCacheKey(client, productId),
3340
- [client, productId]
3341
- );
3342
- const cached = productDealsCache.get(cacheKey);
3343
- const [deals, setDeals] = React3.useState(cached ?? []);
3344
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3345
- const [error, setError] = React3.useState(null);
3346
- const load = React3.useCallback(
3347
- async (force = false) => {
3348
- if (!enabled) {
3349
- setIsLoading(false);
3350
- return;
3351
- }
3352
- setError(null);
3353
- if (!force) {
3354
- const cachedDeals = productDealsCache.get(cacheKey);
3355
- if (cachedDeals) {
3356
- setDeals(cachedDeals);
3357
- setIsLoading(false);
3358
- return;
3359
- }
3360
- }
3361
- setIsLoading(true);
3362
- try {
3363
- const existing = productDealsInflight.get(cacheKey);
3364
- const promise = existing ?? (async () => {
3365
- const result = await client.catalogue.getProductDeals(productId);
3366
- if (!result.ok) {
3367
- throw result.error;
3368
- }
3369
- return result.value;
3370
- })();
3371
- if (!existing) {
3372
- productDealsInflight.set(
3373
- cacheKey,
3374
- promise.finally(() => {
3375
- productDealsInflight.delete(cacheKey);
3376
- })
3377
- );
3378
- }
3379
- const value = await promise;
3380
- productDealsCache.set(cacheKey, value);
3381
- setDeals(value);
3382
- } catch (loadError) {
3383
- setError(loadError);
3384
- } finally {
3385
- setIsLoading(false);
3386
- }
3387
- },
3388
- [cacheKey, client, enabled, productId]
3389
- );
3390
- React3.useEffect(() => {
3391
- void load(false);
3392
- }, [load]);
3393
- const refetch = React3.useCallback(async () => {
3394
- productDealsCache.delete(cacheKey);
3395
- await load(true);
3396
- }, [cacheKey, load]);
3397
- return { deals, isLoading, error, refetch };
3398
- }
3399
- function useValidateDiscount(options = {}) {
3400
- const context = useOptionalCimplifyClient();
3401
- const client = options.client ?? context?.client;
3402
- if (!client) {
3403
- throw new Error("useValidateDiscount must be used within CimplifyProvider or passed { client }.");
3404
- }
3405
- const [isValidating, setIsValidating] = React3.useState(false);
3406
- const [error, setError] = React3.useState(null);
3407
- const validate = React3.useCallback(
3408
- async (code, orderSubtotal, locationId) => {
3409
- setError(null);
3410
- setIsValidating(true);
3411
- try {
3412
- const result = await client.catalogue.validateDiscountCode(code, orderSubtotal, locationId);
3413
- if (!result.ok) {
3414
- setError(result.error);
3415
- return null;
3416
- }
3417
- return result.value;
3418
- } catch (validateError) {
3419
- setError(validateError);
3420
- return null;
3421
- } finally {
3422
- setIsValidating(false);
3423
- }
3424
- },
3425
- [client]
3426
- );
3427
- return { validate, isValidating, error };
3428
- }
3429
- var bundlesCache = /* @__PURE__ */ new Map();
3430
- var bundlesInflight = /* @__PURE__ */ new Map();
3431
- function buildBundlesCacheKey(client, locationId) {
3432
- return JSON.stringify({
3433
- key: client.getPublicKey(),
3434
- location_id: locationId || "__none__"
3435
- });
3436
- }
3437
- function useBundles(options = {}) {
3438
- const context = useOptionalCimplifyClient();
3439
- const client = options.client ?? context?.client;
3440
- if (!client) {
3441
- throw new Error("useBundles must be used within CimplifyProvider or passed { client }.");
3442
- }
3443
- const enabled = options.enabled ?? true;
3444
- const locationId = client.getLocationId();
3445
- const previousLocationIdRef = React3.useRef(locationId);
3446
- const requestIdRef = React3.useRef(0);
3447
- const cacheKey = React3.useMemo(
3448
- () => buildBundlesCacheKey(client, locationId),
3449
- [client, locationId]
3450
- );
3451
- const cached = bundlesCache.get(cacheKey);
3452
- const [bundles, setBundles] = React3.useState(cached?.bundles ?? []);
3453
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3454
- const [error, setError] = React3.useState(null);
3455
- React3.useEffect(() => {
3456
- if (previousLocationIdRef.current !== locationId) {
3457
- bundlesCache.clear();
3458
- bundlesInflight.clear();
3459
- previousLocationIdRef.current = locationId;
3460
- }
3461
- }, [locationId]);
3462
- const load = React3.useCallback(
3463
- async (force = false) => {
3464
- if (!enabled) {
3465
- setIsLoading(false);
3466
- return;
3467
- }
3468
- const nextRequestId = ++requestIdRef.current;
3469
- setError(null);
3470
- if (!force) {
3471
- const cacheEntry = bundlesCache.get(cacheKey);
3472
- if (cacheEntry) {
3473
- setBundles(cacheEntry.bundles);
3474
- setIsLoading(false);
3475
- return;
3476
- }
3477
- }
3478
- setIsLoading(true);
3479
- try {
3480
- const existing = bundlesInflight.get(cacheKey);
3481
- const promise = existing ?? (async () => {
3482
- const result = await client.catalogue.getBundles();
3483
- if (!result.ok) {
3484
- throw result.error;
3485
- }
3486
- return result.value;
3487
- })();
3488
- if (!existing) {
3489
- bundlesInflight.set(cacheKey, promise);
3490
- promise.finally(() => {
3491
- bundlesInflight.delete(cacheKey);
3492
- }).catch(() => void 0);
3493
- }
3494
- const value = await promise;
3495
- bundlesCache.set(cacheKey, { bundles: value });
3496
- if (nextRequestId === requestIdRef.current) {
3497
- setBundles(value);
3498
- setError(null);
3499
- }
3500
- } catch (loadError) {
3501
- if (nextRequestId === requestIdRef.current) {
3502
- setError(loadError);
3503
- }
3504
- } finally {
3505
- if (nextRequestId === requestIdRef.current) {
3506
- setIsLoading(false);
3507
- }
3508
- }
3509
- },
3510
- [cacheKey, client, enabled]
3511
- );
3512
- React3.useEffect(() => {
3513
- void load(false);
3514
- }, [load]);
3515
- const refetch = React3.useCallback(async () => {
3516
- bundlesCache.delete(cacheKey);
3517
- await load(true);
3518
- }, [cacheKey, load]);
3519
- return { bundles, isLoading, error, refetch };
3520
- }
3521
- function useProductPrice(input) {
3522
- const {
3523
- product,
3524
- quantity = 1,
3525
- variant,
3526
- addOnOptions,
3527
- compositePrice,
3528
- bundleTotalPrice
3529
- } = input;
3530
- return React3.useMemo(() => {
3531
- let unitPrice;
3532
- if (bundleTotalPrice != null) {
3533
- unitPrice = bundleTotalPrice;
3534
- } else if (compositePrice) {
3535
- unitPrice = chunk64OCG2TJ_js.parsePrice(compositePrice.final_price);
3536
- } else {
3537
- unitPrice = chunk64OCG2TJ_js.parsePrice(product.default_price);
3538
- if (variant?.price_adjustment) {
3539
- unitPrice += chunk64OCG2TJ_js.parsePrice(variant.price_adjustment);
3540
- }
3541
- if (addOnOptions) {
3542
- for (const option of addOnOptions) {
3543
- if (option.default_price) {
3544
- unitPrice += chunk64OCG2TJ_js.parsePrice(option.default_price);
3545
- }
3546
- }
3547
- }
3548
- }
3549
- unitPrice = Math.round(unitPrice * 100) / 100;
3550
- const totalPrice = Math.round(unitPrice * quantity * 100) / 100;
3551
- return {
3552
- unitPrice,
3553
- totalPrice,
3554
- displayTotalPrice: totalPrice
3555
- };
3556
- }, [product.default_price, quantity, variant?.price_adjustment, addOnOptions, compositePrice, bundleTotalPrice]);
3557
- }
3558
- var ordersCache = /* @__PURE__ */ new Map();
3559
- var ordersInflight = /* @__PURE__ */ new Map();
3560
- function buildOrdersCacheKey(client, status, limit) {
3561
- return JSON.stringify({ key: client.getPublicKey(), status, limit });
3562
- }
3563
- function useOrders(options = {}) {
3564
- const context = useOptionalCimplifyClient();
3565
- const client = options.client ?? context?.client;
3566
- if (!client) {
3567
- throw new Error("useOrders must be used within CimplifyProvider or passed { client }.");
3568
- }
3569
- const enabled = options.enabled ?? true;
3570
- const requestIdRef = React3.useRef(0);
3571
- const cacheKey = React3.useMemo(
3572
- () => buildOrdersCacheKey(client, options.status, options.limit),
3573
- [client, options.status, options.limit]
3574
- );
3575
- const cached = ordersCache.get(cacheKey);
3576
- const [orders, setOrders] = React3.useState(cached ?? []);
3577
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3578
- const [error, setError] = React3.useState(null);
3579
- const load = React3.useCallback(
3580
- async (force = false) => {
3581
- if (!enabled) {
3582
- setIsLoading(false);
3583
- return;
3584
- }
3585
- const nextRequestId = ++requestIdRef.current;
3586
- setError(null);
3587
- if (!force) {
3588
- const cachedOrders = ordersCache.get(cacheKey);
3589
- if (cachedOrders) {
3590
- setOrders(cachedOrders);
3591
- setIsLoading(false);
3592
- return;
3593
- }
3594
- }
3595
- setIsLoading(true);
3596
- try {
3597
- const existing = ordersInflight.get(cacheKey);
3598
- const promise = existing ?? (async () => {
3599
- const result = await client.orders.list({
3600
- status: options.status,
3601
- limit: options.limit
3602
- });
3603
- if (!result.ok) {
3604
- throw result.error;
3605
- }
3606
- return result.value;
3607
- })();
3608
- if (!existing) {
3609
- ordersInflight.set(
3610
- cacheKey,
3611
- promise.finally(() => {
3612
- ordersInflight.delete(cacheKey);
3613
- })
3614
- );
3615
- }
3616
- const value = await promise;
3617
- ordersCache.set(cacheKey, value);
3618
- if (nextRequestId === requestIdRef.current) {
3619
- setOrders(value);
3620
- setError(null);
3621
- }
3622
- } catch (loadError) {
3623
- if (nextRequestId === requestIdRef.current) {
3624
- setError(loadError);
3625
- }
3626
- } finally {
3627
- if (nextRequestId === requestIdRef.current) {
3628
- setIsLoading(false);
3629
- }
3630
- }
3631
- },
3632
- [cacheKey, client, enabled, options.status, options.limit]
3633
- );
3634
- React3.useEffect(() => {
3635
- void load(false);
3636
- }, [load]);
3637
- const refetch = React3.useCallback(async () => {
3638
- ordersCache.delete(cacheKey);
3639
- await load(true);
3640
- }, [cacheKey, load]);
3641
- return { orders, isLoading, error, refetch };
3642
- }
3643
- var servicesCache = /* @__PURE__ */ new Map();
3644
- var servicesInflight = /* @__PURE__ */ new Map();
3645
- function buildServicesCacheKey(client) {
3646
- return JSON.stringify({ key: client.getPublicKey() });
3647
- }
3648
- function useServices(options = {}) {
3649
- const context = useOptionalCimplifyClient();
3650
- const client = options.client ?? context?.client;
3651
- if (!client) {
3652
- throw new Error("useServices must be used within CimplifyProvider or passed { client }.");
3653
- }
3654
- const enabled = options.enabled ?? true;
3655
- const requestIdRef = React3.useRef(0);
3656
- const cacheKey = React3.useMemo(() => buildServicesCacheKey(client), [client]);
3657
- const cached = servicesCache.get(cacheKey);
3658
- const [services, setServices] = React3.useState(cached ?? []);
3659
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3660
- const [error, setError] = React3.useState(null);
3661
- const load = React3.useCallback(
3662
- async (force = false) => {
3663
- if (!enabled) {
3664
- setIsLoading(false);
3665
- return;
3666
- }
3667
- const nextRequestId = ++requestIdRef.current;
3668
- setError(null);
3669
- if (!force) {
3670
- const cachedServices = servicesCache.get(cacheKey);
3671
- if (cachedServices) {
3672
- setServices(cachedServices);
3673
- setIsLoading(false);
3674
- return;
3675
- }
3676
- }
3677
- setIsLoading(true);
3678
- try {
3679
- const existing = servicesInflight.get(cacheKey);
3680
- const promise = existing ?? (async () => {
3681
- const result = await client.scheduling.getServices();
3682
- if (!result.ok) {
3683
- throw result.error;
3684
- }
3685
- return result.value;
3686
- })();
3687
- if (!existing) {
3688
- servicesInflight.set(
3689
- cacheKey,
3690
- promise.finally(() => {
3691
- servicesInflight.delete(cacheKey);
3692
- })
3693
- );
3694
- }
3695
- const value = await promise;
3696
- servicesCache.set(cacheKey, value);
3697
- if (nextRequestId === requestIdRef.current) {
3698
- setServices(value);
3699
- setError(null);
3700
- }
3701
- } catch (loadError) {
3702
- if (nextRequestId === requestIdRef.current) {
3703
- setError(loadError);
3704
- }
3705
- } finally {
3706
- if (nextRequestId === requestIdRef.current) {
3707
- setIsLoading(false);
3708
- }
3709
- }
3710
- },
3711
- [cacheKey, client, enabled]
3712
- );
3713
- React3.useEffect(() => {
3714
- void load(false);
3715
- }, [load]);
3716
- const refetch = React3.useCallback(async () => {
3717
- servicesCache.delete(cacheKey);
3718
- await load(true);
3719
- }, [cacheKey, load]);
3720
- return { services, isLoading, error, refetch };
3721
- }
3722
- var slotsCache = /* @__PURE__ */ new Map();
3723
- var slotsInflight = /* @__PURE__ */ new Map();
3724
- function buildSlotsCacheKey(client, serviceId, date, participantCount) {
3725
- return JSON.stringify({
3726
- key: client.getPublicKey(),
3727
- serviceId,
3728
- date,
3729
- participantCount
3730
- });
3731
- }
3732
- function useAvailableSlots(serviceId, date, options = {}) {
3733
- const context = useOptionalCimplifyClient();
3734
- const client = options.client ?? context?.client;
3735
- if (!client) {
3736
- throw new Error("useAvailableSlots must be used within CimplifyProvider or passed { client }.");
3737
- }
3738
- const enabled = (options.enabled ?? true) && !!serviceId && !!date;
3739
- const requestIdRef = React3.useRef(0);
3740
- const cacheKey = React3.useMemo(
3741
- () => serviceId && date ? buildSlotsCacheKey(client, serviceId, date, options.participantCount) : null,
3742
- [client, serviceId, date, options.participantCount]
3743
- );
3744
- const cached = cacheKey ? slotsCache.get(cacheKey) : void 0;
3745
- const [slots, setSlots] = React3.useState(cached ?? []);
3746
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3747
- const [error, setError] = React3.useState(null);
3748
- const load = React3.useCallback(
3749
- async (force = false) => {
3750
- if (!enabled || !cacheKey || !serviceId || !date) {
3751
- setIsLoading(false);
3752
- return;
3753
- }
3754
- const nextRequestId = ++requestIdRef.current;
3755
- setError(null);
3756
- if (!force) {
3757
- const cachedSlots = slotsCache.get(cacheKey);
3758
- if (cachedSlots) {
3759
- setSlots(cachedSlots);
3760
- setIsLoading(false);
3761
- return;
3762
- }
3763
- }
3764
- setIsLoading(true);
3765
- try {
3766
- const existing = slotsInflight.get(cacheKey);
3767
- const promise = existing ?? (async () => {
3768
- const result = await client.scheduling.getAvailableSlots({
3769
- service_id: serviceId,
3770
- date,
3771
- participant_count: options.participantCount
3772
- });
3773
- if (!result.ok) {
3774
- throw result.error;
3775
- }
3776
- return result.value;
3777
- })();
3778
- if (!existing) {
3779
- slotsInflight.set(
3780
- cacheKey,
3781
- promise.finally(() => {
3782
- slotsInflight.delete(cacheKey);
3783
- })
3784
- );
3785
- }
3786
- const value = await promise;
3787
- slotsCache.set(cacheKey, value);
3788
- if (nextRequestId === requestIdRef.current) {
3789
- setSlots(value);
3790
- setError(null);
3791
- }
3792
- } catch (loadError) {
3793
- if (nextRequestId === requestIdRef.current) {
3794
- setError(loadError);
3795
- }
3796
- } finally {
3797
- if (nextRequestId === requestIdRef.current) {
3798
- setIsLoading(false);
3799
- }
3800
- }
3801
- },
3802
- [cacheKey, client, enabled, serviceId, date, options.participantCount]
3803
- );
3804
- React3.useEffect(() => {
3805
- void load(false);
3806
- }, [load]);
3807
- const refetch = React3.useCallback(async () => {
3808
- if (cacheKey) {
3809
- slotsCache.delete(cacheKey);
3810
- }
3811
- await load(true);
3812
- }, [cacheKey, load]);
3813
- return { slots, isLoading, error, refetch };
3814
- }
3815
- var availabilityCache2 = /* @__PURE__ */ new Map();
3816
- var availabilityInflight2 = /* @__PURE__ */ new Map();
3817
- function buildAvailabilityCacheKey2(client, serviceId, startDate, endDate, participantCount) {
3818
- return JSON.stringify({
3819
- key: client.getPublicKey(),
3820
- serviceId,
3821
- startDate,
3822
- endDate,
3823
- participantCount
3824
- });
3825
- }
3826
- function useServiceAvailability(serviceId, startDate, endDate, options = {}) {
3827
- const context = useOptionalCimplifyClient();
3828
- const client = options.client ?? context?.client;
3829
- if (!client) {
3830
- throw new Error(
3831
- "useServiceAvailability must be used within CimplifyProvider or passed { client }."
3832
- );
3833
- }
3834
- const enabled = (options.enabled ?? true) && !!serviceId && !!startDate && !!endDate;
3835
- const requestIdRef = React3.useRef(0);
3836
- const cacheKey = React3.useMemo(
3837
- () => serviceId && startDate && endDate ? buildAvailabilityCacheKey2(
3838
- client,
3839
- serviceId,
3840
- startDate,
3841
- endDate,
3842
- options.participantCount
3843
- ) : null,
3844
- [client, serviceId, startDate, endDate, options.participantCount]
3845
- );
3846
- const cached = cacheKey ? availabilityCache2.get(cacheKey) : void 0;
3847
- const [days, setDays] = React3.useState(cached ?? []);
3848
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3849
- const [error, setError] = React3.useState(null);
3850
- const load = React3.useCallback(
3851
- async (force = false) => {
3852
- if (!enabled || !cacheKey || !serviceId || !startDate || !endDate) {
3853
- setIsLoading(false);
3854
- return;
3855
- }
3856
- const nextRequestId = ++requestIdRef.current;
3857
- setError(null);
3858
- if (!force) {
3859
- const cachedDays = availabilityCache2.get(cacheKey);
3860
- if (cachedDays) {
3861
- setDays(cachedDays);
3862
- setIsLoading(false);
3863
- return;
3864
- }
3865
- }
3866
- setIsLoading(true);
3867
- try {
3868
- const existing = availabilityInflight2.get(cacheKey);
3869
- const promise = existing ?? (async () => {
3870
- const result = await client.scheduling.getServiceAvailability({
3871
- service_id: serviceId,
3872
- start_date: startDate,
3873
- end_date: endDate,
3874
- location_id: options.locationId,
3875
- participant_count: options.participantCount
3876
- });
3877
- if (!result.ok) {
3878
- throw result.error;
3879
- }
3880
- return result.value.availability;
3881
- })();
3882
- if (!existing) {
3883
- availabilityInflight2.set(
3884
- cacheKey,
3885
- promise.finally(() => {
3886
- availabilityInflight2.delete(cacheKey);
3887
- })
3888
- );
3889
- }
3890
- const value = await promise;
3891
- availabilityCache2.set(cacheKey, value);
3892
- if (nextRequestId === requestIdRef.current) {
3893
- setDays(value);
3894
- setError(null);
3895
- }
3896
- } catch (loadError) {
3897
- if (nextRequestId === requestIdRef.current) {
3898
- setError(loadError);
3899
- }
3900
- } finally {
3901
- if (nextRequestId === requestIdRef.current) {
3902
- setIsLoading(false);
3903
- }
3904
- }
3905
- },
3906
- [cacheKey, client, enabled, serviceId, startDate, endDate, options.locationId, options.participantCount]
3907
- );
3908
- React3.useEffect(() => {
3909
- void load(false);
3910
- }, [load]);
3911
- const refetch = React3.useCallback(async () => {
3912
- if (cacheKey) {
3913
- availabilityCache2.delete(cacheKey);
3914
- }
3915
- await load(true);
3916
- }, [cacheKey, load]);
3917
- return { days, isLoading, error, refetch };
3918
- }
3919
- var bookingsCache = /* @__PURE__ */ new Map();
3920
- var bookingsInflight = /* @__PURE__ */ new Map();
3921
- function buildBookingsCacheKey(client, filter) {
3922
- return JSON.stringify({ key: client.getPublicKey(), filter });
3923
- }
3924
- function useBookings(options = {}) {
3925
- const context = useOptionalCimplifyClient();
3926
- const client = options.client ?? context?.client;
3927
- if (!client) {
3928
- throw new Error("useBookings must be used within CimplifyProvider or passed { client }.");
3929
- }
3930
- const filter = options.filter ?? "all";
3931
- const enabled = options.enabled ?? true;
3932
- const requestIdRef = React3.useRef(0);
3933
- const cacheKey = React3.useMemo(
3934
- () => buildBookingsCacheKey(client, filter),
3935
- [client, filter]
3936
- );
3937
- const cached = bookingsCache.get(cacheKey);
3938
- const [bookings, setBookings] = React3.useState(cached ?? []);
3939
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
3940
- const [error, setError] = React3.useState(null);
3941
- const load = React3.useCallback(
3942
- async (force = false) => {
3943
- if (!enabled) {
3944
- setIsLoading(false);
3945
- return;
3946
- }
3947
- const nextRequestId = ++requestIdRef.current;
3948
- setError(null);
3949
- if (!force) {
3950
- const cachedBookings = bookingsCache.get(cacheKey);
3951
- if (cachedBookings) {
3952
- setBookings(cachedBookings);
3953
- setIsLoading(false);
3954
- return;
3955
- }
3956
- }
3957
- setIsLoading(true);
3958
- try {
3959
- const existing = bookingsInflight.get(cacheKey);
3960
- const promise = existing ?? (async () => {
3961
- let result;
3962
- switch (filter) {
3963
- case "upcoming":
3964
- result = await client.scheduling.getUpcomingBookings();
3965
- break;
3966
- case "past":
3967
- result = await client.scheduling.getPastBookings();
3968
- break;
3969
- default:
3970
- result = await client.scheduling.getCustomerBookings();
3971
- break;
3972
- }
3973
- if (!result.ok) {
3974
- throw result.error;
3975
- }
3976
- return result.value;
3977
- })();
3978
- if (!existing) {
3979
- bookingsInflight.set(
3980
- cacheKey,
3981
- promise.finally(() => {
3982
- bookingsInflight.delete(cacheKey);
3983
- })
3984
- );
3985
- }
3986
- const value = await promise;
3987
- bookingsCache.set(cacheKey, value);
3988
- if (nextRequestId === requestIdRef.current) {
3989
- setBookings(value);
3990
- setError(null);
3991
- }
3992
- } catch (loadError) {
3993
- if (nextRequestId === requestIdRef.current) {
3994
- setError(loadError);
3995
- }
3996
- } finally {
3997
- if (nextRequestId === requestIdRef.current) {
3998
- setIsLoading(false);
3999
- }
4000
- }
4001
- },
4002
- [cacheKey, client, enabled, filter]
4003
- );
4004
- React3.useEffect(() => {
4005
- void load(false);
4006
- }, [load]);
4007
- const refetch = React3.useCallback(async () => {
4008
- bookingsCache.delete(cacheKey);
4009
- await load(true);
4010
- }, [cacheKey, load]);
4011
- const cancelBooking = React3.useCallback(
4012
- async (bookingId, reason) => {
4013
- const result = await client.scheduling.cancelBooking({
4014
- booking_id: bookingId,
4015
- reason
4016
- });
4017
- if (!result.ok) {
4018
- throw result.error;
4019
- }
4020
- for (const key of bookingsCache.keys()) {
4021
- bookingsCache.delete(key);
4022
- }
4023
- await load(true);
4024
- return result.value;
4025
- },
4026
- [client, load]
4027
- );
4028
- return { bookings, isLoading, error, refetch, cancelBooking };
4029
- }
4030
- var definitionsCache = /* @__PURE__ */ new Map();
4031
- var definitionsInflight = /* @__PURE__ */ new Map();
4032
- function buildCacheKey(client, namespace) {
4033
- return `attr_defs_${client.getPublicKey() || "__demo__"}${namespace ? `_${namespace}` : ""}`;
4034
- }
4035
- function useAttributeDefinitions(options = {}) {
4036
- const context = useOptionalCimplifyClient();
4037
- const client = options.client ?? context?.client;
4038
- if (!client) {
4039
- throw new Error(
4040
- "useAttributeDefinitions must be used within CimplifyProvider or passed { client }."
4041
- );
4042
- }
4043
- const enabled = options.enabled ?? true;
4044
- const namespace = options.namespace;
4045
- const cacheKey = React3.useMemo(() => buildCacheKey(client, namespace), [client, namespace]);
4046
- const cached = definitionsCache.get(cacheKey);
4047
- const [definitions, setDefinitions] = React3.useState(cached ?? []);
4048
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4049
- const [error, setError] = React3.useState(null);
4050
- const load = React3.useCallback(
4051
- async (force = false) => {
4052
- if (!enabled) {
4053
- setIsLoading(false);
4054
- return;
4055
- }
4056
- setError(null);
4057
- if (!force) {
4058
- const cachedDefs = definitionsCache.get(cacheKey);
4059
- if (cachedDefs) {
4060
- setDefinitions(cachedDefs);
4061
- setIsLoading(false);
4062
- return;
4063
- }
4064
- }
4065
- setIsLoading(true);
4066
- try {
4067
- const existing = definitionsInflight.get(cacheKey);
4068
- const promise = existing ?? (async () => {
4069
- const result = await client.catalogue.getAttributeDefinitions(namespace);
4070
- if (!result.ok) {
4071
- throw result.error;
4072
- }
4073
- return result.value;
4074
- })();
4075
- if (!existing) {
4076
- definitionsInflight.set(
4077
- cacheKey,
4078
- promise.finally(() => {
4079
- definitionsInflight.delete(cacheKey);
4080
- })
4081
- );
4082
- }
4083
- const value = await promise;
4084
- definitionsCache.set(cacheKey, value);
4085
- setDefinitions(value);
4086
- } catch (loadError) {
4087
- setError(loadError);
4088
- } finally {
4089
- setIsLoading(false);
4090
- }
4091
- },
4092
- [cacheKey, client, enabled]
4093
- );
4094
- React3.useEffect(() => {
4095
- void load(false);
4096
- }, [load]);
4097
- const refetch = React3.useCallback(async () => {
4098
- definitionsCache.delete(cacheKey);
4099
- await load(true);
4100
- }, [cacheKey, load]);
4101
- return { definitions, isLoading, error, refetch };
4102
- }
4103
- var facetsCache = /* @__PURE__ */ new Map();
4104
- var facetsInflight = /* @__PURE__ */ new Map();
4105
- function usePropertyFacets(options = {}) {
4106
- const context = useOptionalCimplifyClient();
4107
- const client = options.client ?? context?.client;
4108
- if (!client) {
4109
- throw new Error(
4110
- "usePropertyFacets must be used within CimplifyProvider or passed { client }."
4111
- );
4112
- }
4113
- const enabled = options.enabled ?? true;
4114
- const cacheKey = React3.useMemo(
4115
- () => `facets_${client.getPublicKey() || "__demo__"}_${options.category_id ?? ""}_${options.product_type ?? ""}`,
4116
- [client, options.category_id, options.product_type]
4117
- );
4118
- const cached = facetsCache.get(cacheKey);
4119
- const [facets, setFacets] = React3.useState(cached ?? []);
4120
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4121
- const [error, setError] = React3.useState(null);
4122
- const load = React3.useCallback(
4123
- async (force = false) => {
4124
- if (!enabled) {
4125
- setIsLoading(false);
4126
- return;
4127
- }
4128
- setError(null);
4129
- if (!force) {
4130
- const cachedFacets = facetsCache.get(cacheKey);
4131
- if (cachedFacets) {
4132
- setFacets(cachedFacets);
4133
- setIsLoading(false);
4134
- return;
4135
- }
4136
- }
4137
- setIsLoading(true);
4138
- try {
4139
- const existing = facetsInflight.get(cacheKey);
4140
- const promise = existing ?? (async () => {
4141
- const result = await client.catalogue.getPropertyFacets({
4142
- category_id: options.category_id,
4143
- product_type: options.product_type
4144
- });
4145
- if (!result.ok) {
4146
- throw result.error;
4147
- }
4148
- return result.value;
4149
- })();
4150
- if (!existing) {
4151
- facetsInflight.set(
4152
- cacheKey,
4153
- promise.finally(() => {
4154
- facetsInflight.delete(cacheKey);
4155
- })
4156
- );
4157
- }
4158
- const value = await promise;
4159
- facetsCache.set(cacheKey, value);
4160
- setFacets(value);
4161
- } catch (loadError) {
4162
- setError(loadError);
4163
- } finally {
4164
- setIsLoading(false);
4165
- }
4166
- },
4167
- [cacheKey, client, enabled, options.category_id, options.product_type]
4168
- );
4169
- React3.useEffect(() => {
4170
- void load(false);
4171
- }, [load]);
4172
- const refetch = React3.useCallback(async () => {
4173
- facetsCache.delete(cacheKey);
4174
- await load(true);
4175
- }, [cacheKey, load]);
4176
- return { facets, isLoading, error, refetch };
4177
- }
4178
- function useBillingPlans(productId, options = {}) {
4179
- const context = useOptionalCimplifyClient();
4180
- const client = options.client ?? context?.client;
4181
- if (!client) {
4182
- throw new Error("useBillingPlans must be used within CimplifyProvider or passed { client }.");
4183
- }
4184
- const enabled = options.enabled ?? true;
4185
- const requestIdRef = React3.useRef(0);
4186
- const [plans, setPlans] = React3.useState([]);
4187
- const [isLoading, setIsLoading] = React3.useState(enabled && !!productId);
4188
- const [error, setError] = React3.useState(null);
4189
- const customerId = options.customerId;
4190
- const quantity = options.quantity;
4191
- const orderValue = options.orderValue;
4192
- const load = React3.useCallback(
4193
- async (force = false) => {
4194
- if (!enabled || !productId) {
4195
- setPlans([]);
4196
- setIsLoading(false);
4197
- return;
4198
- }
4199
- const nextRequestId = ++requestIdRef.current;
4200
- setError(null);
4201
- setIsLoading(true);
4202
- try {
4203
- const result = await client.catalogue.getEligibleBillingPlans(productId, {
4204
- customer_id: customerId,
4205
- quantity,
4206
- order_value: orderValue
4207
- });
4208
- if (!result.ok) {
4209
- throw result.error;
4210
- }
4211
- if (nextRequestId === requestIdRef.current) {
4212
- setPlans(result.value);
4213
- setError(null);
4214
- }
4215
- } catch (loadError) {
4216
- if (nextRequestId === requestIdRef.current) {
4217
- setError(loadError);
4218
- }
4219
- } finally {
4220
- if (nextRequestId === requestIdRef.current) {
4221
- setIsLoading(false);
4222
- }
4223
- }
4224
- },
4225
- [client, enabled, productId, customerId, quantity, orderValue]
4226
- );
4227
- React3.useEffect(() => {
4228
- void load(false);
4229
- }, [load]);
4230
- const refetch = React3.useCallback(async () => {
4231
- await load(true);
4232
- }, [load]);
4233
- const subscriptionPlans = React3.useMemo(
4234
- () => plans.filter((p) => p.plan_type === "subscription"),
4235
- [plans]
4236
- );
4237
- const installmentPlans = React3.useMemo(
4238
- () => plans.filter((p) => p.plan_type === "installment"),
4239
- [plans]
4240
- );
4241
- return { plans, subscriptionPlans, installmentPlans, isLoading, error, refetch };
4242
- }
4243
- function findMatchingVariant(variants, selections) {
4244
- const axisCount = Object.keys(selections).length;
4245
- if (axisCount === 0) return null;
4246
- return variants.find((v) => {
4247
- const sel = v.axis_selections;
4248
- if (!sel) return false;
4249
- return Object.entries(selections).every(([axisId, valueId]) => sel[axisId] === valueId);
4250
- }) ?? null;
4251
- }
4252
- function computeAvailableValues(variants, axes, selections) {
4253
- const result = {};
4254
- for (const axis of axes) {
4255
- const otherSelections = Object.entries(selections).filter(([id]) => id !== axis.id);
4256
- const candidates = variants.filter((v) => {
4257
- const sel = v.axis_selections;
4258
- if (!sel) return false;
4259
- return otherSelections.every(([axisId, valueId]) => sel[axisId] === valueId);
4260
- });
4261
- const available = /* @__PURE__ */ new Set();
4262
- for (const v of candidates) {
4263
- const val = v.axis_selections?.[axis.id];
4264
- if (val) available.add(val);
4265
- }
4266
- result[axis.id] = available;
4267
- }
4268
- return result;
4269
- }
4270
- function useVariantSelector(options) {
4271
- const { variants, axes } = options;
4272
- const [selectedValues, setSelectedValues] = React3.useState({});
4273
- const selectValue = React3.useCallback(
4274
- (axisId, valueId) => {
4275
- setSelectedValues((prev) => {
4276
- if (prev[axisId] === valueId) {
4277
- const next = { ...prev };
4278
- delete next[axisId];
4279
- return next;
4280
- }
4281
- return { ...prev, [axisId]: valueId };
4282
- });
4283
- },
4284
- []
4285
- );
4286
- const reset = React3.useCallback(() => setSelectedValues({}), []);
4287
- const selectedVariant = React3.useMemo(
4288
- () => findMatchingVariant(variants, selectedValues),
4289
- [variants, selectedValues]
4290
- );
4291
- const variantImage = React3.useMemo(
4292
- () => selectedVariant?.images?.[0] ?? null,
4293
- [selectedVariant]
4294
- );
4295
- const availableValues = React3.useMemo(
4296
- () => computeAvailableValues(variants, axes, selectedValues),
4297
- [variants, axes, selectedValues]
4298
- );
4299
- return {
4300
- selectedValues,
4301
- selectedVariant,
4302
- variantImage,
4303
- availableValues,
4304
- selectValue,
4305
- reset
4306
- };
4307
- }
4308
- var activityStateCache = /* @__PURE__ */ new Map();
4309
- var activityStateInflight = /* @__PURE__ */ new Map();
4310
- function buildActivityStateCacheKey(client) {
4311
- return JSON.stringify({ key: client.getPublicKey(), type: "activity_state" });
2672
+ });
2673
+ function useBundles(options = {}) {
2674
+ const { data, isLoading, error, refetch } = bundlesQuery(options);
2675
+ return { bundles: data ?? [], isLoading, error, refetch };
4312
2676
  }
4313
- function useActivityState(options = {}) {
4314
- const context = useOptionalCimplifyClient();
4315
- const client = options.client ?? context?.client;
4316
- if (!client) {
4317
- throw new Error("useActivityState must be used within CimplifyProvider or passed { client }.");
4318
- }
4319
- const enabled = options.enabled ?? true;
4320
- const cacheKey = React3.useMemo(() => buildActivityStateCacheKey(client), [client]);
4321
- const cached = activityStateCache.get(cacheKey);
4322
- const [state, setState] = React3.useState(cached ?? null);
4323
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4324
- const [error, setError] = React3.useState(null);
4325
- const load = React3.useCallback(
4326
- async (force = false) => {
4327
- if (!enabled) {
4328
- setIsLoading(false);
4329
- return;
4330
- }
4331
- setError(null);
4332
- if (!force) {
4333
- const cachedState = activityStateCache.get(cacheKey);
4334
- if (cachedState) {
4335
- setState(cachedState);
4336
- setIsLoading(false);
4337
- return;
4338
- }
2677
+ function useProductPrice(input) {
2678
+ const {
2679
+ product,
2680
+ quantity = 1,
2681
+ variant,
2682
+ addOnOptions,
2683
+ compositePrice,
2684
+ bundleTotalPrice
2685
+ } = input;
2686
+ return React3.useMemo(() => {
2687
+ let unitPrice;
2688
+ if (bundleTotalPrice != null) {
2689
+ unitPrice = bundleTotalPrice;
2690
+ } else if (compositePrice) {
2691
+ unitPrice = chunk64OCG2TJ_js.parsePrice(compositePrice.final_price);
2692
+ } else {
2693
+ unitPrice = chunk64OCG2TJ_js.parsePrice(product.default_price);
2694
+ if (variant?.price_adjustment) {
2695
+ unitPrice += chunk64OCG2TJ_js.parsePrice(variant.price_adjustment);
4339
2696
  }
4340
- setIsLoading(true);
4341
- try {
4342
- const existing = activityStateInflight.get(cacheKey);
4343
- const promise = existing ?? (async () => {
4344
- const result = await client.activity.getState();
4345
- if (!result.ok) {
4346
- throw result.error;
2697
+ if (addOnOptions) {
2698
+ for (const option of addOnOptions) {
2699
+ if (option.default_price) {
2700
+ unitPrice += chunk64OCG2TJ_js.parsePrice(option.default_price);
4347
2701
  }
4348
- return result.value;
4349
- })();
4350
- if (!existing) {
4351
- activityStateInflight.set(
4352
- cacheKey,
4353
- promise.finally(() => {
4354
- activityStateInflight.delete(cacheKey);
4355
- })
4356
- );
4357
2702
  }
4358
- const value = await promise;
4359
- activityStateCache.set(cacheKey, value);
4360
- setState(value);
4361
- } catch (loadError) {
4362
- setError(loadError);
4363
- } finally {
4364
- setIsLoading(false);
4365
- }
4366
- },
4367
- [cacheKey, client, enabled]
4368
- );
4369
- React3.useEffect(() => {
4370
- void load(false);
4371
- }, [load]);
4372
- const refetch = React3.useCallback(async () => {
4373
- activityStateCache.delete(cacheKey);
4374
- await load(true);
4375
- }, [cacheKey, load]);
4376
- const dismissMessage = React3.useCallback(
4377
- async (code) => {
4378
- const result = await client.activity.dismissMessage(code);
4379
- if (!result.ok) {
4380
- setError(result.error);
4381
- return;
4382
2703
  }
4383
- setState((prev) => {
4384
- if (!prev) return prev;
4385
- return { ...prev, messages: result.value.messages };
4386
- });
4387
- activityStateCache.delete(cacheKey);
4388
- await load(true);
4389
- },
4390
- [cacheKey, client, load]
4391
- );
4392
- const messages = state?.messages ?? [];
4393
- const intent = state?.intent ?? "";
4394
- return { state, messages, intent, isLoading, error, refetch, dismissMessage };
4395
- }
4396
- var recommendationsCache = /* @__PURE__ */ new Map();
4397
- var recommendationsInflight = /* @__PURE__ */ new Map();
4398
- function buildRecommendationsCacheKey(client, locationId, limit) {
4399
- return JSON.stringify({
4400
- key: client.getPublicKey(),
4401
- type: "recommendations",
4402
- location_id: locationId,
4403
- limit
4404
- });
2704
+ }
2705
+ unitPrice = Math.round(unitPrice * 100) / 100;
2706
+ const totalPrice = Math.round(unitPrice * quantity * 100) / 100;
2707
+ return {
2708
+ unitPrice,
2709
+ totalPrice,
2710
+ displayTotalPrice: totalPrice
2711
+ };
2712
+ }, [product.default_price, quantity, variant?.price_adjustment, addOnOptions, compositePrice, bundleTotalPrice]);
4405
2713
  }
4406
- function useRecommendations(options = {}) {
4407
- const context = useOptionalCimplifyClient();
4408
- const client = options.client ?? context?.client;
4409
- if (!client) {
4410
- throw new Error(
4411
- "useRecommendations must be used within CimplifyProvider or passed { client }."
4412
- );
2714
+
2715
+ // src/react/hooks/use-orders.ts
2716
+ var ordersQuery = createCachedQuery({
2717
+ name: "useOrders",
2718
+ key: (client, options) => cacheKey(client.getPublicKey(), options.status, options.limit),
2719
+ fetch: async (client, options) => {
2720
+ const result = await client.orders.list({
2721
+ status: options.status,
2722
+ limit: options.limit
2723
+ });
2724
+ if (!result.ok) throw result.error;
2725
+ return result.value;
4413
2726
  }
4414
- const enabled = options.enabled ?? true;
4415
- const locationId = options.locationId ?? client.getLocationId() ?? void 0;
4416
- const limit = options.limit;
4417
- const previousLocationIdRef = React3.useRef(locationId);
4418
- const cacheKey = React3.useMemo(
4419
- () => buildRecommendationsCacheKey(client, locationId, limit),
4420
- [client, locationId, limit]
4421
- );
4422
- const cached = recommendationsCache.get(cacheKey);
4423
- const [response, setResponse] = React3.useState(cached ?? null);
4424
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4425
- const [error, setError] = React3.useState(null);
4426
- React3.useEffect(() => {
4427
- if (previousLocationIdRef.current !== locationId) {
4428
- recommendationsCache.clear();
4429
- recommendationsInflight.clear();
4430
- previousLocationIdRef.current = locationId;
4431
- }
4432
- }, [locationId]);
4433
- const load = React3.useCallback(
4434
- async (force = false) => {
4435
- if (!enabled) {
4436
- setIsLoading(false);
4437
- return;
4438
- }
4439
- setError(null);
4440
- if (!force) {
4441
- const cachedResponse = recommendationsCache.get(cacheKey);
4442
- if (cachedResponse) {
4443
- setResponse(cachedResponse);
4444
- setIsLoading(false);
4445
- return;
4446
- }
4447
- }
4448
- setIsLoading(true);
4449
- try {
4450
- const existing = recommendationsInflight.get(cacheKey);
4451
- const promise = existing ?? (async () => {
4452
- const result = await client.activity.getRecommendations({
4453
- location_id: locationId,
4454
- limit
4455
- });
4456
- if (!result.ok) {
4457
- throw result.error;
4458
- }
4459
- return result.value;
4460
- })();
4461
- if (!existing) {
4462
- recommendationsInflight.set(
4463
- cacheKey,
4464
- promise.finally(() => {
4465
- recommendationsInflight.delete(cacheKey);
4466
- })
4467
- );
4468
- }
4469
- const value = await promise;
4470
- recommendationsCache.set(cacheKey, value);
4471
- setResponse(value);
4472
- } catch (loadError) {
4473
- setError(loadError);
4474
- } finally {
4475
- setIsLoading(false);
4476
- }
4477
- },
4478
- [cacheKey, client, enabled, locationId, limit]
4479
- );
4480
- React3.useEffect(() => {
4481
- void load(false);
4482
- }, [load]);
4483
- const refetch = React3.useCallback(async () => {
4484
- recommendationsCache.delete(cacheKey);
4485
- await load(true);
4486
- }, [cacheKey, load]);
4487
- const recommendations = response?.recommendations ?? [];
4488
- const intent = response?.intent ?? "";
4489
- return { recommendations, intent, isLoading, error, refetch };
4490
- }
4491
- var deliveryFeeCache = /* @__PURE__ */ new Map();
4492
- function buildDeliveryFeeCacheKey(client, latitude, longitude, country) {
4493
- return JSON.stringify({
4494
- key: client.getPublicKey(),
4495
- lat: latitude,
4496
- lng: longitude,
4497
- country
4498
- });
2727
+ });
2728
+ function useOrders(options = {}) {
2729
+ const { data, isLoading, error, refetch } = ordersQuery(options);
2730
+ return { orders: data ?? [], isLoading, error, refetch };
4499
2731
  }
4500
- function useDeliveryFee(options) {
4501
- const context = useOptionalCimplifyClient();
4502
- const client = options.client ?? context?.client;
4503
- if (!client) {
4504
- throw new Error("useDeliveryFee must be used within CimplifyProvider or passed { client }.");
2732
+
2733
+ // src/react/hooks/use-services.ts
2734
+ var servicesQuery = createCachedQuery({
2735
+ name: "useServices",
2736
+ key: (client) => cacheKey(client.getPublicKey()),
2737
+ fetch: async (client) => {
2738
+ const result = await client.scheduling.getServices();
2739
+ if (!result.ok) throw result.error;
2740
+ return result.value;
4505
2741
  }
4506
- const enabled = options.enabled ?? true;
4507
- const { latitude, longitude, country } = options;
4508
- const cacheKey = React3.useMemo(
4509
- () => buildDeliveryFeeCacheKey(client, latitude, longitude, country),
4510
- [client, latitude, longitude, country]
4511
- );
4512
- const cached = deliveryFeeCache.get(cacheKey);
4513
- const [fee, setFee] = React3.useState(cached ?? null);
4514
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4515
- const [error, setError] = React3.useState(null);
4516
- const requestIdRef = React3.useRef(0);
4517
- const load = React3.useCallback(
4518
- async (force = false) => {
4519
- if (!enabled) {
4520
- setIsLoading(false);
4521
- return;
4522
- }
4523
- setError(null);
4524
- if (!force) {
4525
- const cachedFee = deliveryFeeCache.get(cacheKey);
4526
- if (cachedFee) {
4527
- setFee(cachedFee);
4528
- setIsLoading(false);
4529
- return;
4530
- }
4531
- }
4532
- setIsLoading(true);
4533
- const currentRequestId = ++requestIdRef.current;
4534
- try {
4535
- const result = await client.delivery.getFee(latitude, longitude, country);
4536
- if (currentRequestId !== requestIdRef.current) return;
4537
- if (!result.ok) {
4538
- throw result.error;
4539
- }
4540
- deliveryFeeCache.set(cacheKey, result.value);
4541
- setFee(result.value);
4542
- } catch (loadError) {
4543
- if (currentRequestId !== requestIdRef.current) return;
4544
- setError(loadError);
4545
- } finally {
4546
- if (currentRequestId === requestIdRef.current) {
4547
- setIsLoading(false);
4548
- }
4549
- }
4550
- },
4551
- [cacheKey, client, country, enabled, latitude, longitude]
4552
- );
4553
- React3.useEffect(() => {
4554
- void load(false);
4555
- }, [load]);
4556
- const refetch = React3.useCallback(async () => {
4557
- deliveryFeeCache.delete(cacheKey);
4558
- await load(true);
4559
- }, [cacheKey, load]);
4560
- return { fee, isLoading, error, refetch };
2742
+ });
2743
+ function useServices(options = {}) {
2744
+ const { data, isLoading, error, refetch } = servicesQuery(options);
2745
+ return { services: data ?? [], isLoading, error, refetch };
4561
2746
  }
4562
- var fxRateCache = /* @__PURE__ */ new Map();
4563
- var fxRateInflight = /* @__PURE__ */ new Map();
4564
- function buildFxRateCacheKey(client, from, to) {
4565
- return JSON.stringify({ key: client.getPublicKey(), from, to });
2747
+
2748
+ // src/react/hooks/use-available-slots.ts
2749
+ var slotsQuery = createCachedQuery({
2750
+ name: "useAvailableSlots",
2751
+ key: (client, options) => cacheKey(client.getPublicKey(), options.serviceId, options.date, options.participantCount),
2752
+ fetch: async (client, options) => {
2753
+ const result = await client.scheduling.getAvailableSlots({
2754
+ service_id: options.serviceId,
2755
+ date: options.date,
2756
+ participant_count: options.participantCount
2757
+ });
2758
+ if (!result.ok) throw result.error;
2759
+ return result.value;
2760
+ }
2761
+ });
2762
+ function useAvailableSlots(serviceId, date, options = {}) {
2763
+ const { data, isLoading, error, refetch } = slotsQuery({
2764
+ ...options,
2765
+ serviceId: serviceId || "",
2766
+ date: date || "",
2767
+ enabled: (options.enabled ?? true) && !!serviceId && !!date
2768
+ });
2769
+ return { slots: data ?? [], isLoading, error, refetch };
4566
2770
  }
4567
- function useFxRate(options) {
2771
+
2772
+ // src/react/hooks/use-service-availability.ts
2773
+ var serviceAvailabilityQuery = createCachedQuery({
2774
+ name: "useServiceAvailability",
2775
+ key: (client, options) => cacheKey(
2776
+ client.getPublicKey(),
2777
+ options.serviceId,
2778
+ options.startDate,
2779
+ options.endDate,
2780
+ options.participantCount
2781
+ ),
2782
+ fetch: async (client, options) => {
2783
+ const result = await client.scheduling.getServiceAvailability({
2784
+ service_id: options.serviceId,
2785
+ start_date: options.startDate,
2786
+ end_date: options.endDate,
2787
+ location_id: options.locationId,
2788
+ participant_count: options.participantCount
2789
+ });
2790
+ if (!result.ok) throw result.error;
2791
+ return result.value.availability;
2792
+ }
2793
+ });
2794
+ function useServiceAvailability(serviceId, startDate, endDate, options = {}) {
2795
+ const { data, isLoading, error, refetch } = serviceAvailabilityQuery({
2796
+ ...options,
2797
+ serviceId: serviceId || "",
2798
+ startDate: startDate || "",
2799
+ endDate: endDate || "",
2800
+ enabled: (options.enabled ?? true) && !!serviceId && !!startDate && !!endDate
2801
+ });
2802
+ return { days: data ?? [], isLoading, error, refetch };
2803
+ }
2804
+ var bookingsQuery = createCachedQuery({
2805
+ name: "useBookings",
2806
+ key: (client, options) => cacheKey(client.getPublicKey(), options.filter ?? "all"),
2807
+ fetch: async (client, options) => {
2808
+ const filter = options.filter ?? "all";
2809
+ let result;
2810
+ switch (filter) {
2811
+ case "upcoming":
2812
+ result = await client.scheduling.getUpcomingBookings();
2813
+ break;
2814
+ case "past":
2815
+ result = await client.scheduling.getPastBookings();
2816
+ break;
2817
+ default:
2818
+ result = await client.scheduling.getCustomerBookings();
2819
+ break;
2820
+ }
2821
+ if (!result.ok) throw result.error;
2822
+ return result.value;
2823
+ }
2824
+ });
2825
+ function useBookings(options = {}) {
4568
2826
  const context = useOptionalCimplifyClient();
4569
2827
  const client = options.client ?? context?.client;
4570
- if (!client) {
4571
- throw new Error("useFxRate must be used within CimplifyProvider or passed { client }.");
4572
- }
4573
- const enabled = options.enabled ?? true;
4574
- const { from, to } = options;
4575
- const cacheKey = React3.useMemo(
4576
- () => buildFxRateCacheKey(client, from, to),
4577
- [client, from, to]
4578
- );
4579
- const cached = fxRateCache.get(cacheKey);
4580
- const [rate, setRate] = React3.useState(cached ?? null);
4581
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4582
- const [error, setError] = React3.useState(null);
4583
- const load = React3.useCallback(
4584
- async (force = false) => {
4585
- if (!enabled) {
4586
- setIsLoading(false);
4587
- return;
4588
- }
4589
- setError(null);
4590
- if (!force) {
4591
- const cachedRate = fxRateCache.get(cacheKey);
4592
- if (cachedRate) {
4593
- setRate(cachedRate);
4594
- setIsLoading(false);
4595
- return;
4596
- }
4597
- }
4598
- setIsLoading(true);
4599
- try {
4600
- const existing = fxRateInflight.get(cacheKey);
4601
- const promise = existing ?? (async () => {
4602
- const result = await client.fx.getRate(from, to);
4603
- if (!result.ok) {
4604
- throw result.error;
4605
- }
4606
- return result.value;
4607
- })();
4608
- if (!existing) {
4609
- fxRateInflight.set(
4610
- cacheKey,
4611
- promise.finally(() => {
4612
- fxRateInflight.delete(cacheKey);
4613
- })
4614
- );
4615
- }
4616
- const value = await promise;
4617
- fxRateCache.set(cacheKey, value);
4618
- setRate(value);
4619
- } catch (loadError) {
4620
- setError(loadError);
4621
- } finally {
4622
- setIsLoading(false);
4623
- }
2828
+ const { data, isLoading, error, refetch } = bookingsQuery(options);
2829
+ const cancelBooking = React3.useCallback(
2830
+ async (bookingId, reason) => {
2831
+ if (!client) throw new Error("useBookings must be used within CimplifyProvider or passed { client }.");
2832
+ const result = await client.scheduling.cancelBooking({
2833
+ booking_id: bookingId,
2834
+ reason
2835
+ });
2836
+ if (!result.ok) throw result.error;
2837
+ bookingsQuery.clear();
2838
+ await refetch();
2839
+ return result.value;
4624
2840
  },
4625
- [cacheKey, client, enabled, from, to]
2841
+ [client, refetch]
4626
2842
  );
4627
- React3.useEffect(() => {
4628
- void load(false);
4629
- }, [load]);
4630
- const refetch = React3.useCallback(async () => {
4631
- fxRateCache.delete(cacheKey);
4632
- await load(true);
4633
- }, [cacheKey, load]);
4634
- return { rate, isLoading, error, refetch };
2843
+ return { bookings: data ?? [], isLoading, error, refetch, cancelBooking };
2844
+ }
2845
+
2846
+ // src/react/hooks/use-attribute-definitions.ts
2847
+ var attributeDefinitionsQuery = createCachedQuery({
2848
+ name: "useAttributeDefinitions",
2849
+ key: (client, options) => cacheKey(client.getPublicKey() || "__demo__", options.namespace),
2850
+ fetch: async (client, options) => {
2851
+ const result = await client.catalogue.getAttributeDefinitions(options.namespace);
2852
+ if (!result.ok) throw result.error;
2853
+ return result.value;
2854
+ }
2855
+ });
2856
+ function useAttributeDefinitions(options = {}) {
2857
+ const { data, isLoading, error, refetch } = attributeDefinitionsQuery(options);
2858
+ return { definitions: data ?? [], isLoading, error, refetch };
4635
2859
  }
4636
- var bootstrapCache = /* @__PURE__ */ new Map();
4637
- var bootstrapInflight = /* @__PURE__ */ new Map();
4638
- function buildBootstrapCacheKey(client) {
4639
- return JSON.stringify({ key: client.getPublicKey(), type: "bootstrap" });
2860
+
2861
+ // src/react/hooks/use-property-facets.ts
2862
+ var propertyFacetsQuery = createCachedQuery({
2863
+ name: "usePropertyFacets",
2864
+ key: (client, options) => cacheKey(client.getPublicKey() || "__demo__", options.category_id, options.product_type),
2865
+ fetch: async (client, options) => {
2866
+ const result = await client.catalogue.getPropertyFacets({
2867
+ category_id: options.category_id,
2868
+ product_type: options.product_type
2869
+ });
2870
+ if (!result.ok) throw result.error;
2871
+ return result.value;
2872
+ }
2873
+ });
2874
+ function usePropertyFacets(options = {}) {
2875
+ const { data, isLoading, error, refetch } = propertyFacetsQuery(options);
2876
+ return { facets: data ?? [], isLoading, error, refetch };
4640
2877
  }
4641
- function useBootstrap(options = {}) {
2878
+ function useBillingPlans(productId, options = {}) {
4642
2879
  const context = useOptionalCimplifyClient();
4643
2880
  const client = options.client ?? context?.client;
4644
2881
  if (!client) {
4645
- throw new Error("useBootstrap must be used within CimplifyProvider or passed { client }.");
2882
+ throw new Error("useBillingPlans must be used within CimplifyProvider or passed { client }.");
4646
2883
  }
4647
2884
  const enabled = options.enabled ?? true;
4648
- const cacheKey = React3.useMemo(() => buildBootstrapCacheKey(client), [client]);
4649
- const cached = bootstrapCache.get(cacheKey);
4650
- const [bootstrap, setBootstrap] = React3.useState(cached ?? null);
4651
- const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
2885
+ const requestIdRef = React3.useRef(0);
2886
+ const [plans, setPlans] = React3.useState([]);
2887
+ const [isLoading, setIsLoading] = React3.useState(enabled && !!productId);
4652
2888
  const [error, setError] = React3.useState(null);
2889
+ const customerId = options.customerId;
2890
+ const quantity = options.quantity;
2891
+ const orderValue = options.orderValue;
4653
2892
  const load = React3.useCallback(
4654
2893
  async (force = false) => {
4655
- if (!enabled) {
2894
+ if (!enabled || !productId) {
2895
+ setPlans([]);
4656
2896
  setIsLoading(false);
4657
2897
  return;
4658
2898
  }
2899
+ const nextRequestId = ++requestIdRef.current;
4659
2900
  setError(null);
4660
- if (!force) {
4661
- const cachedBootstrap = bootstrapCache.get(cacheKey);
4662
- if (cachedBootstrap) {
4663
- setBootstrap(cachedBootstrap);
4664
- setIsLoading(false);
4665
- return;
4666
- }
4667
- }
4668
2901
  setIsLoading(true);
4669
2902
  try {
4670
- const existing = bootstrapInflight.get(cacheKey);
4671
- const promise = existing ?? (async () => {
4672
- const result = await client.business.getBootstrap();
4673
- if (!result.ok) {
4674
- throw result.error;
4675
- }
4676
- return result.value;
4677
- })();
4678
- if (!existing) {
4679
- bootstrapInflight.set(
4680
- cacheKey,
4681
- promise.finally(() => {
4682
- bootstrapInflight.delete(cacheKey);
4683
- })
4684
- );
2903
+ const result = await client.catalogue.getEligibleBillingPlans(productId, {
2904
+ customer_id: customerId,
2905
+ quantity,
2906
+ order_value: orderValue
2907
+ });
2908
+ if (!result.ok) {
2909
+ throw result.error;
2910
+ }
2911
+ if (nextRequestId === requestIdRef.current) {
2912
+ setPlans(result.value);
2913
+ setError(null);
4685
2914
  }
4686
- const value = await promise;
4687
- bootstrapCache.set(cacheKey, value);
4688
- setBootstrap(value);
4689
2915
  } catch (loadError) {
4690
- setError(loadError);
2916
+ if (nextRequestId === requestIdRef.current) {
2917
+ setError(loadError);
2918
+ }
4691
2919
  } finally {
4692
- setIsLoading(false);
2920
+ if (nextRequestId === requestIdRef.current) {
2921
+ setIsLoading(false);
2922
+ }
4693
2923
  }
4694
2924
  },
4695
- [cacheKey, client, enabled]
2925
+ [client, enabled, productId, customerId, quantity, orderValue]
4696
2926
  );
4697
2927
  React3.useEffect(() => {
4698
2928
  void load(false);
4699
2929
  }, [load]);
4700
2930
  const refetch = React3.useCallback(async () => {
4701
- bootstrapCache.delete(cacheKey);
4702
2931
  await load(true);
4703
- }, [cacheKey, load]);
4704
- return { bootstrap, isLoading, error, refetch };
2932
+ }, [load]);
2933
+ const subscriptionPlans = React3.useMemo(
2934
+ () => plans.filter((p) => p.plan_type === "subscription"),
2935
+ [plans]
2936
+ );
2937
+ const installmentPlans = React3.useMemo(
2938
+ () => plans.filter((p) => p.plan_type === "installment"),
2939
+ [plans]
2940
+ );
2941
+ return { plans, subscriptionPlans, installmentPlans, isLoading, error, refetch };
2942
+ }
2943
+ function findMatchingVariant(variants, selections) {
2944
+ const axisCount = Object.keys(selections).length;
2945
+ if (axisCount === 0) return null;
2946
+ return variants.find((v) => {
2947
+ const sel = v.axis_selections;
2948
+ if (!sel) return false;
2949
+ return Object.entries(selections).every(([axisId, valueId]) => sel[axisId] === valueId);
2950
+ }) ?? null;
2951
+ }
2952
+ function computeAvailableValues(variants, axes, selections) {
2953
+ const result = {};
2954
+ for (const axis of axes) {
2955
+ const otherSelections = Object.entries(selections).filter(([id]) => id !== axis.id);
2956
+ const candidates = variants.filter((v) => {
2957
+ const sel = v.axis_selections;
2958
+ if (!sel) return false;
2959
+ return otherSelections.every(([axisId, valueId]) => sel[axisId] === valueId);
2960
+ });
2961
+ const available = /* @__PURE__ */ new Set();
2962
+ for (const v of candidates) {
2963
+ const val = v.axis_selections?.[axis.id];
2964
+ if (val) available.add(val);
2965
+ }
2966
+ result[axis.id] = available;
2967
+ }
2968
+ return result;
2969
+ }
2970
+ function useVariantSelector(options) {
2971
+ const { variants, axes } = options;
2972
+ const [selectedValues, setSelectedValues] = React3.useState({});
2973
+ const selectValue = React3.useCallback(
2974
+ (axisId, valueId) => {
2975
+ setSelectedValues((prev) => {
2976
+ if (prev[axisId] === valueId) {
2977
+ const next = { ...prev };
2978
+ delete next[axisId];
2979
+ return next;
2980
+ }
2981
+ return { ...prev, [axisId]: valueId };
2982
+ });
2983
+ },
2984
+ []
2985
+ );
2986
+ const reset = React3.useCallback(() => setSelectedValues({}), []);
2987
+ const selectedVariant = React3.useMemo(
2988
+ () => findMatchingVariant(variants, selectedValues),
2989
+ [variants, selectedValues]
2990
+ );
2991
+ const variantImage = React3.useMemo(
2992
+ () => selectedVariant?.images?.[0] ?? null,
2993
+ [selectedVariant]
2994
+ );
2995
+ const availableValues = React3.useMemo(
2996
+ () => computeAvailableValues(variants, axes, selectedValues),
2997
+ [variants, axes, selectedValues]
2998
+ );
2999
+ return {
3000
+ selectedValues,
3001
+ selectedVariant,
3002
+ variantImage,
3003
+ availableValues,
3004
+ selectValue,
3005
+ reset
3006
+ };
3007
+ }
3008
+ var activityStateQuery = createCachedQuery({
3009
+ name: "useActivityState",
3010
+ key: (client) => cacheKey(client.getPublicKey()),
3011
+ fetch: async (client) => {
3012
+ const result = await client.activity.getState();
3013
+ if (!result.ok) throw result.error;
3014
+ return result.value;
3015
+ }
3016
+ });
3017
+ function useActivityState(options = {}) {
3018
+ const context = useOptionalCimplifyClient();
3019
+ const client = options.client ?? context?.client;
3020
+ const { data, isLoading, error, refetch } = activityStateQuery(options);
3021
+ const dismissMessage = React3.useCallback(
3022
+ async (code) => {
3023
+ if (!client) return;
3024
+ const result = await client.activity.dismissMessage(code);
3025
+ if (!result.ok) return;
3026
+ activityStateQuery.clear();
3027
+ await refetch();
3028
+ },
3029
+ [client, refetch]
3030
+ );
3031
+ return {
3032
+ state: data,
3033
+ messages: data?.messages ?? [],
3034
+ intent: data?.intent ?? "",
3035
+ isLoading,
3036
+ error,
3037
+ refetch,
3038
+ dismissMessage
3039
+ };
3040
+ }
3041
+
3042
+ // src/react/hooks/use-recommendations.ts
3043
+ var recommendationsQuery = createCachedQuery({
3044
+ name: "useRecommendations",
3045
+ locationSensitive: true,
3046
+ key: (client, options) => {
3047
+ const locationId = options.locationId ?? client.getLocationId();
3048
+ return cacheKey(client.getPublicKey(), locationId, options.limit);
3049
+ },
3050
+ fetch: async (client, options) => {
3051
+ const locationId = options.locationId ?? client.getLocationId() ?? void 0;
3052
+ const result = await client.activity.getRecommendations({
3053
+ location_id: locationId,
3054
+ limit: options.limit
3055
+ });
3056
+ if (!result.ok) throw result.error;
3057
+ return result.value;
3058
+ }
3059
+ });
3060
+ function useRecommendations(options = {}) {
3061
+ const { data, isLoading, error, refetch } = recommendationsQuery(options);
3062
+ return {
3063
+ recommendations: data?.recommendations ?? [],
3064
+ intent: data?.intent ?? "",
3065
+ isLoading,
3066
+ error,
3067
+ refetch
3068
+ };
3069
+ }
3070
+
3071
+ // src/react/hooks/use-delivery-fee.ts
3072
+ var deliveryFeeQuery = createCachedQuery({
3073
+ name: "useDeliveryFee",
3074
+ key: (client, options) => cacheKey(client.getPublicKey(), options.latitude, options.longitude, options.country),
3075
+ fetch: async (client, options) => {
3076
+ const result = await client.delivery.getFee(options.latitude, options.longitude, options.country);
3077
+ if (!result.ok) throw result.error;
3078
+ return result.value;
3079
+ }
3080
+ });
3081
+ function useDeliveryFee(options) {
3082
+ const { data, isLoading, error, refetch } = deliveryFeeQuery(options);
3083
+ return { fee: data, isLoading, error, refetch };
3084
+ }
3085
+
3086
+ // src/react/hooks/use-fx-rate.ts
3087
+ var fxRateQuery = createCachedQuery({
3088
+ name: "useFxRate",
3089
+ key: (client, options) => cacheKey(client.getPublicKey(), options.from, options.to),
3090
+ fetch: async (client, options) => {
3091
+ const result = await client.fx.getRate(options.from, options.to);
3092
+ if (!result.ok) throw result.error;
3093
+ return result.value;
3094
+ }
3095
+ });
3096
+ function useFxRate(options) {
3097
+ const { data, isLoading, error, refetch } = fxRateQuery(options);
3098
+ return { rate: data, isLoading, error, refetch };
3099
+ }
3100
+
3101
+ // src/react/hooks/use-bootstrap.ts
3102
+ var bootstrapQuery = createCachedQuery({
3103
+ name: "useBootstrap",
3104
+ key: (client) => cacheKey(client.getPublicKey()),
3105
+ fetch: async (client) => {
3106
+ const result = await client.business.getBootstrap();
3107
+ if (!result.ok) throw result.error;
3108
+ return result.value;
3109
+ }
3110
+ });
3111
+ function useBootstrap(options = {}) {
3112
+ const { data, isLoading, error, refetch } = bootstrapQuery(options);
3113
+ return { bootstrap: data, isLoading, error, refetch };
4705
3114
  }
4706
3115
  var ElementsContext = React3.createContext({
4707
3116
  elements: null,
@@ -6882,11 +5291,8 @@ function ProductCard({
6882
5291
  "div",
6883
5292
  {
6884
5293
  "data-cimplify-product-card-image-container": true,
6885
- className: classNames?.imageContainer,
6886
- style: {
6887
- overflow: "hidden",
6888
- ...ASPECT_STYLES2[aspectRatio]
6889
- },
5294
+ className: cn("overflow-hidden rounded-t-xl", classNames?.imageContainer),
5295
+ style: ASPECT_STYLES2[aspectRatio],
6890
5296
  children: renderImage ? renderImage({
6891
5297
  src: imageUrl,
6892
5298
  alt: product.name,
@@ -6896,8 +5302,7 @@ function ProductCard({
6896
5302
  {
6897
5303
  src: imageUrl,
6898
5304
  alt: product.name,
6899
- className: classNames?.image,
6900
- style: { width: "100%", height: "100%", objectFit: "cover" },
5305
+ className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", classNames?.image),
6901
5306
  "data-cimplify-product-card-image": true
6902
5307
  }
6903
5308
  )
@@ -6907,13 +5312,13 @@ function ProductCard({
6907
5312
  "div",
6908
5313
  {
6909
5314
  "data-cimplify-product-card-body": true,
6910
- className: classNames?.body,
5315
+ className: cn("p-4 flex flex-col gap-1", classNames?.body),
6911
5316
  children: [
6912
5317
  /* @__PURE__ */ jsxRuntime.jsx(
6913
5318
  "span",
6914
5319
  {
6915
5320
  "data-cimplify-product-card-name": true,
6916
- className: classNames?.name,
5321
+ className: cn("font-semibold text-foreground leading-tight", classNames?.name),
6917
5322
  children: product.name
6918
5323
  }
6919
5324
  ),
@@ -6921,13 +5326,7 @@ function ProductCard({
6921
5326
  "span",
6922
5327
  {
6923
5328
  "data-cimplify-product-card-description": true,
6924
- className: classNames?.description,
6925
- style: {
6926
- display: "-webkit-box",
6927
- WebkitLineClamp: 2,
6928
- WebkitBoxOrient: "vertical",
6929
- overflow: "hidden"
6930
- },
5329
+ className: cn("text-sm text-muted-foreground line-clamp-2", classNames?.description),
6931
5330
  children: product.description
6932
5331
  }
6933
5332
  ),
@@ -6935,7 +5334,7 @@ function ProductCard({
6935
5334
  Price,
6936
5335
  {
6937
5336
  amount: product.default_price,
6938
- className: classNames?.price
5337
+ className: cn("text-sm font-medium text-foreground mt-1", classNames?.price)
6939
5338
  }
6940
5339
  )
6941
5340
  ]
@@ -6944,7 +5343,7 @@ function ProductCard({
6944
5343
  ] });
6945
5344
  if (mode === "page") {
6946
5345
  const linkHref = href ?? `/menu/${product.slug}`;
6947
- const linkClassName = cn("block no-underline text-[inherit]", className, classNames?.root);
5346
+ const linkClassName = cn("group block no-underline text-[inherit] rounded-xl border border-border bg-background transition-shadow duration-200 hover:shadow-md", className, classNames?.root);
6948
5347
  if (renderLink) {
6949
5348
  return renderLink({ href: linkHref, className: linkClassName, children: cardBody });
6950
5349
  }
@@ -6967,7 +5366,7 @@ function ProductCard({
6967
5366
  "data-cimplify-product-card": true,
6968
5367
  "data-display-mode": "card",
6969
5368
  className: cn(
6970
- "block w-full text-left bg-transparent border-none p-0 cursor-pointer font-[inherit] text-[inherit]",
5369
+ "group block w-full text-left p-0 cursor-pointer font-[inherit] text-[inherit] rounded-xl border border-border bg-background transition-shadow duration-200 hover:shadow-md",
6971
5370
  className,
6972
5371
  classNames?.root
6973
5372
  ),
@@ -8301,10 +6700,14 @@ function BookingCard({
8301
6700
  {
8302
6701
  "data-cimplify-booking-card": true,
8303
6702
  "data-status": booking.status,
8304
- className: cn(className, classNames?.root),
6703
+ className: cn(
6704
+ "rounded-xl border border-border bg-background p-4 flex flex-col gap-3",
6705
+ className,
6706
+ classNames?.root
6707
+ ),
8305
6708
  children: [
8306
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-main": true, children: [
8307
- /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-service": true, className: classNames?.service, children: [
6709
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-main": true, className: "flex items-center justify-between gap-2", children: [
6710
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-booking-service": true, className: cn("font-semibold text-foreground", classNames?.service), children: [
8308
6711
  "Booking #",
8309
6712
  booking.order_id.slice(0, 8)
8310
6713
  ] }),
@@ -8313,22 +6716,37 @@ function BookingCard({
8313
6716
  {
8314
6717
  "data-cimplify-booking-status": true,
8315
6718
  "data-status": booking.status,
8316
- className: classNames?.status,
6719
+ className: cn(
6720
+ "text-xs font-medium px-2 py-0.5 rounded-full",
6721
+ active ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground",
6722
+ classNames?.status
6723
+ ),
8317
6724
  children: STATUS_LABELS3[booking.status] ?? booking.status
8318
6725
  }
8319
6726
  )
8320
6727
  ] }),
8321
- firstItem?.confirmation_code && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-code": true, className: classNames?.confirmationCode, children: firstItem.confirmation_code }),
8322
- scheduledTime && /* @__PURE__ */ jsxRuntime.jsx("time", { "data-cimplify-booking-time": true, className: classNames?.time, children: scheduledTime }),
8323
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-total": true, className: classNames?.total, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: booking.total_price }) }),
8324
- active && (onCancel || onReschedule) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-actions": true, className: classNames?.actions, children: [
6728
+ firstItem?.confirmation_code && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-code": true, className: cn("text-xs font-mono text-muted-foreground tracking-wide", classNames?.confirmationCode), children: firstItem.confirmation_code }),
6729
+ scheduledTime && /* @__PURE__ */ jsxRuntime.jsx(
6730
+ "time",
6731
+ {
6732
+ "data-cimplify-booking-time": true,
6733
+ dateTime: firstItem?.scheduled_start ?? void 0,
6734
+ className: cn("text-sm text-foreground", classNames?.time),
6735
+ children: scheduledTime
6736
+ }
6737
+ ),
6738
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-booking-total": true, className: cn("text-sm font-medium text-foreground", classNames?.total), children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: booking.total_price }) }),
6739
+ active && (onCancel || onReschedule) && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-actions": true, className: cn("flex gap-2 pt-1 border-t border-border mt-1", classNames?.actions), children: [
8325
6740
  onReschedule && /* @__PURE__ */ jsxRuntime.jsx(
8326
6741
  "button",
8327
6742
  {
8328
6743
  type: "button",
8329
6744
  onClick: () => onReschedule(booking),
8330
6745
  "data-cimplify-booking-reschedule": true,
8331
- className: classNames?.rescheduleButton,
6746
+ className: cn(
6747
+ "flex-1 text-sm font-medium py-2 rounded-lg border border-border bg-background text-foreground transition-colors hover:bg-muted cursor-pointer",
6748
+ classNames?.rescheduleButton
6749
+ ),
8332
6750
  children: "Reschedule"
8333
6751
  }
8334
6752
  ),
@@ -8338,7 +6756,10 @@ function BookingCard({
8338
6756
  type: "button",
8339
6757
  onClick: () => onCancel(booking),
8340
6758
  "data-cimplify-booking-cancel": true,
8341
- className: classNames?.cancelButton,
6759
+ className: cn(
6760
+ "flex-1 text-sm font-medium py-2 rounded-lg border border-border bg-background text-destructive transition-colors hover:bg-destructive/10 cursor-pointer",
6761
+ classNames?.cancelButton
6762
+ ),
8342
6763
  children: "Cancel"
8343
6764
  }
8344
6765
  )
@@ -8451,11 +6872,8 @@ function ServiceCard({
8451
6872
  "div",
8452
6873
  {
8453
6874
  "data-cimplify-service-card-image-container": true,
8454
- className: classNames?.imageContainer,
8455
- style: {
8456
- overflow: "hidden",
8457
- ...ASPECT_STYLES3[aspectRatio]
8458
- },
6875
+ className: cn("overflow-hidden rounded-t-xl", classNames?.imageContainer),
6876
+ style: ASPECT_STYLES3[aspectRatio],
8459
6877
  children: renderImage ? renderImage({
8460
6878
  src: imageUrl,
8461
6879
  alt: service.name,
@@ -8465,36 +6883,35 @@ function ServiceCard({
8465
6883
  {
8466
6884
  src: imageUrl,
8467
6885
  alt: service.name,
8468
- className: classNames?.image,
8469
- style: { width: "100%", height: "100%", objectFit: "cover" },
6886
+ className: cn("w-full h-full object-cover transition-transform duration-300 group-hover:scale-105", classNames?.image),
8470
6887
  "data-cimplify-service-card-image": true
8471
6888
  }
8472
6889
  )
8473
6890
  }
8474
6891
  ),
8475
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-service-card-body": true, className: classNames?.body, children: [
8476
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-name": true, className: classNames?.name, children: service.name }),
6892
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-service-card-body": true, className: cn("p-4 flex flex-col gap-1.5", classNames?.body), children: [
6893
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-name": true, className: cn("font-semibold text-foreground leading-tight", classNames?.name), children: service.name }),
8477
6894
  service.description && /* @__PURE__ */ jsxRuntime.jsx(
8478
6895
  "span",
8479
6896
  {
8480
6897
  "data-cimplify-service-card-description": true,
8481
- className: classNames?.description,
8482
- style: {
8483
- display: "-webkit-box",
8484
- WebkitLineClamp: 2,
8485
- WebkitBoxOrient: "vertical",
8486
- overflow: "hidden"
8487
- },
6898
+ className: cn("text-sm text-muted-foreground line-clamp-2", classNames?.description),
8488
6899
  children: service.description
8489
6900
  }
8490
6901
  ),
8491
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-service-card-meta": true, className: classNames?.meta, children: [
8492
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-duration": true, className: classNames?.duration, children: formatDuration2(service.duration_minutes, service.duration_unit) }),
8493
- service.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-price": true, className: classNames?.price, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: service.price }) })
6902
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-service-card-meta": true, className: cn("flex items-center gap-2 mt-1 text-sm", classNames?.meta), children: [
6903
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-duration": true, className: cn("text-muted-foreground", classNames?.duration), children: formatDuration2(service.duration_minutes, service.duration_unit) }),
6904
+ service.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-price": true, className: cn("font-medium text-foreground", classNames?.price), children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: service.price }) })
8494
6905
  ] })
8495
6906
  ] }),
8496
- !href && onBook && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-action": true, className: classNames?.action, children: actionLabel })
6907
+ !href && onBook && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-service-card-action": true, className: cn("px-4 pb-4 pt-1 text-sm font-medium text-primary", classNames?.action), children: actionLabel })
8497
6908
  ] });
6909
+ const cardClasses = cn(
6910
+ "group block w-full rounded-xl border border-border bg-background text-left transition-shadow duration-200 hover:shadow-md",
6911
+ !service.is_available && "opacity-60",
6912
+ className,
6913
+ classNames?.root
6914
+ );
8498
6915
  if (href) {
8499
6916
  return /* @__PURE__ */ jsxRuntime.jsx(
8500
6917
  "a",
@@ -8502,8 +6919,7 @@ function ServiceCard({
8502
6919
  href,
8503
6920
  "data-cimplify-service-card": true,
8504
6921
  "data-available": service.is_available || void 0,
8505
- className: cn(className, classNames?.root),
8506
- style: { display: "block", textDecoration: "none", color: "inherit" },
6922
+ className: cn(cardClasses, "no-underline text-[inherit]"),
8507
6923
  children: cardBody
8508
6924
  }
8509
6925
  );
@@ -8516,18 +6932,7 @@ function ServiceCard({
8516
6932
  disabled: !service.is_available,
8517
6933
  "data-cimplify-service-card": true,
8518
6934
  "data-available": service.is_available || void 0,
8519
- className: cn(className, classNames?.root),
8520
- style: {
8521
- display: "block",
8522
- width: "100%",
8523
- textAlign: "inherit",
8524
- background: "none",
8525
- border: "none",
8526
- padding: 0,
8527
- cursor: service.is_available ? "pointer" : "default",
8528
- font: "inherit",
8529
- color: "inherit"
8530
- },
6935
+ className: cn(cardClasses, "cursor-pointer font-[inherit] p-0 border-border"),
8531
6936
  children: cardBody
8532
6937
  }
8533
6938
  );
@@ -9263,10 +7668,114 @@ function DealsPage({
9263
7668
  isEmpty && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-deals-empty": true, className: classNames?.empty, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No deals available right now. Check back soon!" }) })
9264
7669
  ] });
9265
7670
  }
7671
+ var ANY_VALUE2 = "__any__";
7672
+ function roomToResource(room) {
7673
+ return {
7674
+ id: room.id,
7675
+ name: room.name,
7676
+ capacity: room.capacity,
7677
+ floor: room.floor,
7678
+ is_available: room.status === "available"
7679
+ };
7680
+ }
7681
+ function ResourcePicker({
7682
+ resources,
7683
+ selectedResourceId,
7684
+ onResourceSelect,
7685
+ showAnyOption = true,
7686
+ anyLabel = "Any available",
7687
+ renderImage,
7688
+ className,
7689
+ classNames
7690
+ }) {
7691
+ const groupValue = selectedResourceId === null ? ANY_VALUE2 : selectedResourceId ?? "";
7692
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7693
+ radioGroup.RadioGroup,
7694
+ {
7695
+ "data-cimplify-resource-picker": true,
7696
+ className: cn("flex flex-col gap-2", className, classNames?.root),
7697
+ value: groupValue,
7698
+ onValueChange: (value) => {
7699
+ onResourceSelect?.(value === ANY_VALUE2 ? null : value);
7700
+ },
7701
+ children: [
7702
+ showAnyOption && /* @__PURE__ */ jsxRuntime.jsx(
7703
+ radio.Radio.Root,
7704
+ {
7705
+ value: ANY_VALUE2,
7706
+ "data-cimplify-resource-option": true,
7707
+ "data-selected": selectedResourceId === null || void 0,
7708
+ "data-any": true,
7709
+ className: cn(
7710
+ "flex items-center gap-3 rounded-lg border border-border p-3 transition-colors cursor-pointer",
7711
+ "hover:bg-muted data-[checked]:border-primary data-[checked]:bg-primary/5",
7712
+ classNames?.option
7713
+ ),
7714
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-resource-name": true, className: cn("font-medium text-foreground", classNames?.name), children: anyLabel })
7715
+ }
7716
+ ),
7717
+ resources.map((resource) => {
7718
+ const unavailable = resource.is_available === false;
7719
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7720
+ radio.Radio.Root,
7721
+ {
7722
+ value: resource.id,
7723
+ disabled: unavailable,
7724
+ "data-cimplify-resource-option": true,
7725
+ "data-selected": selectedResourceId === resource.id || void 0,
7726
+ "data-unavailable": unavailable || void 0,
7727
+ className: cn(
7728
+ "flex items-center gap-3 rounded-lg border border-border p-3 transition-colors cursor-pointer",
7729
+ "hover:bg-muted data-[checked]:border-primary data-[checked]:bg-primary/5",
7730
+ unavailable && "opacity-50 cursor-not-allowed",
7731
+ classNames?.option,
7732
+ unavailable ? classNames?.unavailable : void 0
7733
+ ),
7734
+ children: [
7735
+ resource.image_url && (renderImage ? renderImage({
7736
+ src: resource.image_url,
7737
+ alt: resource.name,
7738
+ className: classNames?.image
7739
+ }) : /* @__PURE__ */ jsxRuntime.jsx(
7740
+ "img",
7741
+ {
7742
+ src: resource.image_url,
7743
+ alt: resource.name,
7744
+ "data-cimplify-resource-image": true,
7745
+ className: cn("w-10 h-10 rounded-lg object-cover", classNames?.image)
7746
+ }
7747
+ )),
7748
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5 flex-1 min-w-0", children: [
7749
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-resource-name": true, className: cn("font-medium text-foreground", classNames?.name), children: resource.name }),
7750
+ resource.description && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-resource-description": true, className: cn("text-sm text-muted-foreground truncate", classNames?.description), children: resource.description }),
7751
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-resource-meta": true, className: cn("flex items-center gap-2 text-xs text-muted-foreground", classNames?.meta), children: [
7752
+ resource.capacity !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-resource-capacity": true, className: classNames?.capacity, children: [
7753
+ "Up to ",
7754
+ resource.capacity
7755
+ ] }),
7756
+ resource.floor && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-resource-floor": true, className: classNames?.floor, children: resource.floor })
7757
+ ] })
7758
+ ] })
7759
+ ]
7760
+ },
7761
+ resource.id
7762
+ );
7763
+ })
7764
+ ]
7765
+ }
7766
+ );
7767
+ }
7768
+ var STEP = {
7769
+ SELECT_SLOT: "select-slot",
7770
+ SELECT_RESOURCE: "select-resource",
7771
+ SELECT_STAFF: "select-staff",
7772
+ CONFIRM: "confirm"
7773
+ };
9266
7774
  function BookingPage({
9267
7775
  service,
9268
7776
  product,
9269
7777
  staff,
7778
+ resources,
9270
7779
  participantCount,
9271
7780
  title,
9272
7781
  onBooked,
@@ -9280,12 +7789,14 @@ function BookingPage({
9280
7789
  const { addItem } = useCart();
9281
7790
  const { client } = useCimplifyClient();
9282
7791
  const isReschedule = existingBooking !== void 0;
9283
- const [step, setStep] = React3.useState("select-slot");
7792
+ const [step, setStep] = React3.useState(STEP.SELECT_SLOT);
9284
7793
  const [selectedSlot, setSelectedSlot] = React3.useState(null);
9285
7794
  const [selectedDate, setSelectedDate] = React3.useState(null);
9286
7795
  const [selectedStaffId, setSelectedStaffId] = React3.useState(null);
7796
+ const [selectedResourceId, setSelectedResourceId] = React3.useState(null);
9287
7797
  const [isSubmitting, setIsSubmitting] = React3.useState(false);
9288
7798
  const [error, setError] = React3.useState(null);
7799
+ const hasResourceStep = resources && resources.length > 0;
9289
7800
  const hasStaffStep = staff && staff.length > 0;
9290
7801
  const depositType = product?.deposit_type;
9291
7802
  const depositAmount = product?.deposit_amount;
@@ -9297,28 +7808,45 @@ function BookingPage({
9297
7808
  setSelectedSlot(slot);
9298
7809
  setSelectedDate(date);
9299
7810
  setError(null);
7811
+ if (hasResourceStep) {
7812
+ setStep(STEP.SELECT_RESOURCE);
7813
+ } else if (hasStaffStep) {
7814
+ setStep(STEP.SELECT_STAFF);
7815
+ } else {
7816
+ setStep(STEP.CONFIRM);
7817
+ }
7818
+ },
7819
+ [hasResourceStep, hasStaffStep]
7820
+ );
7821
+ const handleResourceSelect = React3.useCallback(
7822
+ (resourceId) => {
7823
+ setSelectedResourceId(resourceId);
9300
7824
  if (hasStaffStep) {
9301
- setStep("select-staff");
7825
+ setStep(STEP.SELECT_STAFF);
9302
7826
  } else {
9303
- setStep("confirm");
7827
+ setStep(STEP.CONFIRM);
9304
7828
  }
9305
7829
  },
9306
7830
  [hasStaffStep]
9307
7831
  );
9308
7832
  const handleStaffSelect = React3.useCallback((staffId) => {
9309
7833
  setSelectedStaffId(staffId);
9310
- setStep("confirm");
7834
+ setStep(STEP.CONFIRM);
9311
7835
  }, []);
9312
7836
  const handleBack = React3.useCallback(() => {
9313
7837
  setError(null);
9314
- if (step === "confirm" && hasStaffStep) {
9315
- setStep("select-staff");
9316
- } else if (step === "confirm" || step === "select-staff") {
9317
- setStep("select-slot");
7838
+ if (step === STEP.CONFIRM && hasStaffStep) {
7839
+ setStep(STEP.SELECT_STAFF);
7840
+ } else if (step === STEP.CONFIRM && hasResourceStep) {
7841
+ setStep(STEP.SELECT_RESOURCE);
7842
+ } else if (step === STEP.SELECT_STAFF && hasResourceStep) {
7843
+ setStep(STEP.SELECT_RESOURCE);
7844
+ } else if (step === STEP.CONFIRM || step === STEP.SELECT_STAFF || step === STEP.SELECT_RESOURCE) {
7845
+ setStep(STEP.SELECT_SLOT);
9318
7846
  } else {
9319
7847
  onBack?.();
9320
7848
  }
9321
- }, [step, hasStaffStep, onBack]);
7849
+ }, [step, hasStaffStep, hasResourceStep, onBack]);
9322
7850
  const handleConfirm = React3.useCallback(async () => {
9323
7851
  if (!selectedSlot || !selectedDate) return;
9324
7852
  setIsSubmitting(true);
@@ -9358,7 +7886,8 @@ function BookingPage({
9358
7886
  await addItem(serviceProduct, 1, {
9359
7887
  scheduledStart: selectedSlot.start_time,
9360
7888
  scheduledEnd: selectedSlot.end_time,
9361
- staffId: selectedStaffId || void 0
7889
+ staffId: selectedStaffId || void 0,
7890
+ resourceId: selectedResourceId || void 0
9362
7891
  });
9363
7892
  onBooked?.(selectedSlot, selectedStaffId);
9364
7893
  }
@@ -9371,7 +7900,7 @@ function BookingPage({
9371
7900
  }, [selectedSlot, selectedDate, selectedStaffId, service, addItem, onBooked, isReschedule, existingBooking, client, onRescheduled]);
9372
7901
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-page": true, className: cn(className, classNames?.root), children: [
9373
7902
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-page-header": true, className: classNames?.header, children: [
9374
- onBack && step === "select-slot" && /* @__PURE__ */ jsxRuntime.jsx(
7903
+ onBack && step === STEP.SELECT_SLOT && /* @__PURE__ */ jsxRuntime.jsx(
9375
7904
  "button",
9376
7905
  {
9377
7906
  type: "button",
@@ -9381,7 +7910,7 @@ function BookingPage({
9381
7910
  children: "Back"
9382
7911
  }
9383
7912
  ),
9384
- step !== "select-slot" && /* @__PURE__ */ jsxRuntime.jsx(
7913
+ step !== STEP.SELECT_SLOT && /* @__PURE__ */ jsxRuntime.jsx(
9385
7914
  "button",
9386
7915
  {
9387
7916
  type: "button",
@@ -9416,7 +7945,7 @@ function BookingPage({
9416
7945
  ] })
9417
7946
  ] }),
9418
7947
  error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-booking-error": true, className: classNames?.error, children: error }),
9419
- step === "select-slot" && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "select-slot", className: classNames?.step, children: [
7948
+ step === STEP.SELECT_SLOT && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "select-slot", className: classNames?.step, children: [
9420
7949
  /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-cimplify-booking-step-title": true, className: classNames?.stepTitle, children: "Select a date & time" }),
9421
7950
  /* @__PURE__ */ jsxRuntime.jsx(
9422
7951
  DateSlotPicker,
@@ -9429,7 +7958,18 @@ function BookingPage({
9429
7958
  }
9430
7959
  )
9431
7960
  ] }),
9432
- step === "select-staff" && staff && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "select-staff", className: classNames?.step, children: [
7961
+ step === STEP.SELECT_RESOURCE && resources && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "select-resource", className: cn(classNames?.step, classNames?.resourceStep), children: [
7962
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-cimplify-booking-step-title": true, className: classNames?.stepTitle, children: "Choose a room" }),
7963
+ /* @__PURE__ */ jsxRuntime.jsx(
7964
+ ResourcePicker,
7965
+ {
7966
+ resources,
7967
+ selectedResourceId,
7968
+ onResourceSelect: handleResourceSelect
7969
+ }
7970
+ )
7971
+ ] }),
7972
+ step === STEP.SELECT_STAFF && staff && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "select-staff", className: classNames?.step, children: [
9433
7973
  /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-cimplify-booking-step-title": true, className: classNames?.stepTitle, children: "Choose a provider" }),
9434
7974
  /* @__PURE__ */ jsxRuntime.jsx(
9435
7975
  StaffPicker,
@@ -9440,7 +7980,7 @@ function BookingPage({
9440
7980
  }
9441
7981
  )
9442
7982
  ] }),
9443
- step === "confirm" && selectedSlot && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "confirm", className: classNames?.step, children: [
7983
+ step === STEP.CONFIRM && selectedSlot && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-step": "confirm", className: classNames?.step, children: [
9444
7984
  /* @__PURE__ */ jsxRuntime.jsx("h2", { "data-cimplify-booking-step-title": true, className: classNames?.stepTitle, children: "Confirm your booking" }),
9445
7985
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary": true, className: classNames?.summary, children: [
9446
7986
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
@@ -9462,6 +8002,10 @@ function BookingPage({
9462
8002
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Duration" }),
9463
8003
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatDuration2(service.duration_minutes, service.duration_unit) })
9464
8004
  ] }),
8005
+ selectedResourceId && resources && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
8006
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Room" }),
8007
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: resources.find((r) => r.id === selectedResourceId)?.name ?? "Selected" })
8008
+ ] }),
9465
8009
  selectedStaffId && staff && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-booking-summary-row": true, className: classNames?.summaryRow, children: [
9466
8010
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Provider" }),
9467
8011
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: staff.find((s) => s.id === selectedStaffId)?.name ?? "Selected" })
@@ -10079,6 +8623,7 @@ exports.ProductSheet = ProductSheet;
10079
8623
  exports.QuantitySelector = QuantitySelector;
10080
8624
  exports.RecentlyViewed = RecentlyViewed;
10081
8625
  exports.RecommendationCarousel = RecommendationCarousel;
8626
+ exports.ResourcePicker = ResourcePicker;
10082
8627
  exports.SaleBadge = SaleBadge;
10083
8628
  exports.SearchInput = SearchInput;
10084
8629
  exports.SearchPage = SearchPage;
@@ -10090,6 +8635,7 @@ exports.StaffPicker = StaffPicker;
10090
8635
  exports.StoreNav = StoreNav;
10091
8636
  exports.VariantSelector = VariantSelector;
10092
8637
  exports.cn = cn;
8638
+ exports.roomToResource = roomToResource;
10093
8639
  exports.useActivityState = useActivityState;
10094
8640
  exports.useAds = useAds;
10095
8641
  exports.useAttributeDefinitions = useAttributeDefinitions;