@zenky/storefront-vue 0.9.44 → 0.9.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js DELETED
@@ -1,3725 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var vue = require('vue');
6
- var api = require('@zenky/api');
7
- var lodashEs = require('lodash-es');
8
- var pinia = require('pinia');
9
- var events = require('@zenky/events');
10
- var dateFns = require('date-fns');
11
- var Pusher = require('pusher-js');
12
-
13
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
-
15
- var Pusher__default = /*#__PURE__*/_interopDefaultLegacy(Pusher);
16
-
17
- function useDataDestroyer(destroyer, errorHandler) {
18
- const destroying = vue.ref(false);
19
- const destroy = async (id) => {
20
- if (destroying.value) {
21
- return false;
22
- }
23
- destroying.value = true;
24
- try {
25
- await destroyer(id);
26
- return true;
27
- }
28
- catch (e) {
29
- errorHandler({
30
- e,
31
- error: api.getApiError(e),
32
- message: api.getApiErrorMessage(e),
33
- });
34
- }
35
- finally {
36
- destroying.value = false;
37
- }
38
- return false;
39
- };
40
- return {
41
- destroying,
42
- destroy,
43
- };
44
- }
45
-
46
- function getApiErrorHandler(providedHandler, composableName, defaultMessage) {
47
- if (typeof providedHandler === 'function') {
48
- return providedHandler;
49
- }
50
- return function ({ e, error, message }) {
51
- console.error(`[${composableName}] ${defaultMessage}`, {
52
- message,
53
- error,
54
- e,
55
- });
56
- console.info(`[@zenky/storefront] Pass errorHandler argument to the ${composableName}() composable to properly handle this error.`);
57
- };
58
- }
59
-
60
- exports.ZenkyInjection = void 0;
61
- (function (ZenkyInjection) {
62
- ZenkyInjection["ProductsSource"] = "zenky:products:source";
63
- ZenkyInjection["Category"] = "zenky:category";
64
- ZenkyInjection["CategoryNotFound"] = "zenky:category:notFound";
65
- ZenkyInjection["Collection"] = "zenky:collection";
66
- ZenkyInjection["CollectionNotFound"] = "zenky:collection:notFound";
67
- ZenkyInjection["Offer"] = "zenky:offer";
68
- ZenkyInjection["OfferNotFound"] = "zenky:offer:notFound";
69
- ZenkyInjection["CategoryContext"] = "zenky:context:category";
70
- ZenkyInjection["CategoryContextNotFound"] = "zenky:context:category:notFound";
71
- ZenkyInjection["GroupContext"] = "zenky:context:category";
72
- ZenkyInjection["GroupContextNotFound"] = "zenky:context:category:notFound";
73
- ZenkyInjection["VariantOptionContext"] = "zenky:context:variant_option";
74
- ZenkyInjection["VariantOptionContextNotFound"] = "zenky:context:variant_option:notFound";
75
- ZenkyInjection["VariantOptionValueContext"] = "zenky:context:variant_option_value";
76
- ZenkyInjection["VariantOptionValueContextNotFound"] = "zenky:context:variant_option_value:notFound";
77
- })(exports.ZenkyInjection || (exports.ZenkyInjection = {}));
78
-
79
- async function useStateDataLoader(state, loader) {
80
- if (state.value.loaded) {
81
- // Data was already loaded, return it.
82
- return state.value.data;
83
- }
84
- else if (state.value.loading) {
85
- // If data is in loading state, return promise that will be resolved after data loaded.
86
- return new Promise(function (resolve) {
87
- const loaded = vue.computed(() => state.value.loaded);
88
- const stop = vue.watch(loaded, function (val) {
89
- if (val) {
90
- resolve(state.value.data);
91
- stop();
92
- }
93
- }, { immediate: true });
94
- });
95
- }
96
- // Data is not loading nor was loaded, dispatch loader now.
97
- await loader();
98
- return state.value.data;
99
- }
100
- function usePaginatedLoader(provider, errorHandler) {
101
- const state = vue.ref({
102
- waiting: false,
103
- loading: false,
104
- loaded: false,
105
- });
106
- const pagination = vue.ref(null);
107
- const items = vue.ref([]);
108
- const load = async (request, reset = false) => {
109
- if (state.value.loading) {
110
- return;
111
- }
112
- if (reset) {
113
- state.value.loaded = false;
114
- }
115
- state.value.loading = true;
116
- if (!state.value.loaded) {
117
- state.value.waiting = true;
118
- }
119
- try {
120
- const { pagination: currentPagination, items: currentItems, } = await provider(request);
121
- pagination.value = currentPagination;
122
- if (reset) {
123
- items.value = currentItems;
124
- }
125
- else {
126
- currentItems.forEach((item) => items.value.push(item));
127
- }
128
- }
129
- catch (e) {
130
- errorHandler({
131
- e,
132
- error: api.getApiError(e),
133
- message: api.getApiErrorMessage(e),
134
- });
135
- }
136
- finally {
137
- state.value.loading = false;
138
- state.value.waiting = false;
139
- state.value.loaded = true;
140
- }
141
- };
142
- return {
143
- state,
144
- pagination,
145
- items,
146
- load,
147
- };
148
- }
149
- function useListLoader(provider, errorHandler) {
150
- const state = vue.ref({
151
- loading: false,
152
- loaded: false,
153
- });
154
- const items = vue.ref([]);
155
- const load = async (request) => {
156
- if (state.value.loading || state.value.loaded) {
157
- return;
158
- }
159
- state.value.loading = true;
160
- try {
161
- items.value = await provider(request);
162
- }
163
- catch (e) {
164
- errorHandler({
165
- e,
166
- error: api.getApiError(e),
167
- message: api.getApiErrorMessage(e),
168
- });
169
- }
170
- finally {
171
- state.value.loading = false;
172
- state.value.loaded = true;
173
- }
174
- };
175
- return {
176
- state,
177
- items,
178
- load,
179
- };
180
- }
181
- function useItemLoader(provider, errorHandler) {
182
- const state = vue.ref({
183
- loading: false,
184
- loaded: false,
185
- });
186
- const item = vue.ref(null);
187
- const load = async (id, request) => {
188
- if (state.value.loading || state.value.loaded) {
189
- return;
190
- }
191
- state.value.loading = true;
192
- try {
193
- item.value = await provider(id, request);
194
- }
195
- catch (e) {
196
- errorHandler({
197
- e,
198
- error: api.getApiError(e),
199
- message: api.getApiErrorMessage(e),
200
- });
201
- }
202
- finally {
203
- state.value.loading = false;
204
- state.value.loaded = true;
205
- }
206
- };
207
- return {
208
- state,
209
- item,
210
- load,
211
- };
212
- }
213
- function useDataLoader(provider, errorHandler) {
214
- const state = vue.ref({
215
- loading: false,
216
- loaded: false,
217
- });
218
- const data = vue.ref(null);
219
- const load = async () => {
220
- if (state.value.loading || state.value.loaded) {
221
- return;
222
- }
223
- state.value.loading = true;
224
- try {
225
- data.value = await provider();
226
- }
227
- catch (e) {
228
- errorHandler({
229
- e,
230
- error: api.getApiError(e),
231
- message: api.getApiErrorMessage(e),
232
- });
233
- }
234
- finally {
235
- state.value.loading = false;
236
- state.value.loaded = true;
237
- }
238
- };
239
- return {
240
- state,
241
- data,
242
- load,
243
- };
244
- }
245
-
246
- let prefix = null;
247
- const getPrefixedKey = (key) => (prefix ? `${prefix}:${key}` : key);
248
- const storage = {
249
- get(key, defaultValue) {
250
- const item = localStorage.getItem(getPrefixedKey(key));
251
- if (item === undefined || item === null) {
252
- return defaultValue;
253
- }
254
- return JSON.parse(item).value;
255
- },
256
- set(key, value) {
257
- localStorage.setItem(getPrefixedKey(key), JSON.stringify({ value }));
258
- },
259
- delete(key) {
260
- this.set(key, null);
261
- },
262
- };
263
- const createStorage = (storeId) => {
264
- prefix = `zenky:storefront:${storeId}`;
265
- return storage;
266
- };
267
- const getStorage = () => storage;
268
-
269
- function getDaDataEntityName(data, types) {
270
- return types.find((type) => data[type] !== 'undefined' && data[type]);
271
- }
272
- function getHousePart(house) {
273
- if (Number.isNaN(parseInt(house, 10))) {
274
- return `${house}`;
275
- }
276
- return `д ${house}`;
277
- }
278
- function getSettlementPart(suggestion) {
279
- const city = suggestion.city_with_type;
280
- const area = suggestion.area_with_type;
281
- const region = suggestion.region_with_type;
282
- if (city) {
283
- return city === suggestion.settlement_with_type
284
- ? suggestion.settlement_with_type
285
- : `${city}, ${suggestion.settlement_with_type}`;
286
- }
287
- else if (region && area) {
288
- return `${region}, ${area}, ${suggestion.settlement_with_type}`;
289
- }
290
- else if (region) {
291
- return `${region}, ${suggestion.settlement_with_type}`;
292
- }
293
- else if (area) {
294
- return `${area}, ${suggestion.settlement_with_type}`;
295
- }
296
- return suggestion.settlement_with_type;
297
- }
298
- function getCityPart(suggestion) {
299
- if (suggestion.settlement_with_type) {
300
- return getSettlementPart(suggestion);
301
- }
302
- else if (suggestion.city_with_type) {
303
- return suggestion.city_with_type;
304
- }
305
- return null;
306
- }
307
-
308
- function getStockSchedule(schedule) {
309
- if (!schedule) {
310
- return 'Закрыто';
311
- }
312
- else if (!schedule.today.open && schedule.today.next_open_at) {
313
- return `Откроется ${schedule.today.next_open_at.short}`;
314
- }
315
- else if (!schedule.today.open) {
316
- return 'Закрыто';
317
- }
318
- else if (!schedule.today.closing_at) {
319
- return `Сегодня: ${schedule.today.hours[0]}`;
320
- }
321
- const diff = schedule.today.closing_at.timestamp - (new Date().getTime() / 1000);
322
- const min = 60 * 60;
323
- if (diff < min) {
324
- return `Закроется ${schedule.today.closing_at.diff.toLowerCase()}`;
325
- }
326
- return `Сегодня: ${schedule.today.hours[0]}`;
327
- }
328
- function getStockAddress(stock) {
329
- if (!stock || !stock.address) {
330
- return null;
331
- }
332
- return stock.address.address;
333
- }
334
-
335
- const useStoreStore = pinia.defineStore({
336
- id: 'zenky:storefront:store',
337
- state: () => {
338
- const storage = getStorage();
339
- return {
340
- loading: false,
341
- loaded: false,
342
- store: null,
343
- storeId: window.zenky.storeId,
344
- cityId: storage.get('cityId'),
345
- };
346
- },
347
- getters: {
348
- cities() {
349
- if (!this.loaded || !this.store || !this.store.cities) {
350
- return [];
351
- }
352
- return this.store.cities;
353
- },
354
- city() {
355
- if (!this.cityId) {
356
- return null;
357
- }
358
- return this.cities.find((city) => city.id === this.cityId) || null;
359
- },
360
- stocks() {
361
- if (!this.city || !this.city.stocks) {
362
- return [];
363
- }
364
- return this.city.stocks.filter((stock) => stock.visible);
365
- },
366
- settings() {
367
- if (!this.store || !this.store.settings) {
368
- return null;
369
- }
370
- return this.store.settings;
371
- },
372
- addressesResolver() {
373
- if (!this.settings) {
374
- return null;
375
- }
376
- return this.settings.addresses.resolver.id;
377
- },
378
- loyalty() {
379
- if (!this.settings) {
380
- return null;
381
- }
382
- return this.settings.loyalty;
383
- },
384
- },
385
- actions: {
386
- async loadStore(inclusions) {
387
- if (this.loading || this.loaded) {
388
- return;
389
- }
390
- try {
391
- this.store = await api.getStore(inclusions);
392
- this.loaded = true;
393
- }
394
- catch (e) {
395
- //
396
- }
397
- finally {
398
- this.loading = false;
399
- }
400
- },
401
- selectDefaultCity() {
402
- if (this.city) {
403
- return this.city;
404
- }
405
- else if (!this.cities.length) {
406
- return null;
407
- }
408
- return this.selectCity(this.cities[0].id);
409
- },
410
- selectCity(cityId) {
411
- const city = this.cities.find((item) => item.id === cityId);
412
- if (!city) {
413
- return null;
414
- }
415
- const storage = getStorage();
416
- storage.set('cityId', city.id);
417
- this.cityId = city.id;
418
- return city;
419
- },
420
- },
421
- });
422
-
423
- function useDadata() {
424
- const { cityId } = pinia.storeToRefs(useStoreStore());
425
- const query = vue.ref(null);
426
- const loading = vue.ref(false);
427
- const results = vue.ref([]);
428
- vue.watch(query, lodashEs.debounce(async () => {
429
- if (loading.value || !query.value || !cityId.value) {
430
- return;
431
- }
432
- try {
433
- loading.value = true;
434
- const { suggestions } = await api.getAddressSuggestions({
435
- query: query.value,
436
- city_id: cityId.value,
437
- });
438
- results.value = suggestions;
439
- }
440
- catch (e) {
441
- //
442
- }
443
- finally {
444
- loading.value = false;
445
- }
446
- }, 500));
447
- return {
448
- query,
449
- loading,
450
- results,
451
- };
452
- }
453
- function useSuggestionsRestrictedToCity(city) {
454
- const restricted = vue.computed(() => {
455
- if (!city) {
456
- return false;
457
- }
458
- else if (!city.settings) {
459
- return false;
460
- }
461
- return city.settings.addresses.restrict_suggestions
462
- && city.settings.addresses.search_radius === null;
463
- });
464
- return {
465
- restricted,
466
- };
467
- }
468
- function getSelectedAddress(suggestion, house, block) {
469
- const city = getCityPart(suggestion);
470
- const street = suggestion[`${getDaDataEntityName(suggestion, ['street', 'settlement', 'city_district'])}_with_type`];
471
- if (!city || !street) {
472
- return null;
473
- }
474
- let address;
475
- if (city !== street) {
476
- address = `${city}, ${street}, ${getHousePart(house)}`;
477
- }
478
- else {
479
- address = `${city}, ${getHousePart(house)}`;
480
- }
481
- if (block) {
482
- address += ` ${block}`;
483
- }
484
- return address;
485
- }
486
- function getSelectedAddressDisplayValue(suggestion) {
487
- const entityName = getDaDataEntityName(suggestion, ['street', 'settlement', 'city_district']);
488
- if (entityName === null) {
489
- throw new Error('Selected address does not have a single field that we qualify as "street"');
490
- }
491
- const entityWithType = suggestion[`${entityName}_with_type`];
492
- const cityEntityName = getDaDataEntityName(suggestion, ['city', 'settlement']);
493
- const cityEntityWithType = suggestion[`${cityEntityName}_with_type`];
494
- return {
495
- short: entityWithType,
496
- full: cityEntityWithType === entityWithType ? cityEntityWithType : `${cityEntityWithType}, ${entityWithType}`,
497
- };
498
- }
499
- function getExistedAddressDisplayValue(address, restrictedToCity) {
500
- const query = [];
501
- if (address.city && !restrictedToCity) {
502
- query.push(address.city.full);
503
- }
504
- if (address.settlement && query.indexOf(address.settlement) === -1) {
505
- query.push(address.settlement);
506
- }
507
- if (address.street && query.indexOf(address.street.full) === -1) {
508
- query.push(address.street.full);
509
- }
510
- return query.join(', ');
511
- }
512
- function getExistedAddress(address, house, block) {
513
- const pieces = getExistedAddressDisplayValue(address, false).split(',');
514
- if (house) {
515
- pieces.push(`д ${house}`);
516
- }
517
- if (block) {
518
- pieces.push(Number.isNaN(parseInt(block, 10)) ? block : `к ${block}`);
519
- }
520
- return pieces.join(', ');
521
- }
522
-
523
- const getAddressForm = () => ({
524
- suggestion: null,
525
- id: '',
526
- city: '',
527
- street: '',
528
- house: '',
529
- block: '',
530
- address: '',
531
- apartment: '',
532
- entrance: '',
533
- floor: '',
534
- has_intercom: true,
535
- });
536
- exports.AddressFormValueError = void 0;
537
- (function (AddressFormValueError) {
538
- AddressFormValueError["DaDataSuggestionRequired"] = "dadata.suggestion_required";
539
- AddressFormValueError["CityRequired"] = "plain.city_required";
540
- AddressFormValueError["StreetRequired"] = "plain.street_required";
541
- AddressFormValueError["HouseRequired"] = "plain.house_required";
542
- AddressFormValueError["StockRequired"] = "stock_required";
543
- AddressFormValueError["TableRequired"] = "table_required";
544
- })(exports.AddressFormValueError || (exports.AddressFormValueError = {}));
545
- function useAddressFormValue(form, resolver, address) {
546
- const errors = [];
547
- let data = {};
548
- if (resolver === 'dadata') {
549
- if (form.suggestion) {
550
- data = {
551
- address: getSelectedAddress(form.suggestion, form.house, form.block),
552
- apartment: form.apartment,
553
- entrance: form.entrance,
554
- floor: form.floor,
555
- has_intercom: lodashEs.isBoolean(form.has_intercom)
556
- ? form.has_intercom
557
- : form.has_intercom === 'true',
558
- };
559
- }
560
- else if (address) {
561
- data = {
562
- address: getExistedAddress(address, form.house, form.block),
563
- apartment: form.apartment,
564
- entrance: form.entrance,
565
- floor: form.floor,
566
- has_intercom: lodashEs.isBoolean(form.has_intercom)
567
- ? form.has_intercom
568
- : form.has_intercom === 'true',
569
- };
570
- }
571
- else {
572
- errors.push(exports.AddressFormValueError.DaDataSuggestionRequired);
573
- }
574
- }
575
- else if (resolver === 'plain') {
576
- if (!form.city) {
577
- errors.push(exports.AddressFormValueError.CityRequired);
578
- }
579
- else if (!form.street) {
580
- errors.push(exports.AddressFormValueError.StreetRequired);
581
- }
582
- else if (!form.house) {
583
- errors.push(exports.AddressFormValueError.HouseRequired);
584
- }
585
- else {
586
- data = {
587
- city: form.city,
588
- street: form.street,
589
- house: form.house,
590
- block: form.block,
591
- apartment: form.apartment,
592
- entrance: form.entrance,
593
- floor: form.floor,
594
- has_intercom: lodashEs.isBoolean(form.has_intercom)
595
- ? form.has_intercom
596
- : form.has_intercom === 'true',
597
- };
598
- }
599
- }
600
- return {
601
- data,
602
- errors,
603
- };
604
- }
605
-
606
- const useCategoriesStore = pinia.defineStore({
607
- id: 'zenky:storefront:categories',
608
- state: () => ({
609
- loading: false,
610
- loaded: false,
611
- tree: [],
612
- flatTree: null,
613
- }),
614
- actions: {
615
- async load() {
616
- if (this.loading || this.loaded) {
617
- return;
618
- }
619
- this.loading = true;
620
- try {
621
- this.tree = await api.getCategoriesTree({ visibility: api.Visibility.Visible, with: 'media' });
622
- this.loaded = true;
623
- }
624
- catch (e) {
625
- //
626
- }
627
- finally {
628
- this.loading = false;
629
- }
630
- },
631
- setFlatTree(flatTree) {
632
- this.flatTree = flatTree;
633
- },
634
- },
635
- });
636
-
637
- async function getTree() {
638
- const store = useCategoriesStore();
639
- const state = vue.computed(() => ({
640
- loaded: store.loaded,
641
- loading: store.loading,
642
- data: store.tree,
643
- }));
644
- return useStateDataLoader(state, async () => store.load());
645
- }
646
-
647
- const findCategory = (items, id) => {
648
- for (let i = 0; i < items.length; ++i) {
649
- if (items[i].id === id || items[i].short_id === id) {
650
- return items[i];
651
- }
652
- const children = findCategory(items[i].children, id);
653
- if (children !== null) {
654
- return children;
655
- }
656
- }
657
- return null;
658
- };
659
- function useCategories() {
660
- const categories = vue.ref([]);
661
- const load = async (ids) => {
662
- const tree = await getTree();
663
- ids.forEach((id) => {
664
- const category = findCategory(tree, id);
665
- if (category !== null) {
666
- categories.value.push(category);
667
- }
668
- });
669
- };
670
- return {
671
- categories,
672
- load,
673
- };
674
- }
675
- function useCategory() {
676
- const category = vue.ref(null);
677
- const load = async (id) => {
678
- const tree = await getTree();
679
- category.value = findCategory(tree, id);
680
- };
681
- return {
682
- category,
683
- load,
684
- };
685
- }
686
-
687
- const generateFlatTree = (flat, categories, append = '') => {
688
- categories.forEach((category) => {
689
- flat.push({
690
- ...category,
691
- children: [],
692
- name: `${append}${category.name}`,
693
- original_name: category.name,
694
- });
695
- if (category.children.length > 0) {
696
- generateFlatTree(flat, category.children, `${append}${category.name} / `);
697
- }
698
- });
699
- };
700
- function useFlatCategoriesTree() {
701
- const tree = vue.ref([]);
702
- const load = async () => {
703
- const store = useCategoriesStore();
704
- if (store.flatTree !== null) {
705
- tree.value = store.flatTree;
706
- return;
707
- }
708
- const flat = [];
709
- generateFlatTree(flat, await getTree());
710
- store.setFlatTree(flat);
711
- tree.value = flat;
712
- };
713
- return {
714
- tree,
715
- load,
716
- };
717
- }
718
-
719
- const findReversedCategories = (id, stack, categories) => {
720
- for (let i = 0; i < categories.length; ++i) {
721
- if (categories[i].id === id || categories[i].short_id === id) {
722
- return {
723
- category: categories[i],
724
- stack,
725
- };
726
- }
727
- stack.push(categories[i]);
728
- const children = findReversedCategories(id, stack, categories[i].children);
729
- if (children !== null) {
730
- return children;
731
- }
732
- else {
733
- stack.pop();
734
- }
735
- }
736
- return null;
737
- };
738
- function useReversedTree() {
739
- const tree = vue.ref([]);
740
- const load = async (id) => {
741
- const stack = [];
742
- const result = findReversedCategories(id, stack, await getTree());
743
- if (result === null) {
744
- return;
745
- }
746
- tree.value = [...result.stack, result.category];
747
- };
748
- return {
749
- tree,
750
- load,
751
- };
752
- }
753
-
754
- function useSplittedCategoriesTree() {
755
- const visible = vue.ref([]);
756
- const hidden = vue.ref([]);
757
- const load = async (split) => {
758
- const tree = await getTree();
759
- const unrefSplit = vue.unref(split);
760
- visible.value = tree.slice(0, unrefSplit);
761
- hidden.value = tree.slice(unrefSplit);
762
- };
763
- return {
764
- visible,
765
- hidden,
766
- load,
767
- };
768
- }
769
-
770
- function useCategoriesTree() {
771
- const tree = vue.ref([]);
772
- const load = async () => {
773
- tree.value = await getTree();
774
- };
775
- return {
776
- tree,
777
- load,
778
- };
779
- }
780
-
781
- const useCollectionsStore = pinia.defineStore({
782
- id: 'zenky:storefront:collections',
783
- state: () => ({
784
- loading: false,
785
- loaded: false,
786
- collections: [],
787
- }),
788
- actions: {
789
- async load() {
790
- if (this.loading || this.loaded) {
791
- return;
792
- }
793
- this.loading = true;
794
- try {
795
- this.collections = (await api.getProductsCollections({
796
- visibility: api.Visibility.Visible,
797
- order_by: 'name',
798
- with: 'media',
799
- count: 100,
800
- })).items;
801
- this.loaded = true;
802
- }
803
- catch (e) {
804
- //
805
- }
806
- finally {
807
- this.loading = false;
808
- }
809
- },
810
- },
811
- });
812
-
813
- async function getCollections() {
814
- const store = useCollectionsStore();
815
- const state = vue.computed(() => ({
816
- loaded: store.loaded,
817
- loading: store.loading,
818
- data: store.collections,
819
- }));
820
- return useStateDataLoader(state, async () => store.load());
821
- }
822
- function useCollections() {
823
- const collections = vue.ref([]);
824
- const load = async (ids = null) => {
825
- collections.value = [];
826
- const items = await getCollections();
827
- if (ids === null) {
828
- collections.value = items;
829
- }
830
- else if (Array.isArray(ids)) {
831
- collections.value = items.filter((collection) => ids.indexOf(collection.id) !== -1);
832
- }
833
- };
834
- return {
835
- collections,
836
- load,
837
- };
838
- }
839
- function useCollection() {
840
- const collection = vue.ref(null);
841
- const load = async (id) => {
842
- collection.value = null;
843
- const items = await getCollections();
844
- const index = items.findIndex((item) => item.id === id);
845
- if (index !== -1) {
846
- collection.value = items[index];
847
- }
848
- };
849
- return {
850
- collection,
851
- load,
852
- };
853
- }
854
-
855
- function useCategoryFeaturesList(categoryId, errorHandler) {
856
- return useListLoader(async function () {
857
- if (!categoryId) {
858
- return [];
859
- }
860
- return api.getCategoryFeatures(categoryId);
861
- }, getApiErrorHandler(errorHandler, 'useCategoryFeaturesList', 'Unable to load category features list.'));
862
- }
863
- function useCategoryFeaturesGroupsList(categoryId, errorHandler) {
864
- return useListLoader(async function () {
865
- if (!categoryId) {
866
- return [];
867
- }
868
- return api.getCategoryFeaturesGroups(categoryId);
869
- }, getApiErrorHandler(errorHandler, 'useCategoryFeaturesGroupsList', 'Unable to load category features groups list.'));
870
- }
871
-
872
- function useArticlesList(errorHandler) {
873
- return usePaginatedLoader(api.getArticles, getApiErrorHandler(errorHandler, 'useArticlesList', 'Unable to load articles list.'));
874
- }
875
- function useArticleCategoriesList(errorHandler) {
876
- return usePaginatedLoader(api.getArticleCategories, getApiErrorHandler(errorHandler, 'useArticleCategoriesList', 'Unable to load article categories list.'));
877
- }
878
- function useArticleItem(errorHandler) {
879
- return useItemLoader(api.getArticle, getApiErrorHandler(errorHandler, 'useArticleItem', 'Unable to load article.'));
880
- }
881
-
882
- exports.AuthenticationStage = void 0;
883
- (function (AuthenticationStage) {
884
- AuthenticationStage["Check"] = "check";
885
- AuthenticationStage["Login"] = "login";
886
- AuthenticationStage["Register"] = "register";
887
- AuthenticationStage["Confirmation"] = "confirmation";
888
- })(exports.AuthenticationStage || (exports.AuthenticationStage = {}));
889
- exports.AuthenticationEvent = void 0;
890
- (function (AuthenticationEvent) {
891
- AuthenticationEvent["Stage"] = "stage";
892
- AuthenticationEvent["Completed"] = "completed";
893
- })(exports.AuthenticationEvent || (exports.AuthenticationEvent = {}));
894
- exports.AuthenticationResultType = void 0;
895
- (function (AuthenticationResultType) {
896
- AuthenticationResultType["Validation"] = "validation";
897
- AuthenticationResultType["Failed"] = "failed";
898
- AuthenticationResultType["Completed"] = "completed";
899
- AuthenticationResultType["Stage"] = "stage";
900
- })(exports.AuthenticationResultType || (exports.AuthenticationResultType = {}));
901
- exports.AuthenticationFailureReason = void 0;
902
- (function (AuthenticationFailureReason) {
903
- AuthenticationFailureReason["ApiError"] = "api_error";
904
- AuthenticationFailureReason["InProgress"] = "in_progress";
905
- AuthenticationFailureReason["Cooldown"] = "cooldown";
906
- AuthenticationFailureReason["PhoneRequired"] = "phone_required";
907
- AuthenticationFailureReason["PasswordRequired"] = "password_required";
908
- AuthenticationFailureReason["CodeRequired"] = "code_required";
909
- })(exports.AuthenticationFailureReason || (exports.AuthenticationFailureReason = {}));
910
- exports.AddressResultType = void 0;
911
- (function (AddressResultType) {
912
- AddressResultType["Failed"] = "failed";
913
- AddressResultType["Completed"] = "completed";
914
- })(exports.AddressResultType || (exports.AddressResultType = {}));
915
- exports.AddressResultReason = void 0;
916
- (function (AddressResultReason) {
917
- AddressResultReason["InProgress"] = "in_progress";
918
- AddressResultReason["Validation"] = "validation";
919
- AddressResultReason["ApiError"] = "api_error";
920
- })(exports.AddressResultReason || (exports.AddressResultReason = {}));
921
-
922
- function useAuthenticationStatusChecker(form, emit) {
923
- const active = vue.ref(false);
924
- const check = async () => {
925
- if (active.value) {
926
- return {
927
- type: exports.AuthenticationResultType.Failed,
928
- reason: exports.AuthenticationFailureReason.InProgress,
929
- };
930
- }
931
- else if (!form.value.phone.number || !form.value.phone.country) {
932
- return {
933
- type: exports.AuthenticationResultType.Validation,
934
- reason: exports.AuthenticationFailureReason.PhoneRequired,
935
- };
936
- }
937
- active.value = true;
938
- try {
939
- const status = await api.getAuthenticationStatus(form.value.phone);
940
- if (!status.registered) {
941
- emit(exports.AuthenticationEvent.Stage, exports.AuthenticationStage.Register);
942
- return {
943
- type: exports.AuthenticationResultType.Stage,
944
- data: exports.AuthenticationStage.Register,
945
- };
946
- }
947
- else if (!status.confirmed) {
948
- emit(exports.AuthenticationEvent.Stage, exports.AuthenticationStage.Confirmation);
949
- return {
950
- type: exports.AuthenticationResultType.Stage,
951
- data: exports.AuthenticationStage.Confirmation,
952
- };
953
- }
954
- emit(exports.AuthenticationEvent.Stage, exports.AuthenticationStage.Login);
955
- return {
956
- type: exports.AuthenticationResultType.Stage,
957
- data: exports.AuthenticationStage.Login,
958
- };
959
- }
960
- catch (e) {
961
- return {
962
- type: exports.AuthenticationResultType.Failed,
963
- reason: exports.AuthenticationFailureReason.ApiError,
964
- error: api.getApiError(e),
965
- };
966
- }
967
- finally {
968
- active.value = false;
969
- }
970
- };
971
- return {
972
- active,
973
- check,
974
- };
975
- }
976
-
977
- function useAuthenticationForm() {
978
- const stage = vue.ref(exports.AuthenticationStage.Check);
979
- const form = vue.ref({
980
- phone: {
981
- number: '',
982
- country: '',
983
- },
984
- password: '',
985
- confirmation_code: '',
986
- });
987
- const reset = () => {
988
- form.value.phone.country = 'RU';
989
- form.value.phone.number = '';
990
- form.value.password = '';
991
- form.value.confirmation_code = '';
992
- stage.value = exports.AuthenticationStage.Check;
993
- };
994
- return {
995
- stage,
996
- form,
997
- reset,
998
- };
999
- }
1000
-
1001
- const useCustomerStore = pinia.defineStore({
1002
- id: 'zenky:storefront:customer',
1003
- state: () => ({
1004
- inclusions: '',
1005
- loading: false,
1006
- loaded: false,
1007
- token: null,
1008
- customer: null,
1009
- }),
1010
- actions: {
1011
- async initialize(inclusions) {
1012
- this.inclusions = inclusions;
1013
- const storage = getStorage();
1014
- this.token = storage.get('customer.token', null);
1015
- this.loaded = false;
1016
- if (!this.token) {
1017
- this.loaded = true;
1018
- return;
1019
- }
1020
- return this.load();
1021
- },
1022
- async load() {
1023
- if (this.loading || !this.token) {
1024
- return null;
1025
- }
1026
- this.loading = true;
1027
- try {
1028
- api.setAxiosToken(this.token);
1029
- this.customer = await api.getCustomerProfile(this.inclusions);
1030
- events.useCustomerLoaded().publish({ customer: this.customer });
1031
- return this.customer;
1032
- }
1033
- catch (e) {
1034
- api.setAxiosToken();
1035
- }
1036
- finally {
1037
- this.loading = false;
1038
- this.loaded = true;
1039
- }
1040
- return null;
1041
- },
1042
- async setToken(token) {
1043
- this.token = token;
1044
- const storage = getStorage();
1045
- storage.set('customer.token', token);
1046
- const customer = await this.load();
1047
- events.useCustomerAuthenticated().publish({ customer });
1048
- return customer;
1049
- },
1050
- logout() {
1051
- this.token = null;
1052
- this.customer = null;
1053
- const storage = getStorage();
1054
- storage.delete('customer.token');
1055
- api.setAxiosToken();
1056
- events.useCustomerLoggedOut().publish();
1057
- },
1058
- },
1059
- });
1060
-
1061
- function useLogin(form, emit) {
1062
- const active = vue.ref(false);
1063
- const login = async () => {
1064
- if (active.value) {
1065
- return {
1066
- type: exports.AuthenticationResultType.Failed,
1067
- reason: exports.AuthenticationFailureReason.InProgress,
1068
- };
1069
- }
1070
- else if (!form.value.phone.number || !form.value.phone.country) {
1071
- return {
1072
- type: exports.AuthenticationResultType.Validation,
1073
- reason: exports.AuthenticationFailureReason.PhoneRequired,
1074
- };
1075
- }
1076
- else if (!form.value.password) {
1077
- return {
1078
- type: exports.AuthenticationResultType.Validation,
1079
- reason: exports.AuthenticationFailureReason.PasswordRequired,
1080
- };
1081
- }
1082
- active.value = true;
1083
- try {
1084
- const { token } = await api.login({ number: form.value.phone.number, country: form.value.phone.country }, form.value.password);
1085
- const { setToken } = useCustomerStore();
1086
- const customer = await setToken(token);
1087
- emit(exports.AuthenticationEvent.Completed);
1088
- return {
1089
- type: exports.AuthenticationResultType.Completed,
1090
- data: customer,
1091
- };
1092
- }
1093
- catch (e) {
1094
- return {
1095
- type: exports.AuthenticationResultType.Failed,
1096
- reason: exports.AuthenticationFailureReason.ApiError,
1097
- error: api.getApiError(e),
1098
- };
1099
- }
1100
- finally {
1101
- active.value = false;
1102
- }
1103
- };
1104
- return {
1105
- active,
1106
- login,
1107
- };
1108
- }
1109
-
1110
- function useLogout() {
1111
- const logout = () => {
1112
- const store = useCustomerStore();
1113
- store.logout();
1114
- };
1115
- return {
1116
- logout,
1117
- };
1118
- }
1119
-
1120
- function pluralize(value, choices, prependWithValue = true) {
1121
- const word1 = choices[0];
1122
- const word2 = choices[1];
1123
- const word5 = choices[2];
1124
- if (!Number.isInteger(value)) {
1125
- return prependWithValue ? `${value} ${word2}` : word2;
1126
- }
1127
- let n = value % 100;
1128
- if (n >= 5 && n <= 20) {
1129
- return prependWithValue ? `${value} ${word5}` : word5;
1130
- }
1131
- if (n > 19) {
1132
- n %= 10;
1133
- }
1134
- if (n > 4 || n === 0) {
1135
- return prependWithValue ? `${value} ${word5}` : word5;
1136
- }
1137
- if (n === 1) {
1138
- return prependWithValue ? `${value} ${word1}` : word1;
1139
- }
1140
- return prependWithValue ? `${value} ${word2}` : word2;
1141
- }
1142
-
1143
- const useTimer = (cooldown) => {
1144
- const seconds = vue.ref(0);
1145
- const label = vue.computed(() => pluralize(seconds.value, ['секунду', 'секунды', 'секунд']));
1146
- let timerInterval;
1147
- const start = () => {
1148
- clearInterval(timerInterval);
1149
- seconds.value = cooldown;
1150
- timerInterval = setInterval(() => {
1151
- seconds.value -= 1;
1152
- if (seconds.value === 0) {
1153
- clearInterval(timerInterval);
1154
- }
1155
- }, 1000);
1156
- };
1157
- const stop = () => {
1158
- clearInterval(timerInterval);
1159
- };
1160
- return {
1161
- seconds,
1162
- label,
1163
- start,
1164
- stop,
1165
- };
1166
- };
1167
-
1168
- function useRequest(form, active) {
1169
- const { seconds, label, start } = useTimer(60);
1170
- const sent = vue.ref(false);
1171
- const request = async () => {
1172
- if (active.value) {
1173
- return {
1174
- type: exports.AuthenticationResultType.Failed,
1175
- reason: exports.AuthenticationFailureReason.InProgress,
1176
- };
1177
- }
1178
- else if (seconds.value > 0) {
1179
- return {
1180
- type: exports.AuthenticationResultType.Failed,
1181
- reason: exports.AuthenticationFailureReason.Cooldown,
1182
- };
1183
- }
1184
- else if (!form.value.phone.number || !form.value.phone.country) {
1185
- return {
1186
- type: exports.AuthenticationResultType.Validation,
1187
- reason: exports.AuthenticationFailureReason.PhoneRequired,
1188
- };
1189
- }
1190
- active.value = true;
1191
- try {
1192
- await api.requestPasswordResetCode(form.value.phone);
1193
- sent.value = true;
1194
- start();
1195
- return {
1196
- type: exports.AuthenticationResultType.Completed,
1197
- };
1198
- }
1199
- catch (e) {
1200
- return {
1201
- type: exports.AuthenticationResultType.Failed,
1202
- reason: exports.AuthenticationFailureReason.ApiError,
1203
- error: api.getApiError(e),
1204
- };
1205
- }
1206
- finally {
1207
- active.value = false;
1208
- }
1209
- };
1210
- return {
1211
- seconds,
1212
- label,
1213
- request,
1214
- sent,
1215
- };
1216
- }
1217
- function useReset(form, active, emit) {
1218
- const reset = async () => {
1219
- if (active.value) {
1220
- return {
1221
- type: exports.AuthenticationResultType.Failed,
1222
- reason: exports.AuthenticationFailureReason.InProgress,
1223
- };
1224
- }
1225
- else if (!form.value.phone.number || !form.value.phone.country) {
1226
- return {
1227
- type: exports.AuthenticationResultType.Validation,
1228
- reason: exports.AuthenticationFailureReason.PhoneRequired,
1229
- };
1230
- }
1231
- else if (!form.value.password) {
1232
- return {
1233
- type: exports.AuthenticationResultType.Validation,
1234
- reason: exports.AuthenticationFailureReason.PasswordRequired,
1235
- };
1236
- }
1237
- else if (!form.value.confirmation_code) {
1238
- return {
1239
- type: exports.AuthenticationResultType.Validation,
1240
- reason: exports.AuthenticationFailureReason.CodeRequired,
1241
- };
1242
- }
1243
- active.value = true;
1244
- try {
1245
- const result = await api.resetPassword(form.value.phone, form.value.confirmation_code, form.value.password);
1246
- const store = useCustomerStore();
1247
- await store.setToken(result.token);
1248
- emit(exports.AuthenticationEvent.Completed);
1249
- return {
1250
- type: exports.AuthenticationResultType.Completed,
1251
- data: result.customer,
1252
- };
1253
- }
1254
- catch (e) {
1255
- return {
1256
- type: exports.AuthenticationResultType.Failed,
1257
- reason: exports.AuthenticationFailureReason.ApiError,
1258
- error: api.getApiError(e),
1259
- };
1260
- }
1261
- finally {
1262
- active.value = false;
1263
- }
1264
- };
1265
- return {
1266
- reset,
1267
- };
1268
- }
1269
- function usePasswordReset(form, emit) {
1270
- const active = vue.ref(false);
1271
- const { request, sent, seconds, label } = useRequest(form, active);
1272
- const { reset } = useReset(form, active, emit);
1273
- return {
1274
- active,
1275
- sent,
1276
- seconds,
1277
- label,
1278
- request,
1279
- reset,
1280
- };
1281
- }
1282
-
1283
- function useRegistration(form, emit) {
1284
- const active = vue.ref(false);
1285
- const register = async () => {
1286
- if (active.value) {
1287
- return {
1288
- type: exports.AuthenticationResultType.Failed,
1289
- reason: exports.AuthenticationFailureReason.InProgress,
1290
- };
1291
- }
1292
- else if (!form.value.phone.number || !form.value.phone.country) {
1293
- return {
1294
- type: exports.AuthenticationResultType.Validation,
1295
- reason: exports.AuthenticationFailureReason.PhoneRequired,
1296
- };
1297
- }
1298
- else if (!form.value.password) {
1299
- return {
1300
- type: exports.AuthenticationResultType.Validation,
1301
- reason: exports.AuthenticationFailureReason.PasswordRequired,
1302
- };
1303
- }
1304
- active.value = true;
1305
- try {
1306
- const result = await api.register(form.value.phone, form.value.password);
1307
- if (!result.confirmation_required) {
1308
- emit(exports.AuthenticationEvent.Completed);
1309
- return {
1310
- type: exports.AuthenticationResultType.Completed,
1311
- };
1312
- }
1313
- emit(exports.AuthenticationEvent.Stage, exports.AuthenticationStage.Confirmation);
1314
- return {
1315
- type: exports.AuthenticationResultType.Stage,
1316
- data: exports.AuthenticationStage.Confirmation,
1317
- };
1318
- }
1319
- catch (e) {
1320
- return {
1321
- type: exports.AuthenticationResultType.Failed,
1322
- reason: exports.AuthenticationFailureReason.ApiError,
1323
- error: api.getApiError(e),
1324
- };
1325
- }
1326
- finally {
1327
- active.value = false;
1328
- }
1329
- };
1330
- return {
1331
- active,
1332
- register,
1333
- };
1334
- }
1335
-
1336
- function useResend(form, active) {
1337
- const { seconds, label, start } = useTimer(60);
1338
- const resend = async () => {
1339
- if (active.value) {
1340
- return {
1341
- type: exports.AuthenticationResultType.Failed,
1342
- reason: exports.AuthenticationFailureReason.InProgress,
1343
- };
1344
- }
1345
- else if (seconds.value > 0) {
1346
- return {
1347
- type: exports.AuthenticationResultType.Failed,
1348
- reason: exports.AuthenticationFailureReason.Cooldown,
1349
- };
1350
- }
1351
- else if (!form.value.phone.number || !form.value.phone.country) {
1352
- return {
1353
- type: exports.AuthenticationResultType.Validation,
1354
- reason: exports.AuthenticationFailureReason.PhoneRequired,
1355
- };
1356
- }
1357
- active.value = true;
1358
- try {
1359
- await api.resendConfirmationCode(form.value.phone);
1360
- start();
1361
- return {
1362
- type: exports.AuthenticationResultType.Completed,
1363
- };
1364
- }
1365
- catch (e) {
1366
- return {
1367
- type: exports.AuthenticationResultType.Failed,
1368
- reason: exports.AuthenticationFailureReason.ApiError,
1369
- error: api.getApiError(e),
1370
- };
1371
- }
1372
- finally {
1373
- active.value = false;
1374
- }
1375
- };
1376
- return {
1377
- seconds,
1378
- label,
1379
- start,
1380
- resend,
1381
- };
1382
- }
1383
- function useConfirm(form, active, emit) {
1384
- const confirm = async (withPassword = false) => {
1385
- if (active.value) {
1386
- return {
1387
- type: exports.AuthenticationResultType.Failed,
1388
- reason: exports.AuthenticationFailureReason.InProgress,
1389
- };
1390
- }
1391
- else if (!form.value.phone.number || !form.value.phone.country) {
1392
- return {
1393
- type: exports.AuthenticationResultType.Validation,
1394
- reason: exports.AuthenticationFailureReason.PhoneRequired,
1395
- };
1396
- }
1397
- else if (!form.value.confirmation_code) {
1398
- return {
1399
- type: exports.AuthenticationResultType.Validation,
1400
- reason: exports.AuthenticationFailureReason.CodeRequired,
1401
- };
1402
- }
1403
- else if (withPassword && !form.value.password) {
1404
- return {
1405
- type: exports.AuthenticationResultType.Validation,
1406
- reason: exports.AuthenticationFailureReason.PasswordRequired,
1407
- };
1408
- }
1409
- active.value = true;
1410
- try {
1411
- const result = await api.confirm(form.value.phone, form.value.confirmation_code, withPassword ? form.value.password : null);
1412
- const store = useCustomerStore();
1413
- await store.setToken(result.token);
1414
- emit(exports.AuthenticationEvent.Completed);
1415
- return {
1416
- type: exports.AuthenticationResultType.Completed,
1417
- data: result.customer,
1418
- };
1419
- }
1420
- catch (e) {
1421
- if (api.getApiErrorCode(e) === 'auth.registration.password_required') {
1422
- return {
1423
- type: exports.AuthenticationResultType.Validation,
1424
- reason: exports.AuthenticationFailureReason.PasswordRequired,
1425
- };
1426
- }
1427
- return {
1428
- type: exports.AuthenticationResultType.Failed,
1429
- reason: exports.AuthenticationFailureReason.ApiError,
1430
- error: api.getApiError(e),
1431
- };
1432
- }
1433
- finally {
1434
- active.value = false;
1435
- }
1436
- };
1437
- return {
1438
- confirm,
1439
- };
1440
- }
1441
- const usePhoneConfirmation = (form, emit) => {
1442
- const active = vue.ref(false);
1443
- const { seconds, label, start, resend } = useResend(form, active);
1444
- const { confirm } = useConfirm(form, active, emit);
1445
- return {
1446
- active,
1447
- seconds,
1448
- label,
1449
- start,
1450
- resend,
1451
- confirm,
1452
- };
1453
- };
1454
-
1455
- function useDeliveryAddressesList(errorHandler) {
1456
- return usePaginatedLoader(api.getCustomerAddresses, getApiErrorHandler(errorHandler, 'useDeliveryAddressesList', 'Unable to load delivery addresses list.'));
1457
- }
1458
- function useDeliveryAddressDestroyer(errorHandler) {
1459
- return useDataDestroyer(api.deleteAddress, getApiErrorHandler(errorHandler, 'useDeliveryAddressDestroyer', 'Unable to delete delivery address.'));
1460
- }
1461
- function useEditAddressForm(address) {
1462
- var _a, _b;
1463
- const addressFields = address.resolver === 'plain' ? {
1464
- id: address.id,
1465
- name: address.name,
1466
- city: (_a = address === null || address === void 0 ? void 0 : address.city) === null || _a === void 0 ? void 0 : _a.short,
1467
- street: (_b = address === null || address === void 0 ? void 0 : address.street) === null || _b === void 0 ? void 0 : _b.short,
1468
- house: address.house,
1469
- block: address.block || '',
1470
- apartment: address.apartment,
1471
- entrance: address.entrance,
1472
- floor: address.floor,
1473
- has_intercom: address.has_intercom,
1474
- } : {
1475
- id: address.id,
1476
- name: address.name,
1477
- address: getExistedAddressDisplayValue(address, false),
1478
- house: address.house,
1479
- block: address.block || '',
1480
- apartment: address.apartment,
1481
- entrance: address.entrance,
1482
- floor: address.floor,
1483
- has_intercom: address.has_intercom,
1484
- };
1485
- const saving = vue.ref(false);
1486
- const form = vue.ref(addressFields);
1487
- const save = async () => {
1488
- if (saving.value) {
1489
- return {
1490
- type: exports.AddressResultType.Failed,
1491
- reason: exports.AddressResultReason.InProgress,
1492
- };
1493
- }
1494
- const { errors, data } = useAddressFormValue(form.value, address.resolver, address);
1495
- if (errors.length > 0) {
1496
- return {
1497
- type: exports.AddressResultType.Failed,
1498
- reason: exports.AddressResultReason.Validation,
1499
- data: errors,
1500
- };
1501
- }
1502
- saving.value = true;
1503
- try {
1504
- await api.updateAddress(address.id, {
1505
- delivery_address: {
1506
- ...data,
1507
- name: form.value.name,
1508
- },
1509
- });
1510
- return {
1511
- type: exports.AddressResultType.Completed,
1512
- };
1513
- }
1514
- catch (e) {
1515
- return {
1516
- type: exports.AddressResultType.Failed,
1517
- reason: exports.AddressResultReason.ApiError,
1518
- error: api.getApiError(e),
1519
- };
1520
- }
1521
- finally {
1522
- saving.value = false;
1523
- }
1524
- };
1525
- return {
1526
- form,
1527
- saving,
1528
- save,
1529
- };
1530
- }
1531
-
1532
- function useCustomer() {
1533
- const store = useCustomerStore();
1534
- const customer = vue.computed(() => store.customer);
1535
- const loaded = vue.computed(() => store.loaded);
1536
- return {
1537
- customer,
1538
- loaded,
1539
- };
1540
- }
1541
-
1542
- function useOrdersList(errorHandler) {
1543
- return usePaginatedLoader(api.getCustomerOrders, getApiErrorHandler(errorHandler, 'useOrdersList', 'Unable to load orders list.'));
1544
- }
1545
- function useOrderItem(errorHandler) {
1546
- return useItemLoader(api.getOrder, getApiErrorHandler(errorHandler, 'useOrderItem', 'Unable to load order.'));
1547
- }
1548
-
1549
- function usePaymentMethodsList(errorHandler) {
1550
- return usePaginatedLoader(api.getCustomerPaymentMethods, getApiErrorHandler(errorHandler, 'usePaymentMethodsList', 'Unable to load payment methods.'));
1551
- }
1552
- function usePaymentMethodDestroyer(errorHandler) {
1553
- return useDataDestroyer(api.deleteCustomerPaymentMethod, getApiErrorHandler(errorHandler, 'usePaymentMethodDestroyer', 'Unable to delete payment method.'));
1554
- }
1555
-
1556
- function getFirstMedium(media, sizes = ['large', 'medium'], preferWebp = true) {
1557
- const medium = Array.isArray(media) ? media[0] : media;
1558
- if (!medium || !medium.images) {
1559
- return null;
1560
- }
1561
- const sizesMap = {
1562
- 'placeholder': api.ImageType.Placeholder,
1563
- 'placeholder_webp': api.ImageType.PlaceholderWebp,
1564
- 'thumb': api.ImageType.Thumb,
1565
- 'thumb_webp': api.ImageType.ThumbWebp,
1566
- 'medium': api.ImageType.Medium,
1567
- 'medium_webp': api.ImageType.MediumWebp,
1568
- 'large': api.ImageType.Large,
1569
- 'large_webp': api.ImageType.LargeWebp,
1570
- 'xlarge': api.ImageType.XLarge,
1571
- 'xlarge_webp': api.ImageType.XLargeWebp,
1572
- 'hd': api.ImageType.HD,
1573
- 'hd_webp': api.ImageType.HDWebp,
1574
- };
1575
- const images = [];
1576
- sizes.forEach((size) => {
1577
- const webpImage = medium.images[sizesMap[`${size}_webp`]];
1578
- if (preferWebp && webpImage) {
1579
- images.push(webpImage);
1580
- return;
1581
- }
1582
- const jpegImage = medium.images[sizesMap[size]];
1583
- if (jpegImage) {
1584
- images.push(jpegImage);
1585
- }
1586
- });
1587
- return images.length > 0 ? images[0] : null;
1588
- }
1589
-
1590
- function useOffersList(errorHandler) {
1591
- return usePaginatedLoader(api.getOffers, getApiErrorHandler(errorHandler, 'useOffersList', 'Unable to load offers list.'));
1592
- }
1593
- function useOfferItem(errorHandler) {
1594
- return useItemLoader(api.getOffer, getApiErrorHandler(errorHandler, 'useOfferItem', 'Unable to load offer.'));
1595
- }
1596
-
1597
- exports.OrderCheckoutResultType = void 0;
1598
- (function (OrderCheckoutResultType) {
1599
- OrderCheckoutResultType["Validation"] = "validation";
1600
- OrderCheckoutResultType["Completed"] = "completed";
1601
- OrderCheckoutResultType["Failed"] = "failed";
1602
- })(exports.OrderCheckoutResultType || (exports.OrderCheckoutResultType = {}));
1603
- exports.OrderCheckoutResultReason = void 0;
1604
- (function (OrderCheckoutResultReason) {
1605
- OrderCheckoutResultReason["InProgress"] = "in_progress";
1606
- OrderCheckoutResultReason["Cooldown"] = "cooldown";
1607
- OrderCheckoutResultReason["ApiError"] = "api_error";
1608
- OrderCheckoutResultReason["OrderNotReady"] = "order_not_ready";
1609
- OrderCheckoutResultReason["PhoneRequired"] = "phone_required";
1610
- OrderCheckoutResultReason["FirstNameRequired"] = "first_name_required";
1611
- OrderCheckoutResultReason["CodeRequired"] = "code_required";
1612
- OrderCheckoutResultReason["AddressError"] = "address_error";
1613
- })(exports.OrderCheckoutResultReason || (exports.OrderCheckoutResultReason = {}));
1614
- exports.BillSuggestionType = void 0;
1615
- (function (BillSuggestionType) {
1616
- BillSuggestionType["Bill"] = "bill";
1617
- BillSuggestionType["NoChange"] = "no_change";
1618
- BillSuggestionType["Custom"] = "custom";
1619
- })(exports.BillSuggestionType || (exports.BillSuggestionType = {}));
1620
-
1621
- function getUpdatedVariants(currentOrder, order) {
1622
- var _a, _b;
1623
- if (!((_a = order === null || order === void 0 ? void 0 : order.variants) === null || _a === void 0 ? void 0 : _a.length)) {
1624
- return [];
1625
- }
1626
- else if (!((_b = currentOrder === null || currentOrder === void 0 ? void 0 : currentOrder.variants) === null || _b === void 0 ? void 0 : _b.length)) {
1627
- return (order === null || order === void 0 ? void 0 : order.variants) || [];
1628
- }
1629
- let current = lodashEs.cloneDeep(currentOrder.variants);
1630
- let currentVariants = [];
1631
- const currentlyHasVariants = current && current.length > 0;
1632
- if (currentlyHasVariants) {
1633
- currentVariants = current.map((variant) => variant.uuid);
1634
- }
1635
- const actualVariantIds = order.variants.map((variant) => variant.uuid);
1636
- const createdVariantIds = order.variants
1637
- .filter((variant) => currentVariants.indexOf(variant.uuid) === -1)
1638
- .map((variant) => variant.uuid);
1639
- if (currentlyHasVariants) {
1640
- current = current.filter((variant) => actualVariantIds.indexOf(variant.uuid) !== -1);
1641
- }
1642
- if (createdVariantIds.length > 0) {
1643
- current = current || [];
1644
- order.variants.filter((variant) => createdVariantIds.indexOf(variant.uuid) !== -1)
1645
- .forEach((variant) => current.push(variant));
1646
- }
1647
- order.variants.forEach((variant) => {
1648
- const index = current.findIndex((item) => item.uuid === variant.uuid);
1649
- if (index === -1) {
1650
- return;
1651
- }
1652
- current[index].quantity = variant.quantity;
1653
- current[index].original_total_price = variant.original_total_price;
1654
- current[index].total_price = variant.total_price;
1655
- current[index].discount_difference = variant.discount_difference;
1656
- current[index].has_discount = variant.has_discount;
1657
- });
1658
- return current;
1659
- }
1660
-
1661
- function initializeOrderCustomer(credentialsResolver) {
1662
- events.useCustomerAuthenticated().subscribe('order.customer.initialize', async ({ customer }) => {
1663
- const credentials = credentialsResolver();
1664
- if (credentials === null) {
1665
- return;
1666
- }
1667
- try {
1668
- await api.setOrderCheckoutCustomer(credentials, {
1669
- phone: {
1670
- number: customer.phone.e164,
1671
- country: customer.phone.country,
1672
- },
1673
- });
1674
- }
1675
- catch (e) {
1676
- console.error('[orders/customer] Unable to attach customer to order.', { e });
1677
- }
1678
- });
1679
- }
1680
-
1681
- const useOrderStore = pinia.defineStore({
1682
- id: 'zenky:storefront:order',
1683
- state: () => ({
1684
- order: null,
1685
- token: null,
1686
- loading: false,
1687
- inclusions: null,
1688
- orderSettings: {
1689
- loaded: false,
1690
- loading: false,
1691
- settings: null,
1692
- },
1693
- }),
1694
- getters: {
1695
- credentials() {
1696
- if (!this.order || !this.order.id || this.token === null) {
1697
- return null;
1698
- }
1699
- return {
1700
- id: this.order.id,
1701
- token: this.token,
1702
- };
1703
- },
1704
- settings() {
1705
- return this.orderSettings.settings;
1706
- },
1707
- settingsLoaded() {
1708
- return this.orderSettings.loaded;
1709
- },
1710
- },
1711
- actions: {
1712
- async initialize(storeId, cityId, inclusions) {
1713
- this.inclusions = inclusions;
1714
- const storage = getStorage();
1715
- const orderId = storage.get('order.id');
1716
- const orderToken = storage.get('order.token');
1717
- initializeOrderCustomer(() => this.credentials);
1718
- this.loading = true;
1719
- if (orderId && orderToken) {
1720
- return this.load(storeId, cityId, orderId, orderToken);
1721
- }
1722
- return this.create(storeId, cityId);
1723
- },
1724
- async load(storeId, cityId, orderId, token) {
1725
- var _a, _b, _c;
1726
- const { item, load } = useOrderItem();
1727
- await load({ id: orderId, token }, this.inclusions !== null ? { with: this.inclusions.order } : {});
1728
- if (((_c = (_b = (_a = item.value) === null || _a === void 0 ? void 0 : _a.current_status) === null || _b === void 0 ? void 0 : _b.status) === null || _c === void 0 ? void 0 : _c.kind.id) === 'pending') {
1729
- this.order = item.value;
1730
- this.token = item.value.token;
1731
- this.loading = false;
1732
- events.useOrderLoaded().publish(this.order);
1733
- await this.loadSettings();
1734
- return true;
1735
- }
1736
- return this.create(storeId, cityId);
1737
- },
1738
- async loadSettings() {
1739
- if (this.orderSettings.loading) {
1740
- return;
1741
- }
1742
- else if (!this.credentials || !this.order || !this.order.city_id) {
1743
- return;
1744
- }
1745
- this.orderSettings.loading = true;
1746
- try {
1747
- this.orderSettings.settings = await api.getOrderSettings(this.credentials, this.order.city_id);
1748
- }
1749
- catch (e) {
1750
- console.error('[storefront/order] Unable to load order settings.', { e });
1751
- }
1752
- finally {
1753
- this.orderSettings.loading = false;
1754
- this.orderSettings.loaded = true;
1755
- }
1756
- },
1757
- async create(storeId, cityId) {
1758
- try {
1759
- const order = await api.createOrder({ city_id: cityId });
1760
- const storage = getStorage();
1761
- storage.set('order.id', order.id);
1762
- storage.set('order.token', order.token);
1763
- return await this.load(storeId, cityId, order.id, order.token);
1764
- }
1765
- catch (e) {
1766
- events.useOrderInitializationFailed().publish({
1767
- error: api.getApiError(e),
1768
- });
1769
- }
1770
- return false;
1771
- },
1772
- reset() {
1773
- const storage = getStorage();
1774
- storage.delete('order.id');
1775
- storage.delete('order.token');
1776
- },
1777
- async add(productVariantId, quantity, modifiers = [], promotion = null) {
1778
- if (!this.credentials) {
1779
- throw new Error('Order is not yet initialized.');
1780
- }
1781
- try {
1782
- const params = {
1783
- quantity,
1784
- modifiers,
1785
- product_variant_id: productVariantId,
1786
- };
1787
- if (promotion && promotion.id && promotion.reward_id) {
1788
- params.promotion_id = promotion.id;
1789
- params.promotion_reward_id = promotion.reward_id;
1790
- }
1791
- const order = await api.addOrderProductVariant(this.credentials, params, this.inclusions !== null ? { with: this.inclusions.product } : {});
1792
- events.useProductQuantityIncreased().publish({
1793
- order,
1794
- productVariantId,
1795
- quantity,
1796
- modifiers,
1797
- promotion,
1798
- });
1799
- this.update(order);
1800
- return true;
1801
- }
1802
- catch (e) {
1803
- events.useProductQuantityIncreaseFailed().publish({
1804
- error: api.getApiError(e),
1805
- order: this.order,
1806
- productVariantId,
1807
- quantity,
1808
- modifiers,
1809
- promotion,
1810
- });
1811
- }
1812
- return false;
1813
- },
1814
- async remove(productVariantId, quantity, modifiers = [], promotion = null) {
1815
- if (!this.credentials) {
1816
- throw new Error('Order is not yet initialized.');
1817
- }
1818
- try {
1819
- const params = {
1820
- quantity,
1821
- modifiers,
1822
- product_variant_id: productVariantId,
1823
- };
1824
- if (promotion && promotion.id && promotion.reward_id) {
1825
- params.promotion_id = promotion.id;
1826
- params.promotion_reward_id = promotion.reward_id;
1827
- }
1828
- const order = await api.removeOrderProductVariant(this.credentials, params, this.inclusions !== null ? { with: this.inclusions.product } : {});
1829
- events.useProductQuantityDecreased().publish({
1830
- order,
1831
- productVariantId,
1832
- quantity,
1833
- modifiers,
1834
- promotion,
1835
- });
1836
- this.update(order);
1837
- return true;
1838
- }
1839
- catch (e) {
1840
- events.useProductQuantityDecreaseFailed().publish({
1841
- error: api.getApiError(e),
1842
- order: this.order,
1843
- productVariantId,
1844
- quantity,
1845
- modifiers,
1846
- promotion,
1847
- });
1848
- }
1849
- return false;
1850
- },
1851
- update(order) {
1852
- if (this.order === null) {
1853
- this.order = order;
1854
- return;
1855
- }
1856
- this.order.total_price = order.total_price;
1857
- this.order.original_total_price = order.original_total_price;
1858
- this.order.discount_difference = order.discount_difference;
1859
- this.order.has_discount = order.has_discount;
1860
- this.order.variants = getUpdatedVariants(this.order, order);
1861
- },
1862
- async recreate(storeId, cityId, inclusions = null) {
1863
- this.reset();
1864
- if (!this.inclusions && inclusions) {
1865
- this.inclusions = inclusions;
1866
- }
1867
- this.loading = true;
1868
- return this.create(storeId, cityId);
1869
- },
1870
- },
1871
- });
1872
-
1873
- function useStageDetectors(order) {
1874
- const hasCustomer = () => !!order.customer && !!order.customer.id;
1875
- const hasDelivery = () => {
1876
- var _a;
1877
- if (['pickup', 'on_premise'].indexOf(order.delivery_method.id) > -1) {
1878
- return !!order.stock && !!order.stock.id;
1879
- }
1880
- return !!(order === null || order === void 0 ? void 0 : order.delivery_address) && !!((_a = order === null || order === void 0 ? void 0 : order.delivery_address) === null || _a === void 0 ? void 0 : _a.id);
1881
- };
1882
- return {
1883
- hasCustomer,
1884
- hasDelivery,
1885
- };
1886
- }
1887
- exports.CheckoutStage = void 0;
1888
- (function (CheckoutStage) {
1889
- CheckoutStage["Customer"] = "customer";
1890
- CheckoutStage["Delivery"] = "delivery";
1891
- CheckoutStage["Payments"] = "payments";
1892
- CheckoutStage["Summary"] = "summary";
1893
- })(exports.CheckoutStage || (exports.CheckoutStage = {}));
1894
- function useOrderCheckout() {
1895
- const currentStage = vue.ref(exports.CheckoutStage.Customer);
1896
- const stages = vue.ref({
1897
- [exports.CheckoutStage.Customer]: {
1898
- active: false,
1899
- completed: false,
1900
- },
1901
- [exports.CheckoutStage.Delivery]: {
1902
- active: false,
1903
- completed: false,
1904
- },
1905
- [exports.CheckoutStage.Payments]: {
1906
- active: false,
1907
- completed: false,
1908
- },
1909
- [exports.CheckoutStage.Summary]: {
1910
- active: false,
1911
- completed: false,
1912
- },
1913
- });
1914
- const { order, settingsLoaded } = pinia.storeToRefs(useOrderStore());
1915
- const { loaded: customerLoaded } = pinia.storeToRefs(useCustomerStore());
1916
- const ready = vue.computed(() => {
1917
- if (!order.value || !order.value.id || !order.value.token) {
1918
- return false;
1919
- }
1920
- else if (!customerLoaded.value) {
1921
- return false;
1922
- }
1923
- else if (!settingsLoaded.value) {
1924
- return false;
1925
- }
1926
- return true;
1927
- });
1928
- const setStage = (newStage) => {
1929
- currentStage.value = newStage;
1930
- Object.keys(stages.value).forEach((key) => {
1931
- stages.value[key].active = false;
1932
- stages.value[key].completed = false;
1933
- });
1934
- stages.value[newStage].active = true;
1935
- switch (newStage) {
1936
- case exports.CheckoutStage.Customer:
1937
- break;
1938
- case exports.CheckoutStage.Delivery:
1939
- stages.value.customer.completed = true;
1940
- break;
1941
- case exports.CheckoutStage.Payments:
1942
- stages.value.customer.completed = true;
1943
- stages.value.delivery.completed = true;
1944
- break;
1945
- case exports.CheckoutStage.Summary:
1946
- stages.value.customer.completed = true;
1947
- stages.value.delivery.completed = true;
1948
- stages.value.payments.completed = true;
1949
- break;
1950
- default:
1951
- console.error(`[checkout] Unknown stage provided: "${newStage}", resetting to customer stage.`);
1952
- stages.value.customer.completed = false;
1953
- stages.value.delivery.completed = false;
1954
- stages.value.payments.completed = false;
1955
- break;
1956
- }
1957
- };
1958
- vue.watch(ready, () => {
1959
- if (!ready.value || order.value === null) {
1960
- return setStage(exports.CheckoutStage.Customer);
1961
- }
1962
- const detectors = useStageDetectors(order.value);
1963
- if (!detectors.hasCustomer()) {
1964
- return setStage(exports.CheckoutStage.Customer);
1965
- }
1966
- else if (!detectors.hasDelivery()) {
1967
- return setStage(exports.CheckoutStage.Delivery);
1968
- }
1969
- return setStage(exports.CheckoutStage.Payments);
1970
- }, { immediate: true });
1971
- return {
1972
- ready,
1973
- order,
1974
- stages,
1975
- currentStage,
1976
- setStage,
1977
- };
1978
- }
1979
-
1980
- function useCheckoutConfirmation(order) {
1981
- const form = vue.ref({ code: '' });
1982
- const confirming = vue.ref(false);
1983
- const resending = vue.ref(false);
1984
- const credentials = vue.computed(() => ({
1985
- id: order.value.id,
1986
- token: order.value.token,
1987
- }));
1988
- const confirm = async () => {
1989
- if (confirming.value) {
1990
- return {
1991
- type: exports.OrderCheckoutResultType.Failed,
1992
- reason: exports.OrderCheckoutResultReason.InProgress,
1993
- };
1994
- }
1995
- else if (!form.value.code) {
1996
- return {
1997
- type: exports.OrderCheckoutResultType.Validation,
1998
- reason: exports.OrderCheckoutResultReason.CodeRequired,
1999
- };
2000
- }
2001
- confirming.value = true;
2002
- try {
2003
- const response = await api.confirmOrder(credentials.value, form.value);
2004
- return {
2005
- type: exports.OrderCheckoutResultType.Completed,
2006
- data: response,
2007
- };
2008
- }
2009
- catch (e) {
2010
- return {
2011
- type: exports.OrderCheckoutResultType.Failed,
2012
- reason: exports.OrderCheckoutResultReason.ApiError,
2013
- error: api.getApiError(e),
2014
- };
2015
- }
2016
- finally {
2017
- confirming.value = false;
2018
- }
2019
- };
2020
- const resendCode = async () => {
2021
- if (resending.value) {
2022
- return {
2023
- type: exports.OrderCheckoutResultType.Failed,
2024
- reason: exports.OrderCheckoutResultReason.InProgress,
2025
- };
2026
- }
2027
- resending.value = true;
2028
- try {
2029
- const result = await api.resendOrderConfirmationCode(credentials.value);
2030
- if (result.success) {
2031
- return {
2032
- type: exports.OrderCheckoutResultType.Completed,
2033
- };
2034
- }
2035
- return {
2036
- type: exports.OrderCheckoutResultType.Failed,
2037
- reason: exports.OrderCheckoutResultReason.Cooldown,
2038
- };
2039
- }
2040
- catch (e) {
2041
- return {
2042
- type: exports.OrderCheckoutResultType.Failed,
2043
- reason: exports.OrderCheckoutResultReason.ApiError,
2044
- error: api.getApiError(e),
2045
- };
2046
- }
2047
- finally {
2048
- resending.value = false;
2049
- }
2050
- };
2051
- return {
2052
- form,
2053
- confirming,
2054
- confirm,
2055
- resending,
2056
- resendCode,
2057
- };
2058
- }
2059
-
2060
- function useCustomerCheckoutForm(emit) {
2061
- var _a;
2062
- const ready = vue.ref(false);
2063
- const saving = vue.ref(false);
2064
- const form = vue.ref({
2065
- phone: {
2066
- number: '',
2067
- country: 'RU',
2068
- },
2069
- first_name: '',
2070
- last_name: '',
2071
- });
2072
- const { customer } = pinia.storeToRefs(useCustomerStore());
2073
- const { order, credentials } = pinia.storeToRefs(useOrderStore());
2074
- if (((_a = order.value) === null || _a === void 0 ? void 0 : _a.customer) && order.value.customer.id) {
2075
- form.value.phone.number = order.value.customer.phone.national;
2076
- form.value.phone.country = order.value.customer.phone.country;
2077
- form.value.first_name = order.value.customer.first_name || '';
2078
- form.value.last_name = order.value.customer.last_name || '';
2079
- }
2080
- else if (customer.value && customer.value.id) {
2081
- form.value.phone.number = customer.value.phone.national;
2082
- form.value.phone.country = customer.value.phone.country;
2083
- form.value.first_name = customer.value.first_name || '';
2084
- form.value.last_name = customer.value.last_name || '';
2085
- }
2086
- const save = async () => {
2087
- if (!credentials.value) {
2088
- return {
2089
- type: exports.OrderCheckoutResultType.Failed,
2090
- reason: exports.OrderCheckoutResultReason.OrderNotReady,
2091
- };
2092
- }
2093
- else if (saving.value) {
2094
- return {
2095
- type: exports.OrderCheckoutResultType.Failed,
2096
- reason: exports.OrderCheckoutResultReason.InProgress,
2097
- };
2098
- }
2099
- else if (!form.value.phone.number || !form.value.phone.country) {
2100
- return {
2101
- type: exports.OrderCheckoutResultType.Validation,
2102
- reason: exports.OrderCheckoutResultReason.PhoneRequired,
2103
- };
2104
- }
2105
- else if (!form.value.first_name) {
2106
- return {
2107
- type: exports.OrderCheckoutResultType.Validation,
2108
- reason: exports.OrderCheckoutResultReason.FirstNameRequired,
2109
- };
2110
- }
2111
- saving.value = true;
2112
- try {
2113
- await api.setOrderCheckoutCustomer(credentials.value, form.value);
2114
- emit('completed');
2115
- return {
2116
- type: exports.OrderCheckoutResultType.Completed,
2117
- };
2118
- }
2119
- catch (e) {
2120
- return {
2121
- type: exports.OrderCheckoutResultType.Failed,
2122
- reason: exports.OrderCheckoutResultReason.ApiError,
2123
- error: api.getApiError(e),
2124
- };
2125
- }
2126
- finally {
2127
- saving.value = false;
2128
- }
2129
- };
2130
- return {
2131
- ready,
2132
- saving,
2133
- customer,
2134
- form,
2135
- save,
2136
- };
2137
- }
2138
-
2139
- function useTotalPrice() {
2140
- const { order } = pinia.storeToRefs(useOrderStore());
2141
- return {
2142
- totalPrice: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.total_price; }),
2143
- originalTotalPrice: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.original_total_price; }),
2144
- hasDiscount: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.has_discount; }),
2145
- discountDifference: vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.discount_difference; }),
2146
- };
2147
- }
2148
- function useTotalQuantity() {
2149
- const { order } = pinia.storeToRefs(useOrderStore());
2150
- const quantity = vue.computed(() => {
2151
- var _a;
2152
- if (!order.value) {
2153
- return 0;
2154
- }
2155
- return (((_a = order.value) === null || _a === void 0 ? void 0 : _a.variants) || [])
2156
- .map((variant) => variant.quantity)
2157
- .reduce((variantQuantity, total) => variantQuantity + total, 0);
2158
- });
2159
- return {
2160
- order,
2161
- quantity,
2162
- };
2163
- }
2164
- function useOrderVariants() {
2165
- const { order } = pinia.storeToRefs(useOrderStore());
2166
- const variants = vue.computed(() => {
2167
- if (!order.value || !order.value.variants || !order.value.variants.length) {
2168
- return [];
2169
- }
2170
- return order.value.variants;
2171
- });
2172
- return {
2173
- variants,
2174
- };
2175
- }
2176
- const useVariantControls = (variant, modifiers, modifiersHash, promotion, callback) => {
2177
- const { order } = pinia.storeToRefs(useOrderStore());
2178
- const { add: addVariant, remove: removeVariant } = useOrderStore();
2179
- const loading = vue.ref(false);
2180
- const operation = vue.ref(null);
2181
- const orderVariant = vue.computed(() => {
2182
- var _a, _b;
2183
- if (!((_b = (_a = order.value) === null || _a === void 0 ? void 0 : _a.variants) === null || _b === void 0 ? void 0 : _b.length)) {
2184
- return null;
2185
- }
2186
- return order.value.variants.find((item) => {
2187
- if (item.product_variant_id !== variant.value.id || item.modifiers_hash !== modifiersHash.value) {
2188
- return false;
2189
- }
2190
- else if (promotion.value === null) {
2191
- return item.promotion_id === null;
2192
- }
2193
- return item.promotion_id === promotion.value.id && item.promotion_reward_id === promotion.value.reward_id;
2194
- });
2195
- });
2196
- const totalQuantity = vue.computed(() => (orderVariant.value ? orderVariant.value.quantity : 0));
2197
- const quantityModel = vue.ref(totalQuantity.value);
2198
- const updateVariant = async (type, quantity) => {
2199
- if (loading.value) {
2200
- return;
2201
- }
2202
- loading.value = true;
2203
- operation.value = type;
2204
- let result;
2205
- if (type === 'add') {
2206
- result = await addVariant(variant.value.id, quantity, modifiers.value, promotion.value);
2207
- }
2208
- else {
2209
- result = await removeVariant(variant.value.id, quantity, modifiers.value, promotion.value);
2210
- }
2211
- if (typeof callback === 'function') {
2212
- callback(type, result);
2213
- }
2214
- loading.value = false;
2215
- };
2216
- const add = async () => updateVariant('add', 1);
2217
- const remove = async () => updateVariant('remove', totalQuantity.value);
2218
- const getQuantity = (value) => {
2219
- if (typeof value === 'string') {
2220
- return parseInt(value, 10);
2221
- }
2222
- return value;
2223
- };
2224
- const increase = async (quantity = 1) => {
2225
- quantityModel.value = getQuantity(quantityModel.value) + quantity;
2226
- };
2227
- const decrease = async (quantity = 1) => {
2228
- quantityModel.value = Math.max(0, getQuantity(quantityModel.value) - quantity);
2229
- };
2230
- vue.watch(totalQuantity, () => {
2231
- quantityModel.value = totalQuantity.value;
2232
- });
2233
- vue.watch(quantityModel, lodashEs.debounce(async (val) => {
2234
- const difference = getQuantity(val) - totalQuantity.value;
2235
- if (difference < 0) {
2236
- await updateVariant('remove', Math.abs(difference));
2237
- }
2238
- else if (difference > 0) {
2239
- await updateVariant('add', difference);
2240
- }
2241
- }, 1000));
2242
- return {
2243
- orderVariant,
2244
- totalQuantity,
2245
- quantityModel,
2246
- add,
2247
- increase,
2248
- decrease,
2249
- remove,
2250
- loading,
2251
- operation,
2252
- };
2253
- };
2254
-
2255
- function getDeliveryMethod(order, settings) {
2256
- if (!order.value || !settings.value) {
2257
- return 'delivery';
2258
- }
2259
- const methods = settings.value.delivery_methods.map((method) => method.id);
2260
- if (methods.indexOf(order.value.delivery_method.id) !== -1) {
2261
- return order.value.delivery_method.id;
2262
- }
2263
- return methods[0];
2264
- }
2265
- function getStockId(order, stocks) {
2266
- const availableStocks = stocks.value.map((stock) => stock.id);
2267
- if (order.value && order.value.stock_id !== null && availableStocks.indexOf(order.value.stock_id) !== -1) {
2268
- return order.value.stock_id;
2269
- }
2270
- return availableStocks[0];
2271
- }
2272
- function useCustomerAddresses(customer) {
2273
- const addresses = vue.ref([]);
2274
- const loaded = vue.ref(false);
2275
- if (!customer.value || !customer.value.id) {
2276
- loaded.value = true;
2277
- }
2278
- else {
2279
- api.getCustomerAddresses({ count: 100 }).then((response) => {
2280
- addresses.value = response.items;
2281
- loaded.value = true;
2282
- });
2283
- }
2284
- return {
2285
- addresses,
2286
- loaded,
2287
- };
2288
- }
2289
- function getDeliveryPayload(form, addressesResolver) {
2290
- const data = { delivery_method: form.method };
2291
- const errors = [];
2292
- if (form.method === 'pickup') {
2293
- if (form.pickup.stock_id) {
2294
- data.stock_id = form.pickup.stock_id;
2295
- }
2296
- else {
2297
- errors.push(exports.AddressFormValueError.StockRequired);
2298
- }
2299
- }
2300
- else if (form.method === 'on_premise') {
2301
- if (form.on_premise.stock_id) {
2302
- data.stock_id = form.on_premise.stock_id;
2303
- }
2304
- else {
2305
- errors.push(exports.AddressFormValueError.StockRequired);
2306
- }
2307
- if (form.on_premise.table) {
2308
- data.on_premise = { table: form.on_premise.table };
2309
- }
2310
- else {
2311
- errors.push(exports.AddressFormValueError.TableRequired);
2312
- }
2313
- }
2314
- else if (form.method === 'delivery') {
2315
- if (form.delivery.address.id) {
2316
- data.delivery_address = { id: form.delivery.address.id };
2317
- }
2318
- else {
2319
- const { errors: addressErrors, data: address } = useAddressFormValue(form.delivery.address, addressesResolver);
2320
- if (addressErrors.length > 0) {
2321
- errors.push(addressErrors[0]);
2322
- }
2323
- else {
2324
- data.delivery_address = address;
2325
- }
2326
- }
2327
- }
2328
- if (form.deliver_at.mode === 'select' && form.deliver_at.date) {
2329
- data.deliver_at = dateFns.format(Date.parse(form.deliver_at.date), 'yyyy-MM-dd HH:mm');
2330
- }
2331
- return {
2332
- data,
2333
- errors,
2334
- };
2335
- }
2336
- function useDeliveryCheckoutForm(emit) {
2337
- var _a, _b, _c, _d;
2338
- const { credentials, order, settings } = pinia.storeToRefs(useOrderStore());
2339
- const { customer } = pinia.storeToRefs(useCustomerStore());
2340
- const { stocks, addressesResolver } = pinia.storeToRefs(useStoreStore());
2341
- const { addresses, loaded } = useCustomerAddresses(customer);
2342
- const { totalPrice } = useTotalPrice();
2343
- const ready = vue.computed(() => loaded.value);
2344
- const currentAddress = vue.computed(() => { var _a; return (_a = order.value) === null || _a === void 0 ? void 0 : _a.delivery_address; });
2345
- const saving = vue.ref(false);
2346
- const form = vue.ref({
2347
- method: getDeliveryMethod(order, settings),
2348
- delivery: {
2349
- address: getAddressForm(),
2350
- },
2351
- pickup: {
2352
- stock_id: getStockId(order, stocks),
2353
- },
2354
- on_premise: {
2355
- stock_id: getStockId(order, stocks),
2356
- table: '',
2357
- },
2358
- deliver_at: {
2359
- mode: 'asap',
2360
- date: '',
2361
- },
2362
- });
2363
- form.value.delivery.address.id = ((_b = (_a = order.value) === null || _a === void 0 ? void 0 : _a.delivery_address) === null || _b === void 0 ? void 0 : _b.id) || '';
2364
- if ((_d = (_c = order.value) === null || _c === void 0 ? void 0 : _c.deliver_at_local) === null || _d === void 0 ? void 0 : _d.datetime) {
2365
- form.value.deliver_at.mode = 'select';
2366
- form.value.deliver_at.date = dateFns.format(Date.parse(order.value.deliver_at_local.iso), 'yyyy-MM-dd HH:mm');
2367
- }
2368
- const priceIsNotEnough = vue.computed(() => {
2369
- var _a, _b;
2370
- const method = (_a = settings.value) === null || _a === void 0 ? void 0 : _a.delivery_methods.find((item) => item.id === form.value.method);
2371
- if (!method || !method.min_price || !method.min_price.value) {
2372
- return false;
2373
- }
2374
- return method.min_price.value > (((_b = totalPrice.value) === null || _b === void 0 ? void 0 : _b.value) || 0);
2375
- });
2376
- const save = async () => {
2377
- if (!credentials.value || !addressesResolver.value) {
2378
- return {
2379
- type: exports.OrderCheckoutResultType.Failed,
2380
- reason: exports.OrderCheckoutResultReason.OrderNotReady,
2381
- };
2382
- }
2383
- else if (saving.value) {
2384
- return {
2385
- type: exports.OrderCheckoutResultType.Failed,
2386
- reason: exports.OrderCheckoutResultReason.InProgress,
2387
- };
2388
- }
2389
- const { data, errors } = getDeliveryPayload(form.value, addressesResolver.value);
2390
- if (errors.length > 0) {
2391
- return {
2392
- type: exports.OrderCheckoutResultType.Validation,
2393
- reason: exports.OrderCheckoutResultReason.AddressError,
2394
- data: errors,
2395
- };
2396
- }
2397
- saving.value = true;
2398
- try {
2399
- await api.setOrderCheckoutDelivery(credentials.value, data);
2400
- emit('completed');
2401
- return {
2402
- type: exports.OrderCheckoutResultType.Completed,
2403
- };
2404
- }
2405
- catch (e) {
2406
- return {
2407
- type: exports.OrderCheckoutResultType.Failed,
2408
- reason: exports.OrderCheckoutResultReason.ApiError,
2409
- error: api.getApiError(e),
2410
- };
2411
- }
2412
- finally {
2413
- saving.value = false;
2414
- }
2415
- };
2416
- return {
2417
- ready,
2418
- form,
2419
- addresses,
2420
- currentAddress,
2421
- addressesResolver,
2422
- priceIsNotEnough,
2423
- saving,
2424
- save,
2425
- };
2426
- }
2427
-
2428
- function getPaymentMethod(settings) {
2429
- if (!settings.value) {
2430
- return 'cash';
2431
- }
2432
- const available = settings.value.payment_methods.map((method) => method.id);
2433
- return available[0];
2434
- }
2435
- function useBillSuggestions(unpaidAmount, staticAmounts = [10, 50, 200, 5000], availableBills = [100, 500, 1000]) {
2436
- const getClosestMultipleOf = (price, amount) => Math.ceil(price / amount) * amount;
2437
- const suggestions = vue.computed(() => {
2438
- const items = new Set([
2439
- ...staticAmounts,
2440
- ...availableBills.map((billItem) => getClosestMultipleOf(unpaidAmount.value, billItem)),
2441
- unpaidAmount.value,
2442
- ]);
2443
- const bills = [...items]
2444
- .filter((suggestion) => suggestion > unpaidAmount.value)
2445
- .sort((first, second) => (first - second))
2446
- .map((amount) => ({
2447
- value: amount,
2448
- type: exports.BillSuggestionType.Bill,
2449
- }));
2450
- bills.unshift({
2451
- type: exports.BillSuggestionType.NoChange,
2452
- value: '',
2453
- });
2454
- bills.push({
2455
- type: exports.BillSuggestionType.Custom,
2456
- value: 'custom',
2457
- });
2458
- return bills;
2459
- });
2460
- return {
2461
- suggestions,
2462
- };
2463
- }
2464
- function useBonusesPreviewChecker(order, credentials, bonuses, setBonuses) {
2465
- var _a;
2466
- const bonusesAreChecking = vue.ref(false);
2467
- const unpaidAmount = vue.ref((_a = order.value) === null || _a === void 0 ? void 0 : _a.total_price);
2468
- const bonusesChecker = async () => {
2469
- var _a;
2470
- if (!credentials.value) {
2471
- return;
2472
- }
2473
- else if (bonusesAreChecking.value) {
2474
- return;
2475
- }
2476
- else if (!bonuses.value) {
2477
- unpaidAmount.value = (_a = order.value) === null || _a === void 0 ? void 0 : _a.total_price;
2478
- return;
2479
- }
2480
- bonusesAreChecking.value = true;
2481
- try {
2482
- const preview = await api.getOrderBonusesPaymentPreview(credentials.value, bonuses.value);
2483
- unpaidAmount.value = preview.unpaid;
2484
- if (parseFloat(bonuses.value) > parseFloat(preview.bonuses.trimmed)) {
2485
- setBonuses(preview.bonuses.trimmed);
2486
- }
2487
- }
2488
- catch (e) {
2489
- //
2490
- }
2491
- finally {
2492
- bonusesAreChecking.value = false;
2493
- }
2494
- };
2495
- vue.watch(bonuses, lodashEs.debounce(async () => bonusesChecker(), 1000));
2496
- return {
2497
- unpaidAmount,
2498
- bonusesAreChecking,
2499
- };
2500
- }
2501
- function getPaymentsPayload(form) {
2502
- const payments = [];
2503
- if (parseFloat(form.bonuses) > 0.0) {
2504
- payments.push({
2505
- method: 'bonuses',
2506
- amount: form.bonuses,
2507
- });
2508
- }
2509
- const payment = { method: form.method };
2510
- if (form.method === 'cash' && form.bill) {
2511
- payment.bill = form.bill;
2512
- }
2513
- else if (form.method === 'card_token') {
2514
- payment.card_token_id = form.card_token_id;
2515
- }
2516
- else if (form.method === 'cloudpayments') {
2517
- payment.save_card = form.save_card === true;
2518
- }
2519
- payments.push(payment);
2520
- return payments;
2521
- }
2522
- function useDeliveryPaymentsForm(emit) {
2523
- const { order, credentials, settings } = pinia.storeToRefs(useOrderStore());
2524
- const form = vue.ref({
2525
- method: getPaymentMethod(settings),
2526
- bill: '',
2527
- save_card: false,
2528
- bonuses: '',
2529
- card_token_id: '',
2530
- });
2531
- const saving = vue.ref(false);
2532
- const bonuses = vue.computed(() => form.value.bonuses);
2533
- const { unpaidAmount, bonusesAreChecking } = useBonusesPreviewChecker(order, credentials, bonuses, (amount) => {
2534
- form.value.bonuses = amount;
2535
- });
2536
- const save = async () => {
2537
- if (!credentials.value) {
2538
- return {
2539
- type: exports.OrderCheckoutResultType.Failed,
2540
- reason: exports.OrderCheckoutResultReason.OrderNotReady,
2541
- };
2542
- }
2543
- else if (saving.value) {
2544
- return {
2545
- type: exports.OrderCheckoutResultType.Failed,
2546
- reason: exports.OrderCheckoutResultReason.InProgress,
2547
- };
2548
- }
2549
- const payments = getPaymentsPayload(form.value);
2550
- try {
2551
- await api.setOrderCheckoutPayment(credentials.value, { payments });
2552
- emit('completed');
2553
- return {
2554
- type: exports.OrderCheckoutResultType.Completed,
2555
- };
2556
- }
2557
- catch (e) {
2558
- return {
2559
- type: exports.OrderCheckoutResultType.Failed,
2560
- reason: exports.OrderCheckoutResultReason.ApiError,
2561
- error: api.getApiError(e),
2562
- };
2563
- }
2564
- finally {
2565
- saving.value = false;
2566
- }
2567
- };
2568
- return {
2569
- form,
2570
- unpaidAmount,
2571
- bonusesAreChecking,
2572
- saving,
2573
- save,
2574
- };
2575
- }
2576
-
2577
- function useCheckoutSummary(emit) {
2578
- const orderStore = useOrderStore();
2579
- const { credentials, settings } = pinia.storeToRefs(orderStore);
2580
- const { store, city } = pinia.storeToRefs(useStoreStore());
2581
- const form = vue.ref({
2582
- persons_count: '',
2583
- notes: '',
2584
- });
2585
- const hasPersonsCount = vue.computed(() => {
2586
- if (!settings.value) {
2587
- return false;
2588
- }
2589
- const index = settings.value.options.findIndex((option) => option.kind === 'persons_count');
2590
- return index !== -1;
2591
- });
2592
- const saving = vue.ref(false);
2593
- const save = async () => {
2594
- if (!credentials.value) {
2595
- return {
2596
- type: exports.OrderCheckoutResultType.Failed,
2597
- reason: exports.OrderCheckoutResultReason.OrderNotReady,
2598
- };
2599
- }
2600
- else if (saving.value) {
2601
- return {
2602
- type: exports.OrderCheckoutResultType.Failed,
2603
- reason: exports.OrderCheckoutResultReason.InProgress,
2604
- };
2605
- }
2606
- const payload = {
2607
- notes: form.value.notes,
2608
- };
2609
- if (hasPersonsCount.value && form.value.persons_count) {
2610
- payload.persons_count = form.value.persons_count;
2611
- }
2612
- saving.value = true;
2613
- try {
2614
- const response = await api.checkoutOrder(credentials.value, payload);
2615
- if (response.confirmation.required) {
2616
- emit('confirmation', {
2617
- credentials: credentials.value,
2618
- method: response.confirmation.method,
2619
- });
2620
- }
2621
- else {
2622
- emit('completed', response);
2623
- }
2624
- if (store.value && city.value) {
2625
- await orderStore.recreate(store.value.id, city.value.id);
2626
- }
2627
- return {
2628
- type: exports.OrderCheckoutResultType.Completed,
2629
- };
2630
- }
2631
- catch (e) {
2632
- return {
2633
- type: exports.OrderCheckoutResultType.Failed,
2634
- reason: exports.OrderCheckoutResultReason.ApiError,
2635
- error: api.getApiError(e),
2636
- };
2637
- }
2638
- finally {
2639
- saving.value = false;
2640
- }
2641
- };
2642
- return {
2643
- form,
2644
- hasPersonsCount,
2645
- saving,
2646
- save,
2647
- };
2648
- }
2649
-
2650
- function useCheckoutTotal() {
2651
- const { credentials } = pinia.storeToRefs(useOrderStore());
2652
- const loading = vue.ref(false);
2653
- const total = vue.ref(null);
2654
- const load = async () => {
2655
- if (loading.value) {
2656
- return;
2657
- }
2658
- else if (!credentials.value) {
2659
- return;
2660
- }
2661
- loading.value = true;
2662
- try {
2663
- total.value = await api.getOrderCheckoutTotal(credentials.value);
2664
- }
2665
- catch (e) {
2666
- //
2667
- }
2668
- finally {
2669
- loading.value = false;
2670
- }
2671
- };
2672
- return {
2673
- loading,
2674
- load,
2675
- total,
2676
- };
2677
- }
2678
-
2679
- function useSingleModifier(props, emit) {
2680
- const value = vue.computed({
2681
- get: () => props.modelValue,
2682
- set: (val) => emit('update:modelValue', val),
2683
- });
2684
- const checked = vue.computed({
2685
- get: () => value.value.quantity > 0,
2686
- set: (val) => {
2687
- value.value.quantity = val ? 1 : 0;
2688
- },
2689
- });
2690
- const shouldUseQuantityControls = vue.computed(() => props.modifier.max_quantity > 1);
2691
- const increase = () => {
2692
- if (props.limitReached) {
2693
- return;
2694
- }
2695
- value.value.quantity = Math.min(value.value.quantity + 1, props.modifier.max_quantity);
2696
- };
2697
- const decrease = () => {
2698
- value.value.quantity = Math.max(value.value.quantity - 1, props.modifier.min_quantity);
2699
- };
2700
- return {
2701
- value,
2702
- checked,
2703
- shouldUseQuantityControls,
2704
- increase,
2705
- decrease,
2706
- };
2707
- }
2708
-
2709
- function getModifierQuantity(modifier, value) {
2710
- const index = value.value.findIndex((item) => item.modifier_id === modifier.modifier.id);
2711
- if (index === -1) {
2712
- return 0;
2713
- }
2714
- return value.value[index].quantity;
2715
- }
2716
- function getDefaultModifiersGroupModifiers(group, value) {
2717
- const modifiers = {};
2718
- group.modifiers.forEach((modifier) => {
2719
- const quantity = Array.isArray(value.value) ? getModifierQuantity(modifier, value) : 0;
2720
- modifiers[modifier.modifier.id] = {
2721
- quantity,
2722
- modifier_id: modifier.modifier.id,
2723
- };
2724
- });
2725
- return modifiers;
2726
- }
2727
- function getSelectedModifiers$1(group, modifiers) {
2728
- const selected = [];
2729
- Object.keys(modifiers).forEach((modifierId) => {
2730
- if (!modifiers[modifierId].quantity) {
2731
- return;
2732
- }
2733
- selected.push({
2734
- modifiers_group_id: group.group.id,
2735
- modifier_id: modifierId,
2736
- quantity: modifiers[modifierId].quantity,
2737
- });
2738
- });
2739
- return selected;
2740
- }
2741
- function useModifiersGroup(props, emit) {
2742
- const value = vue.computed({
2743
- get: () => props.modelValue,
2744
- set: (val) => emit('update:modelValue', val),
2745
- });
2746
- const selectedModifier = vue.ref('');
2747
- const modifiers = vue.ref(getDefaultModifiersGroupModifiers(props.group, value));
2748
- const shouldUseQuantityControls = vue.computed(() => props.group.max_quantity > 1);
2749
- const totalSelectedCount = vue.computed(() => {
2750
- return value.value
2751
- .map((modifier) => modifier.quantity)
2752
- .reduce((current, total) => current + total, 0);
2753
- });
2754
- const limitReached = vue.computed(() => {
2755
- if (!shouldUseQuantityControls.value) {
2756
- return selectedModifier.value !== '';
2757
- }
2758
- return totalSelectedCount.value >= props.group.max_quantity;
2759
- });
2760
- const requiredModifierIsMissing = vue.computed(() => {
2761
- if (!props.group.is_required) {
2762
- return false;
2763
- }
2764
- else if (props.group.min_quantity === 0) {
2765
- return false;
2766
- }
2767
- return totalSelectedCount.value < props.group.min_quantity;
2768
- });
2769
- vue.watch(selectedModifier, (val) => {
2770
- if (!val) {
2771
- value.value = [];
2772
- return;
2773
- }
2774
- value.value = [{
2775
- modifiers_group_id: props.group.group.id,
2776
- modifier_id: val,
2777
- quantity: 1,
2778
- }];
2779
- });
2780
- vue.watch(modifiers, (val) => {
2781
- value.value = getSelectedModifiers$1(props.group, val);
2782
- }, { deep: true });
2783
- return {
2784
- selectedModifier,
2785
- modifiers,
2786
- shouldUseQuantityControls,
2787
- requiredModifierIsMissing,
2788
- limitReached,
2789
- };
2790
- }
2791
-
2792
- function getModifiers(product, variant) {
2793
- const modifiers = {};
2794
- ((product === null || product === void 0 ? void 0 : product.modifiers) || []).forEach((modifier) => {
2795
- modifiers[modifier.modifier.id] = {
2796
- modifier_id: modifier.modifier.id,
2797
- quantity: 0,
2798
- };
2799
- });
2800
- ((product === null || product === void 0 ? void 0 : product.modifiers_groups) || []).forEach((group) => {
2801
- modifiers[group.group.id] = [];
2802
- });
2803
- if (!variant.value || !variant.value.selected_modifiers || !variant.value.selected_modifiers.modifiers) {
2804
- return modifiers;
2805
- }
2806
- else if (!variant.value.selected_modifiers.modifiers.length) {
2807
- return modifiers;
2808
- }
2809
- variant.value.selected_modifiers.modifiers.forEach((modifier) => {
2810
- if (typeof modifier.modifiers_group_id !== 'undefined' && modifier.modifiers_group_id) {
2811
- modifiers[modifier.modifiers_group_id].push(modifier);
2812
- }
2813
- else if (typeof modifier.modifier_id !== 'undefined' && modifier.modifier_id) {
2814
- modifiers[modifier.modifier_id] = {
2815
- modifier_id: modifier.modifier_id,
2816
- quantity: modifier.quantity,
2817
- };
2818
- }
2819
- });
2820
- return modifiers;
2821
- }
2822
- function getSelectedModifiers(modifiers) {
2823
- const selected = [];
2824
- Object.keys(modifiers.value).forEach((modifierId) => {
2825
- const isGroup = Array.isArray(modifiers.value[modifierId]);
2826
- if (!isGroup && !modifiers.value[modifierId].quantity) {
2827
- return;
2828
- }
2829
- else if (!isGroup) {
2830
- selected.push({
2831
- modifier_id: modifierId,
2832
- quantity: modifiers.value[modifierId].quantity,
2833
- });
2834
- return;
2835
- }
2836
- modifiers.value[modifierId].forEach((modifier) => {
2837
- if (!modifier.modifier_id || !modifier.quantity || !modifier.modifiers_group_id) {
2838
- return;
2839
- }
2840
- selected.push({
2841
- modifiers_group_id: modifier.modifiers_group_id,
2842
- modifier_id: modifier.modifier_id,
2843
- quantity: modifier.quantity,
2844
- });
2845
- });
2846
- });
2847
- return selected;
2848
- }
2849
- function useModifiers(product, variant, recalculate) {
2850
- var _a, _b;
2851
- const modifiersHash = vue.ref(((_b = (_a = variant.value) === null || _a === void 0 ? void 0 : _a.selected_modifiers) === null || _b === void 0 ? void 0 : _b.hash) || null);
2852
- const modifiers = vue.ref(getModifiers(product, variant));
2853
- const selectedModifiers = vue.computed(() => getSelectedModifiers(modifiers));
2854
- vue.watch(variant, () => {
2855
- modifiers.value = getModifiers(product, variant);
2856
- });
2857
- vue.watch(selectedModifiers, async () => {
2858
- modifiersHash.value = await recalculate(selectedModifiers);
2859
- });
2860
- return {
2861
- modifiers,
2862
- selectedModifiers,
2863
- modifiersHash,
2864
- };
2865
- }
2866
-
2867
- async function recalculatePrice(variant, modifiers) {
2868
- if (!variant.value) {
2869
- return null;
2870
- }
2871
- else if (!modifiers.value.length) {
2872
- return null;
2873
- }
2874
- const { cityId } = pinia.storeToRefs(useStoreStore());
2875
- try {
2876
- return await api.getProductVariantPrice(variant.value.product_id, variant.value.id, modifiers.value, {
2877
- city_id: cityId.value || undefined,
2878
- });
2879
- }
2880
- catch (e) {
2881
- //
2882
- }
2883
- return null;
2884
- }
2885
- function getProductVariantsPricesRange(variants) {
2886
- if (!variants.length) {
2887
- return null;
2888
- }
2889
- const sorted = [...variants].sort((first, second) => Math.sign(first.price.value - second.price.value));
2890
- return {
2891
- min: sorted[0].price,
2892
- max: sorted[sorted.length - 1].price,
2893
- };
2894
- }
2895
- function useVariantPrice(variants, variant) {
2896
- const result = vue.ref(null);
2897
- const recalculating = vue.ref(false);
2898
- const totalPrice = vue.computed(() => {
2899
- if (result.value !== null) {
2900
- return {
2901
- recalculated: true,
2902
- recalculating: recalculating.value,
2903
- price: result.value.price,
2904
- original_price: result.value.original_price,
2905
- has_discount: result.value.has_discount,
2906
- discount_id: result.value.discount_id,
2907
- discount_difference: result.value.discount_difference,
2908
- discount_percentage: result.value.discount_percentage,
2909
- };
2910
- }
2911
- else if (!variant.value) {
2912
- return null;
2913
- }
2914
- return {
2915
- recalculated: false,
2916
- recalculating: recalculating.value,
2917
- price: variant.value.price,
2918
- original_price: variant.value.original_price,
2919
- has_discount: variant.value.has_discount,
2920
- discount_id: variant.value.discount_id,
2921
- discount_difference: variant.value.discount_difference,
2922
- discount_percentage: variant.value.discount_percentage,
2923
- };
2924
- });
2925
- const pricesRange = vue.computed(() => getProductVariantsPricesRange(variants));
2926
- const recalculate = async (modifiers) => {
2927
- if (recalculating.value) {
2928
- return null;
2929
- }
2930
- recalculating.value = true;
2931
- result.value = await recalculatePrice(variant, modifiers);
2932
- recalculating.value = false;
2933
- return result.value !== null ? result.value.modifiers_hash : null;
2934
- };
2935
- return {
2936
- totalPrice,
2937
- pricesRange,
2938
- recalculating,
2939
- recalculate,
2940
- };
2941
- }
2942
-
2943
- function getOptionsList(variants) {
2944
- const options = [];
2945
- if (variants.length <= 1) {
2946
- return options;
2947
- }
2948
- variants.forEach((variant) => {
2949
- if (!variant.option_values || !variant.option_values.length) {
2950
- return;
2951
- }
2952
- variant.option_values.forEach((optionValue) => {
2953
- if (!optionValue.option || !optionValue.option.id) {
2954
- return;
2955
- }
2956
- const optionIndex = options.findIndex((option) => { var _a; return option.id === ((_a = optionValue.option) === null || _a === void 0 ? void 0 : _a.id); });
2957
- if (optionIndex === -1) {
2958
- options.push({
2959
- id: optionValue.option.id,
2960
- name: optionValue.option.name,
2961
- type: optionValue.option.type,
2962
- values: [optionValue],
2963
- });
2964
- return;
2965
- }
2966
- const valueIndex = options[optionIndex].values.findIndex((item) => item.id === optionValue.id);
2967
- if (valueIndex !== -1) {
2968
- return;
2969
- }
2970
- options[optionIndex].values.push(optionValue);
2971
- });
2972
- });
2973
- return options;
2974
- }
2975
- function useVariant(variants) {
2976
- const options = vue.ref(getOptionsList(variants));
2977
- const selectedOptions = vue.ref({});
2978
- options.value.forEach((option) => {
2979
- selectedOptions.value[option.id] = option.values.length > 0 ? option.values[0].id : null;
2980
- });
2981
- const variant = vue.computed(() => {
2982
- if (!Array.isArray(variants) || !variants.length) {
2983
- return null;
2984
- }
2985
- else if (variants.length === 1) {
2986
- return variants[0];
2987
- }
2988
- else if (!Object.keys(selectedOptions.value).length) {
2989
- return variants[0];
2990
- }
2991
- const variantIndex = variants.findIndex((item) => {
2992
- if (!item.option_values || !item.option_values.length) {
2993
- return false;
2994
- }
2995
- return item.option_values.every((optionValue) => {
2996
- if (!optionValue.option || !optionValue.option.id) {
2997
- return false;
2998
- }
2999
- else if (typeof selectedOptions.value[optionValue.option.id] === 'undefined') {
3000
- return false;
3001
- }
3002
- else if (selectedOptions.value[optionValue.option.id] !== optionValue.id) {
3003
- return false;
3004
- }
3005
- return true;
3006
- });
3007
- });
3008
- if (variantIndex === -1) {
3009
- return null;
3010
- }
3011
- return variants[variantIndex];
3012
- });
3013
- return {
3014
- variant,
3015
- options,
3016
- selectedOptions,
3017
- };
3018
- }
3019
-
3020
- function useProductItem(errorHandler) {
3021
- return useItemLoader(api.getProduct, getApiErrorHandler(errorHandler, 'useProductItem', 'Unable to load product.'));
3022
- }
3023
- function useProductCard(item) {
3024
- var _a;
3025
- const product = vue.ref({
3026
- id: item.id,
3027
- short_id: item.short_id,
3028
- category_id: Array.isArray(item.categories) && item.categories.length > 0 ? item.categories[0].id : null,
3029
- slug: item.slug,
3030
- name: item.name,
3031
- description: item.description,
3032
- images: item.media || [],
3033
- modifiers: item.modifiers || [],
3034
- modifiers_groups: item.modifiers_groups || [],
3035
- variants_count: ((_a = item.variants) === null || _a === void 0 ? void 0 : _a.length) || 0,
3036
- has_images: (item.media || []).length > 0,
3037
- has_modifiers: (item.modifiers || []).length > 0 || (item.modifiers_groups || []).length > 0,
3038
- });
3039
- const { variant, options, selectedOptions, } = useVariant(item.variants || []);
3040
- const { totalPrice, pricesRange, recalculate, } = useVariantPrice(item.variants || [], variant);
3041
- const { modifiers, selectedModifiers, modifiersHash, } = useModifiers(item, variant, recalculate);
3042
- return {
3043
- product,
3044
- variant,
3045
- options,
3046
- selectedOptions,
3047
- pricesRange,
3048
- totalPrice,
3049
- modifiers,
3050
- modifiersHash,
3051
- selectedModifiers,
3052
- };
3053
- }
3054
-
3055
- function useProductsPricesRange(categoryId, errorHandler) {
3056
- return useDataLoader(async () => api.getProductsPricesRange(categoryId), getApiErrorHandler(errorHandler, 'useProductsPricesRange', 'Unable to load product prices range.'));
3057
- }
3058
-
3059
- function useFeaturesFilters(categoryId, values) {
3060
- const loader = useCategoryFeaturesList(categoryId);
3061
- const filters = vue.ref({});
3062
- const load = async () => {
3063
- await loader.load();
3064
- loader.items.value.forEach((feature) => {
3065
- filters.value[feature.alias] = values && values[feature.alias] ? values[feature.alias] : [];
3066
- });
3067
- };
3068
- return {
3069
- filters,
3070
- load,
3071
- items: loader.items,
3072
- };
3073
- }
3074
- function useFeaturesGroupsFilters(categoryId, values) {
3075
- const loader = useCategoryFeaturesGroupsList(categoryId);
3076
- const filters = vue.ref({});
3077
- const load = async () => {
3078
- await loader.load();
3079
- loader.items.value.forEach((container) => {
3080
- container.features.forEach((item) => {
3081
- filters.value[item.feature.alias] = values && values[item.feature.alias] ? values[item.feature.alias] : [];
3082
- });
3083
- });
3084
- };
3085
- return {
3086
- filters,
3087
- load,
3088
- items: loader.items,
3089
- };
3090
- }
3091
- function useProductsPricesRangeFilters(categoryId, values) {
3092
- const loader = useProductsPricesRange(categoryId);
3093
- const filters = vue.ref({
3094
- min: (values === null || values === void 0 ? void 0 : values.min) || '',
3095
- max: (values === null || values === void 0 ? void 0 : values.max) || '',
3096
- });
3097
- return {
3098
- filters,
3099
- load: async () => loader.load(),
3100
- range: loader.data,
3101
- };
3102
- }
3103
-
3104
- exports.ProductsSourceType = void 0;
3105
- (function (ProductsSourceType) {
3106
- ProductsSourceType["Category"] = "category";
3107
- ProductsSourceType["Collection"] = "collection";
3108
- ProductsSourceType["CategoryContext"] = "category_context";
3109
- ProductsSourceType["GroupContext"] = "group_context";
3110
- ProductsSourceType["VariantOptionContext"] = "variant_option_context";
3111
- ProductsSourceType["VariantOptionValueContext"] = "variant_option_value_context";
3112
- })(exports.ProductsSourceType || (exports.ProductsSourceType = {}));
3113
- exports.ProductsSorting = void 0;
3114
- (function (ProductsSorting) {
3115
- ProductsSorting["Manual"] = "manual";
3116
- ProductsSorting["NameAsc"] = "name";
3117
- ProductsSorting["NameDesc"] = "-name";
3118
- ProductsSorting["PriceAsc"] = "price";
3119
- ProductsSorting["PriceDesc"] = "-price";
3120
- })(exports.ProductsSorting || (exports.ProductsSorting = {}));
3121
- exports.ProductsFiltersType = void 0;
3122
- (function (ProductsFiltersType) {
3123
- ProductsFiltersType["Features"] = "features";
3124
- ProductsFiltersType["FeaturesGroups"] = "featuresGroups";
3125
- })(exports.ProductsFiltersType || (exports.ProductsFiltersType = {}));
3126
-
3127
- function getSourceParams(source, promotion) {
3128
- if (source === null || !source.id || !source.type) {
3129
- return {};
3130
- }
3131
- else if (promotion !== null) {
3132
- return {};
3133
- }
3134
- switch (source.type) {
3135
- case exports.ProductsSourceType.Category:
3136
- return { category_id: source.id };
3137
- case exports.ProductsSourceType.Collection:
3138
- return { collection_id: source.id };
3139
- case exports.ProductsSourceType.CategoryContext:
3140
- return {
3141
- context_type: 'category',
3142
- context_id: source.id,
3143
- };
3144
- case exports.ProductsSourceType.GroupContext:
3145
- return {
3146
- context_type: 'group',
3147
- context_id: source.id,
3148
- };
3149
- case exports.ProductsSourceType.VariantOptionContext:
3150
- return {
3151
- context_type: 'variant_option',
3152
- context_id: source.id,
3153
- };
3154
- case exports.ProductsSourceType.VariantOptionValueContext:
3155
- return {
3156
- context_type: 'variant_option_value',
3157
- context_id: source.id,
3158
- };
3159
- default:
3160
- return {};
3161
- }
3162
- }
3163
- function getSortingParams(sorting) {
3164
- if (!sorting) {
3165
- return {};
3166
- }
3167
- switch (sorting) {
3168
- case exports.ProductsSorting.Manual:
3169
- case exports.ProductsSorting.NameAsc:
3170
- case exports.ProductsSorting.NameDesc:
3171
- case exports.ProductsSorting.PriceAsc:
3172
- case exports.ProductsSorting.PriceDesc:
3173
- return { order_by: sorting };
3174
- default:
3175
- return {};
3176
- }
3177
- }
3178
- function getFiltersParams(filters) {
3179
- if (typeof filters !== 'object' || !Object.keys(filters).length) {
3180
- return {};
3181
- }
3182
- const features = {};
3183
- Object.keys(filters).forEach((key) => {
3184
- if (Array.isArray(filters[key]) && filters[key].length > 0) {
3185
- features[key] = filters[key].join(',');
3186
- }
3187
- });
3188
- if (!Object.keys(features).length) {
3189
- return {};
3190
- }
3191
- return { f: features };
3192
- }
3193
- function getPricesFiltersParams(filters) {
3194
- const params = {};
3195
- if (filters.min) {
3196
- params.min_price = filters.min;
3197
- }
3198
- if (filters.max) {
3199
- params.max_price = filters.max;
3200
- }
3201
- return params;
3202
- }
3203
- function getLoaderParams(page, loader) {
3204
- const params = {
3205
- page,
3206
- count: loader.pagination.count,
3207
- };
3208
- if (loader.cityId) {
3209
- params.city_id = loader.cityId;
3210
- }
3211
- if (loader.visibility) {
3212
- params.visibility = loader.visibility;
3213
- }
3214
- if (loader.with) {
3215
- params.with = loader.with;
3216
- }
3217
- if (loader.search) {
3218
- params.search = loader.search;
3219
- }
3220
- if (typeof loader.promotion === 'undefined' || loader.promotion === null) {
3221
- return params;
3222
- }
3223
- params.promotion_reward = 'all';
3224
- if (!loader.promotion.context_type || !loader.promotion.context_id) {
3225
- return params;
3226
- }
3227
- params.context_type = loader.promotion.context_type;
3228
- params.context_id = loader.promotion.context_id;
3229
- return params;
3230
- }
3231
- function getProductsPaginationRequest(page, loader) {
3232
- if (loader.source && typeof loader.source.error !== 'undefined' && loader.source.error) {
3233
- return null;
3234
- }
3235
- return {
3236
- ...getSourceParams(loader.source, loader.promotion),
3237
- ...getSortingParams(loader.sorting),
3238
- ...getFiltersParams(loader.filters),
3239
- ...getPricesFiltersParams(loader.pricesFilters),
3240
- ...getLoaderParams(page, loader),
3241
- };
3242
- }
3243
-
3244
- function getCategoryIdFromSource(source) {
3245
- if (!source || !source.type || !source.id || source.error) {
3246
- return null;
3247
- }
3248
- else if (source.type !== exports.ProductsSourceType.Category) {
3249
- return null;
3250
- }
3251
- return source.id;
3252
- }
3253
- function useProductsList(config, errorHandler) {
3254
- const productsLoader = usePaginatedLoader(api.getProducts, getApiErrorHandler(errorHandler, 'useProductsList', 'Unable to load products list.'));
3255
- const store = useStoreStore();
3256
- const cityId = vue.computed(() => store.cityId);
3257
- const sorting = vue.ref(config.value.sorting || exports.ProductsSorting.Manual);
3258
- const search = vue.ref(config.value.search || '');
3259
- const { filters, load: loadFilters, items: features, } = config.value.filtersType === exports.ProductsFiltersType.Features
3260
- ? useFeaturesFilters(getCategoryIdFromSource(config.value.source), config.value.filters)
3261
- : useFeaturesGroupsFilters(getCategoryIdFromSource(config.value.source), config.value.filters);
3262
- const { filters: pricesFilters, load: loadPricesRange, range, } = useProductsPricesRangeFilters(getCategoryIdFromSource(config.value.source), config.value.pricesFilters);
3263
- const allowed = vue.ref(false);
3264
- const loader = vue.computed(() => ({
3265
- source: config.value.source,
3266
- cityId: cityId.value,
3267
- sorting: sorting.value,
3268
- search: search.value,
3269
- filters: filters.value,
3270
- pricesFilters: pricesFilters.value,
3271
- pagination: {
3272
- count: config.value.count,
3273
- },
3274
- with: config.value.with || '',
3275
- promotion: config.value.promotion || null,
3276
- }));
3277
- const load = async (page, reset = false, callback) => {
3278
- const request = getProductsPaginationRequest(page, loader.value);
3279
- if (request === null) {
3280
- allowed.value = false;
3281
- if (typeof callback === 'function') {
3282
- callback(null);
3283
- }
3284
- return;
3285
- }
3286
- allowed.value = true;
3287
- await productsLoader.load(request, reset);
3288
- if (typeof callback === 'function') {
3289
- callback(request);
3290
- }
3291
- };
3292
- const init = async (callback) => {
3293
- if (config.value.filtersType !== null) {
3294
- await loadFilters();
3295
- }
3296
- await loadPricesRange();
3297
- vue.watch(loader, lodashEs.debounce(async () => load(1, true, callback), 1000), {
3298
- deep: true,
3299
- });
3300
- await load(1, true, callback);
3301
- };
3302
- return {
3303
- state: productsLoader.state,
3304
- pagination: productsLoader.pagination,
3305
- items: productsLoader.items,
3306
- allowed,
3307
- filters,
3308
- pricesFilters,
3309
- sorting,
3310
- features,
3311
- search,
3312
- pricesRange: range,
3313
- init,
3314
- load,
3315
- };
3316
- }
3317
- function getFiltersForUrl(filters) {
3318
- const params = [];
3319
- Object.keys(filters).forEach((key) => {
3320
- params.push(`${key}:${filters[key]}`);
3321
- });
3322
- return params.join(';');
3323
- }
3324
- function getFiltersFromUrl(param) {
3325
- const items = param.split(';');
3326
- const filters = {};
3327
- items.forEach((item) => {
3328
- const [filter, value] = item.split(':');
3329
- if (!filter || !value) {
3330
- return;
3331
- }
3332
- filters[filter] = value.split(',');
3333
- });
3334
- return filters;
3335
- }
3336
- function getProductsListQueryParamsWithPromotion(params, promotion) {
3337
- if (!promotion) {
3338
- return params;
3339
- }
3340
- const clone = {
3341
- ...params,
3342
- promotion_id: promotion.id,
3343
- reward_id: promotion.reward_id,
3344
- };
3345
- if (promotion.context_type) {
3346
- clone.context_type = promotion.context_type;
3347
- }
3348
- if (promotion.context_id) {
3349
- clone.context_id = promotion.context_id;
3350
- }
3351
- return clone;
3352
- }
3353
- function getProductsListQueryParams(config, request) {
3354
- if (request === null) {
3355
- return getProductsListQueryParamsWithPromotion({}, config.promotion);
3356
- }
3357
- const query = {};
3358
- if (request.order_by && request.order_by !== config.sorting) {
3359
- query.order_by = request.order_by;
3360
- }
3361
- if (typeof request.f !== 'undefined' && Object.keys(request.f).length > 0) {
3362
- query.f = getFiltersForUrl(request.f);
3363
- }
3364
- if (request.min_price) {
3365
- query.min_price = request.min_price;
3366
- }
3367
- if (request.max_price) {
3368
- query.max_price = request.max_price;
3369
- }
3370
- if (request.search) {
3371
- query.search = request.search;
3372
- }
3373
- return getProductsListQueryParamsWithPromotion(query, config.promotion);
3374
- }
3375
- function getQueryParam(query, param) {
3376
- return typeof query[param] !== 'undefined' && query[param] ? query[param] : null;
3377
- }
3378
- function getPromotionFromQuery(query) {
3379
- const promotionId = getQueryParam(query, 'promotion_id');
3380
- const rewardId = getQueryParam(query, 'reward_id');
3381
- if (!promotionId || !rewardId) {
3382
- return null;
3383
- }
3384
- const contextType = getQueryParam(query, 'context_type');
3385
- const contextId = getQueryParam(query, 'context_id');
3386
- return {
3387
- id: promotionId,
3388
- reward_id: rewardId,
3389
- context_type: contextType,
3390
- context_id: contextId,
3391
- };
3392
- }
3393
- function getProductsListParamsFromQuery(query) {
3394
- if (!query) {
3395
- return null;
3396
- }
3397
- return {
3398
- sorting: typeof query.order_by !== 'undefined' ? query.order_by : null,
3399
- f: typeof query.f === 'string' ? getFiltersFromUrl(query.f) : null,
3400
- min_price: getQueryParam(query, 'min_price'),
3401
- max_price: getQueryParam(query, 'max_price'),
3402
- search: getQueryParam(query, 'search'),
3403
- promotion: getPromotionFromQuery(query),
3404
- };
3405
- }
3406
-
3407
- function getInjectedSource(sourceInjection, notFoundInjection, type) {
3408
- const source = vue.inject(sourceInjection);
3409
- const notFound = vue.inject(notFoundInjection);
3410
- if (!source) {
3411
- return null;
3412
- }
3413
- else if (notFound && notFound.value) {
3414
- return {
3415
- error: true,
3416
- };
3417
- }
3418
- return {
3419
- type: type,
3420
- id: source.value.id,
3421
- };
3422
- }
3423
- function getProductsSource(source) {
3424
- if (source && source.type && source.id) {
3425
- return source;
3426
- }
3427
- else if (source && source.error) {
3428
- return null;
3429
- }
3430
- const injected = vue.inject(exports.ZenkyInjection.ProductsSource, null);
3431
- if (!injected) {
3432
- return null;
3433
- }
3434
- switch (injected) {
3435
- case exports.ProductsSourceType.Category:
3436
- return getInjectedSource(exports.ZenkyInjection.Category, exports.ZenkyInjection.CategoryNotFound, injected);
3437
- case exports.ProductsSourceType.Collection:
3438
- return getInjectedSource(exports.ZenkyInjection.Collection, exports.ZenkyInjection.CollectionNotFound, injected);
3439
- case exports.ProductsSourceType.CategoryContext:
3440
- return getInjectedSource(exports.ZenkyInjection.CategoryContext, exports.ZenkyInjection.CategoryContextNotFound, injected);
3441
- case exports.ProductsSourceType.GroupContext:
3442
- return getInjectedSource(exports.ZenkyInjection.GroupContext, exports.ZenkyInjection.GroupContextNotFound, injected);
3443
- case exports.ProductsSourceType.VariantOptionContext:
3444
- return getInjectedSource(exports.ZenkyInjection.VariantOptionContext, exports.ZenkyInjection.VariantOptionContextNotFound, injected);
3445
- case exports.ProductsSourceType.VariantOptionValueContext:
3446
- return getInjectedSource(exports.ZenkyInjection.VariantOptionValueContext, exports.ZenkyInjection.VariantOptionValueContextNotFound, injected);
3447
- default:
3448
- return null;
3449
- }
3450
- }
3451
-
3452
- const usePromotionsStore = pinia.defineStore({
3453
- id: 'zenky:storefront:promotions',
3454
- state: () => ({
3455
- checking: false,
3456
- failed: false,
3457
- selector: {
3458
- available: false,
3459
- closed: false,
3460
- offer: null,
3461
- promotion_id: '',
3462
- reward_id: '',
3463
- max_quantity: 0,
3464
- context: null,
3465
- },
3466
- }),
3467
- getters: {
3468
- hasSelector() {
3469
- if (this.checking) {
3470
- return false;
3471
- }
3472
- else if (!this.selector.available) {
3473
- return false;
3474
- }
3475
- else if (!this.selector.promotion_id || !this.selector.reward_id) {
3476
- return false;
3477
- }
3478
- return true;
3479
- },
3480
- hasSelectorContext() {
3481
- if (this.selector.context === null) {
3482
- return false;
3483
- }
3484
- return !!this.selector.context.id && !!this.selector.context.type;
3485
- },
3486
- },
3487
- actions: {
3488
- setCheckerState(value, timedOut = false) {
3489
- this.checking = value;
3490
- this.failed = timedOut;
3491
- },
3492
- disableRewardsSelector() {
3493
- this.selector.available = false;
3494
- this.selector.offer = null;
3495
- this.selector.promotion_id = '';
3496
- this.selector.reward_id = '';
3497
- this.selector.max_quantity = 0;
3498
- this.selector.context = null;
3499
- },
3500
- enableRewardsSelector(selector) {
3501
- this.selector.available = true;
3502
- this.selector.offer = selector.offer;
3503
- this.selector.promotion_id = selector.promotion_id;
3504
- this.selector.reward_id = selector.reward_id;
3505
- this.selector.max_quantity = selector.limit;
3506
- this.selector.context = selector.context;
3507
- },
3508
- closeRewardsSelector() {
3509
- this.selector.closed = true;
3510
- },
3511
- openRewardsSelector() {
3512
- this.selector.closed = false;
3513
- },
3514
- initialize() {
3515
- events.usePromotionsCheckerStarted().subscribe('storefront.promotions.initialize', () => this.setCheckerState(true));
3516
- events.usePromotionsCheckerCompleted().subscribe('storefront.promotions.initialize', (params) => this.setCheckerState(false, params && params.timeout === true));
3517
- events.useDisplayOrderPromotionRewardSelection().subscribe('storefront.promotions.initialize', ({ data }) => this.enableRewardsSelector(data));
3518
- events.useOrderPromotionsNotFound().subscribe('storefront.promotions.initialize', () => this.disableRewardsSelector());
3519
- },
3520
- },
3521
- });
3522
-
3523
- function initializePromotions(order, timeout = 10000) {
3524
- const promotionsStore = usePromotionsStore();
3525
- promotionsStore.initialize();
3526
- const promotionsAreChecking = vue.computed(() => promotionsStore.checking);
3527
- let manualTimeout = undefined;
3528
- const checker = async () => {
3529
- if (promotionsAreChecking.value) {
3530
- return;
3531
- }
3532
- if (manualTimeout) {
3533
- clearTimeout(manualTimeout);
3534
- }
3535
- events.usePromotionsCheckerStarted().publish();
3536
- await api.checkCompletedPromotions({ id: order.id, token: order.token });
3537
- manualTimeout = setTimeout(() => {
3538
- if (promotionsAreChecking.value) {
3539
- events.usePromotionsCheckerCompleted().publish({ timeout: true });
3540
- }
3541
- }, timeout);
3542
- };
3543
- events.useProductQuantityIncreased().subscribe('promotions.init', checker);
3544
- events.useProductQuantityDecreased().subscribe('promotions.init', checker);
3545
- api.checkCompletedPromotions({ id: order.id, token: order.token }).then(() => {
3546
- console.log('[storefront/promotions] Promotions checker has been initialized.');
3547
- });
3548
- }
3549
- function useRewardsSelector() {
3550
- const promotionsStore = usePromotionsStore();
3551
- const selector = vue.computed(() => promotionsStore.selector);
3552
- const checking = vue.computed(() => promotionsStore.checking);
3553
- const failed = vue.computed(() => promotionsStore.failed);
3554
- const available = vue.computed(() => selector.value.available);
3555
- const collapsed = vue.computed(() => selector.value.closed);
3556
- const close = () => promotionsStore.closeRewardsSelector();
3557
- const open = () => promotionsStore.openRewardsSelector();
3558
- return {
3559
- checking,
3560
- failed,
3561
- available,
3562
- collapsed,
3563
- selector,
3564
- open,
3565
- close,
3566
- };
3567
- }
3568
-
3569
- exports.ZenkyWebsocketEvent = void 0;
3570
- (function (ZenkyWebsocketEvent) {
3571
- ZenkyWebsocketEvent["OrderPriceRecalculated"] = "orders.price.recalculated";
3572
- ZenkyWebsocketEvent["OrderMustBeReloaded"] = "orders.reload";
3573
- ZenkyWebsocketEvent["OrderRewardsMustBeReloaded"] = "orders.rewards.reload";
3574
- ZenkyWebsocketEvent["DisplayOrderRewardsSelection"] = "orders.rewards.display_selection";
3575
- ZenkyWebsocketEvent["PromotionsNotFound"] = "orders.promotions.not_found";
3576
- })(exports.ZenkyWebsocketEvent || (exports.ZenkyWebsocketEvent = {}));
3577
-
3578
- let instance = null;
3579
- function createWebsocketsConnection(store) {
3580
- if (instance !== null) {
3581
- return instance;
3582
- }
3583
- else if (typeof store.settings === 'undefined' || store.settings === null) {
3584
- throw new Error('You must provide store with settings.');
3585
- }
3586
- else if (typeof store.settings.websockets === 'undefined' || store.settings.websockets === null) {
3587
- throw new Error('You must provide store with websockets settings.');
3588
- }
3589
- instance = new Pusher__default["default"](store.settings.websockets.app_key, {
3590
- wsHost: store.settings.websockets.options.host,
3591
- wsPort: store.settings.websockets.options.port,
3592
- forceTLS: false,
3593
- enableStats: false,
3594
- enabledTransports: ['ws', 'wss'],
3595
- });
3596
- return instance;
3597
- }
3598
- function getWebsocketsConnection() {
3599
- if (instance === null) {
3600
- throw new Error('You must create websockets connection using [createWebsocketsConnection] function.');
3601
- }
3602
- return instance;
3603
- }
3604
- function subscribeToOrderEvents(order) {
3605
- if (instance === null) {
3606
- throw new Error('You must create websocket connection using `createWebsocketConnection` function!');
3607
- }
3608
- const channel = instance.subscribe(`orders.${order.id}.${order.token}`);
3609
- channel.bind(exports.ZenkyWebsocketEvent.OrderPriceRecalculated, (data) => {
3610
- events.useOrderPriceRecalculated().publish({ order, data });
3611
- });
3612
- channel.bind(exports.ZenkyWebsocketEvent.OrderMustBeReloaded, () => {
3613
- events.useOrderShouldBeReloaded().publish({ order });
3614
- });
3615
- channel.bind(exports.ZenkyWebsocketEvent.OrderRewardsMustBeReloaded, () => {
3616
- events.useOrderPromotionRewardsShouldBeReloaded().publish({ order });
3617
- });
3618
- channel.bind(exports.ZenkyWebsocketEvent.DisplayOrderRewardsSelection, (data) => {
3619
- events.useDisplayOrderPromotionRewardSelection().publish({ order, data });
3620
- events.usePromotionsCheckerCompleted().publish();
3621
- });
3622
- channel.bind(exports.ZenkyWebsocketEvent.PromotionsNotFound, () => {
3623
- events.useOrderPromotionsNotFound().publish({ order });
3624
- events.usePromotionsCheckerCompleted().publish();
3625
- });
3626
- events.useOrderSubmitted().subscribe('websockets.subscribe', ({ order: submittedOrder }) => {
3627
- if (instance === null) {
3628
- throw new Error('You must create websocket connection using `createWebsocketConnection` function!');
3629
- }
3630
- instance.unsubscribe(`orders.${submittedOrder.id}.${submittedOrder.token}`);
3631
- });
3632
- }
3633
-
3634
- exports.createStorage = createStorage;
3635
- exports.createWebsocketsConnection = createWebsocketsConnection;
3636
- exports.getAddressForm = getAddressForm;
3637
- exports.getApiErrorHandler = getApiErrorHandler;
3638
- exports.getExistedAddress = getExistedAddress;
3639
- exports.getExistedAddressDisplayValue = getExistedAddressDisplayValue;
3640
- exports.getFirstMedium = getFirstMedium;
3641
- exports.getProductVariantsPricesRange = getProductVariantsPricesRange;
3642
- exports.getProductsListParamsFromQuery = getProductsListParamsFromQuery;
3643
- exports.getProductsListQueryParams = getProductsListQueryParams;
3644
- exports.getProductsPaginationRequest = getProductsPaginationRequest;
3645
- exports.getProductsSource = getProductsSource;
3646
- exports.getSelectedAddress = getSelectedAddress;
3647
- exports.getSelectedAddressDisplayValue = getSelectedAddressDisplayValue;
3648
- exports.getStockAddress = getStockAddress;
3649
- exports.getStockSchedule = getStockSchedule;
3650
- exports.getStorage = getStorage;
3651
- exports.getUpdatedVariants = getUpdatedVariants;
3652
- exports.getWebsocketsConnection = getWebsocketsConnection;
3653
- exports.initializeOrderCustomer = initializeOrderCustomer;
3654
- exports.initializePromotions = initializePromotions;
3655
- exports.subscribeToOrderEvents = subscribeToOrderEvents;
3656
- exports.useAddressFormValue = useAddressFormValue;
3657
- exports.useArticleCategoriesList = useArticleCategoriesList;
3658
- exports.useArticleItem = useArticleItem;
3659
- exports.useArticlesList = useArticlesList;
3660
- exports.useAuthenticationForm = useAuthenticationForm;
3661
- exports.useAuthenticationStatusChecker = useAuthenticationStatusChecker;
3662
- exports.useBillSuggestions = useBillSuggestions;
3663
- exports.useCategories = useCategories;
3664
- exports.useCategoriesStore = useCategoriesStore;
3665
- exports.useCategoriesTree = useCategoriesTree;
3666
- exports.useCategory = useCategory;
3667
- exports.useCategoryFeaturesGroupsList = useCategoryFeaturesGroupsList;
3668
- exports.useCategoryFeaturesList = useCategoryFeaturesList;
3669
- exports.useCheckoutConfirmation = useCheckoutConfirmation;
3670
- exports.useCheckoutSummary = useCheckoutSummary;
3671
- exports.useCheckoutTotal = useCheckoutTotal;
3672
- exports.useCollection = useCollection;
3673
- exports.useCollections = useCollections;
3674
- exports.useCollectionsStore = useCollectionsStore;
3675
- exports.useCustomer = useCustomer;
3676
- exports.useCustomerCheckoutForm = useCustomerCheckoutForm;
3677
- exports.useCustomerStore = useCustomerStore;
3678
- exports.useDadata = useDadata;
3679
- exports.useDataDestroyer = useDataDestroyer;
3680
- exports.useDataLoader = useDataLoader;
3681
- exports.useDeliveryAddressDestroyer = useDeliveryAddressDestroyer;
3682
- exports.useDeliveryAddressesList = useDeliveryAddressesList;
3683
- exports.useDeliveryCheckoutForm = useDeliveryCheckoutForm;
3684
- exports.useDeliveryPaymentsForm = useDeliveryPaymentsForm;
3685
- exports.useEditAddressForm = useEditAddressForm;
3686
- exports.useFeaturesFilters = useFeaturesFilters;
3687
- exports.useFeaturesGroupsFilters = useFeaturesGroupsFilters;
3688
- exports.useFlatCategoriesTree = useFlatCategoriesTree;
3689
- exports.useItemLoader = useItemLoader;
3690
- exports.useListLoader = useListLoader;
3691
- exports.useLogin = useLogin;
3692
- exports.useLogout = useLogout;
3693
- exports.useModifiers = useModifiers;
3694
- exports.useModifiersGroup = useModifiersGroup;
3695
- exports.useOfferItem = useOfferItem;
3696
- exports.useOffersList = useOffersList;
3697
- exports.useOrderCheckout = useOrderCheckout;
3698
- exports.useOrderItem = useOrderItem;
3699
- exports.useOrderStore = useOrderStore;
3700
- exports.useOrderVariants = useOrderVariants;
3701
- exports.useOrdersList = useOrdersList;
3702
- exports.usePaginatedLoader = usePaginatedLoader;
3703
- exports.usePasswordReset = usePasswordReset;
3704
- exports.usePaymentMethodDestroyer = usePaymentMethodDestroyer;
3705
- exports.usePaymentMethodsList = usePaymentMethodsList;
3706
- exports.usePhoneConfirmation = usePhoneConfirmation;
3707
- exports.useProductCard = useProductCard;
3708
- exports.useProductItem = useProductItem;
3709
- exports.useProductsList = useProductsList;
3710
- exports.useProductsPricesRange = useProductsPricesRange;
3711
- exports.useProductsPricesRangeFilters = useProductsPricesRangeFilters;
3712
- exports.usePromotionsStore = usePromotionsStore;
3713
- exports.useRegistration = useRegistration;
3714
- exports.useReversedTree = useReversedTree;
3715
- exports.useRewardsSelector = useRewardsSelector;
3716
- exports.useSingleModifier = useSingleModifier;
3717
- exports.useSplittedCategoriesTree = useSplittedCategoriesTree;
3718
- exports.useStateDataLoader = useStateDataLoader;
3719
- exports.useStoreStore = useStoreStore;
3720
- exports.useSuggestionsRestrictedToCity = useSuggestionsRestrictedToCity;
3721
- exports.useTotalPrice = useTotalPrice;
3722
- exports.useTotalQuantity = useTotalQuantity;
3723
- exports.useVariant = useVariant;
3724
- exports.useVariantControls = useVariantControls;
3725
- exports.useVariantPrice = useVariantPrice;