arky-sdk 0.9.6 → 0.9.11
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/README.md +113 -194
- package/dist/{admin-DjYydKeB.d.ts → admin-BKXmDIVk.d.ts} +412 -405
- package/dist/{admin-DlL8mCxL.d.cts → admin-CAwQrMOX.d.cts} +412 -405
- package/dist/admin.cjs +767 -373
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +3 -3
- package/dist/admin.d.ts +3 -3
- package/dist/admin.js +767 -373
- package/dist/admin.js.map +1 -1
- package/dist/{api-BbBHcd4p.d.cts → api-DJI3S6XA.d.cts} +1440 -525
- package/dist/{api-BbBHcd4p.d.ts → api-DJI3S6XA.d.ts} +1440 -525
- package/dist/{index-CZxubTDA.d.ts → index-BaSBPLdF.d.ts} +1 -1
- package/dist/{index-nCF3Z6Af.d.cts → index-u-gjHnKs.d.cts} +1 -1
- package/dist/index.cjs +874 -471
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +874 -471
- package/dist/index.js.map +1 -1
- package/dist/storefront.cjs +493 -300
- package/dist/storefront.cjs.map +1 -1
- package/dist/storefront.d.cts +172 -89
- package/dist/storefront.d.ts +172 -89
- package/dist/storefront.js +491 -299
- package/dist/storefront.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.d.cts +2 -2
- package/dist/utils.d.ts +2 -2
- package/package.json +7 -10
- package/scripts/contract-admin.mjs +137 -0
- package/scripts/contract-storefront.mjs +296 -0
- package/dist/storefront-store.cjs +0 -2809
- package/dist/storefront-store.cjs.map +0 -1
- package/dist/storefront-store.d.cts +0 -5
- package/dist/storefront-store.d.ts +0 -5
- package/dist/storefront-store.js +0 -2807
- package/dist/storefront-store.js.map +0 -1
- package/scripts/smoke-store.mjs +0 -41
package/dist/storefront-store.js
DELETED
|
@@ -1,2807 +0,0 @@
|
|
|
1
|
-
import { atom, computed, map } from 'nanostores';
|
|
2
|
-
|
|
3
|
-
// src/storefrontStore/createArkyStore.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/blocks.ts
|
|
6
|
-
function getBlockLabel(block) {
|
|
7
|
-
if (!block) return "";
|
|
8
|
-
return block.key?.replace(/_/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()) ?? "";
|
|
9
|
-
}
|
|
10
|
-
function formatBlockValue(block) {
|
|
11
|
-
if (!block || block.value === null || block.value === void 0) return "";
|
|
12
|
-
const value = block.value;
|
|
13
|
-
switch (block.type) {
|
|
14
|
-
case "boolean":
|
|
15
|
-
return value ? "Yes" : "No";
|
|
16
|
-
case "number":
|
|
17
|
-
if (block.properties?.variant === "DATE" || block.properties?.variant === "DATE_TIME") {
|
|
18
|
-
return new Date(value).toLocaleDateString();
|
|
19
|
-
}
|
|
20
|
-
return String(value);
|
|
21
|
-
case "relationship_entry":
|
|
22
|
-
case "relationship_media":
|
|
23
|
-
if (value && typeof value === "object") {
|
|
24
|
-
return value.mime_type ? value.name || value.id : value.title || value.name || value.id;
|
|
25
|
-
}
|
|
26
|
-
return String(value);
|
|
27
|
-
default:
|
|
28
|
-
return String(value);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function prepareBlocksForSubmission(formData, blockTypes) {
|
|
32
|
-
return Object.keys(formData).filter((key) => formData[key] !== null && formData[key] !== void 0).map((key) => ({
|
|
33
|
-
key,
|
|
34
|
-
value: blockTypes?.[key] === "list" && !Array.isArray(formData[key]) ? [formData[key]] : formData[key]
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
|
-
function extractBlockValues(blocks) {
|
|
38
|
-
const values = {};
|
|
39
|
-
blocks.forEach((block) => {
|
|
40
|
-
values[block.key] = block.value ?? null;
|
|
41
|
-
});
|
|
42
|
-
return values;
|
|
43
|
-
}
|
|
44
|
-
var getBlockValue = (entry, blockKey) => {
|
|
45
|
-
const block = entry?.blocks?.find((f) => f.key === blockKey);
|
|
46
|
-
return block?.value ?? null;
|
|
47
|
-
};
|
|
48
|
-
var getBlockTextValue = (block, locale = "en") => {
|
|
49
|
-
if (!block || block.value === null || block.value === void 0) return "";
|
|
50
|
-
if (block.type === "localized_text" || block.type === "markdown") {
|
|
51
|
-
if (typeof block.value === "object" && block.value !== null) {
|
|
52
|
-
return block.value[locale] ?? block.value["en"] ?? "";
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (typeof block.value === "string") return block.value;
|
|
56
|
-
return String(block.value ?? "");
|
|
57
|
-
};
|
|
58
|
-
var getBlockValues = (entry, blockKey) => {
|
|
59
|
-
const block = entry?.blocks?.find((f) => f.key === blockKey);
|
|
60
|
-
if (!block) return [];
|
|
61
|
-
if (block.type === "list" && Array.isArray(block.value)) {
|
|
62
|
-
return block.value;
|
|
63
|
-
}
|
|
64
|
-
return [];
|
|
65
|
-
};
|
|
66
|
-
function unwrapBlock(block, locale) {
|
|
67
|
-
if (!block?.type || block.value === void 0) return block;
|
|
68
|
-
if (block.type === "list") {
|
|
69
|
-
return block.value.map((obj) => {
|
|
70
|
-
const parsed = {};
|
|
71
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
72
|
-
parsed[k] = unwrapBlock(v, locale);
|
|
73
|
-
}
|
|
74
|
-
return parsed;
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
if (block.type === "map") {
|
|
78
|
-
const parsed = {};
|
|
79
|
-
for (const [k, v] of Object.entries(block.value || {})) {
|
|
80
|
-
parsed[k] = unwrapBlock(v, locale);
|
|
81
|
-
}
|
|
82
|
-
return parsed;
|
|
83
|
-
}
|
|
84
|
-
if (block.type === "localized_text" || block.type === "markdown") {
|
|
85
|
-
return block.value?.[locale];
|
|
86
|
-
}
|
|
87
|
-
return block.value;
|
|
88
|
-
}
|
|
89
|
-
var getBlockObjectValues = (entry, blockKey, locale = "en") => {
|
|
90
|
-
const block = entry?.blocks?.find((f) => f.key === blockKey);
|
|
91
|
-
if (!block || block.type !== "list" || !Array.isArray(block.value)) return [];
|
|
92
|
-
return block.value.map((obj) => {
|
|
93
|
-
if (!obj?.value || !Array.isArray(obj.value)) return {};
|
|
94
|
-
return obj.value.reduce((acc, current) => {
|
|
95
|
-
acc[current.key] = unwrapBlock(current, locale);
|
|
96
|
-
return acc;
|
|
97
|
-
}, {});
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
var getBlockFromArray = (entry, blockKey, locale = "en") => {
|
|
101
|
-
const block = entry?.blocks?.find((f) => f.key === blockKey);
|
|
102
|
-
if (!block) return {};
|
|
103
|
-
if (block.type === "list" && Array.isArray(block.value)) {
|
|
104
|
-
return block.value.reduce((acc, current) => {
|
|
105
|
-
acc[current.key] = unwrapBlock(current, locale);
|
|
106
|
-
return acc;
|
|
107
|
-
}, {});
|
|
108
|
-
}
|
|
109
|
-
if (block.type === "map" && block.value && typeof block.value === "object") {
|
|
110
|
-
const result = {};
|
|
111
|
-
for (const [k, v] of Object.entries(block.value)) {
|
|
112
|
-
result[k] = unwrapBlock(v, locale);
|
|
113
|
-
}
|
|
114
|
-
return result;
|
|
115
|
-
}
|
|
116
|
-
return { [block.key]: unwrapBlock(block, locale) };
|
|
117
|
-
};
|
|
118
|
-
var getImageUrl = (imageBlock, isBlock = true) => {
|
|
119
|
-
if (!imageBlock) return null;
|
|
120
|
-
if (imageBlock.type === "relationship_media") {
|
|
121
|
-
const mediaValue = imageBlock.value;
|
|
122
|
-
return mediaValue?.resolutions?.original?.url || mediaValue?.url || null;
|
|
123
|
-
}
|
|
124
|
-
if (isBlock) {
|
|
125
|
-
if (typeof imageBlock === "string") return imageBlock;
|
|
126
|
-
if (imageBlock.url) return imageBlock.url;
|
|
127
|
-
}
|
|
128
|
-
return imageBlock.resolutions?.original?.url || null;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// src/utils/orderItems.ts
|
|
132
|
-
function normalizeOrderCheckoutItems(items) {
|
|
133
|
-
return items.map((item) => {
|
|
134
|
-
if ("type" in item) {
|
|
135
|
-
return item;
|
|
136
|
-
}
|
|
137
|
-
if ("product_id" in item) {
|
|
138
|
-
return { type: "product", ...item };
|
|
139
|
-
}
|
|
140
|
-
return { type: "service", ...item };
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
function normalizePublicCheckoutItems(items) {
|
|
144
|
-
return normalizeOrderCheckoutItems(items).map((item) => {
|
|
145
|
-
const { price: _price, ...publicItem } = item;
|
|
146
|
-
return publicItem;
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// src/api/storefront.ts
|
|
151
|
-
var COMMON_ACTIVITY_TYPES = [
|
|
152
|
-
"page_view",
|
|
153
|
-
"product_view",
|
|
154
|
-
"service_view",
|
|
155
|
-
"provider_view",
|
|
156
|
-
"cart_added",
|
|
157
|
-
"cart_removed",
|
|
158
|
-
"checkout_started",
|
|
159
|
-
"purchase",
|
|
160
|
-
"order_created",
|
|
161
|
-
"signin",
|
|
162
|
-
"signup",
|
|
163
|
-
"verified_email",
|
|
164
|
-
"search",
|
|
165
|
-
"share",
|
|
166
|
-
"wishlist_added"
|
|
167
|
-
];
|
|
168
|
-
var createActivityApi = (apiConfig) => ({
|
|
169
|
-
COMMON_ACTIVITY_TYPES,
|
|
170
|
-
async track(params) {
|
|
171
|
-
try {
|
|
172
|
-
await apiConfig.httpClient.post(
|
|
173
|
-
`/v1/storefront/${apiConfig.storeId}/activities/track`,
|
|
174
|
-
{ type: params.type, payload: params.payload }
|
|
175
|
-
);
|
|
176
|
-
} catch {
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
var createStorefrontApi = (apiConfig, updateProfileSession) => {
|
|
181
|
-
const base = (storeId = apiConfig.storeId) => `/v1/storefront/${storeId}`;
|
|
182
|
-
return {
|
|
183
|
-
store: {
|
|
184
|
-
getStore(options) {
|
|
185
|
-
return apiConfig.httpClient.get(base(), options);
|
|
186
|
-
},
|
|
187
|
-
location: {
|
|
188
|
-
getCountries(options) {
|
|
189
|
-
return apiConfig.httpClient.get(`/v1/platform/countries`, options);
|
|
190
|
-
},
|
|
191
|
-
getCountry(countryCode, options) {
|
|
192
|
-
return apiConfig.httpClient.get(
|
|
193
|
-
`/v1/platform/countries/${countryCode}`,
|
|
194
|
-
options
|
|
195
|
-
);
|
|
196
|
-
},
|
|
197
|
-
list(options) {
|
|
198
|
-
return apiConfig.httpClient.get(`${base()}/locations`, options);
|
|
199
|
-
},
|
|
200
|
-
get(id, options) {
|
|
201
|
-
return apiConfig.httpClient.get(`${base()}/locations/${id}`, options);
|
|
202
|
-
}
|
|
203
|
-
},
|
|
204
|
-
market: {
|
|
205
|
-
list(options) {
|
|
206
|
-
return apiConfig.httpClient.get(`${base()}/markets`, options);
|
|
207
|
-
},
|
|
208
|
-
get(id, options) {
|
|
209
|
-
return apiConfig.httpClient.get(`${base()}/markets/${id}`, options);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
},
|
|
213
|
-
cms: {
|
|
214
|
-
node: {
|
|
215
|
-
async get(params, options) {
|
|
216
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
217
|
-
let identifier;
|
|
218
|
-
if (params.id) {
|
|
219
|
-
identifier = params.id;
|
|
220
|
-
} else if (params.slug) {
|
|
221
|
-
identifier = `${store_id}:${apiConfig.locale}:${params.slug}`;
|
|
222
|
-
} else if (params.key) {
|
|
223
|
-
identifier = `${store_id}:${params.key}`;
|
|
224
|
-
} else {
|
|
225
|
-
throw new Error("GetNodeParams requires id, slug, or key");
|
|
226
|
-
}
|
|
227
|
-
const response = await apiConfig.httpClient.get(
|
|
228
|
-
`${base(store_id)}/nodes/${identifier}`,
|
|
229
|
-
options
|
|
230
|
-
);
|
|
231
|
-
return {
|
|
232
|
-
...response,
|
|
233
|
-
getBlock(key) {
|
|
234
|
-
return getBlockFromArray(response, key, apiConfig.locale);
|
|
235
|
-
},
|
|
236
|
-
getBlockValues(key) {
|
|
237
|
-
return getBlockObjectValues(response, key, apiConfig.locale);
|
|
238
|
-
},
|
|
239
|
-
getImage(key) {
|
|
240
|
-
const block = getBlockFromArray(response, key, apiConfig.locale);
|
|
241
|
-
return getImageUrl(block, true);
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
},
|
|
245
|
-
find(params, options) {
|
|
246
|
-
const { store_id, ...queryParams } = params;
|
|
247
|
-
return apiConfig.httpClient.get(`${base(store_id)}/nodes`, {
|
|
248
|
-
...options,
|
|
249
|
-
params: queryParams
|
|
250
|
-
});
|
|
251
|
-
},
|
|
252
|
-
getChildren(params, options) {
|
|
253
|
-
const { id, store_id, ...queryParams } = params;
|
|
254
|
-
return apiConfig.httpClient.get(`${base(store_id)}/nodes/${id}/children`, {
|
|
255
|
-
...options,
|
|
256
|
-
params: queryParams
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
form: {
|
|
261
|
-
get(params, options) {
|
|
262
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
263
|
-
let identifier;
|
|
264
|
-
if (params.id) {
|
|
265
|
-
identifier = params.id;
|
|
266
|
-
} else if (params.key) {
|
|
267
|
-
identifier = `${store_id}:${params.key}`;
|
|
268
|
-
} else {
|
|
269
|
-
throw new Error("GetFormParams requires id or key");
|
|
270
|
-
}
|
|
271
|
-
return apiConfig.httpClient.get(
|
|
272
|
-
`${base(store_id)}/forms/${identifier}`,
|
|
273
|
-
options
|
|
274
|
-
);
|
|
275
|
-
},
|
|
276
|
-
submit(params, options) {
|
|
277
|
-
const { store_id, form_id, ...payload } = params;
|
|
278
|
-
const target_store_id = store_id || apiConfig.storeId;
|
|
279
|
-
if (!form_id) {
|
|
280
|
-
throw new Error("SubmitFormParams requires form_id");
|
|
281
|
-
}
|
|
282
|
-
return apiConfig.httpClient.post(
|
|
283
|
-
`${base(target_store_id)}/forms/${form_id}/submissions`,
|
|
284
|
-
{ ...payload, form_id, store_id: target_store_id },
|
|
285
|
-
options
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
},
|
|
289
|
-
taxonomy: {
|
|
290
|
-
get(params, options) {
|
|
291
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
292
|
-
let identifier;
|
|
293
|
-
if (params.id) {
|
|
294
|
-
identifier = params.id;
|
|
295
|
-
} else if (params.key) {
|
|
296
|
-
identifier = `${store_id}:${params.key}`;
|
|
297
|
-
} else {
|
|
298
|
-
throw new Error("GetTaxonomyParams requires id or key");
|
|
299
|
-
}
|
|
300
|
-
return apiConfig.httpClient.get(
|
|
301
|
-
`${base(store_id)}/taxonomies/${identifier}`,
|
|
302
|
-
options
|
|
303
|
-
);
|
|
304
|
-
},
|
|
305
|
-
getChildren(params, options) {
|
|
306
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
307
|
-
return apiConfig.httpClient.get(
|
|
308
|
-
`${base(store_id)}/taxonomies/${params.id}/children`,
|
|
309
|
-
options
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
},
|
|
314
|
-
eshop: {
|
|
315
|
-
product: {
|
|
316
|
-
get(params, options) {
|
|
317
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
318
|
-
let identifier;
|
|
319
|
-
if (params.id) {
|
|
320
|
-
identifier = params.id;
|
|
321
|
-
} else if (params.slug) {
|
|
322
|
-
identifier = `${store_id}:${apiConfig.locale}:${params.slug}`;
|
|
323
|
-
} else {
|
|
324
|
-
throw new Error("GetProductParams requires id or slug");
|
|
325
|
-
}
|
|
326
|
-
return apiConfig.httpClient.get(
|
|
327
|
-
`${base(store_id)}/products/${identifier}`,
|
|
328
|
-
options
|
|
329
|
-
);
|
|
330
|
-
},
|
|
331
|
-
find(params, options) {
|
|
332
|
-
const { store_id, ...queryParams } = params;
|
|
333
|
-
return apiConfig.httpClient.get(`${base(store_id)}/products`, {
|
|
334
|
-
...options,
|
|
335
|
-
params: queryParams
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
|
-
cart: {
|
|
340
|
-
current(params = {}, options) {
|
|
341
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
342
|
-
const { store_id: _store_id, ...payload } = params;
|
|
343
|
-
return apiConfig.httpClient.post(
|
|
344
|
-
`${base(store_id)}/carts/current`,
|
|
345
|
-
{ ...payload, store_id, market: payload.market || apiConfig.market },
|
|
346
|
-
options
|
|
347
|
-
);
|
|
348
|
-
},
|
|
349
|
-
get(params, options) {
|
|
350
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
351
|
-
return apiConfig.httpClient.get(`${base(store_id)}/carts/${params.id}`, {
|
|
352
|
-
...options,
|
|
353
|
-
params: params.token ? { token: params.token } : options?.params
|
|
354
|
-
});
|
|
355
|
-
},
|
|
356
|
-
update(params, options) {
|
|
357
|
-
const { store_id, items, ...payload } = params;
|
|
358
|
-
const target = store_id || apiConfig.storeId;
|
|
359
|
-
return apiConfig.httpClient.put(
|
|
360
|
-
`${base(target)}/carts/${params.id}`,
|
|
361
|
-
{
|
|
362
|
-
...payload,
|
|
363
|
-
store_id: target,
|
|
364
|
-
...items ? { items: normalizePublicCheckoutItems(items) } : {}
|
|
365
|
-
},
|
|
366
|
-
options
|
|
367
|
-
);
|
|
368
|
-
},
|
|
369
|
-
addItem(params, options) {
|
|
370
|
-
const { store_id, item, ...payload } = params;
|
|
371
|
-
const target = store_id || apiConfig.storeId;
|
|
372
|
-
return apiConfig.httpClient.post(
|
|
373
|
-
`${base(target)}/carts/${params.id}/items`,
|
|
374
|
-
{
|
|
375
|
-
...payload,
|
|
376
|
-
store_id: target,
|
|
377
|
-
item: normalizePublicCheckoutItems([item])[0]
|
|
378
|
-
},
|
|
379
|
-
options
|
|
380
|
-
);
|
|
381
|
-
},
|
|
382
|
-
removeItem(params, options) {
|
|
383
|
-
const { store_id, ...payload } = params;
|
|
384
|
-
const target = store_id || apiConfig.storeId;
|
|
385
|
-
return apiConfig.httpClient.post(
|
|
386
|
-
`${base(target)}/carts/${params.id}/items/remove`,
|
|
387
|
-
{ ...payload, store_id: target },
|
|
388
|
-
options
|
|
389
|
-
);
|
|
390
|
-
},
|
|
391
|
-
clear(params, options) {
|
|
392
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
393
|
-
return apiConfig.httpClient.post(
|
|
394
|
-
`${base(store_id)}/carts/${params.id}/clear`,
|
|
395
|
-
{ id: params.id, store_id },
|
|
396
|
-
options
|
|
397
|
-
);
|
|
398
|
-
},
|
|
399
|
-
quote(params, options) {
|
|
400
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
401
|
-
return apiConfig.httpClient.post(
|
|
402
|
-
`${base(store_id)}/carts/${params.id}/quote`,
|
|
403
|
-
{ id: params.id, store_id },
|
|
404
|
-
options
|
|
405
|
-
);
|
|
406
|
-
},
|
|
407
|
-
checkout(params, options) {
|
|
408
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
409
|
-
return apiConfig.httpClient.post(
|
|
410
|
-
`${base(store_id)}/carts/${params.id}/checkout`,
|
|
411
|
-
{
|
|
412
|
-
id: params.id,
|
|
413
|
-
store_id,
|
|
414
|
-
payment_method_id: params.payment_method_id
|
|
415
|
-
},
|
|
416
|
-
options
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
},
|
|
420
|
-
order: {
|
|
421
|
-
get(params, options) {
|
|
422
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
423
|
-
return apiConfig.httpClient.get(
|
|
424
|
-
`${base(store_id)}/orders/${params.id}`,
|
|
425
|
-
options
|
|
426
|
-
);
|
|
427
|
-
},
|
|
428
|
-
find(params, options) {
|
|
429
|
-
const { store_id, ...queryParams } = params;
|
|
430
|
-
return apiConfig.httpClient.get(`${base(store_id)}/orders`, {
|
|
431
|
-
...options,
|
|
432
|
-
params: queryParams
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
},
|
|
436
|
-
service: {
|
|
437
|
-
get(params, options) {
|
|
438
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
439
|
-
let identifier;
|
|
440
|
-
if (params.id) {
|
|
441
|
-
identifier = params.id;
|
|
442
|
-
} else if (params.slug) {
|
|
443
|
-
identifier = `${store_id}:${apiConfig.locale}:${params.slug}`;
|
|
444
|
-
} else {
|
|
445
|
-
throw new Error("GetServiceParams requires id or slug");
|
|
446
|
-
}
|
|
447
|
-
return apiConfig.httpClient.get(
|
|
448
|
-
`${base(store_id)}/services/${identifier}`,
|
|
449
|
-
options
|
|
450
|
-
);
|
|
451
|
-
},
|
|
452
|
-
find(params, options) {
|
|
453
|
-
const { store_id, ...queryParams } = params;
|
|
454
|
-
return apiConfig.httpClient.get(`${base(store_id)}/services`, {
|
|
455
|
-
...options,
|
|
456
|
-
params: queryParams
|
|
457
|
-
});
|
|
458
|
-
},
|
|
459
|
-
findProviders(params, options) {
|
|
460
|
-
const { store_id, ...queryParams } = params;
|
|
461
|
-
return apiConfig.httpClient.get(`${base(store_id)}/service-providers`, {
|
|
462
|
-
...options,
|
|
463
|
-
params: queryParams
|
|
464
|
-
});
|
|
465
|
-
},
|
|
466
|
-
getAvailability(params, options) {
|
|
467
|
-
const { store_id, ...queryParams } = params;
|
|
468
|
-
const target_store_id = store_id || apiConfig.storeId;
|
|
469
|
-
return apiConfig.httpClient.get(
|
|
470
|
-
`${base(target_store_id)}/services/availability`,
|
|
471
|
-
{ ...options, params: queryParams }
|
|
472
|
-
);
|
|
473
|
-
}
|
|
474
|
-
},
|
|
475
|
-
provider: {
|
|
476
|
-
get(params, options) {
|
|
477
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
478
|
-
let identifier;
|
|
479
|
-
if (params.id) {
|
|
480
|
-
identifier = params.id;
|
|
481
|
-
} else if (params.slug) {
|
|
482
|
-
identifier = `${store_id}:${apiConfig.locale}:${params.slug}`;
|
|
483
|
-
} else {
|
|
484
|
-
throw new Error("GetProviderParams requires id or slug");
|
|
485
|
-
}
|
|
486
|
-
return apiConfig.httpClient.get(
|
|
487
|
-
`${base(store_id)}/providers/${identifier}`,
|
|
488
|
-
options
|
|
489
|
-
);
|
|
490
|
-
},
|
|
491
|
-
find(params, options) {
|
|
492
|
-
const { store_id, ...queryParams } = params;
|
|
493
|
-
return apiConfig.httpClient.get(`${base(store_id)}/providers`, {
|
|
494
|
-
...options,
|
|
495
|
-
params: queryParams
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
},
|
|
500
|
-
crm: {
|
|
501
|
-
profile: {
|
|
502
|
-
async identify(params, options) {
|
|
503
|
-
const store_id = apiConfig.storeId;
|
|
504
|
-
const result = await apiConfig.httpClient.post(
|
|
505
|
-
`${base(store_id)}/profiles/identify`,
|
|
506
|
-
{
|
|
507
|
-
store_id,
|
|
508
|
-
market: params?.market || apiConfig.market || null,
|
|
509
|
-
email: params?.email,
|
|
510
|
-
verify: params?.verify ?? false
|
|
511
|
-
},
|
|
512
|
-
options
|
|
513
|
-
);
|
|
514
|
-
if (result?.token?.token) {
|
|
515
|
-
updateProfileSession(() => ({
|
|
516
|
-
access_token: result.token.token,
|
|
517
|
-
profile: result.profile,
|
|
518
|
-
store: result.store,
|
|
519
|
-
market: result.market
|
|
520
|
-
}));
|
|
521
|
-
}
|
|
522
|
-
return result;
|
|
523
|
-
},
|
|
524
|
-
async verify(params, options) {
|
|
525
|
-
const store_id = apiConfig.storeId;
|
|
526
|
-
const result = await apiConfig.httpClient.post(
|
|
527
|
-
`${base(store_id)}/profiles/verify`,
|
|
528
|
-
{ store_id, code: params.code },
|
|
529
|
-
options
|
|
530
|
-
);
|
|
531
|
-
if (result?.token) {
|
|
532
|
-
updateProfileSession(
|
|
533
|
-
(prev) => prev ? { ...prev, access_token: result.token } : null
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
return result;
|
|
537
|
-
},
|
|
538
|
-
async logout(options) {
|
|
539
|
-
const store_id = apiConfig.storeId;
|
|
540
|
-
try {
|
|
541
|
-
await apiConfig.httpClient.post(
|
|
542
|
-
`${base(store_id)}/profiles/logout`,
|
|
543
|
-
{},
|
|
544
|
-
options
|
|
545
|
-
);
|
|
546
|
-
} finally {
|
|
547
|
-
updateProfileSession(() => null);
|
|
548
|
-
}
|
|
549
|
-
},
|
|
550
|
-
getMe(options) {
|
|
551
|
-
return apiConfig.httpClient.get(`${base()}/profiles/me`, options);
|
|
552
|
-
}
|
|
553
|
-
},
|
|
554
|
-
profileList: {
|
|
555
|
-
get(params, options) {
|
|
556
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
557
|
-
return apiConfig.httpClient.get(
|
|
558
|
-
`${base(store_id)}/profile-lists/${params.id}`,
|
|
559
|
-
options
|
|
560
|
-
);
|
|
561
|
-
},
|
|
562
|
-
find(params, options) {
|
|
563
|
-
const { store_id, ...queryParams } = params || {};
|
|
564
|
-
return apiConfig.httpClient.get(`${base(store_id)}/profile-lists`, {
|
|
565
|
-
...options,
|
|
566
|
-
params: queryParams
|
|
567
|
-
});
|
|
568
|
-
},
|
|
569
|
-
subscribe(params, options) {
|
|
570
|
-
const { store_id, id, ...payload } = params;
|
|
571
|
-
return apiConfig.httpClient.post(
|
|
572
|
-
`${base(store_id)}/profile-lists/${id}/subscribe`,
|
|
573
|
-
payload,
|
|
574
|
-
options
|
|
575
|
-
);
|
|
576
|
-
},
|
|
577
|
-
checkAccess(params, options) {
|
|
578
|
-
const store_id = params.store_id || apiConfig.storeId;
|
|
579
|
-
return apiConfig.httpClient.get(
|
|
580
|
-
`${base(store_id)}/profile-lists/${params.id}/access`,
|
|
581
|
-
options
|
|
582
|
-
);
|
|
583
|
-
},
|
|
584
|
-
unsubscribe(token, options) {
|
|
585
|
-
return apiConfig.httpClient.get(`${base()}/profile-lists/unsubscribe`, {
|
|
586
|
-
...options,
|
|
587
|
-
params: { token }
|
|
588
|
-
});
|
|
589
|
-
},
|
|
590
|
-
confirm(token, options) {
|
|
591
|
-
return apiConfig.httpClient.get(`${base()}/profile-lists/confirm`, {
|
|
592
|
-
...options,
|
|
593
|
-
params: { token }
|
|
594
|
-
});
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
},
|
|
598
|
-
activity: createActivityApi(apiConfig)
|
|
599
|
-
};
|
|
600
|
-
};
|
|
601
|
-
|
|
602
|
-
// src/cartController.ts
|
|
603
|
-
function hasCartId(params) {
|
|
604
|
-
return "id" in params && typeof params.id === "string" && params.id.length > 0;
|
|
605
|
-
}
|
|
606
|
-
function createCartController(cartApi) {
|
|
607
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
608
|
-
let state = {
|
|
609
|
-
cart: null,
|
|
610
|
-
quote: null,
|
|
611
|
-
checkoutResult: null,
|
|
612
|
-
loading: false,
|
|
613
|
-
initialized: false,
|
|
614
|
-
error: null
|
|
615
|
-
};
|
|
616
|
-
function emit() {
|
|
617
|
-
for (const listener of listeners) {
|
|
618
|
-
Promise.resolve().then(() => listener(state)).catch(() => {
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
function setState(patch) {
|
|
623
|
-
state = { ...state, ...patch };
|
|
624
|
-
emit();
|
|
625
|
-
return state;
|
|
626
|
-
}
|
|
627
|
-
function currentCartId(id) {
|
|
628
|
-
const cartId = id || state.cart?.id;
|
|
629
|
-
if (!cartId) {
|
|
630
|
-
throw new Error("Cart has not been initialized and no cart id was provided");
|
|
631
|
-
}
|
|
632
|
-
return cartId;
|
|
633
|
-
}
|
|
634
|
-
async function runCartMutation(operation) {
|
|
635
|
-
setState({ loading: true, error: null });
|
|
636
|
-
try {
|
|
637
|
-
const cart = await operation();
|
|
638
|
-
setState({
|
|
639
|
-
cart,
|
|
640
|
-
quote: null,
|
|
641
|
-
checkoutResult: null,
|
|
642
|
-
loading: false,
|
|
643
|
-
initialized: true,
|
|
644
|
-
error: null
|
|
645
|
-
});
|
|
646
|
-
return cart;
|
|
647
|
-
} catch (error) {
|
|
648
|
-
setState({ loading: false, error });
|
|
649
|
-
throw error;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
return {
|
|
653
|
-
subscribe(listener) {
|
|
654
|
-
listeners.add(listener);
|
|
655
|
-
Promise.resolve().then(() => listener(state)).catch(() => {
|
|
656
|
-
});
|
|
657
|
-
return () => {
|
|
658
|
-
listeners.delete(listener);
|
|
659
|
-
};
|
|
660
|
-
},
|
|
661
|
-
getState() {
|
|
662
|
-
return state;
|
|
663
|
-
},
|
|
664
|
-
init(params = {}, options) {
|
|
665
|
-
if (state.initialized && state.cart) {
|
|
666
|
-
return Promise.resolve(state.cart);
|
|
667
|
-
}
|
|
668
|
-
return this.refresh(params, options);
|
|
669
|
-
},
|
|
670
|
-
refresh(params = {}, options) {
|
|
671
|
-
return runCartMutation(
|
|
672
|
-
() => hasCartId(params) ? cartApi.get(params, options) : cartApi.current(params, options)
|
|
673
|
-
);
|
|
674
|
-
},
|
|
675
|
-
addItem(params, options) {
|
|
676
|
-
return runCartMutation(
|
|
677
|
-
() => cartApi.addItem({ ...params, id: currentCartId(params.id) }, options)
|
|
678
|
-
);
|
|
679
|
-
},
|
|
680
|
-
update(params, options) {
|
|
681
|
-
return runCartMutation(
|
|
682
|
-
() => cartApi.update({ ...params, id: currentCartId(params.id) }, options)
|
|
683
|
-
);
|
|
684
|
-
},
|
|
685
|
-
removeItem(params, options) {
|
|
686
|
-
return runCartMutation(
|
|
687
|
-
() => cartApi.removeItem({ ...params, id: currentCartId(params.id) }, options)
|
|
688
|
-
);
|
|
689
|
-
},
|
|
690
|
-
clear(params = {}, options) {
|
|
691
|
-
return runCartMutation(
|
|
692
|
-
() => cartApi.clear({ ...params, id: currentCartId(params.id) }, options)
|
|
693
|
-
);
|
|
694
|
-
},
|
|
695
|
-
async quote(params = {}, options) {
|
|
696
|
-
setState({ loading: true, error: null });
|
|
697
|
-
try {
|
|
698
|
-
const quote = await cartApi.quote(
|
|
699
|
-
{ ...params, id: currentCartId(params.id) },
|
|
700
|
-
options
|
|
701
|
-
);
|
|
702
|
-
setState({ quote, loading: false, error: null });
|
|
703
|
-
return quote;
|
|
704
|
-
} catch (error) {
|
|
705
|
-
setState({ loading: false, error });
|
|
706
|
-
throw error;
|
|
707
|
-
}
|
|
708
|
-
},
|
|
709
|
-
async checkout(params = {}, options) {
|
|
710
|
-
setState({ loading: true, error: null });
|
|
711
|
-
try {
|
|
712
|
-
const checkoutResult = await cartApi.checkout(
|
|
713
|
-
{ ...params, id: currentCartId(params.id) },
|
|
714
|
-
options
|
|
715
|
-
);
|
|
716
|
-
setState({ checkoutResult, loading: false, error: null });
|
|
717
|
-
return checkoutResult;
|
|
718
|
-
} catch (error) {
|
|
719
|
-
setState({ loading: false, error });
|
|
720
|
-
throw error;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
};
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
// src/utils/errors.ts
|
|
727
|
-
var convertServerErrorToRequestError = (serverError, renameRules) => {
|
|
728
|
-
const validationErrors = serverError?.validationErrors ?? [];
|
|
729
|
-
return {
|
|
730
|
-
...serverError,
|
|
731
|
-
validationErrors: validationErrors.map((validationError) => {
|
|
732
|
-
const field = validationError.field;
|
|
733
|
-
return {
|
|
734
|
-
field,
|
|
735
|
-
error: validationError.error || "GENERAL.VALIDATION_ERROR"
|
|
736
|
-
};
|
|
737
|
-
})
|
|
738
|
-
};
|
|
739
|
-
};
|
|
740
|
-
|
|
741
|
-
// src/utils/queryParams.ts
|
|
742
|
-
function buildQueryString(params) {
|
|
743
|
-
const queryParts = [];
|
|
744
|
-
Object.entries(params).forEach(([key, value]) => {
|
|
745
|
-
if (value === null || value === void 0) {
|
|
746
|
-
return;
|
|
747
|
-
}
|
|
748
|
-
if (Array.isArray(value)) {
|
|
749
|
-
const jsonString = JSON.stringify(value);
|
|
750
|
-
queryParts.push(`${key}=${encodeURIComponent(jsonString)}`);
|
|
751
|
-
} else if (typeof value === "string") {
|
|
752
|
-
queryParts.push(`${key}=${encodeURIComponent(value)}`);
|
|
753
|
-
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
754
|
-
queryParts.push(`${key}=${value}`);
|
|
755
|
-
} else if (typeof value === "object") {
|
|
756
|
-
const jsonString = JSON.stringify(value);
|
|
757
|
-
queryParts.push(`${key}=${encodeURIComponent(jsonString)}`);
|
|
758
|
-
}
|
|
759
|
-
});
|
|
760
|
-
return queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// src/services/createHttpClient.ts
|
|
764
|
-
function createHttpClient(cfg) {
|
|
765
|
-
const { authStorage } = cfg;
|
|
766
|
-
let refreshPromise = null;
|
|
767
|
-
function getRefreshEndpoint() {
|
|
768
|
-
const refreshPath = typeof cfg.refreshPath === "function" ? cfg.refreshPath() : cfg.refreshPath || "/v1/auth/refresh";
|
|
769
|
-
return `${cfg.baseUrl}${refreshPath}`;
|
|
770
|
-
}
|
|
771
|
-
async function ensureFreshToken() {
|
|
772
|
-
if (refreshPromise) {
|
|
773
|
-
return refreshPromise;
|
|
774
|
-
}
|
|
775
|
-
refreshPromise = (async () => {
|
|
776
|
-
const tokens = authStorage.getTokens();
|
|
777
|
-
const refresh_token = tokens?.refresh_token;
|
|
778
|
-
if (!refresh_token) {
|
|
779
|
-
authStorage.onForcedLogout();
|
|
780
|
-
const err = new Error("No refresh token available");
|
|
781
|
-
err.name = "ApiError";
|
|
782
|
-
err.statusCode = 401;
|
|
783
|
-
throw err;
|
|
784
|
-
}
|
|
785
|
-
const refRes = await fetch(getRefreshEndpoint(), {
|
|
786
|
-
method: "POST",
|
|
787
|
-
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
|
788
|
-
body: JSON.stringify({ refresh_token })
|
|
789
|
-
});
|
|
790
|
-
if (!refRes.ok) {
|
|
791
|
-
authStorage.onForcedLogout();
|
|
792
|
-
const err = new Error("Token refresh failed");
|
|
793
|
-
err.name = "ApiError";
|
|
794
|
-
err.statusCode = 401;
|
|
795
|
-
throw err;
|
|
796
|
-
}
|
|
797
|
-
const data = await refRes.json();
|
|
798
|
-
authStorage.onTokensRefreshed(data);
|
|
799
|
-
})().finally(() => {
|
|
800
|
-
refreshPromise = null;
|
|
801
|
-
});
|
|
802
|
-
return refreshPromise;
|
|
803
|
-
}
|
|
804
|
-
async function request(method, path, body, options) {
|
|
805
|
-
if (options?.transformRequest) {
|
|
806
|
-
body = options.transformRequest(body);
|
|
807
|
-
}
|
|
808
|
-
const headers = {
|
|
809
|
-
Accept: "application/json",
|
|
810
|
-
"Content-Type": "application/json",
|
|
811
|
-
...options?.headers || {}
|
|
812
|
-
};
|
|
813
|
-
let tokens = authStorage.getTokens();
|
|
814
|
-
const nowSec = Date.now() / 1e3;
|
|
815
|
-
if (tokens?.access_expires_at && nowSec > tokens.access_expires_at) {
|
|
816
|
-
await ensureFreshToken();
|
|
817
|
-
tokens = authStorage.getTokens();
|
|
818
|
-
}
|
|
819
|
-
if (tokens?.access_token) {
|
|
820
|
-
headers["Authorization"] = `Bearer ${tokens.access_token}`;
|
|
821
|
-
}
|
|
822
|
-
const finalPath = options?.params ? path + buildQueryString(options.params) : path;
|
|
823
|
-
const fetchOpts = { method, headers };
|
|
824
|
-
if (!["GET", "DELETE"].includes(method) && body !== void 0) {
|
|
825
|
-
fetchOpts.body = JSON.stringify(body);
|
|
826
|
-
}
|
|
827
|
-
const fullUrl = `${cfg.baseUrl}${finalPath}`;
|
|
828
|
-
let res;
|
|
829
|
-
let data;
|
|
830
|
-
const startedAt = Date.now();
|
|
831
|
-
try {
|
|
832
|
-
res = await fetch(fullUrl, fetchOpts);
|
|
833
|
-
} catch (error) {
|
|
834
|
-
const err = new Error(error instanceof Error ? error.message : "Network request failed");
|
|
835
|
-
err.name = "NetworkError";
|
|
836
|
-
err.method = method;
|
|
837
|
-
err.url = fullUrl;
|
|
838
|
-
if (options?.onError && method !== "GET") {
|
|
839
|
-
Promise.resolve(
|
|
840
|
-
options.onError({ error: err, method, url: fullUrl, aborted: false })
|
|
841
|
-
).catch(() => {
|
|
842
|
-
});
|
|
843
|
-
}
|
|
844
|
-
throw err;
|
|
845
|
-
}
|
|
846
|
-
if (res.status === 401 && !options?.["_retried"]) {
|
|
847
|
-
try {
|
|
848
|
-
await ensureFreshToken();
|
|
849
|
-
const refreshed = authStorage.getTokens();
|
|
850
|
-
if (refreshed?.access_token) {
|
|
851
|
-
headers["Authorization"] = `Bearer ${refreshed.access_token}`;
|
|
852
|
-
fetchOpts.headers = headers;
|
|
853
|
-
}
|
|
854
|
-
return request(method, path, body, { ...options, _retried: true });
|
|
855
|
-
} catch (refreshError) {
|
|
856
|
-
throw refreshError;
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
try {
|
|
860
|
-
const contentLength = res.headers.get("content-length");
|
|
861
|
-
const contentType = res.headers.get("content-type");
|
|
862
|
-
if (res.status === 204 || contentLength === "0" || !contentType?.includes("application/json")) {
|
|
863
|
-
data = {};
|
|
864
|
-
} else {
|
|
865
|
-
data = await res.json();
|
|
866
|
-
}
|
|
867
|
-
} catch (error) {
|
|
868
|
-
const err = new Error("Failed to parse response");
|
|
869
|
-
err.name = "ParseError";
|
|
870
|
-
err.method = method;
|
|
871
|
-
err.url = fullUrl;
|
|
872
|
-
err.status = res.status;
|
|
873
|
-
if (options?.onError && method !== "GET") {
|
|
874
|
-
Promise.resolve(
|
|
875
|
-
options.onError({ error: err, method, url: fullUrl, status: res.status })
|
|
876
|
-
).catch(() => {
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
throw err;
|
|
880
|
-
}
|
|
881
|
-
if (!res.ok) {
|
|
882
|
-
const serverErr = data;
|
|
883
|
-
const reqErr = convertServerErrorToRequestError(serverErr);
|
|
884
|
-
const err = new Error(serverErr.message || "Request failed");
|
|
885
|
-
err.name = "ApiError";
|
|
886
|
-
err.statusCode = serverErr.statusCode || res.status;
|
|
887
|
-
err.validationErrors = reqErr.validationErrors;
|
|
888
|
-
err.method = method;
|
|
889
|
-
err.url = fullUrl;
|
|
890
|
-
const requestId = res.headers.get("x-request-id") || res.headers.get("request-id");
|
|
891
|
-
if (requestId) err.requestId = requestId;
|
|
892
|
-
if (options?.onError && method !== "GET") {
|
|
893
|
-
Promise.resolve(
|
|
894
|
-
options.onError({
|
|
895
|
-
error: err,
|
|
896
|
-
method,
|
|
897
|
-
url: fullUrl,
|
|
898
|
-
status: res.status,
|
|
899
|
-
response: serverErr,
|
|
900
|
-
request_id: requestId || null,
|
|
901
|
-
duration_ms: Date.now() - startedAt
|
|
902
|
-
})
|
|
903
|
-
).catch(() => {
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
throw err;
|
|
907
|
-
}
|
|
908
|
-
if (options?.onSuccess && method !== "GET") {
|
|
909
|
-
const requestId = res.headers.get("x-request-id") || res.headers.get("request-id");
|
|
910
|
-
Promise.resolve(
|
|
911
|
-
options.onSuccess({
|
|
912
|
-
data,
|
|
913
|
-
method,
|
|
914
|
-
url: fullUrl,
|
|
915
|
-
status: res.status,
|
|
916
|
-
request_id: requestId || null,
|
|
917
|
-
duration_ms: Date.now() - startedAt
|
|
918
|
-
})
|
|
919
|
-
).catch(() => {
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
return data;
|
|
923
|
-
}
|
|
924
|
-
return {
|
|
925
|
-
get: (path, opts) => request("GET", path, void 0, opts),
|
|
926
|
-
post: (path, body, opts) => request("POST", path, body, opts),
|
|
927
|
-
put: (path, body, opts) => request("PUT", path, body, opts),
|
|
928
|
-
patch: (path, body, opts) => request("PATCH", path, body, opts),
|
|
929
|
-
delete: (path, opts) => request("DELETE", path, void 0, opts)
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// src/api/support.ts
|
|
934
|
-
function supportConversationQuery(params) {
|
|
935
|
-
const qs = new URLSearchParams({ store_id: params.store_id });
|
|
936
|
-
if (params.message_limit) qs.set("message_limit", String(params.message_limit));
|
|
937
|
-
if (typeof params.after_created_at === "number") qs.set("after_created_at", String(params.after_created_at));
|
|
938
|
-
if (params.after_id) qs.set("after_id", params.after_id);
|
|
939
|
-
return qs.toString();
|
|
940
|
-
}
|
|
941
|
-
function createStorefrontSupportApi(config) {
|
|
942
|
-
const { httpClient, storeId } = config;
|
|
943
|
-
return {
|
|
944
|
-
async startConversation(params = {}, opts) {
|
|
945
|
-
return httpClient.post(
|
|
946
|
-
`/v1/storefront/${storeId}/support/conversations`,
|
|
947
|
-
{ store_id: storeId, ...params },
|
|
948
|
-
opts
|
|
949
|
-
);
|
|
950
|
-
},
|
|
951
|
-
async sendMessage(params, opts) {
|
|
952
|
-
return httpClient.post(
|
|
953
|
-
`/v1/storefront/${storeId}/support/conversations/${params.conversation_id}/messages`,
|
|
954
|
-
{ store_id: storeId, ...params },
|
|
955
|
-
opts
|
|
956
|
-
);
|
|
957
|
-
},
|
|
958
|
-
async getConversation(params, opts) {
|
|
959
|
-
const qs = supportConversationQuery({ store_id: storeId, ...params });
|
|
960
|
-
return httpClient.get(
|
|
961
|
-
`/v1/storefront/${storeId}/support/conversations/${params.conversation_id}?${qs}`,
|
|
962
|
-
opts
|
|
963
|
-
);
|
|
964
|
-
}
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
// src/utils/price.ts
|
|
969
|
-
function formatCurrency(amount, currencyCode, locale = "en") {
|
|
970
|
-
if (!currencyCode) return "";
|
|
971
|
-
return new Intl.NumberFormat(locale, {
|
|
972
|
-
style: "currency",
|
|
973
|
-
currency: currencyCode.toUpperCase()
|
|
974
|
-
}).format(amount);
|
|
975
|
-
}
|
|
976
|
-
function getMinorUnits(currency) {
|
|
977
|
-
try {
|
|
978
|
-
const formatter = new Intl.NumberFormat("en", {
|
|
979
|
-
style: "currency",
|
|
980
|
-
currency: currency.toUpperCase()
|
|
981
|
-
});
|
|
982
|
-
const parts = formatter.formatToParts(1.11);
|
|
983
|
-
const fractionPart = parts.find((p) => p.type === "fraction");
|
|
984
|
-
return fractionPart?.value.length ?? 2;
|
|
985
|
-
} catch {
|
|
986
|
-
return 2;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
function convertToMajor(minorAmount, currency) {
|
|
990
|
-
const units = getMinorUnits(currency);
|
|
991
|
-
return minorAmount / Math.pow(10, units);
|
|
992
|
-
}
|
|
993
|
-
function getCurrencySymbol(currency) {
|
|
994
|
-
try {
|
|
995
|
-
return new Intl.NumberFormat("en", {
|
|
996
|
-
style: "currency",
|
|
997
|
-
currency: currency.toUpperCase(),
|
|
998
|
-
currencyDisplay: "narrowSymbol"
|
|
999
|
-
}).formatToParts(0).find((p) => p.type === "currency")?.value || currency.toUpperCase();
|
|
1000
|
-
} catch {
|
|
1001
|
-
return currency.toUpperCase();
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
function getCurrencyName(currency) {
|
|
1005
|
-
try {
|
|
1006
|
-
return new Intl.DisplayNames(["en"], { type: "currency" }).of(currency.toUpperCase()) || currency.toUpperCase();
|
|
1007
|
-
} catch {
|
|
1008
|
-
return currency.toUpperCase();
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
function formatMinor(amountMinor, currency) {
|
|
1012
|
-
if (!currency) return "";
|
|
1013
|
-
return formatCurrency(convertToMajor(amountMinor, currency), currency);
|
|
1014
|
-
}
|
|
1015
|
-
function formatPayment(payment) {
|
|
1016
|
-
return formatMinor(payment.total, payment.currency);
|
|
1017
|
-
}
|
|
1018
|
-
function formatPrice(prices, marketId) {
|
|
1019
|
-
if (!prices || prices.length === 0) return "";
|
|
1020
|
-
const price = marketId ? prices.find((p) => p.market === marketId) || prices[0] : prices[0];
|
|
1021
|
-
if (!price) return "";
|
|
1022
|
-
return formatMinor(price.amount, price.currency);
|
|
1023
|
-
}
|
|
1024
|
-
function getPriceAmount(prices, marketId) {
|
|
1025
|
-
if (!prices || prices.length === 0) return 0;
|
|
1026
|
-
const price = prices.find((p) => p.market === marketId) || prices[0];
|
|
1027
|
-
return price?.amount || 0;
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
// src/utils/validation.ts
|
|
1031
|
-
function validatePhoneNumber(phone) {
|
|
1032
|
-
if (!phone) {
|
|
1033
|
-
return { isValid: false, error: "Phone number is required" };
|
|
1034
|
-
}
|
|
1035
|
-
const cleaned = phone.replace(/\D/g, "");
|
|
1036
|
-
if (cleaned.length < 8) {
|
|
1037
|
-
return { isValid: false, error: "Phone number is too short" };
|
|
1038
|
-
}
|
|
1039
|
-
if (cleaned.length > 15) {
|
|
1040
|
-
return { isValid: false, error: "Phone number is too long" };
|
|
1041
|
-
}
|
|
1042
|
-
return { isValid: true };
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
// src/utils/timezone.ts
|
|
1046
|
-
var tzGroups = [
|
|
1047
|
-
{
|
|
1048
|
-
label: "US",
|
|
1049
|
-
zones: [
|
|
1050
|
-
{ label: "Eastern Time", value: "America/New_York" },
|
|
1051
|
-
{ label: "Central Time", value: "America/Chicago" },
|
|
1052
|
-
{ label: "Mountain Time", value: "America/Denver" },
|
|
1053
|
-
{ label: "Pacific Time", value: "America/Los_Angeles" }
|
|
1054
|
-
]
|
|
1055
|
-
},
|
|
1056
|
-
{
|
|
1057
|
-
label: "Europe",
|
|
1058
|
-
zones: [
|
|
1059
|
-
{ label: "London", value: "Europe/London" },
|
|
1060
|
-
{ label: "Paris", value: "Europe/Paris" },
|
|
1061
|
-
{ label: "Berlin", value: "Europe/Berlin" },
|
|
1062
|
-
{ label: "Rome", value: "Europe/Rome" }
|
|
1063
|
-
]
|
|
1064
|
-
},
|
|
1065
|
-
{
|
|
1066
|
-
label: "Asia",
|
|
1067
|
-
zones: [
|
|
1068
|
-
{ label: "Tokyo", value: "Asia/Tokyo" },
|
|
1069
|
-
{ label: "Shanghai", value: "Asia/Shanghai" },
|
|
1070
|
-
{ label: "Mumbai", value: "Asia/Kolkata" },
|
|
1071
|
-
{ label: "Dubai", value: "Asia/Dubai" }
|
|
1072
|
-
]
|
|
1073
|
-
}
|
|
1074
|
-
];
|
|
1075
|
-
function findTimeZone(groups) {
|
|
1076
|
-
try {
|
|
1077
|
-
const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1078
|
-
for (const group of groups) {
|
|
1079
|
-
for (const zone of group.zones) {
|
|
1080
|
-
if (zone.value === detected) {
|
|
1081
|
-
return detected;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
return "UTC";
|
|
1086
|
-
} catch (e) {
|
|
1087
|
-
return "UTC";
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// src/utils/text.ts
|
|
1092
|
-
var locales = ["en", "sr-latn"];
|
|
1093
|
-
var localeMap = {
|
|
1094
|
-
"en": "en-US",
|
|
1095
|
-
"sr-latn": "sr-RS"
|
|
1096
|
-
};
|
|
1097
|
-
function slugify(text) {
|
|
1098
|
-
return text.toString().toLowerCase().replace(/\s+/g, "-").replace(/[^\w-]+/g, "").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
|
|
1099
|
-
}
|
|
1100
|
-
function humanize(text) {
|
|
1101
|
-
const slugifiedText = slugify(text);
|
|
1102
|
-
return slugifiedText.replace(/-/g, " ").replace(
|
|
1103
|
-
/\w\S*/g,
|
|
1104
|
-
(w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1107
|
-
function categorify(text) {
|
|
1108
|
-
const slugifiedText = slugify(text);
|
|
1109
|
-
return slugifiedText.replace(/-/g, " ").toUpperCase();
|
|
1110
|
-
}
|
|
1111
|
-
function formatDate(date, locale) {
|
|
1112
|
-
let localeString = "en-US";
|
|
1113
|
-
if (locales.includes(locale)) {
|
|
1114
|
-
localeString = localeMap[locale];
|
|
1115
|
-
}
|
|
1116
|
-
return new Date(date).toLocaleDateString(localeString, {
|
|
1117
|
-
timeZone: "UTC",
|
|
1118
|
-
year: "numeric",
|
|
1119
|
-
month: "short",
|
|
1120
|
-
day: "numeric"
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
// src/utils/svg.ts
|
|
1125
|
-
async function fetchSvgContent(mediaObject) {
|
|
1126
|
-
if (!mediaObject) return null;
|
|
1127
|
-
const svgUrl = getImageUrl(mediaObject, false);
|
|
1128
|
-
try {
|
|
1129
|
-
const response = await fetch(svgUrl);
|
|
1130
|
-
if (!response.ok) {
|
|
1131
|
-
console.error(`Failed to fetch SVG: ${response.status} ${response.statusText}`);
|
|
1132
|
-
return null;
|
|
1133
|
-
}
|
|
1134
|
-
const svgContent = await response.text();
|
|
1135
|
-
return svgContent;
|
|
1136
|
-
} catch (error) {
|
|
1137
|
-
console.error("Error fetching SVG:", error);
|
|
1138
|
-
return null;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
async function getSvgContentForAstro(mediaObject) {
|
|
1142
|
-
try {
|
|
1143
|
-
const svgContent = await fetchSvgContent(mediaObject);
|
|
1144
|
-
return svgContent || "";
|
|
1145
|
-
} catch (error) {
|
|
1146
|
-
console.error("Error getting SVG content for Astro:", error);
|
|
1147
|
-
return "";
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
async function injectSvgIntoElement(mediaObject, targetElement, className) {
|
|
1151
|
-
if (!targetElement) return;
|
|
1152
|
-
try {
|
|
1153
|
-
const svgContent = await fetchSvgContent(mediaObject);
|
|
1154
|
-
if (svgContent) {
|
|
1155
|
-
targetElement.innerHTML = svgContent;
|
|
1156
|
-
if (className) {
|
|
1157
|
-
const svgElement = targetElement.querySelector("svg");
|
|
1158
|
-
if (svgElement) {
|
|
1159
|
-
svgElement.classList.add(...className.split(" "));
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
} catch (error) {
|
|
1164
|
-
console.error("Error injecting SVG:", error);
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
// src/utils/keyValidation.ts
|
|
1169
|
-
var KEY_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
1170
|
-
function isValidKey(key) {
|
|
1171
|
-
if (!key || key.length === 0) return false;
|
|
1172
|
-
return KEY_PATTERN.test(key);
|
|
1173
|
-
}
|
|
1174
|
-
function validateKey(key) {
|
|
1175
|
-
if (!key || key.length === 0) {
|
|
1176
|
-
return { valid: false, error: "Key is required" };
|
|
1177
|
-
}
|
|
1178
|
-
if (key.length > 255) {
|
|
1179
|
-
return { valid: false, error: "Key must be 255 characters or less" };
|
|
1180
|
-
}
|
|
1181
|
-
if (!KEY_PATTERN.test(key)) {
|
|
1182
|
-
return {
|
|
1183
|
-
valid: false,
|
|
1184
|
-
error: "Key can only contain letters, numbers, underscores (_) and hyphens (-)"
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
return { valid: true };
|
|
1188
|
-
}
|
|
1189
|
-
function toKey(input) {
|
|
1190
|
-
if (!input) return "";
|
|
1191
|
-
return input.toLowerCase().trim().replace(/\s+/g, "_").replace(/[^a-z0-9_-]/g, "").replace(/^[-_]+|[-_]+$/g, "").replace(/[-_]{2,}/g, "_");
|
|
1192
|
-
}
|
|
1193
|
-
function nameToKey(name) {
|
|
1194
|
-
return toKey(name);
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
// src/utils/inventory.ts
|
|
1198
|
-
function getAvailableStock(variant) {
|
|
1199
|
-
if (!variant?.inventory) return 0;
|
|
1200
|
-
return variant.inventory.reduce((sum, inv) => sum + inv.available, 0);
|
|
1201
|
-
}
|
|
1202
|
-
function getReservedStock(variant) {
|
|
1203
|
-
if (!variant?.inventory) return 0;
|
|
1204
|
-
return variant.inventory.reduce((sum, inv) => sum + inv.reserved, 0);
|
|
1205
|
-
}
|
|
1206
|
-
function hasStock(variant, quantity = 1) {
|
|
1207
|
-
return getAvailableStock(variant) >= quantity;
|
|
1208
|
-
}
|
|
1209
|
-
function getInventoryAt(variant, locationId) {
|
|
1210
|
-
return variant?.inventory?.find((inv) => inv.location_id === locationId);
|
|
1211
|
-
}
|
|
1212
|
-
function getFirstAvailableFCId(variant, quantity = 1) {
|
|
1213
|
-
const inv = variant?.inventory?.find((i) => i.available >= quantity);
|
|
1214
|
-
return inv?.location_id;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
// src/index.ts
|
|
1218
|
-
function createUtilitySurface(apiConfig) {
|
|
1219
|
-
return {
|
|
1220
|
-
getImageUrl: (imageBlock, isBlock = true) => getImageUrl(imageBlock, isBlock),
|
|
1221
|
-
getBlockValue,
|
|
1222
|
-
getBlockTextValue,
|
|
1223
|
-
getBlockValues,
|
|
1224
|
-
getBlockLabel,
|
|
1225
|
-
getBlockObjectValues,
|
|
1226
|
-
getBlockFromArray,
|
|
1227
|
-
formatBlockValue,
|
|
1228
|
-
prepareBlocksForSubmission,
|
|
1229
|
-
extractBlockValues,
|
|
1230
|
-
formatPrice: (prices) => formatPrice(prices, apiConfig.market),
|
|
1231
|
-
getPriceAmount: (prices) => getPriceAmount(prices, apiConfig.market),
|
|
1232
|
-
formatPayment,
|
|
1233
|
-
formatMinor,
|
|
1234
|
-
getCurrencySymbol,
|
|
1235
|
-
getCurrencyName,
|
|
1236
|
-
validatePhoneNumber,
|
|
1237
|
-
tzGroups,
|
|
1238
|
-
findTimeZone,
|
|
1239
|
-
slugify,
|
|
1240
|
-
humanize,
|
|
1241
|
-
categorify,
|
|
1242
|
-
formatDate,
|
|
1243
|
-
getSvgContentForAstro,
|
|
1244
|
-
fetchSvgContent,
|
|
1245
|
-
injectSvgIntoElement,
|
|
1246
|
-
isValidKey,
|
|
1247
|
-
validateKey,
|
|
1248
|
-
toKey,
|
|
1249
|
-
nameToKey,
|
|
1250
|
-
getAvailableStock,
|
|
1251
|
-
getReservedStock,
|
|
1252
|
-
hasStock,
|
|
1253
|
-
getInventoryAt,
|
|
1254
|
-
getFirstAvailableFCId
|
|
1255
|
-
};
|
|
1256
|
-
}
|
|
1257
|
-
var PROFILE_STORAGE_KEY = "arky_profile_session";
|
|
1258
|
-
function readProfileSession() {
|
|
1259
|
-
if (typeof window === "undefined") return null;
|
|
1260
|
-
try {
|
|
1261
|
-
const raw = localStorage.getItem(PROFILE_STORAGE_KEY);
|
|
1262
|
-
return raw ? JSON.parse(raw) : null;
|
|
1263
|
-
} catch {
|
|
1264
|
-
return null;
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
function writeProfileSession(s) {
|
|
1268
|
-
if (typeof window === "undefined") return;
|
|
1269
|
-
if (s) {
|
|
1270
|
-
localStorage.setItem(PROFILE_STORAGE_KEY, JSON.stringify(s));
|
|
1271
|
-
} else {
|
|
1272
|
-
localStorage.removeItem(PROFILE_STORAGE_KEY);
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
function createStorefront(config) {
|
|
1276
|
-
const locale = config.locale || "en";
|
|
1277
|
-
const initialMarket = config.market || "";
|
|
1278
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
1279
|
-
let bareIdentifyPromise = null;
|
|
1280
|
-
function toPublic(s) {
|
|
1281
|
-
return s ? { profile: s.profile, store: s.store, market: s.market } : null;
|
|
1282
|
-
}
|
|
1283
|
-
function emit() {
|
|
1284
|
-
const pub = toPublic(readProfileSession());
|
|
1285
|
-
for (const l of listeners) {
|
|
1286
|
-
Promise.resolve().then(() => l(pub)).catch(() => {
|
|
1287
|
-
});
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
const updateSession = (updater) => {
|
|
1291
|
-
if (config.apiToken) return;
|
|
1292
|
-
const prev = readProfileSession();
|
|
1293
|
-
const next = updater(prev);
|
|
1294
|
-
writeProfileSession(next);
|
|
1295
|
-
emit();
|
|
1296
|
-
};
|
|
1297
|
-
const authStorage = config.apiToken ? {
|
|
1298
|
-
getTokens: () => ({ access_token: config.apiToken }),
|
|
1299
|
-
onTokensRefreshed: () => {
|
|
1300
|
-
},
|
|
1301
|
-
onForcedLogout: () => {
|
|
1302
|
-
}
|
|
1303
|
-
} : {
|
|
1304
|
-
getTokens() {
|
|
1305
|
-
const s = readProfileSession();
|
|
1306
|
-
return s ? { access_token: s.access_token } : null;
|
|
1307
|
-
},
|
|
1308
|
-
onTokensRefreshed() {
|
|
1309
|
-
},
|
|
1310
|
-
onForcedLogout() {
|
|
1311
|
-
bareIdentifyPromise = null;
|
|
1312
|
-
updateSession(() => null);
|
|
1313
|
-
}
|
|
1314
|
-
};
|
|
1315
|
-
const httpClient = createHttpClient({
|
|
1316
|
-
baseUrl: config.baseUrl,
|
|
1317
|
-
storeId: config.storeId,
|
|
1318
|
-
refreshPath: config.refreshPath,
|
|
1319
|
-
navigate: config.navigate,
|
|
1320
|
-
loginFallbackPath: config.loginFallbackPath,
|
|
1321
|
-
authStorage
|
|
1322
|
-
});
|
|
1323
|
-
const apiConfig = {
|
|
1324
|
-
httpClient,
|
|
1325
|
-
storeId: config.storeId,
|
|
1326
|
-
baseUrl: config.baseUrl,
|
|
1327
|
-
market: initialMarket,
|
|
1328
|
-
locale,
|
|
1329
|
-
authStorage
|
|
1330
|
-
};
|
|
1331
|
-
const storefrontApi = createStorefrontApi(apiConfig, updateSession);
|
|
1332
|
-
const profileApi = storefrontApi.crm.profile;
|
|
1333
|
-
function identify(params) {
|
|
1334
|
-
if (params?.market !== void 0) apiConfig.market = params.market;
|
|
1335
|
-
const isBareCall = !params?.email && !params?.verify;
|
|
1336
|
-
if (isBareCall && bareIdentifyPromise) return bareIdentifyPromise;
|
|
1337
|
-
const promise = (async () => {
|
|
1338
|
-
try {
|
|
1339
|
-
const result = await profileApi.identify({
|
|
1340
|
-
market: apiConfig.market,
|
|
1341
|
-
email: params?.email,
|
|
1342
|
-
verify: params?.verify
|
|
1343
|
-
});
|
|
1344
|
-
return {
|
|
1345
|
-
profile: result.profile,
|
|
1346
|
-
store: result.store,
|
|
1347
|
-
market: result.market
|
|
1348
|
-
};
|
|
1349
|
-
} catch (err) {
|
|
1350
|
-
const e = err;
|
|
1351
|
-
const status = e?.statusCode || e?.status || e?.response?.status;
|
|
1352
|
-
if (isBareCall && status === 401) {
|
|
1353
|
-
updateSession(() => null);
|
|
1354
|
-
const result = await profileApi.identify({ market: apiConfig.market });
|
|
1355
|
-
return {
|
|
1356
|
-
profile: result.profile,
|
|
1357
|
-
store: result.store,
|
|
1358
|
-
market: result.market
|
|
1359
|
-
};
|
|
1360
|
-
}
|
|
1361
|
-
throw err;
|
|
1362
|
-
}
|
|
1363
|
-
})().catch((err) => {
|
|
1364
|
-
if (isBareCall) bareIdentifyPromise = null;
|
|
1365
|
-
throw err;
|
|
1366
|
-
});
|
|
1367
|
-
if (isBareCall) bareIdentifyPromise = promise;
|
|
1368
|
-
return promise;
|
|
1369
|
-
}
|
|
1370
|
-
async function verify(params) {
|
|
1371
|
-
const result = await profileApi.verify(params);
|
|
1372
|
-
bareIdentifyPromise = null;
|
|
1373
|
-
return result;
|
|
1374
|
-
}
|
|
1375
|
-
async function logout() {
|
|
1376
|
-
if (config.apiToken) return;
|
|
1377
|
-
bareIdentifyPromise = null;
|
|
1378
|
-
try {
|
|
1379
|
-
await profileApi.logout();
|
|
1380
|
-
} catch {
|
|
1381
|
-
updateSession(() => null);
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
return {
|
|
1385
|
-
identify,
|
|
1386
|
-
verify,
|
|
1387
|
-
logout,
|
|
1388
|
-
me: () => profileApi.getMe(),
|
|
1389
|
-
get session() {
|
|
1390
|
-
if (config.apiToken) return null;
|
|
1391
|
-
return toPublic(readProfileSession());
|
|
1392
|
-
},
|
|
1393
|
-
get isAuthenticated() {
|
|
1394
|
-
if (config.apiToken) return true;
|
|
1395
|
-
const s = readProfileSession();
|
|
1396
|
-
return s !== null && !!s.access_token;
|
|
1397
|
-
},
|
|
1398
|
-
onAuthStateChanged(listener) {
|
|
1399
|
-
listeners.add(listener);
|
|
1400
|
-
const current = toPublic(readProfileSession());
|
|
1401
|
-
if (current) {
|
|
1402
|
-
Promise.resolve().then(() => listener(current)).catch(() => {
|
|
1403
|
-
});
|
|
1404
|
-
}
|
|
1405
|
-
return () => {
|
|
1406
|
-
listeners.delete(listener);
|
|
1407
|
-
};
|
|
1408
|
-
},
|
|
1409
|
-
store: storefrontApi.store,
|
|
1410
|
-
cart: createCartController(storefrontApi.eshop.cart),
|
|
1411
|
-
cms: storefrontApi.cms,
|
|
1412
|
-
eshop: storefrontApi.eshop,
|
|
1413
|
-
crm: storefrontApi.crm,
|
|
1414
|
-
activity: storefrontApi.activity,
|
|
1415
|
-
support: createStorefrontSupportApi(apiConfig),
|
|
1416
|
-
setStoreId: (storeId) => {
|
|
1417
|
-
apiConfig.storeId = storeId;
|
|
1418
|
-
bareIdentifyPromise = null;
|
|
1419
|
-
},
|
|
1420
|
-
getStoreId: () => apiConfig.storeId,
|
|
1421
|
-
setMarket: (key) => {
|
|
1422
|
-
apiConfig.market = key;
|
|
1423
|
-
bareIdentifyPromise = null;
|
|
1424
|
-
},
|
|
1425
|
-
getMarket: () => apiConfig.market,
|
|
1426
|
-
setLocale: (l) => {
|
|
1427
|
-
apiConfig.locale = l;
|
|
1428
|
-
},
|
|
1429
|
-
getLocale: () => apiConfig.locale,
|
|
1430
|
-
extractBlockValues,
|
|
1431
|
-
utils: createUtilitySurface(apiConfig)
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
// src/storefrontStore/utils.ts
|
|
1436
|
-
function readErrorMessage(error, fallback) {
|
|
1437
|
-
if (error instanceof Error && error.message) return error.message;
|
|
1438
|
-
if (typeof error === "string" && error.length > 0) return error;
|
|
1439
|
-
return fallback;
|
|
1440
|
-
}
|
|
1441
|
-
function createId(prefix) {
|
|
1442
|
-
const cryptoValue = globalThis.crypto;
|
|
1443
|
-
if (cryptoValue && "randomUUID" in cryptoValue) return cryptoValue.randomUUID();
|
|
1444
|
-
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
1445
|
-
}
|
|
1446
|
-
function firstLocalized(value, locale) {
|
|
1447
|
-
if (typeof value === "string") return value;
|
|
1448
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return "";
|
|
1449
|
-
const record = value;
|
|
1450
|
-
const localeValue = record[locale];
|
|
1451
|
-
if (typeof localeValue === "string") return localeValue;
|
|
1452
|
-
const englishValue = record.en;
|
|
1453
|
-
if (typeof englishValue === "string") return englishValue;
|
|
1454
|
-
for (const entry of Object.values(record)) {
|
|
1455
|
-
if (typeof entry === "string") return entry;
|
|
1456
|
-
}
|
|
1457
|
-
return "";
|
|
1458
|
-
}
|
|
1459
|
-
function findBlock(blocks, keys) {
|
|
1460
|
-
return (blocks || []).find((block) => keys.includes(block.key)) || null;
|
|
1461
|
-
}
|
|
1462
|
-
function blockText(blocks, keys, locale) {
|
|
1463
|
-
const block = findBlock(blocks, keys);
|
|
1464
|
-
if (!block) return "";
|
|
1465
|
-
return firstLocalized(block.value, locale);
|
|
1466
|
-
}
|
|
1467
|
-
function productName(product, locale) {
|
|
1468
|
-
return blockText(product.blocks, ["name", "title"], locale) || product.key || product.id;
|
|
1469
|
-
}
|
|
1470
|
-
function serviceName(service, locale) {
|
|
1471
|
-
return blockText(service.blocks, ["name", "title"], locale) || service.key || service.id;
|
|
1472
|
-
}
|
|
1473
|
-
function providerName(provider, locale) {
|
|
1474
|
-
return blockText(provider.blocks, ["name", "title"], locale) || provider.key || provider.id;
|
|
1475
|
-
}
|
|
1476
|
-
function entitySlug(entity, locale) {
|
|
1477
|
-
return entity.slug?.[locale] || entity.slug?.en || Object.values(entity.slug || {})[0] || entity.id;
|
|
1478
|
-
}
|
|
1479
|
-
function priceForMarket(prices, market, fallbackCurrency) {
|
|
1480
|
-
const price = prices.find((candidate) => candidate.market === market) || prices[0];
|
|
1481
|
-
return {
|
|
1482
|
-
amount: price?.amount || 0,
|
|
1483
|
-
market: price?.market || market,
|
|
1484
|
-
currency: price?.currency || fallbackCurrency || "",
|
|
1485
|
-
compare_at: price?.compare_at,
|
|
1486
|
-
profile_list_id: price?.profile_list_id
|
|
1487
|
-
};
|
|
1488
|
-
}
|
|
1489
|
-
function availableStock(client, variant) {
|
|
1490
|
-
const fromUtility = client.utils.getAvailableStock(variant);
|
|
1491
|
-
if (Number.isFinite(fromUtility)) return fromUtility;
|
|
1492
|
-
const stock = (variant.inventory || []).reduce((total, row) => total + (row.available || 0), 0);
|
|
1493
|
-
return stock > 0 ? stock : void 0;
|
|
1494
|
-
}
|
|
1495
|
-
function locationToAddress(location) {
|
|
1496
|
-
return {
|
|
1497
|
-
country: location.country || "",
|
|
1498
|
-
state: location.state || "",
|
|
1499
|
-
city: location.city || "",
|
|
1500
|
-
postal_code: location.postal_code || "",
|
|
1501
|
-
name: "",
|
|
1502
|
-
street1: "",
|
|
1503
|
-
street2: null
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
function normalizeForms(forms) {
|
|
1507
|
-
return forms;
|
|
1508
|
-
}
|
|
1509
|
-
function toProductCheckoutItems(items) {
|
|
1510
|
-
return items.map((item) => ({
|
|
1511
|
-
type: "product",
|
|
1512
|
-
id: item.id,
|
|
1513
|
-
product_id: item.product_id,
|
|
1514
|
-
variant_id: item.variant_id,
|
|
1515
|
-
quantity: item.quantity
|
|
1516
|
-
}));
|
|
1517
|
-
}
|
|
1518
|
-
function toServiceCheckoutItems(items) {
|
|
1519
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1520
|
-
for (const item of items) {
|
|
1521
|
-
const key = `${item.service_id}:${item.provider_id}`;
|
|
1522
|
-
const slot = { from: item.from, to: item.to };
|
|
1523
|
-
const existing = groups.get(key);
|
|
1524
|
-
if (existing) {
|
|
1525
|
-
existing.slots.push(slot);
|
|
1526
|
-
continue;
|
|
1527
|
-
}
|
|
1528
|
-
groups.set(key, {
|
|
1529
|
-
type: "service",
|
|
1530
|
-
id: item.id,
|
|
1531
|
-
service_id: item.service_id,
|
|
1532
|
-
provider_id: item.provider_id,
|
|
1533
|
-
slots: [slot],
|
|
1534
|
-
forms: item.forms || []
|
|
1535
|
-
});
|
|
1536
|
-
}
|
|
1537
|
-
return [...groups.values()].map((item) => ({
|
|
1538
|
-
...item,
|
|
1539
|
-
slots: [...item.slots].sort((a, b) => a.from - b.from)
|
|
1540
|
-
}));
|
|
1541
|
-
}
|
|
1542
|
-
function formFieldsFromBlocks(blocks) {
|
|
1543
|
-
return blocks.map((block) => ({
|
|
1544
|
-
id: block.id,
|
|
1545
|
-
key: block.key,
|
|
1546
|
-
type: block.type,
|
|
1547
|
-
value: block.value
|
|
1548
|
-
}));
|
|
1549
|
-
}
|
|
1550
|
-
function getFormBlockType(field) {
|
|
1551
|
-
if (field.key === "email") return "email";
|
|
1552
|
-
if (field.key === "phone") return "phone";
|
|
1553
|
-
if (field.type === "geo_location") return "address";
|
|
1554
|
-
return field.type;
|
|
1555
|
-
}
|
|
1556
|
-
function getFormBlockValue(field) {
|
|
1557
|
-
if (field.type === "boolean") return false;
|
|
1558
|
-
if (field.type === "number") return field.min ?? 0;
|
|
1559
|
-
if (field.type === "geo_location") return {};
|
|
1560
|
-
return "";
|
|
1561
|
-
}
|
|
1562
|
-
function formSchemaToBlock(field) {
|
|
1563
|
-
return {
|
|
1564
|
-
id: field.id,
|
|
1565
|
-
key: field.key,
|
|
1566
|
-
type: getFormBlockType(field),
|
|
1567
|
-
properties: {
|
|
1568
|
-
isRequired: field.required,
|
|
1569
|
-
minValues: field.required ? 1 : 0,
|
|
1570
|
-
min: field.min,
|
|
1571
|
-
max: field.max,
|
|
1572
|
-
options: field.options,
|
|
1573
|
-
pattern: field.key === "email" ? "^.+@.+\\..+$" : field.key === "phone" ? "^.{6,20}$" : void 0
|
|
1574
|
-
},
|
|
1575
|
-
value: getFormBlockValue(field)
|
|
1576
|
-
};
|
|
1577
|
-
}
|
|
1578
|
-
function formatServiceTime(ts, tz) {
|
|
1579
|
-
return new Date(ts * 1e3).toLocaleTimeString([], {
|
|
1580
|
-
hour: "2-digit",
|
|
1581
|
-
minute: "2-digit",
|
|
1582
|
-
timeZone: tz
|
|
1583
|
-
});
|
|
1584
|
-
}
|
|
1585
|
-
function formatServiceSlotTime(from, to, tz) {
|
|
1586
|
-
return `${formatServiceTime(from, tz)} - ${formatServiceTime(to, tz)}`;
|
|
1587
|
-
}
|
|
1588
|
-
function getSlotsForDate(availability, dateStr, providerId) {
|
|
1589
|
-
if (!availability) return [];
|
|
1590
|
-
const slots = [];
|
|
1591
|
-
for (const provider of availability.providers) {
|
|
1592
|
-
if (providerId && provider.provider_id !== providerId) continue;
|
|
1593
|
-
const day = provider.days.find((candidate) => candidate.date === dateStr);
|
|
1594
|
-
if (!day) continue;
|
|
1595
|
-
for (const slot of day.slots) {
|
|
1596
|
-
if (slot.spots > 0) slots.push({ from: slot.from, to: slot.to, providerId: provider.provider_id });
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
return slots.sort((a, b) => a.from - b.from);
|
|
1600
|
-
}
|
|
1601
|
-
function hasAvailableSlotsForDate(availability, dateStr, providerId) {
|
|
1602
|
-
if (!availability) return false;
|
|
1603
|
-
return availability.providers.some((provider) => {
|
|
1604
|
-
if (providerId && provider.provider_id !== providerId) return false;
|
|
1605
|
-
const day = provider.days.find((candidate) => candidate.date === dateStr);
|
|
1606
|
-
return !!day?.slots.some((slot) => slot.spots > 0);
|
|
1607
|
-
});
|
|
1608
|
-
}
|
|
1609
|
-
var SERVICE_WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
1610
|
-
function createServiceInitialState() {
|
|
1611
|
-
return {
|
|
1612
|
-
service: null,
|
|
1613
|
-
availability: null,
|
|
1614
|
-
providers: [],
|
|
1615
|
-
selectedProviderId: null,
|
|
1616
|
-
currentMonth: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
|
|
1617
|
-
calendar: [],
|
|
1618
|
-
selectedDate: null,
|
|
1619
|
-
startDate: null,
|
|
1620
|
-
endDate: null,
|
|
1621
|
-
slots: [],
|
|
1622
|
-
selectedSlot: null,
|
|
1623
|
-
cart: [],
|
|
1624
|
-
timezone: typeof window !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : "UTC",
|
|
1625
|
-
tzGroups: {},
|
|
1626
|
-
loading: false,
|
|
1627
|
-
weekdays: SERVICE_WEEKDAYS,
|
|
1628
|
-
quote: null,
|
|
1629
|
-
fetchingQuote: false,
|
|
1630
|
-
quoteError: null,
|
|
1631
|
-
currency: null,
|
|
1632
|
-
dateTimeConfirmed: false,
|
|
1633
|
-
isMultiDay: false,
|
|
1634
|
-
availablePaymentMethods: [],
|
|
1635
|
-
cartId: null,
|
|
1636
|
-
promoCode: null
|
|
1637
|
-
};
|
|
1638
|
-
}
|
|
1639
|
-
function normalizeTimezoneGroups(groups) {
|
|
1640
|
-
const normalized = {};
|
|
1641
|
-
for (const group of groups) {
|
|
1642
|
-
normalized[group.label] = group.zones.map((zone) => ({
|
|
1643
|
-
zone: zone.value,
|
|
1644
|
-
name: zone.label
|
|
1645
|
-
}));
|
|
1646
|
-
}
|
|
1647
|
-
return normalized;
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
// src/storefrontStore/createArkyStore.ts
|
|
1651
|
-
function createArkyStore(config) {
|
|
1652
|
-
const client = createStorefront(config);
|
|
1653
|
-
const session = atom(client.session);
|
|
1654
|
-
const locale = atom(config.locale || client.getLocale());
|
|
1655
|
-
const market_key = atom(config.market || client.getMarket());
|
|
1656
|
-
const market = computed(session, (value) => value?.market || null);
|
|
1657
|
-
const currency = computed(market, (value) => value?.currency || null);
|
|
1658
|
-
const allowed_payment_methods = computed(market, (value) => value?.payment_methods || []);
|
|
1659
|
-
const payment_config = computed(session, (value) => {
|
|
1660
|
-
const store = value?.store;
|
|
1661
|
-
const methods = value?.market?.payment_methods || [];
|
|
1662
|
-
const hasCreditCard = methods.some((method) => method.id === "credit_card");
|
|
1663
|
-
return { provider: store?.payment || null, enabled: hasCreditCard && !!store?.payment };
|
|
1664
|
-
});
|
|
1665
|
-
const cart = atom(null);
|
|
1666
|
-
const product_items = atom([]);
|
|
1667
|
-
const service_items = atom([]);
|
|
1668
|
-
const quote = atom(null);
|
|
1669
|
-
const promo_code = atom(null);
|
|
1670
|
-
const last_order = atom(null);
|
|
1671
|
-
const cart_status = map({
|
|
1672
|
-
loading: false,
|
|
1673
|
-
syncing: false,
|
|
1674
|
-
fetching_quote: false,
|
|
1675
|
-
processing_checkout: false,
|
|
1676
|
-
error: null,
|
|
1677
|
-
quote_error: null,
|
|
1678
|
-
selected_shipping_method_id: null,
|
|
1679
|
-
user_token: null
|
|
1680
|
-
});
|
|
1681
|
-
function rawProductItemCount(value) {
|
|
1682
|
-
return (value?.items || []).reduce((total, item) => {
|
|
1683
|
-
if (item.type !== "product") return total;
|
|
1684
|
-
return total + (item.quantity || 0);
|
|
1685
|
-
}, 0);
|
|
1686
|
-
}
|
|
1687
|
-
function rawServiceItemCount(value) {
|
|
1688
|
-
return (value?.items || []).reduce((total, item) => {
|
|
1689
|
-
if (item.type !== "service") return total;
|
|
1690
|
-
return total + Math.max(1, item.slots?.length || 0);
|
|
1691
|
-
}, 0);
|
|
1692
|
-
}
|
|
1693
|
-
const product_item_count = computed(
|
|
1694
|
-
[cart, product_items],
|
|
1695
|
-
(cartValue, items) => Math.max(
|
|
1696
|
-
rawProductItemCount(cartValue),
|
|
1697
|
-
items.reduce((total, item) => total + (item.quantity || 0), 0)
|
|
1698
|
-
)
|
|
1699
|
-
);
|
|
1700
|
-
const service_item_count = computed(
|
|
1701
|
-
[cart, service_items],
|
|
1702
|
-
(cartValue, items) => Math.max(rawServiceItemCount(cartValue), items.length)
|
|
1703
|
-
);
|
|
1704
|
-
const item_count = computed(
|
|
1705
|
-
[cart, product_item_count, service_item_count],
|
|
1706
|
-
(cartValue, products, services) => Math.max(cartValue?.item_count || 0, products + services)
|
|
1707
|
-
);
|
|
1708
|
-
const snapshot = computed([cart, product_items, service_items, item_count], (cartValue, products, services, count) => ({
|
|
1709
|
-
cart: cartValue,
|
|
1710
|
-
product_items: products,
|
|
1711
|
-
service_items: services,
|
|
1712
|
-
item_count: count
|
|
1713
|
-
}));
|
|
1714
|
-
let cartWriteRevision = 0;
|
|
1715
|
-
let sessionRequest = null;
|
|
1716
|
-
let cartRequest = null;
|
|
1717
|
-
function nextCartWriteRevision() {
|
|
1718
|
-
cartWriteRevision += 1;
|
|
1719
|
-
return cartWriteRevision;
|
|
1720
|
-
}
|
|
1721
|
-
const cms_state = map({
|
|
1722
|
-
nodes: {},
|
|
1723
|
-
forms: {},
|
|
1724
|
-
loading: false,
|
|
1725
|
-
error: null
|
|
1726
|
-
});
|
|
1727
|
-
const eshop_state = map({
|
|
1728
|
-
products: [],
|
|
1729
|
-
services: [],
|
|
1730
|
-
providers: [],
|
|
1731
|
-
product_cursor: null,
|
|
1732
|
-
service_cursor: null,
|
|
1733
|
-
provider_cursor: null,
|
|
1734
|
-
availability: null,
|
|
1735
|
-
loading_products: false,
|
|
1736
|
-
loading_services: false,
|
|
1737
|
-
loading_providers: false,
|
|
1738
|
-
loading_availability: false,
|
|
1739
|
-
error: null
|
|
1740
|
-
});
|
|
1741
|
-
const service_state = map(createServiceInitialState());
|
|
1742
|
-
const service_form_node = atom(null);
|
|
1743
|
-
const service_form_blocks = computed(service_form_node, (node) => node?.blocks || []);
|
|
1744
|
-
client.onAuthStateChanged((value) => session.set(value));
|
|
1745
|
-
currency.subscribe((value) => service_state.setKey("currency", value));
|
|
1746
|
-
session.subscribe((value) => {
|
|
1747
|
-
const methods = value?.market?.payment_methods || [];
|
|
1748
|
-
if (methods.length && service_state.get().availablePaymentMethods.length === 0) {
|
|
1749
|
-
service_state.setKey("availablePaymentMethods", methods);
|
|
1750
|
-
}
|
|
1751
|
-
});
|
|
1752
|
-
function currentMarketKey() {
|
|
1753
|
-
return market_key.get() || client.getMarket() || market.get()?.key || "";
|
|
1754
|
-
}
|
|
1755
|
-
function currentLocale() {
|
|
1756
|
-
return locale.get() || client.getLocale() || "en";
|
|
1757
|
-
}
|
|
1758
|
-
function currentCurrency() {
|
|
1759
|
-
return currency.get() || market.get()?.currency || null;
|
|
1760
|
-
}
|
|
1761
|
-
function marketForLocale(value) {
|
|
1762
|
-
return config.marketForLocale?.(value) || null;
|
|
1763
|
-
}
|
|
1764
|
-
async function ensureSession() {
|
|
1765
|
-
const current = session.get();
|
|
1766
|
-
const marketKey = currentMarketKey();
|
|
1767
|
-
if (current && (!marketKey || current.market?.key === marketKey)) return current;
|
|
1768
|
-
if (!sessionRequest) {
|
|
1769
|
-
sessionRequest = identify({ market: marketKey }).finally(() => {
|
|
1770
|
-
sessionRequest = null;
|
|
1771
|
-
});
|
|
1772
|
-
}
|
|
1773
|
-
return sessionRequest;
|
|
1774
|
-
}
|
|
1775
|
-
async function identify(params = {}) {
|
|
1776
|
-
if (params.market) setMarket(params.market);
|
|
1777
|
-
const result = await client.identify({ ...params, market: params.market || currentMarketKey() });
|
|
1778
|
-
session.set(result);
|
|
1779
|
-
return result;
|
|
1780
|
-
}
|
|
1781
|
-
function setMarket(key) {
|
|
1782
|
-
market_key.set(key);
|
|
1783
|
-
client.setMarket(key);
|
|
1784
|
-
}
|
|
1785
|
-
function setLocale(value, options = {}) {
|
|
1786
|
-
locale.set(value);
|
|
1787
|
-
client.setLocale(value);
|
|
1788
|
-
const nextMarket = options.market || marketForLocale(value);
|
|
1789
|
-
if (nextMarket) setMarket(nextMarket);
|
|
1790
|
-
}
|
|
1791
|
-
function setContext(context) {
|
|
1792
|
-
if (context.locale) {
|
|
1793
|
-
setLocale(context.locale, { market: context.market });
|
|
1794
|
-
return;
|
|
1795
|
-
}
|
|
1796
|
-
if (context.market) setMarket(context.market);
|
|
1797
|
-
}
|
|
1798
|
-
async function ensureCart() {
|
|
1799
|
-
if (cartRequest) return cartRequest;
|
|
1800
|
-
cart_status.setKey("loading", true);
|
|
1801
|
-
cart_status.setKey("error", null);
|
|
1802
|
-
const refreshRevision = cartWriteRevision;
|
|
1803
|
-
cartRequest = (async () => {
|
|
1804
|
-
await ensureSession();
|
|
1805
|
-
const response = await client.cart.refresh({ market: currentMarketKey() });
|
|
1806
|
-
await hydrateCart(response, { ifRevision: refreshRevision });
|
|
1807
|
-
return response;
|
|
1808
|
-
})();
|
|
1809
|
-
try {
|
|
1810
|
-
return await cartRequest;
|
|
1811
|
-
} catch (error) {
|
|
1812
|
-
cart_status.setKey("error", readErrorMessage(error, "Failed to load cart."));
|
|
1813
|
-
throw error;
|
|
1814
|
-
} finally {
|
|
1815
|
-
cartRequest = null;
|
|
1816
|
-
cart_status.setKey("loading", false);
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
async function hydrateProductItem(item, source) {
|
|
1820
|
-
try {
|
|
1821
|
-
const product = await client.eshop.product.get({ id: item.product_id });
|
|
1822
|
-
const variant = product.variants.find((candidate) => candidate.id === item.variant_id);
|
|
1823
|
-
if (!variant) return null;
|
|
1824
|
-
return {
|
|
1825
|
-
id: item.id || createId("product"),
|
|
1826
|
-
product_id: product.id,
|
|
1827
|
-
variant_id: variant.id,
|
|
1828
|
-
product_name: productName(product, currentLocale()),
|
|
1829
|
-
product_slug: entitySlug(product, currentLocale()),
|
|
1830
|
-
variant_attributes: variant.attributes,
|
|
1831
|
-
price: priceForMarket(variant.prices, currentMarketKey(), currentCurrency()),
|
|
1832
|
-
quantity: item.quantity,
|
|
1833
|
-
added_at: source.created_at ? source.created_at * 1e3 : Date.now(),
|
|
1834
|
-
max_stock: availableStock(client, variant)
|
|
1835
|
-
};
|
|
1836
|
-
} catch {
|
|
1837
|
-
return null;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
async function hydrateServiceItems(items) {
|
|
1841
|
-
const rows = [];
|
|
1842
|
-
for (const item of items) {
|
|
1843
|
-
let service = null;
|
|
1844
|
-
let provider = null;
|
|
1845
|
-
try {
|
|
1846
|
-
service = await client.eshop.service.get({ id: item.service_id });
|
|
1847
|
-
} catch {
|
|
1848
|
-
}
|
|
1849
|
-
try {
|
|
1850
|
-
provider = await client.eshop.provider.get({ id: item.provider_id });
|
|
1851
|
-
} catch {
|
|
1852
|
-
}
|
|
1853
|
-
for (const [index, slot] of item.slots.entries()) {
|
|
1854
|
-
rows.push({
|
|
1855
|
-
id: item.id || createId(`service_${index}`),
|
|
1856
|
-
service_id: item.service_id,
|
|
1857
|
-
provider_id: item.provider_id,
|
|
1858
|
-
from: slot.from,
|
|
1859
|
-
to: slot.to,
|
|
1860
|
-
forms: item.forms || [],
|
|
1861
|
-
service_name: service ? serviceName(service, currentLocale()) : item.service_id,
|
|
1862
|
-
provider_name: provider ? providerName(provider, currentLocale()) : item.provider_id
|
|
1863
|
-
});
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
return rows;
|
|
1867
|
-
}
|
|
1868
|
-
async function hydrateCart(response, options = {}) {
|
|
1869
|
-
if (options.ifRevision !== void 0 && options.ifRevision !== cartWriteRevision) {
|
|
1870
|
-
return cart.get() || response;
|
|
1871
|
-
}
|
|
1872
|
-
cart.set(response);
|
|
1873
|
-
cart_status.setKey("user_token", response.token || null);
|
|
1874
|
-
cart_status.setKey("selected_shipping_method_id", response.shipping_method_id || null);
|
|
1875
|
-
promo_code.set(response.promo_code || null);
|
|
1876
|
-
quote.set(response.quote_snapshot || null);
|
|
1877
|
-
const items = response.items || [];
|
|
1878
|
-
const products = await Promise.all(
|
|
1879
|
-
items.filter((item) => item.type === "product").map((item) => hydrateProductItem(item, response))
|
|
1880
|
-
);
|
|
1881
|
-
const services = await hydrateServiceItems(
|
|
1882
|
-
items.filter((item) => item.type === "service")
|
|
1883
|
-
);
|
|
1884
|
-
product_items.set(products.filter((item) => item !== null));
|
|
1885
|
-
service_items.set(services);
|
|
1886
|
-
return response;
|
|
1887
|
-
}
|
|
1888
|
-
function checkoutItems(input = {}) {
|
|
1889
|
-
return [
|
|
1890
|
-
...toProductCheckoutItems(input.product_items || product_items.get()),
|
|
1891
|
-
...toServiceCheckoutItems(input.service_items || service_items.get())
|
|
1892
|
-
];
|
|
1893
|
-
}
|
|
1894
|
-
async function syncCart(input = {}, writeRevision = nextCartWriteRevision()) {
|
|
1895
|
-
cart_status.setKey("syncing", true);
|
|
1896
|
-
cart_status.setKey("error", null);
|
|
1897
|
-
try {
|
|
1898
|
-
const current = cart.get() || await ensureCart();
|
|
1899
|
-
const response = await client.cart.update({
|
|
1900
|
-
id: current.id,
|
|
1901
|
-
market: currentMarketKey(),
|
|
1902
|
-
items: checkoutItems(input),
|
|
1903
|
-
shipping_address: input.shipping_address || void 0,
|
|
1904
|
-
billing_address: input.billing_address || void 0,
|
|
1905
|
-
forms: normalizeForms(input.forms),
|
|
1906
|
-
promo_code: input.promo_code === void 0 ? promo_code.get() || void 0 : input.promo_code || void 0,
|
|
1907
|
-
payment_method_id: input.payment_method_id || void 0,
|
|
1908
|
-
shipping_method_id: input.shipping_method_id || cart_status.get().selected_shipping_method_id || void 0
|
|
1909
|
-
});
|
|
1910
|
-
if (input.promo_code !== void 0) promo_code.set(input.promo_code);
|
|
1911
|
-
if (input.shipping_method_id !== void 0) {
|
|
1912
|
-
cart_status.setKey("selected_shipping_method_id", input.shipping_method_id);
|
|
1913
|
-
}
|
|
1914
|
-
await hydrateCart(response, { ifRevision: writeRevision });
|
|
1915
|
-
return response;
|
|
1916
|
-
} catch (error) {
|
|
1917
|
-
cart_status.setKey("error", readErrorMessage(error, "Failed to sync cart."));
|
|
1918
|
-
throw error;
|
|
1919
|
-
} finally {
|
|
1920
|
-
cart_status.setKey("syncing", false);
|
|
1921
|
-
}
|
|
1922
|
-
}
|
|
1923
|
-
async function addProduct(product, variant, quantity = 1) {
|
|
1924
|
-
cart_status.setKey("error", null);
|
|
1925
|
-
const writeRevision = nextCartWriteRevision();
|
|
1926
|
-
try {
|
|
1927
|
-
const current = cart.get() || await ensureCart();
|
|
1928
|
-
const response = await client.cart.addItem({
|
|
1929
|
-
id: current.id,
|
|
1930
|
-
item: {
|
|
1931
|
-
type: "product",
|
|
1932
|
-
product_id: product.id,
|
|
1933
|
-
variant_id: variant.id,
|
|
1934
|
-
quantity
|
|
1935
|
-
}
|
|
1936
|
-
});
|
|
1937
|
-
await hydrateCart(response, { ifRevision: writeRevision });
|
|
1938
|
-
await client.activity.track({ type: "cart_added", payload: { product_id: product.id, variant_id: variant.id, quantity } });
|
|
1939
|
-
return response;
|
|
1940
|
-
} catch (error) {
|
|
1941
|
-
cart_status.setKey("error", readErrorMessage(error, "Failed to add product to cart."));
|
|
1942
|
-
throw error;
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
async function setProductQuantity(itemId, quantity) {
|
|
1946
|
-
const writeRevision = nextCartWriteRevision();
|
|
1947
|
-
const next = product_items.get().map((item) => {
|
|
1948
|
-
if (item.id !== itemId) return item;
|
|
1949
|
-
const bounded = item.max_stock ? Math.min(Math.max(1, quantity), item.max_stock) : Math.max(1, quantity);
|
|
1950
|
-
return { ...item, quantity: bounded };
|
|
1951
|
-
});
|
|
1952
|
-
product_items.set(next);
|
|
1953
|
-
return syncCart({ product_items: next }, writeRevision);
|
|
1954
|
-
}
|
|
1955
|
-
async function removeProduct(itemId) {
|
|
1956
|
-
const writeRevision = nextCartWriteRevision();
|
|
1957
|
-
const item = product_items.get().find((candidate) => candidate.id === itemId);
|
|
1958
|
-
product_items.set(product_items.get().filter((candidate) => candidate.id !== itemId));
|
|
1959
|
-
const current = cart.get();
|
|
1960
|
-
if (!current || !item) return null;
|
|
1961
|
-
const response = await client.cart.removeItem({
|
|
1962
|
-
id: current.id,
|
|
1963
|
-
item_id: item.id,
|
|
1964
|
-
product_id: item.product_id,
|
|
1965
|
-
variant_id: item.variant_id
|
|
1966
|
-
});
|
|
1967
|
-
await hydrateCart(response, { ifRevision: writeRevision });
|
|
1968
|
-
await client.activity.track({ type: "cart_removed", payload: { product_id: item.product_id, variant_id: item.variant_id } });
|
|
1969
|
-
return response;
|
|
1970
|
-
}
|
|
1971
|
-
async function addServiceItem(item) {
|
|
1972
|
-
const writeRevision = nextCartWriteRevision();
|
|
1973
|
-
const next = [...service_items.get(), item];
|
|
1974
|
-
service_items.set(next);
|
|
1975
|
-
return syncCart({ service_items: next }, writeRevision);
|
|
1976
|
-
}
|
|
1977
|
-
async function removeServiceItem(itemId) {
|
|
1978
|
-
const writeRevision = nextCartWriteRevision();
|
|
1979
|
-
const next = service_items.get().filter((item) => item.id !== itemId);
|
|
1980
|
-
service_items.set(next);
|
|
1981
|
-
return syncCart({ service_items: next }, writeRevision);
|
|
1982
|
-
}
|
|
1983
|
-
async function clearCart() {
|
|
1984
|
-
const writeRevision = nextCartWriteRevision();
|
|
1985
|
-
product_items.set([]);
|
|
1986
|
-
service_items.set([]);
|
|
1987
|
-
quote.set(null);
|
|
1988
|
-
promo_code.set(null);
|
|
1989
|
-
cart_status.setKey("selected_shipping_method_id", null);
|
|
1990
|
-
const current = cart.get();
|
|
1991
|
-
if (!current) return null;
|
|
1992
|
-
const response = await client.cart.clear({ id: current.id });
|
|
1993
|
-
await hydrateCart(response, { ifRevision: writeRevision });
|
|
1994
|
-
return response;
|
|
1995
|
-
}
|
|
1996
|
-
async function fetchQuote(input = {}) {
|
|
1997
|
-
if (checkoutItems(input).length === 0) {
|
|
1998
|
-
quote.set(null);
|
|
1999
|
-
return null;
|
|
2000
|
-
}
|
|
2001
|
-
cart_status.setKey("fetching_quote", true);
|
|
2002
|
-
cart_status.setKey("quote_error", null);
|
|
2003
|
-
try {
|
|
2004
|
-
const current = await syncCart(input);
|
|
2005
|
-
const response = await client.cart.quote({ id: current.id });
|
|
2006
|
-
quote.set(response);
|
|
2007
|
-
return response;
|
|
2008
|
-
} catch (error) {
|
|
2009
|
-
quote.set(null);
|
|
2010
|
-
cart_status.setKey("quote_error", readErrorMessage(error, "Failed to fetch quote."));
|
|
2011
|
-
throw error;
|
|
2012
|
-
} finally {
|
|
2013
|
-
cart_status.setKey("fetching_quote", false);
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
async function checkout(input = {}) {
|
|
2017
|
-
if (checkoutItems(input).length === 0) throw new Error("Cart is empty");
|
|
2018
|
-
cart_status.setKey("processing_checkout", true);
|
|
2019
|
-
cart_status.setKey("error", null);
|
|
2020
|
-
try {
|
|
2021
|
-
const current = await syncCart(input);
|
|
2022
|
-
await client.activity.track({ type: "checkout_started", payload: { cart_id: current.id } });
|
|
2023
|
-
const response = await client.cart.checkout({
|
|
2024
|
-
id: current.id,
|
|
2025
|
-
payment_method_id: input.payment_method_id || void 0
|
|
2026
|
-
});
|
|
2027
|
-
const quoteValue = quote.get();
|
|
2028
|
-
const stored = {
|
|
2029
|
-
order_id: response.order_id,
|
|
2030
|
-
number: response.number,
|
|
2031
|
-
client_secret: response.client_secret,
|
|
2032
|
-
payment: response.payment,
|
|
2033
|
-
product_items: input.product_items || product_items.get(),
|
|
2034
|
-
service_items: input.service_items || service_items.get(),
|
|
2035
|
-
shipping_address: input.shipping_address || null,
|
|
2036
|
-
billing_address: input.billing_address || null,
|
|
2037
|
-
total: quoteValue?.payment?.total || quoteValue?.total || response.payment?.total,
|
|
2038
|
-
currency: quoteValue?.payment?.currency || currentCurrency(),
|
|
2039
|
-
payment_method_id: input.payment_method_id || null,
|
|
2040
|
-
created_at: Date.now()
|
|
2041
|
-
};
|
|
2042
|
-
last_order.set(stored);
|
|
2043
|
-
product_items.set([]);
|
|
2044
|
-
service_items.set([]);
|
|
2045
|
-
cart.set(null);
|
|
2046
|
-
quote.set(null);
|
|
2047
|
-
promo_code.set(null);
|
|
2048
|
-
cart_status.setKey("selected_shipping_method_id", null);
|
|
2049
|
-
await client.activity.track({ type: "purchase", payload: { order_id: response.order_id, number: response.number } });
|
|
2050
|
-
return response;
|
|
2051
|
-
} catch (error) {
|
|
2052
|
-
cart_status.setKey("error", readErrorMessage(error, "Checkout failed."));
|
|
2053
|
-
throw error;
|
|
2054
|
-
} finally {
|
|
2055
|
-
cart_status.setKey("processing_checkout", false);
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
function serviceCalendar() {
|
|
2059
|
-
const state = service_state.get();
|
|
2060
|
-
const { currentMonth, selectedDate, startDate, endDate, availability, selectedProviderId } = state;
|
|
2061
|
-
const year = currentMonth.getFullYear();
|
|
2062
|
-
const monthIndex = currentMonth.getMonth();
|
|
2063
|
-
const first = new Date(year, monthIndex, 1);
|
|
2064
|
-
const last = new Date(year, monthIndex + 1, 0);
|
|
2065
|
-
const today = /* @__PURE__ */ new Date();
|
|
2066
|
-
today.setHours(0, 0, 0, 0);
|
|
2067
|
-
const cells = [];
|
|
2068
|
-
const pad = (first.getDay() + 6) % 7;
|
|
2069
|
-
for (let i = 0; i < pad; i++) {
|
|
2070
|
-
cells.push({
|
|
2071
|
-
date: /* @__PURE__ */ new Date(0),
|
|
2072
|
-
iso: "",
|
|
2073
|
-
available: false,
|
|
2074
|
-
isSelected: false,
|
|
2075
|
-
isInRange: false,
|
|
2076
|
-
isToday: false,
|
|
2077
|
-
blank: true
|
|
2078
|
-
});
|
|
2079
|
-
}
|
|
2080
|
-
for (let day = 1; day <= last.getDate(); day++) {
|
|
2081
|
-
const date = new Date(year, monthIndex, day);
|
|
2082
|
-
const iso = `${year}-${String(monthIndex + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
2083
|
-
const isSelected = iso === selectedDate || iso === startDate || iso === endDate;
|
|
2084
|
-
let isInRange = false;
|
|
2085
|
-
if (startDate && endDate) {
|
|
2086
|
-
const time = date.getTime();
|
|
2087
|
-
isInRange = time > new Date(startDate).getTime() && time < new Date(endDate).getTime();
|
|
2088
|
-
}
|
|
2089
|
-
cells.push({
|
|
2090
|
-
date,
|
|
2091
|
-
iso,
|
|
2092
|
-
available: hasAvailableSlotsForDate(availability, iso, selectedProviderId),
|
|
2093
|
-
isSelected,
|
|
2094
|
-
isInRange,
|
|
2095
|
-
isToday: date.getTime() === today.getTime(),
|
|
2096
|
-
blank: false
|
|
2097
|
-
});
|
|
2098
|
-
}
|
|
2099
|
-
const suffix = (7 - cells.length % 7) % 7;
|
|
2100
|
-
for (let i = 0; i < suffix; i++) {
|
|
2101
|
-
cells.push({
|
|
2102
|
-
date: /* @__PURE__ */ new Date(0),
|
|
2103
|
-
iso: "",
|
|
2104
|
-
available: false,
|
|
2105
|
-
isSelected: false,
|
|
2106
|
-
isInRange: false,
|
|
2107
|
-
isToday: false,
|
|
2108
|
-
blank: true
|
|
2109
|
-
});
|
|
2110
|
-
}
|
|
2111
|
-
return cells;
|
|
2112
|
-
}
|
|
2113
|
-
function computeServiceSlots(dateStr) {
|
|
2114
|
-
const state = service_state.get();
|
|
2115
|
-
const { availability, selectedProviderId, timezone, service } = state;
|
|
2116
|
-
return getSlotsForDate(availability, dateStr, selectedProviderId).map((slot, index) => ({
|
|
2117
|
-
id: `${service?.id || "service"}-${slot.from}-${index}`,
|
|
2118
|
-
serviceId: service?.id || "",
|
|
2119
|
-
providerId: slot.providerId,
|
|
2120
|
-
from: slot.from,
|
|
2121
|
-
to: slot.to,
|
|
2122
|
-
timeText: formatServiceSlotTime(slot.from, slot.to, timezone),
|
|
2123
|
-
dateText: new Date(slot.from * 1e3).toLocaleDateString([], {
|
|
2124
|
-
weekday: "short",
|
|
2125
|
-
month: "short",
|
|
2126
|
-
day: "numeric",
|
|
2127
|
-
timeZone: timezone
|
|
2128
|
-
})
|
|
2129
|
-
}));
|
|
2130
|
-
}
|
|
2131
|
-
function toServiceCartItem(slot) {
|
|
2132
|
-
return {
|
|
2133
|
-
id: slot.id,
|
|
2134
|
-
service_id: slot.serviceId,
|
|
2135
|
-
provider_id: slot.providerId,
|
|
2136
|
-
from: slot.from,
|
|
2137
|
-
to: slot.to,
|
|
2138
|
-
forms: [],
|
|
2139
|
-
service_name: slot.serviceName,
|
|
2140
|
-
date_text: slot.dateText,
|
|
2141
|
-
time_text: slot.timeText,
|
|
2142
|
-
is_multi_day: slot.isMultiDay
|
|
2143
|
-
};
|
|
2144
|
-
}
|
|
2145
|
-
function fromServiceCartItem(item) {
|
|
2146
|
-
return {
|
|
2147
|
-
id: item.id,
|
|
2148
|
-
serviceId: item.service_id,
|
|
2149
|
-
providerId: item.provider_id,
|
|
2150
|
-
from: item.from,
|
|
2151
|
-
to: item.to,
|
|
2152
|
-
serviceName: item.service_name || "",
|
|
2153
|
-
date: item.date_text || "",
|
|
2154
|
-
dateText: item.date_text || "",
|
|
2155
|
-
timeText: item.time_text || formatServiceSlotTime(item.from, item.to, service_state.get().timezone),
|
|
2156
|
-
isMultiDay: item.is_multi_day
|
|
2157
|
-
};
|
|
2158
|
-
}
|
|
2159
|
-
function setServiceCartFromServiceItems(items) {
|
|
2160
|
-
const next = items.map(fromServiceCartItem);
|
|
2161
|
-
const current = service_state.get().cart;
|
|
2162
|
-
if (JSON.stringify(current) !== JSON.stringify(next)) {
|
|
2163
|
-
service_state.setKey("cart", next);
|
|
2164
|
-
}
|
|
2165
|
-
}
|
|
2166
|
-
async function syncServiceCart(slots) {
|
|
2167
|
-
try {
|
|
2168
|
-
return await syncCart({
|
|
2169
|
-
product_items: product_items.get(),
|
|
2170
|
-
service_items: slots.map(toServiceCartItem)
|
|
2171
|
-
});
|
|
2172
|
-
} catch (error) {
|
|
2173
|
-
service_state.setKey("quoteError", readErrorMessage(error, "Failed to sync service cart."));
|
|
2174
|
-
throw error;
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
function serviceCurrentStepName() {
|
|
2178
|
-
const state = service_state.get();
|
|
2179
|
-
if (!state.service) return "";
|
|
2180
|
-
if (!state.selectedSlot || !state.dateTimeConfirmed) return "datetime";
|
|
2181
|
-
return "review";
|
|
2182
|
-
}
|
|
2183
|
-
const service_current_step_name = computed(service_state, serviceCurrentStepName);
|
|
2184
|
-
const service_can_proceed = computed(service_state, (state) => {
|
|
2185
|
-
const step = serviceCurrentStepName();
|
|
2186
|
-
if (step === "datetime") {
|
|
2187
|
-
return state.isMultiDay ? !!(state.startDate && state.endDate && state.selectedSlot) : !!(state.selectedDate && state.selectedSlot);
|
|
2188
|
-
}
|
|
2189
|
-
if (step === "review") return true;
|
|
2190
|
-
return false;
|
|
2191
|
-
});
|
|
2192
|
-
const service_month_year = computed(
|
|
2193
|
-
service_state,
|
|
2194
|
-
(state) => state.currentMonth.toLocaleString(void 0, { month: "long", year: "numeric" })
|
|
2195
|
-
);
|
|
2196
|
-
const service_chain_start = computed(service_state, (state) => {
|
|
2197
|
-
if (!state.cart.length) return null;
|
|
2198
|
-
return Math.max(...state.cart.map((slot) => slot.to));
|
|
2199
|
-
});
|
|
2200
|
-
const service_total_steps = computed(service_state, (state) => state.service ? 2 : 0);
|
|
2201
|
-
const service_steps = computed(service_state, () => ({
|
|
2202
|
-
1: { name: "datetime" },
|
|
2203
|
-
2: { name: "review" }
|
|
2204
|
-
}));
|
|
2205
|
-
const service_current_step = computed([service_current_step_name, service_steps], (name, steps) => {
|
|
2206
|
-
for (const [idx, step] of Object.entries(steps)) {
|
|
2207
|
-
if (step.name === name) return Number(idx);
|
|
2208
|
-
}
|
|
2209
|
-
return 1;
|
|
2210
|
-
});
|
|
2211
|
-
function formatServiceDateDisplay(value) {
|
|
2212
|
-
if (!value) return "";
|
|
2213
|
-
return new Date(value).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
2214
|
-
}
|
|
2215
|
-
function serviceProviderId(provider) {
|
|
2216
|
-
return "provider_id" in provider ? provider.provider_id : provider.id;
|
|
2217
|
-
}
|
|
2218
|
-
function getFirstServiceProviderEntry(state) {
|
|
2219
|
-
const serviceWithProviders = state.service;
|
|
2220
|
-
const providers = serviceWithProviders?.providers;
|
|
2221
|
-
if (!providers?.length) return null;
|
|
2222
|
-
if (state.selectedProviderId) {
|
|
2223
|
-
const match = providers.find((provider) => provider.provider_id === state.selectedProviderId);
|
|
2224
|
-
if (match) return match;
|
|
2225
|
-
}
|
|
2226
|
-
return providers[0];
|
|
2227
|
-
}
|
|
2228
|
-
async function loadServiceForm() {
|
|
2229
|
-
try {
|
|
2230
|
-
const form = await loadForm({ key: "order-form" });
|
|
2231
|
-
const blocks = (form.schema || []).map(formSchemaToBlock);
|
|
2232
|
-
service_form_node.set({ blocks });
|
|
2233
|
-
return blocks;
|
|
2234
|
-
} catch {
|
|
2235
|
-
service_form_node.set({ blocks: [] });
|
|
2236
|
-
return [];
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
const service_controller = {
|
|
2240
|
-
async initialize() {
|
|
2241
|
-
service_state.setKey("tzGroups", normalizeTimezoneGroups(client.utils.tzGroups));
|
|
2242
|
-
await ensureCart();
|
|
2243
|
-
setServiceCartFromServiceItems(service_items.get());
|
|
2244
|
-
const methods = session.get()?.market?.payment_methods || [];
|
|
2245
|
-
if (methods.length) service_state.setKey("availablePaymentMethods", methods);
|
|
2246
|
-
await loadServiceForm();
|
|
2247
|
-
},
|
|
2248
|
-
setTimezone(tz) {
|
|
2249
|
-
service_state.setKey("timezone", tz);
|
|
2250
|
-
service_state.setKey("calendar", serviceCalendar());
|
|
2251
|
-
const state = service_state.get();
|
|
2252
|
-
if (state.selectedDate) {
|
|
2253
|
-
service_state.setKey("slots", computeServiceSlots(state.selectedDate));
|
|
2254
|
-
service_state.setKey("selectedSlot", null);
|
|
2255
|
-
}
|
|
2256
|
-
},
|
|
2257
|
-
async select(service) {
|
|
2258
|
-
service_state.setKey("loading", true);
|
|
2259
|
-
try {
|
|
2260
|
-
const isMultiDayBlock = service.blocks?.find((block) => block.key === "isMultiDay");
|
|
2261
|
-
const blockValue = isMultiDayBlock?.value;
|
|
2262
|
-
const isMultiDay = Array.isArray(blockValue) ? blockValue[0] === true : blockValue === true;
|
|
2263
|
-
const [fullService, serviceProviders] = await Promise.all([
|
|
2264
|
-
client.eshop.service.get({ id: service.id }),
|
|
2265
|
-
client.eshop.service.findProviders({ service_id: service.id })
|
|
2266
|
-
]);
|
|
2267
|
-
const providerIds = [...new Set(serviceProviders.map(serviceProviderId))];
|
|
2268
|
-
const providerResults = await Promise.all(
|
|
2269
|
-
providerIds.map((id) => client.eshop.provider.get({ id }).catch(() => null))
|
|
2270
|
-
);
|
|
2271
|
-
service_state.set({
|
|
2272
|
-
...service_state.get(),
|
|
2273
|
-
service: fullService,
|
|
2274
|
-
providers: providerResults.filter((provider) => provider !== null),
|
|
2275
|
-
selectedProviderId: null,
|
|
2276
|
-
availability: null,
|
|
2277
|
-
selectedDate: null,
|
|
2278
|
-
startDate: null,
|
|
2279
|
-
endDate: null,
|
|
2280
|
-
slots: [],
|
|
2281
|
-
selectedSlot: null,
|
|
2282
|
-
currentMonth: new Date((/* @__PURE__ */ new Date()).getFullYear(), (/* @__PURE__ */ new Date()).getMonth(), 1),
|
|
2283
|
-
loading: false,
|
|
2284
|
-
isMultiDay
|
|
2285
|
-
});
|
|
2286
|
-
await service_controller.loadMonth();
|
|
2287
|
-
} catch (error) {
|
|
2288
|
-
service_state.setKey("loading", false);
|
|
2289
|
-
throw error;
|
|
2290
|
-
}
|
|
2291
|
-
},
|
|
2292
|
-
async loadMonth() {
|
|
2293
|
-
const state = service_state.get();
|
|
2294
|
-
if (!state.service) return;
|
|
2295
|
-
service_state.setKey("loading", true);
|
|
2296
|
-
try {
|
|
2297
|
-
const chainedStart = service_chain_start.get();
|
|
2298
|
-
let from;
|
|
2299
|
-
let to;
|
|
2300
|
-
if (chainedStart) {
|
|
2301
|
-
from = chainedStart;
|
|
2302
|
-
to = chainedStart;
|
|
2303
|
-
} else {
|
|
2304
|
-
const month = state.currentMonth;
|
|
2305
|
-
from = Math.floor(Date.UTC(month.getFullYear(), month.getMonth(), 1) / 1e3);
|
|
2306
|
-
to = Math.floor(Date.UTC(month.getFullYear(), month.getMonth() + 1, 1) / 1e3);
|
|
2307
|
-
}
|
|
2308
|
-
const availability = await loadAvailability({
|
|
2309
|
-
service_id: state.service.id,
|
|
2310
|
-
from,
|
|
2311
|
-
to
|
|
2312
|
-
});
|
|
2313
|
-
service_state.setKey("availability", availability);
|
|
2314
|
-
service_state.setKey("calendar", serviceCalendar());
|
|
2315
|
-
} finally {
|
|
2316
|
-
service_state.setKey("loading", false);
|
|
2317
|
-
}
|
|
2318
|
-
},
|
|
2319
|
-
prevMonth() {
|
|
2320
|
-
const { currentMonth } = service_state.get();
|
|
2321
|
-
service_state.setKey("currentMonth", new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1, 1));
|
|
2322
|
-
void service_controller.loadMonth();
|
|
2323
|
-
},
|
|
2324
|
-
nextMonth() {
|
|
2325
|
-
const { currentMonth } = service_state.get();
|
|
2326
|
-
service_state.setKey("currentMonth", new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1, 1));
|
|
2327
|
-
void service_controller.loadMonth();
|
|
2328
|
-
},
|
|
2329
|
-
selectProvider(providerId) {
|
|
2330
|
-
service_state.set({
|
|
2331
|
-
...service_state.get(),
|
|
2332
|
-
selectedProviderId: providerId,
|
|
2333
|
-
selectedDate: null,
|
|
2334
|
-
startDate: null,
|
|
2335
|
-
endDate: null,
|
|
2336
|
-
slots: [],
|
|
2337
|
-
selectedSlot: null
|
|
2338
|
-
});
|
|
2339
|
-
void service_controller.loadMonth();
|
|
2340
|
-
},
|
|
2341
|
-
selectDate(cell) {
|
|
2342
|
-
if (cell.blank || !cell.available) return;
|
|
2343
|
-
service_state.setKey("dateTimeConfirmed", false);
|
|
2344
|
-
const state = service_state.get();
|
|
2345
|
-
if (state.isMultiDay) {
|
|
2346
|
-
if (!state.startDate) {
|
|
2347
|
-
service_state.setKey("startDate", cell.iso);
|
|
2348
|
-
service_state.setKey("selectedDate", cell.iso);
|
|
2349
|
-
service_state.setKey("endDate", null);
|
|
2350
|
-
service_state.setKey("selectedSlot", null);
|
|
2351
|
-
} else if (!state.endDate) {
|
|
2352
|
-
if (cell.date.getTime() < new Date(state.startDate).getTime()) {
|
|
2353
|
-
service_state.setKey("startDate", cell.iso);
|
|
2354
|
-
service_state.setKey("endDate", state.startDate);
|
|
2355
|
-
} else {
|
|
2356
|
-
service_state.setKey("endDate", cell.iso);
|
|
2357
|
-
}
|
|
2358
|
-
service_controller.createMultiDaySlots();
|
|
2359
|
-
} else {
|
|
2360
|
-
service_state.setKey("startDate", cell.iso);
|
|
2361
|
-
service_state.setKey("selectedDate", cell.iso);
|
|
2362
|
-
service_state.setKey("endDate", null);
|
|
2363
|
-
service_state.setKey("selectedSlot", null);
|
|
2364
|
-
}
|
|
2365
|
-
service_controller.updateCalendar();
|
|
2366
|
-
} else {
|
|
2367
|
-
service_state.set({
|
|
2368
|
-
...state,
|
|
2369
|
-
selectedDate: cell.iso,
|
|
2370
|
-
slots: computeServiceSlots(cell.iso),
|
|
2371
|
-
selectedSlot: null
|
|
2372
|
-
});
|
|
2373
|
-
service_state.setKey("calendar", serviceCalendar());
|
|
2374
|
-
}
|
|
2375
|
-
},
|
|
2376
|
-
createMultiDaySlots() {
|
|
2377
|
-
const state = service_state.get();
|
|
2378
|
-
if (!state.startDate || !state.endDate || !state.availability) return;
|
|
2379
|
-
const slots = [];
|
|
2380
|
-
for (let day = new Date(state.startDate); day <= new Date(state.endDate); day.setDate(day.getDate() + 1)) {
|
|
2381
|
-
const iso = day.toISOString().slice(0, 10);
|
|
2382
|
-
for (const slot of getSlotsForDate(state.availability, iso, state.selectedProviderId)) {
|
|
2383
|
-
slots.push({
|
|
2384
|
-
id: `${state.service?.id || "service"}-${slot.from}-${slots.length}`,
|
|
2385
|
-
serviceId: state.service?.id || "",
|
|
2386
|
-
providerId: slot.providerId,
|
|
2387
|
-
from: slot.from,
|
|
2388
|
-
to: slot.to,
|
|
2389
|
-
timeText: formatServiceSlotTime(slot.from, slot.to, state.timezone),
|
|
2390
|
-
dateText: new Date(slot.from * 1e3).toLocaleDateString([], {
|
|
2391
|
-
weekday: "short",
|
|
2392
|
-
month: "short",
|
|
2393
|
-
day: "numeric",
|
|
2394
|
-
timeZone: state.timezone
|
|
2395
|
-
}),
|
|
2396
|
-
isMultiDay: true
|
|
2397
|
-
});
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
|
-
service_state.setKey("slots", slots);
|
|
2401
|
-
service_state.setKey("selectedSlot", slots.length === 1 ? slots[0] : null);
|
|
2402
|
-
},
|
|
2403
|
-
selectTimeSlot(slot) {
|
|
2404
|
-
service_state.setKey("dateTimeConfirmed", false);
|
|
2405
|
-
service_state.setKey("selectedSlot", slot);
|
|
2406
|
-
},
|
|
2407
|
-
resetDateSelection() {
|
|
2408
|
-
service_state.setKey("selectedDate", null);
|
|
2409
|
-
service_state.setKey("startDate", null);
|
|
2410
|
-
service_state.setKey("endDate", null);
|
|
2411
|
-
service_state.setKey("slots", []);
|
|
2412
|
-
service_state.setKey("selectedSlot", null);
|
|
2413
|
-
service_state.setKey("dateTimeConfirmed", false);
|
|
2414
|
-
},
|
|
2415
|
-
updateCalendar() {
|
|
2416
|
-
service_state.setKey("calendar", serviceCalendar());
|
|
2417
|
-
},
|
|
2418
|
-
findFirstAvailable() {
|
|
2419
|
-
for (const day of service_state.get().calendar) {
|
|
2420
|
-
if (!day.blank && day.available) {
|
|
2421
|
-
service_controller.selectDate(day);
|
|
2422
|
-
return;
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
},
|
|
2426
|
-
async addToCart() {
|
|
2427
|
-
const state = service_state.get();
|
|
2428
|
-
const serviceBlocks = state.service?.forms || [];
|
|
2429
|
-
const enrich = (slot) => ({
|
|
2430
|
-
...slot,
|
|
2431
|
-
serviceName: state.service ? serviceName(state.service, currentLocale()) : "",
|
|
2432
|
-
date: slot.dateText,
|
|
2433
|
-
serviceBlocks
|
|
2434
|
-
});
|
|
2435
|
-
const selected = state.isMultiDay && state.slots.length > 0 ? state.slots.map(enrich) : state.selectedSlot ? [enrich(state.selectedSlot)] : [];
|
|
2436
|
-
if (!selected.length) return;
|
|
2437
|
-
const nextCart = [...state.cart, ...selected];
|
|
2438
|
-
service_state.set({
|
|
2439
|
-
...state,
|
|
2440
|
-
cart: nextCart,
|
|
2441
|
-
selectedDate: null,
|
|
2442
|
-
startDate: null,
|
|
2443
|
-
endDate: null,
|
|
2444
|
-
slots: [],
|
|
2445
|
-
selectedSlot: null
|
|
2446
|
-
});
|
|
2447
|
-
await syncServiceCart(nextCart);
|
|
2448
|
-
service_state.setKey("calendar", serviceCalendar());
|
|
2449
|
-
},
|
|
2450
|
-
async removeFromCart(slotId) {
|
|
2451
|
-
const nextCart = service_state.get().cart.filter((slot) => slot.id !== slotId);
|
|
2452
|
-
service_state.setKey("cart", nextCart);
|
|
2453
|
-
await syncServiceCart(nextCart);
|
|
2454
|
-
},
|
|
2455
|
-
async clearCart() {
|
|
2456
|
-
service_state.setKey("cart", []);
|
|
2457
|
-
await syncServiceCart([]);
|
|
2458
|
-
},
|
|
2459
|
-
async checkout(paymentMethodId, forms = []) {
|
|
2460
|
-
const state = service_state.get();
|
|
2461
|
-
if (!state.cart.length) return { success: false, error: "Cart is empty" };
|
|
2462
|
-
service_state.setKey("loading", true);
|
|
2463
|
-
try {
|
|
2464
|
-
const result = await checkout({
|
|
2465
|
-
service_items: state.cart.map((slot) => ({
|
|
2466
|
-
...toServiceCartItem(slot),
|
|
2467
|
-
forms: []
|
|
2468
|
-
})),
|
|
2469
|
-
payment_method_id: paymentMethodId,
|
|
2470
|
-
promo_code: state.promoCode || void 0,
|
|
2471
|
-
forms
|
|
2472
|
-
});
|
|
2473
|
-
service_state.setKey("cartId", cart.get()?.id || null);
|
|
2474
|
-
return { success: true, data: result };
|
|
2475
|
-
} catch (error) {
|
|
2476
|
-
return { success: false, error: readErrorMessage(error, "Checkout failed.") };
|
|
2477
|
-
} finally {
|
|
2478
|
-
service_state.setKey("loading", false);
|
|
2479
|
-
}
|
|
2480
|
-
},
|
|
2481
|
-
async fetchQuote(paymentMethodId, promoCode) {
|
|
2482
|
-
const state = service_state.get();
|
|
2483
|
-
if (!state.cart.length) return null;
|
|
2484
|
-
service_state.setKey("fetchingQuote", true);
|
|
2485
|
-
service_state.setKey("quoteError", null);
|
|
2486
|
-
try {
|
|
2487
|
-
service_state.setKey("promoCode", promoCode || null);
|
|
2488
|
-
const response = await fetchQuote({
|
|
2489
|
-
service_items: state.cart.map(toServiceCartItem),
|
|
2490
|
-
payment_method_id: paymentMethodId,
|
|
2491
|
-
promo_code: promoCode || void 0
|
|
2492
|
-
});
|
|
2493
|
-
service_state.setKey("cartId", cart.get()?.id || null);
|
|
2494
|
-
service_state.setKey("quote", response);
|
|
2495
|
-
const methods = response?.payment_methods || session.get()?.market?.payment_methods || [];
|
|
2496
|
-
if (methods.length) service_state.setKey("availablePaymentMethods", methods);
|
|
2497
|
-
return response;
|
|
2498
|
-
} catch (error) {
|
|
2499
|
-
service_state.setKey("quoteError", readErrorMessage(error, "Failed to fetch quote."));
|
|
2500
|
-
return null;
|
|
2501
|
-
} finally {
|
|
2502
|
-
service_state.setKey("fetchingQuote", false);
|
|
2503
|
-
}
|
|
2504
|
-
},
|
|
2505
|
-
getProvidersList() {
|
|
2506
|
-
return service_state.get().providers;
|
|
2507
|
-
},
|
|
2508
|
-
prevStep() {
|
|
2509
|
-
const current = serviceCurrentStepName();
|
|
2510
|
-
if (current === "review") {
|
|
2511
|
-
service_state.setKey("dateTimeConfirmed", false);
|
|
2512
|
-
return;
|
|
2513
|
-
}
|
|
2514
|
-
if (current === "datetime") {
|
|
2515
|
-
service_state.setKey("selectedSlot", null);
|
|
2516
|
-
service_state.setKey("dateTimeConfirmed", false);
|
|
2517
|
-
}
|
|
2518
|
-
},
|
|
2519
|
-
nextStep() {
|
|
2520
|
-
if (serviceCurrentStepName() === "datetime" && service_can_proceed.get()) {
|
|
2521
|
-
service_state.setKey("dateTimeConfirmed", true);
|
|
2522
|
-
}
|
|
2523
|
-
},
|
|
2524
|
-
getServicePrice() {
|
|
2525
|
-
const state = service_state.get();
|
|
2526
|
-
if (state.quote?.total !== void 0) return String(state.quote.total);
|
|
2527
|
-
const provider = getFirstServiceProviderEntry(state);
|
|
2528
|
-
if (!provider?.prices) return "";
|
|
2529
|
-
return client.utils.formatPrice(provider.prices) || "0";
|
|
2530
|
-
},
|
|
2531
|
-
formatDateDisplay: formatServiceDateDisplay,
|
|
2532
|
-
serviceItemsFromSlots(slots) {
|
|
2533
|
-
return slots.map(toServiceCartItem);
|
|
2534
|
-
}
|
|
2535
|
-
};
|
|
2536
|
-
service_items.subscribe((items) => setServiceCartFromServiceItems(items));
|
|
2537
|
-
async function loadNode(params, options) {
|
|
2538
|
-
cms_state.setKey("loading", true);
|
|
2539
|
-
cms_state.setKey("error", null);
|
|
2540
|
-
try {
|
|
2541
|
-
const { locale: nextLocale, market: nextMarket, ...nodeParams } = params;
|
|
2542
|
-
setContext({ locale: nextLocale, market: nextMarket });
|
|
2543
|
-
const node = await client.cms.node.get(nodeParams, options);
|
|
2544
|
-
const key = nodeParams.key || nodeParams.id || nodeParams.slug || node.id;
|
|
2545
|
-
cms_state.setKey("nodes", { ...cms_state.get().nodes, [key]: node });
|
|
2546
|
-
return node;
|
|
2547
|
-
} catch (error) {
|
|
2548
|
-
cms_state.setKey("error", readErrorMessage(error, "Failed to load CMS node."));
|
|
2549
|
-
throw error;
|
|
2550
|
-
} finally {
|
|
2551
|
-
cms_state.setKey("loading", false);
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
|
-
async function loadForm(params, options) {
|
|
2555
|
-
cms_state.setKey("loading", true);
|
|
2556
|
-
cms_state.setKey("error", null);
|
|
2557
|
-
try {
|
|
2558
|
-
const form = await client.cms.form.get(params, options);
|
|
2559
|
-
const key = params.key || params.id || form.key || form.id;
|
|
2560
|
-
cms_state.setKey("forms", { ...cms_state.get().forms, [key]: form });
|
|
2561
|
-
return form;
|
|
2562
|
-
} catch (error) {
|
|
2563
|
-
cms_state.setKey("error", readErrorMessage(error, "Failed to load CMS form."));
|
|
2564
|
-
throw error;
|
|
2565
|
-
} finally {
|
|
2566
|
-
cms_state.setKey("loading", false);
|
|
2567
|
-
}
|
|
2568
|
-
}
|
|
2569
|
-
async function submitFormByKey(key, fieldsOrBlocks, options) {
|
|
2570
|
-
const forms = cms_state.get().forms;
|
|
2571
|
-
const form = forms[key] || await loadForm({ key });
|
|
2572
|
-
const fields = fieldsOrBlocks.length > 0 && "properties" in fieldsOrBlocks[0] ? formFieldsFromBlocks(fieldsOrBlocks) : fieldsOrBlocks;
|
|
2573
|
-
const payload = { form_id: form.id, fields };
|
|
2574
|
-
return client.cms.form.submit(payload, options);
|
|
2575
|
-
}
|
|
2576
|
-
async function loadProducts(params = {}, options) {
|
|
2577
|
-
eshop_state.setKey("loading_products", true);
|
|
2578
|
-
eshop_state.setKey("error", null);
|
|
2579
|
-
try {
|
|
2580
|
-
const response = await client.eshop.product.find(params, options);
|
|
2581
|
-
eshop_state.setKey("products", response.items || []);
|
|
2582
|
-
eshop_state.setKey("product_cursor", response.cursor || null);
|
|
2583
|
-
return response;
|
|
2584
|
-
} catch (error) {
|
|
2585
|
-
eshop_state.setKey("error", readErrorMessage(error, "Failed to load products."));
|
|
2586
|
-
throw error;
|
|
2587
|
-
} finally {
|
|
2588
|
-
eshop_state.setKey("loading_products", false);
|
|
2589
|
-
}
|
|
2590
|
-
}
|
|
2591
|
-
async function loadServices(params = {}, options) {
|
|
2592
|
-
eshop_state.setKey("loading_services", true);
|
|
2593
|
-
eshop_state.setKey("error", null);
|
|
2594
|
-
try {
|
|
2595
|
-
const response = await client.eshop.service.find(params, options);
|
|
2596
|
-
eshop_state.setKey("services", response.items || []);
|
|
2597
|
-
eshop_state.setKey("service_cursor", response.cursor || null);
|
|
2598
|
-
return response;
|
|
2599
|
-
} catch (error) {
|
|
2600
|
-
eshop_state.setKey("error", readErrorMessage(error, "Failed to load services."));
|
|
2601
|
-
throw error;
|
|
2602
|
-
} finally {
|
|
2603
|
-
eshop_state.setKey("loading_services", false);
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
async function loadProviders(params = {}, options) {
|
|
2607
|
-
eshop_state.setKey("loading_providers", true);
|
|
2608
|
-
eshop_state.setKey("error", null);
|
|
2609
|
-
try {
|
|
2610
|
-
const response = await client.eshop.provider.find(params, options);
|
|
2611
|
-
eshop_state.setKey("providers", response.items || []);
|
|
2612
|
-
eshop_state.setKey("provider_cursor", response.cursor || null);
|
|
2613
|
-
return response;
|
|
2614
|
-
} catch (error) {
|
|
2615
|
-
eshop_state.setKey("error", readErrorMessage(error, "Failed to load providers."));
|
|
2616
|
-
throw error;
|
|
2617
|
-
} finally {
|
|
2618
|
-
eshop_state.setKey("loading_providers", false);
|
|
2619
|
-
}
|
|
2620
|
-
}
|
|
2621
|
-
async function loadAvailability(params, options) {
|
|
2622
|
-
eshop_state.setKey("loading_availability", true);
|
|
2623
|
-
eshop_state.setKey("error", null);
|
|
2624
|
-
try {
|
|
2625
|
-
const response = await client.eshop.service.getAvailability(params, options);
|
|
2626
|
-
eshop_state.setKey("availability", response);
|
|
2627
|
-
return response;
|
|
2628
|
-
} catch (error) {
|
|
2629
|
-
eshop_state.setKey("error", readErrorMessage(error, "Failed to load availability."));
|
|
2630
|
-
throw error;
|
|
2631
|
-
} finally {
|
|
2632
|
-
eshop_state.setKey("loading_availability", false);
|
|
2633
|
-
}
|
|
2634
|
-
}
|
|
2635
|
-
async function setup(options = {}) {
|
|
2636
|
-
setContext(options);
|
|
2637
|
-
const shouldIdentify = options.identify === true || !!options.hydrateCart || !!options.track;
|
|
2638
|
-
const results = {
|
|
2639
|
-
session: session.get()
|
|
2640
|
-
};
|
|
2641
|
-
if (shouldIdentify) results.session = await ensureSession();
|
|
2642
|
-
if (options.hydrateCart) results.cart = await ensureCart();
|
|
2643
|
-
if (options.track) await client.activity.track(options.track);
|
|
2644
|
-
return results;
|
|
2645
|
-
}
|
|
2646
|
-
async function initialize(options = {}) {
|
|
2647
|
-
return setup(options);
|
|
2648
|
-
}
|
|
2649
|
-
const cart_store = {
|
|
2650
|
-
cart,
|
|
2651
|
-
product_items,
|
|
2652
|
-
service_items,
|
|
2653
|
-
quote_result: quote,
|
|
2654
|
-
promo_code,
|
|
2655
|
-
last_order,
|
|
2656
|
-
status: cart_status,
|
|
2657
|
-
product_item_count,
|
|
2658
|
-
service_item_count,
|
|
2659
|
-
item_count,
|
|
2660
|
-
snapshot,
|
|
2661
|
-
ensure: ensureCart,
|
|
2662
|
-
hydrate: hydrateCart,
|
|
2663
|
-
sync: syncCart,
|
|
2664
|
-
addProduct,
|
|
2665
|
-
setProductQuantity,
|
|
2666
|
-
removeProduct,
|
|
2667
|
-
addServiceItem,
|
|
2668
|
-
removeServiceItem,
|
|
2669
|
-
clear: clearCart,
|
|
2670
|
-
quote: fetchQuote,
|
|
2671
|
-
checkout,
|
|
2672
|
-
applyPromoCode(code, input = {}) {
|
|
2673
|
-
promo_code.set(code);
|
|
2674
|
-
return fetchQuote({ ...input, promo_code: code });
|
|
2675
|
-
},
|
|
2676
|
-
removePromoCode(input = {}) {
|
|
2677
|
-
promo_code.set(null);
|
|
2678
|
-
return fetchQuote({ ...input, promo_code: null });
|
|
2679
|
-
},
|
|
2680
|
-
selectShippingMethod(id) {
|
|
2681
|
-
cart_status.setKey("selected_shipping_method_id", id);
|
|
2682
|
-
},
|
|
2683
|
-
locationToAddress,
|
|
2684
|
-
buildItems: checkoutItems,
|
|
2685
|
-
buildProductItems: toProductCheckoutItems,
|
|
2686
|
-
buildServiceItems: toServiceCheckoutItems
|
|
2687
|
-
};
|
|
2688
|
-
const product_store = {
|
|
2689
|
-
get: (params, options) => client.eshop.product.get(params, options),
|
|
2690
|
-
find: loadProducts,
|
|
2691
|
-
list: loadProducts,
|
|
2692
|
-
loadListing: loadProducts,
|
|
2693
|
-
loadDetail: (params, options) => client.eshop.product.get(params, options)
|
|
2694
|
-
};
|
|
2695
|
-
const service_store = {
|
|
2696
|
-
get: (params, options) => client.eshop.service.get(params, options),
|
|
2697
|
-
find: loadServices,
|
|
2698
|
-
list: loadServices,
|
|
2699
|
-
loadListing: loadServices,
|
|
2700
|
-
loadDetail: (params, options) => client.eshop.service.get(params, options),
|
|
2701
|
-
listProviders: (params, options) => client.eshop.service.findProviders(params, options),
|
|
2702
|
-
findProviders: (params, options) => client.eshop.service.findProviders(params, options),
|
|
2703
|
-
getAvailability: loadAvailability,
|
|
2704
|
-
state: service_state,
|
|
2705
|
-
form_blocks: service_form_blocks,
|
|
2706
|
-
current_step_name: service_current_step_name,
|
|
2707
|
-
can_proceed: service_can_proceed,
|
|
2708
|
-
month_year: service_month_year,
|
|
2709
|
-
chain_start: service_chain_start,
|
|
2710
|
-
total_steps: service_total_steps,
|
|
2711
|
-
steps: service_steps,
|
|
2712
|
-
current_step: service_current_step,
|
|
2713
|
-
initialize: service_controller.initialize,
|
|
2714
|
-
select: service_controller.select,
|
|
2715
|
-
setTimezone: service_controller.setTimezone,
|
|
2716
|
-
loadMonth: service_controller.loadMonth,
|
|
2717
|
-
prevMonth: service_controller.prevMonth,
|
|
2718
|
-
nextMonth: service_controller.nextMonth,
|
|
2719
|
-
selectProvider: service_controller.selectProvider,
|
|
2720
|
-
selectDate: service_controller.selectDate,
|
|
2721
|
-
createMultiDaySlots: service_controller.createMultiDaySlots,
|
|
2722
|
-
selectTimeSlot: service_controller.selectTimeSlot,
|
|
2723
|
-
resetDateSelection: service_controller.resetDateSelection,
|
|
2724
|
-
updateCalendar: service_controller.updateCalendar,
|
|
2725
|
-
findFirstAvailable: service_controller.findFirstAvailable,
|
|
2726
|
-
addToCart: service_controller.addToCart,
|
|
2727
|
-
removeFromCart: service_controller.removeFromCart,
|
|
2728
|
-
clearCart: service_controller.clearCart,
|
|
2729
|
-
getProvidersList: service_controller.getProvidersList,
|
|
2730
|
-
prevStep: service_controller.prevStep,
|
|
2731
|
-
nextStep: service_controller.nextStep,
|
|
2732
|
-
getServicePrice: service_controller.getServicePrice,
|
|
2733
|
-
formatDateDisplay: service_controller.formatDateDisplay,
|
|
2734
|
-
serviceItemsFromSlots: service_controller.serviceItemsFromSlots
|
|
2735
|
-
};
|
|
2736
|
-
return {
|
|
2737
|
-
client,
|
|
2738
|
-
session,
|
|
2739
|
-
market,
|
|
2740
|
-
market_key,
|
|
2741
|
-
locale,
|
|
2742
|
-
currency,
|
|
2743
|
-
allowed_payment_methods,
|
|
2744
|
-
payment_config,
|
|
2745
|
-
setup,
|
|
2746
|
-
initialize,
|
|
2747
|
-
identify,
|
|
2748
|
-
verify: client.verify,
|
|
2749
|
-
me: client.me,
|
|
2750
|
-
logout: client.logout,
|
|
2751
|
-
onAuthStateChanged: client.onAuthStateChanged,
|
|
2752
|
-
get currentSession() {
|
|
2753
|
-
return session.get();
|
|
2754
|
-
},
|
|
2755
|
-
get isAuthenticated() {
|
|
2756
|
-
return client.isAuthenticated;
|
|
2757
|
-
},
|
|
2758
|
-
setMarket,
|
|
2759
|
-
setLocale,
|
|
2760
|
-
setContext,
|
|
2761
|
-
getStoreId: client.getStoreId,
|
|
2762
|
-
getMarket: currentMarketKey,
|
|
2763
|
-
getLocale: currentLocale,
|
|
2764
|
-
cms: {
|
|
2765
|
-
state: cms_state,
|
|
2766
|
-
node: {
|
|
2767
|
-
get: loadNode,
|
|
2768
|
-
find: (params, options) => client.cms.node.find(params, options),
|
|
2769
|
-
getChildren: (params, options) => client.cms.node.getChildren(params, options)
|
|
2770
|
-
},
|
|
2771
|
-
form: {
|
|
2772
|
-
get: loadForm,
|
|
2773
|
-
submit: (params, options) => client.cms.form.submit(params, options),
|
|
2774
|
-
submitByKey: submitFormByKey
|
|
2775
|
-
},
|
|
2776
|
-
taxonomy: client.cms.taxonomy
|
|
2777
|
-
},
|
|
2778
|
-
eshop: {
|
|
2779
|
-
state: eshop_state,
|
|
2780
|
-
product: product_store,
|
|
2781
|
-
service: service_store,
|
|
2782
|
-
provider: {
|
|
2783
|
-
get: (params, options) => client.eshop.provider.get(params, options),
|
|
2784
|
-
find: loadProviders
|
|
2785
|
-
},
|
|
2786
|
-
order: client.eshop.order,
|
|
2787
|
-
cart: cart_store
|
|
2788
|
-
},
|
|
2789
|
-
crm: client.crm,
|
|
2790
|
-
activity: {
|
|
2791
|
-
track(params) {
|
|
2792
|
-
return client.activity.track(params);
|
|
2793
|
-
},
|
|
2794
|
-
pageView(payload = {}) {
|
|
2795
|
-
return client.activity.track({ type: "page_view", payload });
|
|
2796
|
-
},
|
|
2797
|
-
state: atom(null)
|
|
2798
|
-
},
|
|
2799
|
-
support: client.support,
|
|
2800
|
-
store: client.store,
|
|
2801
|
-
utils: client.utils
|
|
2802
|
-
};
|
|
2803
|
-
}
|
|
2804
|
-
|
|
2805
|
-
export { createArkyStore };
|
|
2806
|
-
//# sourceMappingURL=storefront-store.js.map
|
|
2807
|
-
//# sourceMappingURL=storefront-store.js.map
|