arky-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/api/cms.d.ts +19 -0
  2. package/dist/api/cms.d.ts.map +1 -0
  3. package/dist/api/cms.js +41 -0
  4. package/dist/api/eshop.d.ts +89 -0
  5. package/dist/api/eshop.d.ts.map +1 -0
  6. package/dist/api/eshop.js +183 -0
  7. package/dist/api/index.d.ts +6 -0
  8. package/dist/api/index.d.ts.map +1 -0
  9. package/dist/api/index.js +5 -0
  10. package/dist/api/newsletter.d.ts +32 -0
  11. package/dist/api/newsletter.d.ts.map +1 -0
  12. package/dist/api/newsletter.js +70 -0
  13. package/dist/api/reservation.d.ts +84 -0
  14. package/dist/api/reservation.d.ts.map +1 -0
  15. package/dist/api/reservation.js +239 -0
  16. package/dist/config.d.ts +15 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +20 -0
  19. package/dist/index.d.ts +26 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +57 -0
  22. package/dist/services/auth.d.ts +17 -0
  23. package/dist/services/auth.d.ts.map +1 -0
  24. package/dist/services/auth.js +62 -0
  25. package/dist/services/http.d.ts +20 -0
  26. package/dist/services/http.d.ts.map +1 -0
  27. package/dist/services/http.js +73 -0
  28. package/dist/stores/business.d.ts +28 -0
  29. package/dist/stores/business.d.ts.map +1 -0
  30. package/dist/stores/business.js +122 -0
  31. package/dist/stores/cart.d.ts +8 -0
  32. package/dist/stores/cart.d.ts.map +1 -0
  33. package/dist/stores/cart.js +20 -0
  34. package/dist/stores/eshop.d.ts +121 -0
  35. package/dist/stores/eshop.d.ts.map +1 -0
  36. package/dist/stores/eshop.js +377 -0
  37. package/dist/stores/index.d.ts +7 -0
  38. package/dist/stores/index.d.ts.map +1 -0
  39. package/dist/stores/index.js +19 -0
  40. package/dist/stores/reservation.d.ts +237 -0
  41. package/dist/stores/reservation.d.ts.map +1 -0
  42. package/dist/stores/reservation.js +853 -0
  43. package/dist/types/index.d.ts +244 -0
  44. package/dist/types/index.d.ts.map +1 -0
  45. package/dist/types/index.js +8 -0
  46. package/dist/utils/blocks.d.ts +30 -0
  47. package/dist/utils/blocks.d.ts.map +1 -0
  48. package/dist/utils/blocks.js +237 -0
  49. package/dist/utils/currency.d.ts +9 -0
  50. package/dist/utils/currency.d.ts.map +1 -0
  51. package/dist/utils/currency.js +99 -0
  52. package/dist/utils/errors.d.ts +121 -0
  53. package/dist/utils/errors.d.ts.map +1 -0
  54. package/dist/utils/errors.js +114 -0
  55. package/dist/utils/i18n.d.ts +5 -0
  56. package/dist/utils/i18n.d.ts.map +1 -0
  57. package/dist/utils/i18n.js +37 -0
  58. package/dist/utils/index.d.ts +9 -0
  59. package/dist/utils/index.d.ts.map +1 -0
  60. package/dist/utils/index.js +10 -0
  61. package/dist/utils/price.d.ts +33 -0
  62. package/dist/utils/price.d.ts.map +1 -0
  63. package/dist/utils/price.js +141 -0
  64. package/dist/utils/queryParams.d.ts +21 -0
  65. package/dist/utils/queryParams.d.ts.map +1 -0
  66. package/dist/utils/queryParams.js +47 -0
  67. package/dist/utils/svg.d.ts +17 -0
  68. package/dist/utils/svg.d.ts.map +1 -0
  69. package/dist/utils/svg.js +62 -0
  70. package/dist/utils/text.d.ts +26 -0
  71. package/dist/utils/text.d.ts.map +1 -0
  72. package/dist/utils/text.js +64 -0
  73. package/dist/utils/timezone.d.ts +9 -0
  74. package/dist/utils/timezone.d.ts.map +1 -0
  75. package/dist/utils/timezone.js +49 -0
  76. package/dist/utils/validation.d.ts +9 -0
  77. package/dist/utils/validation.d.ts.map +1 -0
  78. package/dist/utils/validation.js +44 -0
  79. package/package.json +58 -0
@@ -0,0 +1,122 @@
1
+ // Unified Business Store - Single Source of Truth
2
+ import { computed, deepMap } from "nanostores";
3
+ import { BUSINESS_ID } from "../config";
4
+ import * as authService from "../services/auth";
5
+ import { getCurrencySymbol } from "../utils/currency";
6
+ // Core business state
7
+ export const businessStore = deepMap({
8
+ data: null,
9
+ loading: false,
10
+ error: null,
11
+ initialized: false,
12
+ });
13
+ // Computed values derived from business data
14
+ export const selectedMarket = computed(businessStore, (state) => {
15
+ if (!state.data?.configs?.markets)
16
+ return null;
17
+ const markets = state.data.configs.markets;
18
+ // For arky website, always use 'us' market (hardcoded for headless)
19
+ return markets.find(m => m.id === 'us') ||
20
+ markets[0] ||
21
+ null;
22
+ });
23
+ export const currency = computed(selectedMarket, (market) => {
24
+ return market?.currency || 'USD';
25
+ });
26
+ export const currencySymbol = computed(selectedMarket, (market) => {
27
+ return getCurrencySymbol(market?.currency || 'USD');
28
+ });
29
+ export const markets = computed(businessStore, (state) => {
30
+ if (!state.data?.configs?.markets)
31
+ return [];
32
+ return state.data.configs.markets;
33
+ });
34
+ export const zones = computed(businessStore, (state) => {
35
+ if (!state.data?.configs?.zones)
36
+ return [];
37
+ return state.data.configs.zones;
38
+ });
39
+ // Get zone by country code
40
+ export const getZoneByCountry = (countryCode) => {
41
+ const allZones = zones.get();
42
+ return allZones.find(zone => zone.countries.length === 0 || // Empty = all countries
43
+ zone.countries.includes(countryCode.toUpperCase())) || null;
44
+ };
45
+ // Get shipping methods for a specific country
46
+ export const getShippingMethodsForCountry = (countryCode) => {
47
+ const zone = getZoneByCountry(countryCode);
48
+ return zone?.shippingMethods || [];
49
+ };
50
+ export const paymentMethods = computed(selectedMarket, (market) => {
51
+ if (!market)
52
+ return ['CASH'];
53
+ const methods = market.paymentMethods || [];
54
+ return methods.map((pm) => pm.method || pm);
55
+ });
56
+ export const paymentConfig = computed(businessStore, (state) => {
57
+ if (!state.data?.configs)
58
+ return { provider: null, enabled: false };
59
+ const provider = state.data.configs.paymentProvider || null;
60
+ const hasCreditCard = paymentMethods.get().includes('CREDIT_CARD');
61
+ return {
62
+ provider,
63
+ enabled: hasCreditCard && !!provider
64
+ };
65
+ });
66
+ export const orderBlocks = computed(businessStore, (state) => {
67
+ return state.data?.configs?.orderBlocks || [];
68
+ });
69
+ export const reservationBlocks = computed(businessStore, (state) => {
70
+ return state.data?.configs?.reservationBlocks || [];
71
+ });
72
+ // Actions
73
+ export const businessActions = {
74
+ // Initialize business data - SINGLE API CALL for entire app
75
+ async init() {
76
+ const state = businessStore.get();
77
+ if (state.initialized && state.data) {
78
+ // Already loaded, skip
79
+ return;
80
+ }
81
+ try {
82
+ businessStore.setKey('loading', true);
83
+ businessStore.setKey('error', null);
84
+ const result = await authService.getBusinessConfig(BUSINESS_ID);
85
+ if (result.success) {
86
+ businessStore.setKey('data', result.data);
87
+ businessStore.setKey('initialized', true);
88
+ }
89
+ else {
90
+ throw new Error(result.error || 'Failed to load business configuration');
91
+ }
92
+ }
93
+ catch (error) {
94
+ businessStore.setKey('error', error.message);
95
+ console.error('Business store initialization failed:', error);
96
+ }
97
+ finally {
98
+ businessStore.setKey('loading', false);
99
+ }
100
+ },
101
+ // Reset store (useful for testing)
102
+ reset() {
103
+ businessStore.setKey('data', null);
104
+ businessStore.setKey('loading', false);
105
+ businessStore.setKey('error', null);
106
+ businessStore.setKey('initialized', false);
107
+ },
108
+ // Get business data (with auto-init)
109
+ async getBusiness() {
110
+ const state = businessStore.get();
111
+ if (!state.initialized || !state.data) {
112
+ await this.init();
113
+ }
114
+ return businessStore.get().data;
115
+ }
116
+ };
117
+ // Export everything for easy access
118
+ export { businessStore as store, businessActions as actions };
119
+ // Auto-initialize on first import (ensures data is always available)
120
+ if (typeof window !== 'undefined') {
121
+ businessActions.init().catch(console.error);
122
+ }
@@ -0,0 +1,8 @@
1
+ export declare const totalCartItems: import("nanostores").ReadableAtom<number>;
2
+ export declare const hasEshopItems: import("nanostores").ReadableAtom<boolean>;
3
+ export declare const hasReservationItems: import("nanostores").ReadableAtom<boolean>;
4
+ export declare const isCartEmpty: import("nanostores").ReadableAtom<boolean>;
5
+ export declare const showEshopSection: import("nanostores").ReadableAtom<boolean>;
6
+ export declare const showReservationSection: import("nanostores").ReadableAtom<boolean>;
7
+ export declare const showBothSections: import("nanostores").ReadableAtom<boolean>;
8
+ //# sourceMappingURL=cart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../src/stores/cart.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc,2CAIzB,CAAC;AAGH,eAAO,MAAM,aAAa,4CAAqD,CAAC;AAChF,eAAO,MAAM,mBAAmB,4CAA2D,CAAC;AAC5F,eAAO,MAAM,WAAW,4CAEtB,CAAC;AAGH,eAAO,MAAM,gBAAgB,4CAAqF,CAAC;AACnH,eAAO,MAAM,sBAAsB,4CAAuG,CAAC;AAC3I,eAAO,MAAM,gBAAgB,4CAA2G,CAAC"}
@@ -0,0 +1,20 @@
1
+ // Unified cart store that manages both e-shop and reservation carts
2
+ import { computed } from "nanostores";
3
+ import { cartItems as eshopItems } from "./eshop";
4
+ import { cartParts as reservationItems } from "./reservation";
5
+ // Combined cart count
6
+ export const totalCartItems = computed([eshopItems, reservationItems], (eshop, reservation) => {
7
+ const eshopCount = eshop?.reduce((sum, item) => sum + item.quantity, 0) || 0;
8
+ const reservationCount = reservation?.length || 0;
9
+ return eshopCount + reservationCount;
10
+ });
11
+ // Cart state helpers
12
+ export const hasEshopItems = computed(eshopItems, (items) => items?.length > 0);
13
+ export const hasReservationItems = computed(reservationItems, (items) => items?.length > 0);
14
+ export const isCartEmpty = computed([eshopItems, reservationItems], (eshop, reservation) => {
15
+ return (!eshop || eshop.length === 0) && (!reservation || reservation.length === 0);
16
+ });
17
+ // Cart section visibility logic
18
+ export const showEshopSection = computed([hasEshopItems, isCartEmpty], (hasEshop, isEmpty) => hasEshop || isEmpty);
19
+ export const showReservationSection = computed([hasReservationItems, isCartEmpty], (hasReservation, isEmpty) => hasReservation || isEmpty);
20
+ export const showBothSections = computed([hasEshopItems, hasReservationItems], (hasEshop, hasReservation) => hasEshop && hasReservation);
@@ -0,0 +1,121 @@
1
+ import { currency, paymentConfig, orderBlocks } from "./business";
2
+ import type { EshopCartItem, Block, Price, Payment, Quote } from "../types";
3
+ import { PaymentMethod } from "../types";
4
+ export declare const cartItems: import("nanostores").WritableAtom<EshopCartItem[]>;
5
+ export declare const promoCodeAtom: import("nanostores").PreinitializedWritableAtom<string> & object;
6
+ export declare const quoteAtom: import("nanostores").PreinitializedWritableAtom<Quote> & object;
7
+ export declare const store: import("nanostores").DeepMapStore<{
8
+ businessId: string;
9
+ selectedShippingMethodId: any;
10
+ shippingLocation: any;
11
+ userToken: any;
12
+ processingCheckout: boolean;
13
+ loading: boolean;
14
+ error: any;
15
+ phoneNumber: string;
16
+ phoneError: any;
17
+ verificationCode: string;
18
+ verifyError: any;
19
+ fetchingQuote: boolean;
20
+ quoteError: any;
21
+ }>;
22
+ export declare const cartTotal: import("nanostores").ReadableAtom<Payment>;
23
+ export declare const cartItemCount: import("nanostores").ReadableAtom<number>;
24
+ export { currency, paymentConfig, orderBlocks };
25
+ export declare const allowedPaymentMethods: import("nanostores").ReadableAtom<any[]>;
26
+ export declare const actions: {
27
+ addItem(product: any, variant: any, quantity?: number): void;
28
+ updateQuantity(itemId: string, newQuantity: number): void;
29
+ removeItem(itemId: string): void;
30
+ clearCart(): void;
31
+ getGuestToken(): Promise<string>;
32
+ prepareOrderItems(): {
33
+ productId: string;
34
+ variantId: string;
35
+ quantity: number;
36
+ }[];
37
+ getOrderInfoBlocks(): Block[];
38
+ checkout(paymentMethod?: PaymentMethod, orderInfoBlocks?: Block[], promoCode?: string | null): Promise<{
39
+ success: boolean;
40
+ error: string;
41
+ data?: undefined;
42
+ } | {
43
+ success: boolean;
44
+ data: {
45
+ orderId: any;
46
+ orderNumber: any;
47
+ clientSecret: any;
48
+ };
49
+ error?: undefined;
50
+ }>;
51
+ updateProfilePhone(): Promise<boolean>;
52
+ verifyPhoneCode(): Promise<boolean>;
53
+ formatPrice(priceOrPayment: Price | Payment): string;
54
+ getCartPayment(): Payment;
55
+ getAvailablePaymentMethods(): PaymentMethod[];
56
+ getShippingMethodsForCountry(countryCode: string): import("..").ShippingMethod[];
57
+ fetchQuote(promoCode?: string | null): Promise<void>;
58
+ applyPromoCode(code: string): Promise<void>;
59
+ removePromoCode(): Promise<void>;
60
+ };
61
+ export declare function initEshopStore(): void;
62
+ declare const _default: {
63
+ store: import("nanostores").DeepMapStore<{
64
+ businessId: string;
65
+ selectedShippingMethodId: any;
66
+ shippingLocation: any;
67
+ userToken: any;
68
+ processingCheckout: boolean;
69
+ loading: boolean;
70
+ error: any;
71
+ phoneNumber: string;
72
+ phoneError: any;
73
+ verificationCode: string;
74
+ verifyError: any;
75
+ fetchingQuote: boolean;
76
+ quoteError: any;
77
+ }>;
78
+ actions: {
79
+ addItem(product: any, variant: any, quantity?: number): void;
80
+ updateQuantity(itemId: string, newQuantity: number): void;
81
+ removeItem(itemId: string): void;
82
+ clearCart(): void;
83
+ getGuestToken(): Promise<string>;
84
+ prepareOrderItems(): {
85
+ productId: string;
86
+ variantId: string;
87
+ quantity: number;
88
+ }[];
89
+ getOrderInfoBlocks(): Block[];
90
+ checkout(paymentMethod?: PaymentMethod, orderInfoBlocks?: Block[], promoCode?: string | null): Promise<{
91
+ success: boolean;
92
+ error: string;
93
+ data?: undefined;
94
+ } | {
95
+ success: boolean;
96
+ data: {
97
+ orderId: any;
98
+ orderNumber: any;
99
+ clientSecret: any;
100
+ };
101
+ error?: undefined;
102
+ }>;
103
+ updateProfilePhone(): Promise<boolean>;
104
+ verifyPhoneCode(): Promise<boolean>;
105
+ formatPrice(priceOrPayment: Price | Payment): string;
106
+ getCartPayment(): Payment;
107
+ getAvailablePaymentMethods(): PaymentMethod[];
108
+ getShippingMethodsForCountry(countryCode: string): import("..").ShippingMethod[];
109
+ fetchQuote(promoCode?: string | null): Promise<void>;
110
+ applyPromoCode(code: string): Promise<void>;
111
+ removePromoCode(): Promise<void>;
112
+ };
113
+ cartItems: import("nanostores").WritableAtom<EshopCartItem[]>;
114
+ cartTotal: import("nanostores").ReadableAtom<Payment>;
115
+ cartItemCount: import("nanostores").ReadableAtom<number>;
116
+ currency: import("nanostores").ReadableAtom<string>;
117
+ allowedPaymentMethods: import("nanostores").ReadableAtom<any[]>;
118
+ initEshopStore: typeof initEshopStore;
119
+ };
120
+ export default _default;
121
+ //# sourceMappingURL=eshop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eshop.d.ts","sourceRoot":"","sources":["../../src/stores/eshop.ts"],"names":[],"mappings":"AAOA,OAAO,EAEH,QAAQ,EAGR,aAAa,EACb,WAAW,EAEd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAmB,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAIzC,eAAO,MAAM,SAAS,oDAGpB,CAAC;AAGH,eAAO,MAAM,aAAa,kEAA4B,CAAC;AAGvD,eAAO,MAAM,SAAS,iEAA2B,CAAC;AAGlD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;EAgBhB,CAAC;AAGH,eAAO,MAAM,SAAS,4CAcpB,CAAC;AAEH,eAAO,MAAM,aAAa,2CAExB,CAAC;AAGH,OAAO,EACH,QAAQ,EACR,aAAa,EACb,WAAW,EACd,CAAC;AAGF,eAAO,MAAM,qBAAqB,0CAAiB,CAAC;AAGpD,eAAO,MAAM,OAAO;qBAEC,GAAG,WAAW,GAAG,aAAY,MAAM;2BAmD7B,MAAM,eAAe,MAAM;uBAS/B,MAAM;;qBAeF,OAAO,CAAC,MAAM,CAAC;;;;;;0BAoBhB,KAAK,EAAE;6BAKC,aAAa,oBAAyC,KAAK,EAAE,cAAc,MAAM,GAAG,IAAI;;;;;;;;;;;;;0BA+E1F,OAAO,CAAC,OAAO,CAAC;uBAenB,OAAO,CAAC,OAAO,CAAC;gCAgBb,KAAK,GAAG,OAAO,GAAG,MAAM;sBASlC,OAAO;kCAuBK,aAAa,EAAE;8CAKH,MAAM;2BAKnB,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;yBAyD/B,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;uBAMxB,OAAO,CAAC,IAAI,CAAC;CAIzC,CAAC;AAwBF,wBAAgB,cAAc,SAM7B;;;;;;;;;;;;;;;;;;yBA7VoB,GAAG,WAAW,GAAG,aAAY,MAAM;+BAmD7B,MAAM,eAAe,MAAM;2BAS/B,MAAM;;yBAeF,OAAO,CAAC,MAAM,CAAC;;;;;;8BAoBhB,KAAK,EAAE;iCAKC,aAAa,oBAAyC,KAAK,EAAE,cAAc,MAAM,GAAG,IAAI;;;;;;;;;;;;;8BA+E1F,OAAO,CAAC,OAAO,CAAC;2BAenB,OAAO,CAAC,OAAO,CAAC;oCAgBb,KAAK,GAAG,OAAO,GAAG,MAAM;0BASlC,OAAO;sCAuBK,aAAa,EAAE;kDAKH,MAAM;+BAKnB,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;6BAyD/B,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;2BAMxB,OAAO,CAAC,IAAI,CAAC;;;;;;;;;AAoC1C,wBASE"}
@@ -0,0 +1,377 @@
1
+ // E-shop store with TypeScript - Simplified with Business Store
2
+ import { atom, computed, deepMap } from "nanostores";
3
+ import { persistentAtom } from "@nanostores/persistent";
4
+ import { BUSINESS_ID } from "../config";
5
+ import { eshopApi } from "../api/eshop";
6
+ import { createPaymentForCheckout, getPriceAmount, formatPayment, formatMinor } from "../utils/price";
7
+ import * as authService from "../services/auth";
8
+ import { selectedMarket, currency, getShippingMethodsForCountry, paymentMethods, paymentConfig, orderBlocks, businessActions } from "./business";
9
+ import { PaymentMethod } from "../types";
10
+ // Toast notifications should be handled by UI layer
11
+ // Frontend cart items
12
+ export const cartItems = persistentAtom("eshopCart", [], {
13
+ encode: JSON.stringify,
14
+ decode: JSON.parse,
15
+ });
16
+ // Promo code state (not persisted - cleared on page reload)
17
+ export const promoCodeAtom = atom(null);
18
+ // Quote atom (fetched from backend)
19
+ export const quoteAtom = atom(null);
20
+ // Simplified store for cart-specific state only
21
+ export const store = deepMap({
22
+ businessId: BUSINESS_ID,
23
+ selectedShippingMethodId: null, // Selected shipping method ID
24
+ shippingLocation: null, // Deprecated; kept for backward compat
25
+ userToken: null,
26
+ processingCheckout: false,
27
+ loading: false,
28
+ error: null,
29
+ // Phone verification
30
+ phoneNumber: "",
31
+ phoneError: null,
32
+ verificationCode: "",
33
+ verifyError: null,
34
+ // Quote fetching
35
+ fetchingQuote: false,
36
+ quoteError: null,
37
+ });
38
+ // Computed values using business store
39
+ export const cartTotal = computed([cartItems, selectedMarket, currency], (items, market, curr) => {
40
+ // Return a Payment object with amounts in minor units
41
+ const subtotalMinor = (items || []).reduce((sum, item) => {
42
+ let amountMinor = 0;
43
+ if ('amount' in item.price) {
44
+ amountMinor = item.price.amount || 0;
45
+ }
46
+ return sum + (amountMinor * item.quantity);
47
+ }, 0);
48
+ const marketId = market?.id || 'us';
49
+ const currencyCode = curr || 'USD';
50
+ return createPaymentForCheckout(subtotalMinor, marketId, currencyCode, PaymentMethod.Cash);
51
+ });
52
+ export const cartItemCount = computed(cartItems, (items) => {
53
+ return items.reduce((sum, item) => sum + item.quantity, 0);
54
+ });
55
+ // Re-export business store computed values for convenience
56
+ export { currency, paymentConfig, orderBlocks };
57
+ // Create alias for backward compatibility
58
+ export const allowedPaymentMethods = paymentMethods;
59
+ // Actions
60
+ export const actions = {
61
+ // Add item to cart
62
+ addItem(product, variant, quantity = 1) {
63
+ const items = cartItems.get();
64
+ const market = selectedMarket.get();
65
+ // Check if item already exists in cart
66
+ const existingItemIndex = items.findIndex((item) => item.productId === product.id && item.variantId === variant.id);
67
+ if (existingItemIndex !== -1) {
68
+ // Update existing item quantity
69
+ const updatedItems = [...items];
70
+ updatedItems[existingItemIndex].quantity += quantity;
71
+ cartItems.set(updatedItems);
72
+ }
73
+ else {
74
+ // Add new item with market-based pricing
75
+ let cartPrice;
76
+ if (variant.prices && Array.isArray(variant.prices)) {
77
+ // Market-based pricing from backend (amounts are minor units)
78
+ const marketCode = market?.id || 'us';
79
+ const marketAmount = getPriceAmount(variant.prices, marketCode);
80
+ cartPrice = {
81
+ amount: marketAmount ?? 0,
82
+ market: marketCode
83
+ };
84
+ }
85
+ else {
86
+ // Fallback
87
+ cartPrice = { amount: 0, market: market?.id || 'us' };
88
+ }
89
+ const newItem = {
90
+ id: crypto.randomUUID(),
91
+ productId: product.id,
92
+ variantId: variant.id,
93
+ productName: product.name,
94
+ productSlug: product.slug,
95
+ variantAttributes: variant.attributes || {},
96
+ price: cartPrice,
97
+ quantity,
98
+ addedAt: Date.now(),
99
+ };
100
+ cartItems.set([...items, newItem]);
101
+ }
102
+ // Toast notification should be handled by UI layer
103
+ // showToast(`${product.name} added to cart!`, "success", 3000);
104
+ },
105
+ // Update item quantity
106
+ updateQuantity(itemId, newQuantity) {
107
+ const items = cartItems.get();
108
+ const updatedItems = items.map((item) => item.id === itemId ? { ...item, quantity: Math.max(1, newQuantity) } : item);
109
+ cartItems.set(updatedItems);
110
+ },
111
+ // Remove item from cart
112
+ removeItem(itemId) {
113
+ const items = cartItems.get();
114
+ const updatedItems = items.filter((item) => item.id !== itemId);
115
+ cartItems.set(updatedItems);
116
+ // Toast notification should be handled by UI layer
117
+ // showToast("Item removed from cart!", "success", 2000);
118
+ },
119
+ // Clear entire cart
120
+ clearCart() {
121
+ cartItems.set([]);
122
+ },
123
+ // Get guest token
124
+ async getGuestToken() {
125
+ const state = store.get();
126
+ const token = await authService.getGuestToken(state.userToken);
127
+ if (token !== state.userToken) {
128
+ store.setKey("userToken", token);
129
+ }
130
+ return token;
131
+ },
132
+ // Prepare order items for checkout API
133
+ prepareOrderItems() {
134
+ const items = cartItems.get();
135
+ return items.map((item) => ({
136
+ productId: item.productId,
137
+ variantId: item.variantId,
138
+ quantity: item.quantity,
139
+ }));
140
+ },
141
+ // Get order info blocks (they already have values from DynamicForm)
142
+ getOrderInfoBlocks() {
143
+ return orderBlocks.get() || [];
144
+ },
145
+ // Process checkout - Updated to use Payment structure
146
+ async checkout(paymentMethod = PaymentMethod.Cash, orderInfoBlocks, promoCode) {
147
+ const items = cartItems.get();
148
+ if (!items.length) {
149
+ return { success: false, error: "Cart is empty" };
150
+ }
151
+ try {
152
+ store.setKey("processingCheckout", true);
153
+ store.setKey("error", null);
154
+ const token = await this.getGuestToken();
155
+ const orderItems = this.prepareOrderItems();
156
+ const blocks = orderInfoBlocks || this.getOrderInfoBlocks();
157
+ const state = store.get();
158
+ const market = selectedMarket.get();
159
+ if (!market) {
160
+ throw new Error("No market selected");
161
+ }
162
+ // Extract country code from location block
163
+ const locationBlock = blocks.find(b => b.key === 'location' && b.type === 'GEO_LOCATION');
164
+ const countryCode = locationBlock?.value?.[0]?.countryCode;
165
+ if (!countryCode) {
166
+ throw new Error("Country is required for checkout");
167
+ }
168
+ // Get available shipping methods for the country
169
+ const availableShippingMethods = getShippingMethodsForCountry(countryCode) || [];
170
+ if (!availableShippingMethods || availableShippingMethods.length === 0) {
171
+ throw new Error(`No shipping methods available for country: ${countryCode}`);
172
+ }
173
+ // Get selected shipping method or first available
174
+ const shippingMethodId = state.selectedShippingMethodId;
175
+ const shippingMethod = availableShippingMethods.find(sm => sm.id === shippingMethodId) ||
176
+ availableShippingMethods[0];
177
+ if (!shippingMethod) {
178
+ throw new Error("No shipping method available");
179
+ }
180
+ const promo = promoCode !== undefined ? promoCode : promoCodeAtom.get();
181
+ const response = await eshopApi.checkout({
182
+ token,
183
+ businessId: BUSINESS_ID,
184
+ items: orderItems,
185
+ paymentMethod: paymentMethod,
186
+ blocks,
187
+ market: market.id,
188
+ shippingMethodId: shippingMethod.id,
189
+ promoCode: promo || undefined,
190
+ });
191
+ if (response.success) {
192
+ return {
193
+ success: true,
194
+ data: {
195
+ orderId: response.data.orderId,
196
+ orderNumber: response.data.orderNumber,
197
+ clientSecret: response.data.clientSecret,
198
+ },
199
+ };
200
+ }
201
+ else {
202
+ throw new Error(response.error || "Failed to place order");
203
+ }
204
+ }
205
+ catch (err) {
206
+ const errorMessage = `Checkout failed: ${err.message}`;
207
+ store.setKey("error", errorMessage);
208
+ console.error("Checkout error:", err);
209
+ return { success: false, error: errorMessage };
210
+ }
211
+ finally {
212
+ store.setKey("processingCheckout", false);
213
+ }
214
+ },
215
+ // Phone verification for eshop
216
+ async updateProfilePhone() {
217
+ try {
218
+ const token = await this.getGuestToken();
219
+ const phoneNumber = store.get().phoneNumber;
220
+ await authService.updateProfilePhone(token, phoneNumber);
221
+ store.setKey("phoneError", null);
222
+ return true;
223
+ }
224
+ catch (error) {
225
+ console.error("Phone update error:", error);
226
+ store.setKey("phoneError", error.message);
227
+ return false;
228
+ }
229
+ },
230
+ async verifyPhoneCode() {
231
+ try {
232
+ const token = await this.getGuestToken();
233
+ const phoneNumber = store.get().phoneNumber;
234
+ const verificationCode = store.get().verificationCode;
235
+ await authService.verifyPhoneCode(token, phoneNumber, verificationCode);
236
+ store.setKey("verifyError", null);
237
+ return true;
238
+ }
239
+ catch (error) {
240
+ console.error("Phone verification error:", error);
241
+ store.setKey("verifyError", error.message);
242
+ return false;
243
+ }
244
+ },
245
+ formatPrice(priceOrPayment) {
246
+ const currencyCode = currency.get();
247
+ if ('total' in priceOrPayment) {
248
+ return formatPayment(priceOrPayment, { showSymbols: true, decimalPlaces: 2 });
249
+ }
250
+ return formatMinor(priceOrPayment.amount || 0, currencyCode);
251
+ },
252
+ getCartPayment() {
253
+ const items = cartItems.get();
254
+ const market = selectedMarket.get();
255
+ const currencyCode = currency.get();
256
+ const marketId = market?.id || 'us';
257
+ if (!items || items.length === 0) {
258
+ return createPaymentForCheckout(0, marketId, currencyCode, PaymentMethod.Cash);
259
+ }
260
+ const subtotalMinor = items.reduce((sum, item) => {
261
+ let amountMinor = 0;
262
+ if ('amount' in item.price) {
263
+ amountMinor = item.price.amount || 0;
264
+ }
265
+ return sum + (amountMinor * item.quantity);
266
+ }, 0);
267
+ return createPaymentForCheckout(subtotalMinor, marketId, currencyCode, PaymentMethod.Cash);
268
+ },
269
+ // Get available payment methods for selected market
270
+ getAvailablePaymentMethods() {
271
+ return paymentMethods.get() || [PaymentMethod.Cash];
272
+ },
273
+ // Get shipping methods for a country code
274
+ getShippingMethodsForCountry(countryCode) {
275
+ return getShippingMethodsForCountry(countryCode);
276
+ },
277
+ // Fetch quote from backend
278
+ async fetchQuote(promoCode) {
279
+ const items = cartItems.get();
280
+ const market = selectedMarket.get();
281
+ const currencyCode = currency.get();
282
+ const state = store.get();
283
+ const promo = promoCode !== undefined ? promoCode : promoCodeAtom.get();
284
+ if (!items || items.length === 0) {
285
+ quoteAtom.set(null);
286
+ return;
287
+ }
288
+ if (!market) {
289
+ console.error('No market selected for quote');
290
+ return;
291
+ }
292
+ try {
293
+ store.setKey('fetchingQuote', true);
294
+ store.setKey('quoteError', null);
295
+ const token = await this.getGuestToken();
296
+ const shippingMethodId = state.selectedShippingMethodId || undefined;
297
+ const response = await eshopApi.getQuote({
298
+ token,
299
+ businessId: BUSINESS_ID,
300
+ items: items.map(item => ({
301
+ productId: item.productId,
302
+ variantId: item.variantId,
303
+ quantity: item.quantity,
304
+ })),
305
+ market: market.id,
306
+ currency: currencyCode,
307
+ userId: token,
308
+ paymentMethod: PaymentMethod.Cash,
309
+ shippingMethodId,
310
+ promoCode: promo || undefined,
311
+ });
312
+ if (response.success && response.data) {
313
+ quoteAtom.set(response.data);
314
+ }
315
+ else {
316
+ const friendly = mapQuoteError(response.code, response.error);
317
+ store.setKey('quoteError', friendly);
318
+ quoteAtom.set(null);
319
+ }
320
+ }
321
+ catch (error) {
322
+ console.error('Quote fetch error:', error);
323
+ store.setKey('quoteError', error.message);
324
+ quoteAtom.set(null);
325
+ }
326
+ finally {
327
+ store.setKey('fetchingQuote', false);
328
+ }
329
+ },
330
+ // Apply promo code
331
+ async applyPromoCode(code) {
332
+ promoCodeAtom.set(code);
333
+ await this.fetchQuote();
334
+ },
335
+ // Remove promo code
336
+ async removePromoCode() {
337
+ promoCodeAtom.set(null);
338
+ await this.fetchQuote();
339
+ },
340
+ };
341
+ function mapQuoteError(code, fallback) {
342
+ switch (code) {
343
+ case 'PROMO.MIN_ORDER':
344
+ return fallback || 'Promo requires a higher minimum order.';
345
+ case 'PROMO.NOT_ACTIVE':
346
+ return 'Promo code is not active.';
347
+ case 'PROMO.NOT_YET_VALID':
348
+ return 'Promo code is not yet valid.';
349
+ case 'PROMO.EXPIRED':
350
+ return 'Promo code has expired.';
351
+ case 'PROMO.MAX_USES':
352
+ return 'Promo code usage limit exceeded.';
353
+ case 'PROMO.MAX_USES_PER_USER':
354
+ return 'You have already used this promo code.';
355
+ case 'PROMO.NOT_FOUND':
356
+ return 'Promo code not found.';
357
+ default:
358
+ return fallback || 'Failed to fetch quote.';
359
+ }
360
+ }
361
+ // Initialize the store
362
+ export function initEshopStore() {
363
+ // Initialize business data (if not already initialized)
364
+ businessActions.init();
365
+ // Note: Shipping method selection now happens after user enters shipping address
366
+ // and we determine their country → zone → available shipping methods
367
+ }
368
+ export default {
369
+ store,
370
+ actions,
371
+ cartItems,
372
+ cartTotal,
373
+ cartItemCount,
374
+ currency,
375
+ allowedPaymentMethods,
376
+ initEshopStore
377
+ };
@@ -0,0 +1,7 @@
1
+ import { type ArkyConfig } from '../config';
2
+ export { businessStore, businessActions, selectedMarket, currency, currencySymbol, markets, zones, getZoneByCountry, getShippingMethodsForCountry, paymentMethods, paymentConfig, orderBlocks, reservationBlocks } from './business';
3
+ export { cartItems, cartTotal, cartItemCount, promoCodeAtom, quoteAtom, store as eshopStore, actions as eshopActions, initEshopStore, allowedPaymentMethods } from './eshop';
4
+ export { cartParts, store as reservationStore, actions as reservationActions, initReservationStore, canProceed, currentStepName } from './reservation';
5
+ export * from './cart';
6
+ export declare function initArky(config: ArkyConfig): ArkyConfig;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACrO,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,IAAI,UAAU,EAAE,OAAO,IAAI,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAC7K,OAAO,EAAE,SAAS,EAAE,KAAK,IAAI,gBAAgB,EAAE,OAAO,IAAI,kBAAkB,EAAE,oBAAoB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGvJ,cAAc,QAAQ,CAAC;AAGvB,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAUvD"}