arky-sdk 0.3.83 → 0.3.85

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/index.cjs CHANGED
@@ -1,7 +1,5 @@
1
1
  'use strict';
2
2
 
3
- var nanostores = require('nanostores');
4
-
5
3
  // src/types/index.ts
6
4
  var PaymentMethodType = /* @__PURE__ */ ((PaymentMethodType2) => {
7
5
  PaymentMethodType2["Cash"] = "CASH";
@@ -1713,6 +1711,8 @@ async function injectSvgIntoElement(mediaObject, targetElement, className) {
1713
1711
  console.error("Error injecting SVG:", error);
1714
1712
  }
1715
1713
  }
1714
+
1715
+ // src/utils/time.ts
1716
1716
  function formatTime(ts, tz) {
1717
1717
  return new Date(ts * 1e3).toLocaleTimeString([], {
1718
1718
  hour: "2-digit",
@@ -1733,17 +1733,38 @@ function toUtcTimestamp(year, month, day, mins, tz) {
1733
1733
  const offset = getTzOffset(midnight, tz);
1734
1734
  return Math.floor(midnight.getTime() / 1e3) + (mins + offset) * 60;
1735
1735
  }
1736
+ function formatDateDisplay(dateStr, tz) {
1737
+ if (!dateStr) return "";
1738
+ const date = /* @__PURE__ */ new Date(dateStr + "T00:00:00");
1739
+ return date.toLocaleDateString("en-US", {
1740
+ weekday: "short",
1741
+ month: "short",
1742
+ day: "numeric",
1743
+ timeZone: tz
1744
+ });
1745
+ }
1746
+ function getIsoDate(date, tz) {
1747
+ return date.toLocaleDateString("en-CA", { timeZone: tz });
1748
+ }
1749
+ function parseIsoDate(isoDate) {
1750
+ const [year, month, day] = isoDate.split("-").map(Number);
1751
+ return { year, month, day };
1752
+ }
1753
+
1754
+ // src/utils/slots.ts
1755
+ function getTotalDuration(durations) {
1756
+ return durations.reduce((sum, d) => sum + d.duration, 0);
1757
+ }
1736
1758
  function isBlocked(from, to, timeline, limit) {
1737
1759
  const before = timeline.filter((p) => p.timestamp <= from).sort((a, b) => b.timestamp - a.timestamp);
1738
1760
  if (before.length > 0 && before[0].concurrent >= limit) return true;
1739
1761
  for (const p of timeline) {
1740
- if (p.timestamp >= from && p.timestamp < to && p.concurrent >= limit) return true;
1762
+ if (p.timestamp >= from && p.timestamp < to && p.concurrent >= limit) {
1763
+ return true;
1764
+ }
1741
1765
  }
1742
1766
  return false;
1743
1767
  }
1744
- function getTotalDuration(durations) {
1745
- return durations.reduce((sum, d) => sum + d.duration, 0);
1746
- }
1747
1768
  function getWorkingHoursForDate(wt, date, tz) {
1748
1769
  if (!wt) return [];
1749
1770
  const dayName = date.toLocaleDateString("en-US", { weekday: "long", timeZone: tz }).toLowerCase();
@@ -1766,14 +1787,15 @@ function computeSlotsForDate(opts) {
1766
1787
  today.setHours(0, 0, 0, 0);
1767
1788
  if (date < today) return [];
1768
1789
  const [year, month, day] = date.toLocaleDateString("en-CA", { timeZone: timezone }).split("-").map(Number);
1769
- for (const p of providers) {
1770
- for (const wh of getWorkingHoursForDate(p.workingTime, date, timezone)) {
1790
+ for (const provider of providers) {
1791
+ const workingHours = getWorkingHoursForDate(provider.workingTime, date, timezone);
1792
+ for (const wh of workingHours) {
1771
1793
  for (let m = wh.from; m + total <= wh.to; m += interval) {
1772
1794
  const from = toUtcTimestamp(year, month, day, m, timezone);
1773
1795
  const to = from + total * 60;
1774
1796
  if (from < nowTs) continue;
1775
- if (!isBlocked(from, to, p.timeline, p.concurrentLimit)) {
1776
- slots.push({ from, to, providerId: p.id });
1797
+ if (!isBlocked(from, to, provider.timeline, provider.concurrentLimit)) {
1798
+ slots.push({ from, to, providerId: provider.id });
1777
1799
  }
1778
1800
  }
1779
1801
  }
@@ -1783,240 +1805,71 @@ function computeSlotsForDate(opts) {
1783
1805
  function hasAvailableSlots(opts) {
1784
1806
  return computeSlotsForDate(opts).length > 0;
1785
1807
  }
1786
- var createInitialState = (timezone) => ({
1787
- service: null,
1788
- providers: [],
1789
- selectedProvider: null,
1790
- currentMonth: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
1791
- calendar: [],
1792
- selectedDate: null,
1793
- startDate: null,
1794
- endDate: null,
1795
- slots: [],
1796
- selectedSlot: null,
1797
- cart: [],
1798
- timezone,
1799
- loading: false
1800
- });
1801
- var createReservationEngine = (api, config = {}) => {
1802
- const timezone = config.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
1803
- const store = nanostores.map(createInitialState(timezone));
1804
- const getServiceDurations = () => {
1805
- const state = store.get();
1806
- if (!state.service?.durations?.length) return [{ duration: 60, isPause: false }];
1807
- return state.service.durations.map((d) => ({
1808
- duration: d.duration,
1809
- isPause: d.isPause || d.is_pause || false
1810
- }));
1811
- };
1812
- const buildCalendar = () => {
1813
- const state = store.get();
1814
- const { currentMonth, selectedDate, startDate, endDate, providers, selectedProvider, timezone: timezone2 } = state;
1815
- const year = currentMonth.getFullYear();
1816
- const month = currentMonth.getMonth();
1817
- const first = new Date(year, month, 1);
1818
- const last = new Date(year, month + 1, 0);
1819
- const today = /* @__PURE__ */ new Date();
1820
- today.setHours(0, 0, 0, 0);
1821
- const cells = [];
1822
- const pad = (first.getDay() + 6) % 7;
1823
- for (let i = 0; i < pad; i++) {
1824
- cells.push({ date: /* @__PURE__ */ new Date(0), iso: "", available: false, isSelected: false, isInRange: false, isToday: false, blank: true });
1825
- }
1826
- const activeProviders = selectedProvider ? providers.filter((p) => p.id === selectedProvider.id) : providers;
1827
- const durations = getServiceDurations();
1828
- for (let d = 1; d <= last.getDate(); d++) {
1829
- const date = new Date(year, month, d);
1830
- const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
1831
- const available = activeProviders.length > 0 && hasAvailableSlots({ providers: activeProviders, date, durations, timezone: timezone2 });
1832
- const isToday = date.getTime() === today.getTime();
1833
- const isSelected = iso === selectedDate || iso === startDate || iso === endDate;
1834
- let isInRange = false;
1808
+ function buildCalendar(opts) {
1809
+ const {
1810
+ currentMonth,
1811
+ selectedDate,
1812
+ startDate,
1813
+ endDate,
1814
+ providers,
1815
+ selectedProvider,
1816
+ durations,
1817
+ timezone,
1818
+ isMultiDay
1819
+ } = opts;
1820
+ const year = currentMonth.getFullYear();
1821
+ const month = currentMonth.getMonth();
1822
+ const first = new Date(year, month, 1);
1823
+ const last = new Date(year, month + 1, 0);
1824
+ const today = /* @__PURE__ */ new Date();
1825
+ today.setHours(0, 0, 0, 0);
1826
+ const cells = [];
1827
+ const pad = (first.getDay() + 6) % 7;
1828
+ for (let i = 0; i < pad; i++) {
1829
+ cells.push({
1830
+ date: /* @__PURE__ */ new Date(0),
1831
+ iso: "",
1832
+ available: false,
1833
+ isSelected: false,
1834
+ isInRange: false,
1835
+ isToday: false,
1836
+ blank: true
1837
+ });
1838
+ }
1839
+ const activeProviders = selectedProvider ? providers.filter((p) => p.id === selectedProvider.id) : providers;
1840
+ for (let d = 1; d <= last.getDate(); d++) {
1841
+ const date = new Date(year, month, d);
1842
+ const iso = `${year}-${String(month + 1).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
1843
+ const available = activeProviders.length > 0 && hasAvailableSlots({ providers: activeProviders, date, durations, timezone });
1844
+ const isToday = date.getTime() === today.getTime();
1845
+ let isSelected = false;
1846
+ let isInRange = false;
1847
+ if (isMultiDay) {
1848
+ isSelected = iso === startDate || iso === endDate;
1835
1849
  if (startDate && endDate) {
1836
- const t = date.getTime();
1837
- isInRange = t > new Date(startDate).getTime() && t < new Date(endDate).getTime();
1838
- }
1839
- cells.push({ date, iso, available, isSelected, isInRange, isToday, blank: false });
1840
- }
1841
- const suffix = (7 - cells.length % 7) % 7;
1842
- for (let i = 0; i < suffix; i++) {
1843
- cells.push({ date: /* @__PURE__ */ new Date(0), iso: "", available: false, isSelected: false, isInRange: false, isToday: false, blank: true });
1844
- }
1845
- return cells;
1846
- };
1847
- const computeSlots = (dateStr) => {
1848
- const state = store.get();
1849
- const { providers, selectedProvider, timezone: timezone2, service } = state;
1850
- const date = /* @__PURE__ */ new Date(dateStr + "T00:00:00");
1851
- const activeProviders = selectedProvider ? providers.filter((p) => p.id === selectedProvider.id) : providers;
1852
- const raw = computeSlotsForDate({ providers: activeProviders, date, durations: getServiceDurations(), timezone: timezone2 });
1853
- return raw.map((s, i) => ({
1854
- id: `${service?.id}-${s.from}-${i}`,
1855
- serviceId: service?.id || "",
1856
- providerId: s.providerId,
1857
- from: s.from,
1858
- to: s.to,
1859
- timeText: formatSlotTime(s.from, s.to, timezone2),
1860
- dateText: new Date(s.from * 1e3).toLocaleDateString([], { weekday: "short", month: "short", day: "numeric", timeZone: timezone2 })
1861
- }));
1862
- };
1863
- const actions = {
1864
- setTimezone(tz) {
1865
- store.setKey("timezone", tz);
1866
- store.setKey("calendar", buildCalendar());
1867
- const state = store.get();
1868
- if (state.selectedDate) {
1869
- store.setKey("slots", computeSlots(state.selectedDate));
1870
- store.setKey("selectedSlot", null);
1871
- }
1872
- },
1873
- async setService(serviceId) {
1874
- store.setKey("loading", true);
1875
- try {
1876
- const service = await api.getService({ id: serviceId });
1877
- store.set({
1878
- ...store.get(),
1879
- service,
1880
- selectedProvider: null,
1881
- providers: [],
1882
- selectedDate: null,
1883
- startDate: null,
1884
- endDate: null,
1885
- slots: [],
1886
- selectedSlot: null,
1887
- currentMonth: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
1888
- loading: false
1889
- });
1890
- await actions.loadMonth();
1891
- } catch (e) {
1892
- store.setKey("loading", false);
1893
- throw e;
1894
- }
1895
- },
1896
- async loadMonth() {
1897
- const state = store.get();
1898
- if (!state.service) return;
1899
- store.setKey("loading", true);
1900
- try {
1901
- const { currentMonth, service } = state;
1902
- const year = currentMonth.getFullYear();
1903
- const month = currentMonth.getMonth();
1904
- const from = Math.floor(new Date(year, month, 1).getTime() / 1e3);
1905
- const to = Math.floor(new Date(year, month + 1, 0, 23, 59, 59).getTime() / 1e3);
1906
- const providers = await api.getServiceProviders({ serviceId: service.id, from, to });
1907
- store.setKey("providers", providers || []);
1908
- store.setKey("calendar", buildCalendar());
1909
- } finally {
1910
- store.setKey("loading", false);
1911
- }
1912
- },
1913
- prevMonth() {
1914
- const { currentMonth } = store.get();
1915
- store.setKey("currentMonth", new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1));
1916
- actions.loadMonth();
1917
- },
1918
- nextMonth() {
1919
- const { currentMonth } = store.get();
1920
- store.setKey("currentMonth", new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1));
1921
- actions.loadMonth();
1922
- },
1923
- selectProvider(provider) {
1924
- store.set({
1925
- ...store.get(),
1926
- selectedProvider: provider,
1927
- selectedDate: null,
1928
- startDate: null,
1929
- endDate: null,
1930
- slots: [],
1931
- selectedSlot: null
1932
- });
1933
- store.setKey("calendar", buildCalendar());
1934
- },
1935
- selectDate(day) {
1936
- if (day.blank || !day.available) return;
1937
- const state = store.get();
1938
- const slots = computeSlots(day.iso);
1939
- store.set({ ...state, selectedDate: day.iso, slots, selectedSlot: null });
1940
- store.setKey("calendar", buildCalendar());
1941
- },
1942
- selectSlot(slot) {
1943
- store.setKey("selectedSlot", slot);
1944
- },
1945
- findFirstAvailable() {
1946
- const state = store.get();
1947
- for (const day of state.calendar) {
1948
- if (!day.blank && day.available) {
1949
- actions.selectDate(day);
1950
- return;
1951
- }
1952
- }
1953
- },
1954
- updateCalendar() {
1955
- store.setKey("calendar", buildCalendar());
1956
- },
1957
- addToCart() {
1958
- const state = store.get();
1959
- if (!state.selectedSlot) return;
1960
- store.set({
1961
- ...state,
1962
- cart: [...state.cart, state.selectedSlot],
1963
- selectedDate: null,
1964
- startDate: null,
1965
- endDate: null,
1966
- slots: [],
1967
- selectedSlot: null
1968
- });
1969
- store.setKey("calendar", buildCalendar());
1970
- },
1971
- removeFromCart(slotId) {
1972
- const state = store.get();
1973
- store.setKey("cart", state.cart.filter((s) => s.id !== slotId));
1974
- },
1975
- clearCart() {
1976
- store.setKey("cart", []);
1977
- },
1978
- async checkout(options = {}) {
1979
- const state = store.get();
1980
- if (!state.cart.length) throw new Error("Cart is empty");
1981
- store.setKey("loading", true);
1982
- try {
1983
- return api.checkout({
1984
- items: state.cart.map((s) => ({
1985
- serviceId: s.serviceId,
1986
- providerId: s.providerId,
1987
- from: s.from,
1988
- to: s.to,
1989
- blocks: s.serviceBlocks || []
1990
- })),
1991
- paymentMethod: options.paymentMethod,
1992
- promoCode: options.promoCode ?? null,
1993
- blocks: options.blocks || []
1994
- });
1995
- } finally {
1996
- store.setKey("loading", false);
1850
+ isInRange = iso > startDate && iso < endDate;
1997
1851
  }
1998
- },
1999
- async getQuote(options = {}) {
2000
- const state = store.get();
2001
- if (!state.cart.length) return null;
2002
- return api.getQuote({
2003
- items: state.cart.map((s) => ({ serviceId: s.serviceId })),
2004
- paymentMethod: options.paymentMethod || "CASH",
2005
- promoCode: options.promoCode
2006
- });
2007
- },
2008
- async getProvidersList() {
2009
- const state = store.get();
2010
- if (!state.service) return [];
2011
- const response = await api.getProviders({ serviceId: state.service.id, limit: 100 });
2012
- return response?.items || [];
1852
+ } else {
1853
+ isSelected = iso === selectedDate;
2013
1854
  }
2014
- };
2015
- return { store, ...actions };
2016
- };
1855
+ cells.push({
1856
+ date,
1857
+ iso,
1858
+ available,
1859
+ isSelected,
1860
+ isInRange,
1861
+ isToday,
1862
+ blank: false
1863
+ });
1864
+ }
1865
+ return cells;
1866
+ }
1867
+ function getMonthYear(date) {
1868
+ return date.toLocaleDateString("en-US", { month: "long", year: "numeric" });
1869
+ }
2017
1870
 
2018
1871
  // src/index.ts
2019
- var SDK_VERSION = "0.3.83";
1872
+ var SDK_VERSION = "0.3.85";
2020
1873
  var SUPPORTED_FRAMEWORKS = [
2021
1874
  "astro",
2022
1875
  "react",
@@ -2067,11 +1920,6 @@ async function createArkySDK(config) {
2067
1920
  database: createDatabaseApi(apiConfig),
2068
1921
  featureFlags: createFeatureFlagsApi(apiConfig),
2069
1922
  location: createLocationApi(apiConfig),
2070
- // High-level reservation engine
2071
- reservationEngine: (engineConfig) => {
2072
- const reservationApi = createReservationApi(apiConfig);
2073
- return createReservationEngine(reservationApi, engineConfig);
2074
- },
2075
1923
  setBusinessId: (businessId) => {
2076
1924
  apiConfig.businessId = businessId;
2077
1925
  },
@@ -2122,7 +1970,23 @@ async function createArkySDK(config) {
2122
1970
  // SVG utilities
2123
1971
  getSvgContentForAstro,
2124
1972
  fetchSvgContent,
2125
- injectSvgIntoElement
1973
+ injectSvgIntoElement,
1974
+ // Time utilities
1975
+ formatTime,
1976
+ formatSlotTime,
1977
+ getTzOffset,
1978
+ toUtcTimestamp,
1979
+ formatDateDisplay,
1980
+ getIsoDate,
1981
+ parseIsoDate,
1982
+ // Slot computation utilities
1983
+ computeSlotsForDate,
1984
+ hasAvailableSlots,
1985
+ buildCalendar,
1986
+ getMonthYear,
1987
+ getTotalDuration,
1988
+ isBlocked,
1989
+ getWorkingHoursForDate
2126
1990
  }
2127
1991
  };
2128
1992
  return sdk;