@zenky/storefront-vue 0.9.39 → 0.9.40

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 CHANGED
@@ -2521,6 +2521,388 @@ function useCheckoutTotal() {
2521
2521
  };
2522
2522
  }
2523
2523
 
2524
+ function useSingleModifier(props, emit) {
2525
+ const value = vue.computed({
2526
+ get: () => props.modelValue,
2527
+ set: (val) => emit('update:modelValue', val),
2528
+ });
2529
+ const checked = vue.computed({
2530
+ get: () => value.value.quantity > 0,
2531
+ set: (val) => {
2532
+ value.value.quantity = val ? 1 : 0;
2533
+ },
2534
+ });
2535
+ const shouldUseQuantityControls = vue.computed(() => props.modifier.max_quantity > 1);
2536
+ const increase = () => {
2537
+ if (props.limitReached) {
2538
+ return;
2539
+ }
2540
+ value.value.quantity = Math.min(value.value.quantity + 1, props.modifier.max_quantity);
2541
+ };
2542
+ const decrease = () => {
2543
+ value.value.quantity = Math.max(value.value.quantity - 1, props.modifier.min_quantity);
2544
+ };
2545
+ return {
2546
+ value,
2547
+ checked,
2548
+ shouldUseQuantityControls,
2549
+ increase,
2550
+ decrease,
2551
+ };
2552
+ }
2553
+
2554
+ function getModifierQuantity(modifier, value) {
2555
+ const index = value.value.findIndex((item) => item.modifier_id === modifier.modifier.id);
2556
+ if (index === -1) {
2557
+ return 0;
2558
+ }
2559
+ return value.value[index].quantity;
2560
+ }
2561
+ function getDefaultModifiersGroupModifiers(group, value) {
2562
+ const modifiers = {};
2563
+ group.modifiers.forEach((modifier) => {
2564
+ const quantity = Array.isArray(value.value) ? getModifierQuantity(modifier, value) : 0;
2565
+ modifiers[modifier.modifier.id] = {
2566
+ quantity,
2567
+ modifier_id: modifier.modifier.id,
2568
+ };
2569
+ });
2570
+ return modifiers;
2571
+ }
2572
+ function getSelectedModifiers$1(group, modifiers) {
2573
+ const selected = [];
2574
+ Object.keys(modifiers).forEach((modifierId) => {
2575
+ if (!modifiers[modifierId].quantity) {
2576
+ return;
2577
+ }
2578
+ selected.push({
2579
+ modifiers_group_id: group.group.id,
2580
+ modifier_id: modifierId,
2581
+ quantity: modifiers[modifierId].quantity,
2582
+ });
2583
+ });
2584
+ return selected;
2585
+ }
2586
+ function useModifiersGroup(props, emit) {
2587
+ const value = vue.computed({
2588
+ get: () => props.modelValue,
2589
+ set: (val) => emit('update:modelValue', val),
2590
+ });
2591
+ const selectedModifier = vue.ref('');
2592
+ const modifiers = vue.ref(getDefaultModifiersGroupModifiers(props.group, value));
2593
+ const shouldUseQuantityControls = vue.computed(() => props.group.max_quantity > 1);
2594
+ const totalSelectedCount = vue.computed(() => {
2595
+ return value.value
2596
+ .map((modifier) => modifier.quantity)
2597
+ .reduce((current, total) => current + total, 0);
2598
+ });
2599
+ const limitReached = vue.computed(() => {
2600
+ if (!shouldUseQuantityControls.value) {
2601
+ return selectedModifier.value !== '';
2602
+ }
2603
+ return totalSelectedCount.value >= props.group.max_quantity;
2604
+ });
2605
+ const requiredModifierIsMissing = vue.computed(() => {
2606
+ if (!props.group.is_required) {
2607
+ return false;
2608
+ }
2609
+ else if (props.group.min_quantity === 0) {
2610
+ return false;
2611
+ }
2612
+ return totalSelectedCount.value < props.group.min_quantity;
2613
+ });
2614
+ vue.watch(selectedModifier, (val) => {
2615
+ if (!val) {
2616
+ value.value = [];
2617
+ return;
2618
+ }
2619
+ value.value = [{
2620
+ modifiers_group_id: props.group.group.id,
2621
+ modifier_id: val,
2622
+ quantity: 1,
2623
+ }];
2624
+ });
2625
+ vue.watch(modifiers, (val) => {
2626
+ value.value = getSelectedModifiers$1(props.group, val);
2627
+ }, { deep: true });
2628
+ return {
2629
+ selectedModifier,
2630
+ modifiers,
2631
+ shouldUseQuantityControls,
2632
+ requiredModifierIsMissing,
2633
+ limitReached,
2634
+ };
2635
+ }
2636
+
2637
+ function getModifiers(product, variant) {
2638
+ const modifiers = {};
2639
+ ((product === null || product === void 0 ? void 0 : product.modifiers) || []).forEach((modifier) => {
2640
+ modifiers[modifier.modifier.id] = {
2641
+ modifier_id: modifier.modifier.id,
2642
+ quantity: 0,
2643
+ };
2644
+ });
2645
+ ((product === null || product === void 0 ? void 0 : product.modifiers_groups) || []).forEach((group) => {
2646
+ modifiers[group.group.id] = [];
2647
+ });
2648
+ if (!variant.value || !variant.value.selected_modifiers || !variant.value.selected_modifiers.modifiers) {
2649
+ return modifiers;
2650
+ }
2651
+ else if (!variant.value.selected_modifiers.modifiers.length) {
2652
+ return modifiers;
2653
+ }
2654
+ variant.value.selected_modifiers.modifiers.forEach((modifier) => {
2655
+ if (typeof modifier.modifiers_group_id !== 'undefined' && modifier.modifiers_group_id) {
2656
+ modifiers[modifier.modifiers_group_id].push(modifier);
2657
+ }
2658
+ else if (typeof modifier.modifier_id !== 'undefined' && modifier.modifier_id) {
2659
+ modifiers[modifier.modifier_id] = {
2660
+ modifier_id: modifier.modifier_id,
2661
+ quantity: modifier.quantity,
2662
+ };
2663
+ }
2664
+ });
2665
+ return modifiers;
2666
+ }
2667
+ function getSelectedModifiers(modifiers) {
2668
+ const selected = [];
2669
+ Object.keys(modifiers.value).forEach((modifierId) => {
2670
+ const isGroup = Array.isArray(modifiers.value[modifierId]);
2671
+ if (!isGroup && !modifiers.value[modifierId].quantity) {
2672
+ return;
2673
+ }
2674
+ else if (!isGroup) {
2675
+ selected.push({
2676
+ modifier_id: modifierId,
2677
+ quantity: modifiers.value[modifierId].quantity,
2678
+ });
2679
+ return;
2680
+ }
2681
+ modifiers.value[modifierId].forEach((modifier) => {
2682
+ if (!modifier.modifier_id || !modifier.quantity || !modifier.modifiers_group_id) {
2683
+ return;
2684
+ }
2685
+ selected.push({
2686
+ modifiers_group_id: modifier.modifiers_group_id,
2687
+ modifier_id: modifier.modifier_id,
2688
+ quantity: modifier.quantity,
2689
+ });
2690
+ });
2691
+ });
2692
+ return selected;
2693
+ }
2694
+ function useModifiers(product, variant, recalculate) {
2695
+ var _a, _b;
2696
+ 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);
2697
+ const modifiers = vue.ref(getModifiers(product, variant));
2698
+ const selectedModifiers = vue.computed(() => getSelectedModifiers(modifiers));
2699
+ vue.watch(variant, () => {
2700
+ modifiers.value = getModifiers(product, variant);
2701
+ });
2702
+ vue.watch(selectedModifiers, async () => {
2703
+ const hash = await recalculate(selectedModifiers);
2704
+ if (hash === null) {
2705
+ return;
2706
+ }
2707
+ modifiersHash.value = hash;
2708
+ });
2709
+ return {
2710
+ modifiers,
2711
+ selectedModifiers,
2712
+ modifiersHash,
2713
+ };
2714
+ }
2715
+
2716
+ async function recalculatePrice(variant, modifiers) {
2717
+ if (!variant.value) {
2718
+ return null;
2719
+ }
2720
+ else if (!modifiers.value.length) {
2721
+ return null;
2722
+ }
2723
+ const { cityId } = pinia.storeToRefs(useStoreStore());
2724
+ try {
2725
+ return await api.getProductVariantPrice(variant.value.product_id, variant.value.id, modifiers.value, {
2726
+ city_id: cityId.value || undefined,
2727
+ });
2728
+ }
2729
+ catch (e) {
2730
+ //
2731
+ }
2732
+ return null;
2733
+ }
2734
+ function getProductVariantsPricesRange(variants) {
2735
+ if (!variants.length) {
2736
+ return null;
2737
+ }
2738
+ const sorted = [...variants].sort((first, second) => Math.sign(first.price.value - second.price.value));
2739
+ return {
2740
+ min: sorted[0].price,
2741
+ max: sorted[sorted.length - 1].price,
2742
+ };
2743
+ }
2744
+ function useVariantPrice(variants, variant) {
2745
+ const result = vue.ref(null);
2746
+ const recalculating = vue.ref(false);
2747
+ const totalPrice = vue.computed(() => {
2748
+ if (result.value !== null) {
2749
+ return {
2750
+ recalculated: true,
2751
+ recalculating: recalculating.value,
2752
+ price: result.value.price,
2753
+ original_price: result.value.original_price,
2754
+ has_discount: result.value.has_discount,
2755
+ discount_id: result.value.discount_id,
2756
+ discount_difference: result.value.discount_difference,
2757
+ discount_percentage: result.value.discount_percentage,
2758
+ };
2759
+ }
2760
+ else if (!variant.value) {
2761
+ return null;
2762
+ }
2763
+ return {
2764
+ recalculated: false,
2765
+ recalculating: recalculating.value,
2766
+ price: variant.value.price,
2767
+ original_price: variant.value.original_price,
2768
+ has_discount: variant.value.has_discount,
2769
+ discount_id: variant.value.discount_id,
2770
+ discount_difference: variant.value.discount_difference,
2771
+ discount_percentage: variant.value.discount_percentage,
2772
+ };
2773
+ });
2774
+ const pricesRange = vue.computed(() => getProductVariantsPricesRange(variants));
2775
+ const recalculate = async (modifiers) => {
2776
+ if (recalculating.value) {
2777
+ return null;
2778
+ }
2779
+ recalculating.value = true;
2780
+ result.value = await recalculatePrice(variant, modifiers);
2781
+ recalculating.value = false;
2782
+ return result.value !== null ? result.value.modifiers_hash : null;
2783
+ };
2784
+ return {
2785
+ totalPrice,
2786
+ pricesRange,
2787
+ recalculating,
2788
+ recalculate,
2789
+ };
2790
+ }
2791
+
2792
+ function getOptionsList(variants) {
2793
+ const options = [];
2794
+ if (variants.length <= 1) {
2795
+ return options;
2796
+ }
2797
+ variants.forEach((variant) => {
2798
+ if (!variant.option_values || !variant.option_values.length) {
2799
+ return;
2800
+ }
2801
+ variant.option_values.forEach((optionValue) => {
2802
+ if (!optionValue.option || !optionValue.option.id) {
2803
+ return;
2804
+ }
2805
+ const optionIndex = options.findIndex((option) => { var _a; return option.id === ((_a = optionValue.option) === null || _a === void 0 ? void 0 : _a.id); });
2806
+ if (optionIndex === -1) {
2807
+ options.push({
2808
+ id: optionValue.option.id,
2809
+ name: optionValue.option.name,
2810
+ type: optionValue.option.type,
2811
+ values: [optionValue],
2812
+ });
2813
+ return;
2814
+ }
2815
+ const valueIndex = options[optionIndex].values.findIndex((item) => item.id === optionValue.id);
2816
+ if (valueIndex !== -1) {
2817
+ return;
2818
+ }
2819
+ options[optionIndex].values.push(optionValue);
2820
+ });
2821
+ });
2822
+ return options;
2823
+ }
2824
+ function useVariant(variants) {
2825
+ const options = vue.ref(getOptionsList(variants));
2826
+ const selectedOptions = vue.ref({});
2827
+ options.value.forEach((option) => {
2828
+ selectedOptions.value[option.id] = option.values.length > 0 ? option.values[0].id : null;
2829
+ });
2830
+ const variant = vue.computed(() => {
2831
+ if (!Array.isArray(variants) || !variants.length) {
2832
+ return null;
2833
+ }
2834
+ else if (variants.length === 1) {
2835
+ return variants[0];
2836
+ }
2837
+ else if (!Object.keys(selectedOptions.value).length) {
2838
+ return variants[0];
2839
+ }
2840
+ const variantIndex = variants.findIndex((item) => {
2841
+ if (!item.option_values || !item.option_values.length) {
2842
+ return false;
2843
+ }
2844
+ return item.option_values.every((optionValue) => {
2845
+ if (!optionValue.option || !optionValue.option.id) {
2846
+ return false;
2847
+ }
2848
+ else if (typeof selectedOptions.value[optionValue.option.id] === 'undefined') {
2849
+ return false;
2850
+ }
2851
+ else if (selectedOptions.value[optionValue.option.id] !== optionValue.id) {
2852
+ return false;
2853
+ }
2854
+ return true;
2855
+ });
2856
+ });
2857
+ if (variantIndex === -1) {
2858
+ return null;
2859
+ }
2860
+ return variants[variantIndex];
2861
+ });
2862
+ return {
2863
+ variant,
2864
+ options,
2865
+ selectedOptions,
2866
+ };
2867
+ }
2868
+
2869
+ function useProductItem(errorHandler) {
2870
+ return useItemLoader(api.getProduct, getApiErrorHandler(errorHandler, function (e) {
2871
+ ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Товар не найден.'));
2872
+ }));
2873
+ }
2874
+ function useProductCard(item) {
2875
+ var _a;
2876
+ const product = vue.ref({
2877
+ id: item.id,
2878
+ short_id: item.short_id,
2879
+ category_id: Array.isArray(item.categories) && item.categories.length > 0 ? item.categories[0].id : null,
2880
+ slug: item.slug,
2881
+ name: item.name,
2882
+ description: item.description,
2883
+ images: item.media || [],
2884
+ modifiers: item.modifiers || [],
2885
+ modifiers_groups: item.modifiers_groups || [],
2886
+ variants_count: ((_a = item.variants) === null || _a === void 0 ? void 0 : _a.length) || 0,
2887
+ has_images: (item.media || []).length > 0,
2888
+ has_modifiers: (item.modifiers || []).length > 0 || (item.modifiers_groups || []).length > 0,
2889
+ });
2890
+ const { variant, options, selectedOptions, } = useVariant(item.variants || []);
2891
+ const { totalPrice, pricesRange, recalculate, } = useVariantPrice(item.variants || [], variant);
2892
+ const { modifiers, selectedModifiers, modifiersHash, } = useModifiers(item, variant, recalculate);
2893
+ return {
2894
+ product,
2895
+ variant,
2896
+ options,
2897
+ selectedOptions,
2898
+ pricesRange,
2899
+ totalPrice,
2900
+ modifiers,
2901
+ modifiersHash,
2902
+ selectedModifiers,
2903
+ };
2904
+ }
2905
+
2524
2906
  function useProductsPricesRange(categoryId, errorHandler) {
2525
2907
  return useDataLoader(async () => api.getProductsPricesRange(categoryId), getApiErrorHandler(errorHandler, function (e) {
2526
2908
  ui.useNotification('error', 'Ошибка', api.getApiErrorMessage(e, 'Не удалось загрузить диапазон цен.'));
@@ -2572,7 +2954,7 @@ function useProductsPricesRangeFilters(categoryId, values) {
2572
2954
  };
2573
2955
  }
2574
2956
 
2575
- var ProductsSourceType;
2957
+ exports.ProductsSourceType = void 0;
2576
2958
  (function (ProductsSourceType) {
2577
2959
  ProductsSourceType["Category"] = "category";
2578
2960
  ProductsSourceType["Collection"] = "collection";
@@ -2580,20 +2962,20 @@ var ProductsSourceType;
2580
2962
  ProductsSourceType["GroupContext"] = "group_context";
2581
2963
  ProductsSourceType["VariantOptionContext"] = "variant_option_context";
2582
2964
  ProductsSourceType["VariantOptionValueContext"] = "variant_option_value_context";
2583
- })(ProductsSourceType || (ProductsSourceType = {}));
2584
- var ProductsSorting;
2965
+ })(exports.ProductsSourceType || (exports.ProductsSourceType = {}));
2966
+ exports.ProductsSorting = void 0;
2585
2967
  (function (ProductsSorting) {
2586
2968
  ProductsSorting["Manual"] = "manual";
2587
2969
  ProductsSorting["NameAsc"] = "name";
2588
2970
  ProductsSorting["NameDesc"] = "-name";
2589
2971
  ProductsSorting["PriceAsc"] = "price";
2590
2972
  ProductsSorting["PriceDesc"] = "-price";
2591
- })(ProductsSorting || (ProductsSorting = {}));
2592
- var ProductsFiltersType;
2973
+ })(exports.ProductsSorting || (exports.ProductsSorting = {}));
2974
+ exports.ProductsFiltersType = void 0;
2593
2975
  (function (ProductsFiltersType) {
2594
2976
  ProductsFiltersType["Features"] = "features";
2595
2977
  ProductsFiltersType["FeaturesGroups"] = "featuresGroups";
2596
- })(ProductsFiltersType || (ProductsFiltersType = {}));
2978
+ })(exports.ProductsFiltersType || (exports.ProductsFiltersType = {}));
2597
2979
 
2598
2980
  function getSourceParams(source, promotion) {
2599
2981
  if (source === null || !source.id || !source.type) {
@@ -2603,26 +2985,26 @@ function getSourceParams(source, promotion) {
2603
2985
  return {};
2604
2986
  }
2605
2987
  switch (source.type) {
2606
- case ProductsSourceType.Category:
2988
+ case exports.ProductsSourceType.Category:
2607
2989
  return { category_id: source.id };
2608
- case ProductsSourceType.Collection:
2990
+ case exports.ProductsSourceType.Collection:
2609
2991
  return { collection_id: source.id };
2610
- case ProductsSourceType.CategoryContext:
2992
+ case exports.ProductsSourceType.CategoryContext:
2611
2993
  return {
2612
2994
  context_type: 'category',
2613
2995
  context_id: source.id,
2614
2996
  };
2615
- case ProductsSourceType.GroupContext:
2997
+ case exports.ProductsSourceType.GroupContext:
2616
2998
  return {
2617
2999
  context_type: 'group',
2618
3000
  context_id: source.id,
2619
3001
  };
2620
- case ProductsSourceType.VariantOptionContext:
3002
+ case exports.ProductsSourceType.VariantOptionContext:
2621
3003
  return {
2622
3004
  context_type: 'variant_option',
2623
3005
  context_id: source.id,
2624
3006
  };
2625
- case ProductsSourceType.VariantOptionValueContext:
3007
+ case exports.ProductsSourceType.VariantOptionValueContext:
2626
3008
  return {
2627
3009
  context_type: 'variant_option_value',
2628
3010
  context_id: source.id,
@@ -2636,11 +3018,11 @@ function getSortingParams(sorting) {
2636
3018
  return {};
2637
3019
  }
2638
3020
  switch (sorting) {
2639
- case ProductsSorting.Manual:
2640
- case ProductsSorting.NameAsc:
2641
- case ProductsSorting.NameDesc:
2642
- case ProductsSorting.PriceAsc:
2643
- case ProductsSorting.PriceDesc:
3021
+ case exports.ProductsSorting.Manual:
3022
+ case exports.ProductsSorting.NameAsc:
3023
+ case exports.ProductsSorting.NameDesc:
3024
+ case exports.ProductsSorting.PriceAsc:
3025
+ case exports.ProductsSorting.PriceDesc:
2644
3026
  return { order_by: sorting };
2645
3027
  default:
2646
3028
  return {};
@@ -2716,7 +3098,7 @@ function getCategoryIdFromSource(source) {
2716
3098
  if (!source || !source.type || !source.id || source.error) {
2717
3099
  return null;
2718
3100
  }
2719
- else if (source.type !== ProductsSourceType.Category) {
3101
+ else if (source.type !== exports.ProductsSourceType.Category) {
2720
3102
  return null;
2721
3103
  }
2722
3104
  return source.id;
@@ -2727,9 +3109,9 @@ function useProductsList(config, errorHandler) {
2727
3109
  }));
2728
3110
  const store = useStoreStore();
2729
3111
  const cityId = vue.computed(() => store.cityId);
2730
- const sorting = vue.ref(config.value.sorting || ProductsSorting.Manual);
3112
+ const sorting = vue.ref(config.value.sorting || exports.ProductsSorting.Manual);
2731
3113
  const search = vue.ref(config.value.search || '');
2732
- const { filters, load: loadFilters, items: features, } = config.value.filtersType === ProductsFiltersType.Features
3114
+ const { filters, load: loadFilters, items: features, } = config.value.filtersType === exports.ProductsFiltersType.Features
2733
3115
  ? useFeaturesFilters(getCategoryIdFromSource(config.value.source), config.value.filters)
2734
3116
  : useFeaturesGroupsFilters(getCategoryIdFromSource(config.value.source), config.value.filters);
2735
3117
  const { filters: pricesFilters, load: loadPricesRange, range, } = useProductsPricesRangeFilters(getCategoryIdFromSource(config.value.source), config.value.pricesFilters);
@@ -2905,17 +3287,17 @@ function getProductsSource(source) {
2905
3287
  return null;
2906
3288
  }
2907
3289
  switch (injected) {
2908
- case ProductsSourceType.Category:
3290
+ case exports.ProductsSourceType.Category:
2909
3291
  return getInjectedSource(exports.ZenkyInjection.Category, exports.ZenkyInjection.CategoryNotFound, injected);
2910
- case ProductsSourceType.Collection:
3292
+ case exports.ProductsSourceType.Collection:
2911
3293
  return getInjectedSource(exports.ZenkyInjection.Collection, exports.ZenkyInjection.CollectionNotFound, injected);
2912
- case ProductsSourceType.CategoryContext:
3294
+ case exports.ProductsSourceType.CategoryContext:
2913
3295
  return getInjectedSource(exports.ZenkyInjection.CategoryContext, exports.ZenkyInjection.CategoryContextNotFound, injected);
2914
- case ProductsSourceType.GroupContext:
3296
+ case exports.ProductsSourceType.GroupContext:
2915
3297
  return getInjectedSource(exports.ZenkyInjection.GroupContext, exports.ZenkyInjection.GroupContextNotFound, injected);
2916
- case ProductsSourceType.VariantOptionContext:
3298
+ case exports.ProductsSourceType.VariantOptionContext:
2917
3299
  return getInjectedSource(exports.ZenkyInjection.VariantOptionContext, exports.ZenkyInjection.VariantOptionContextNotFound, injected);
2918
- case ProductsSourceType.VariantOptionValueContext:
3300
+ case exports.ProductsSourceType.VariantOptionValueContext:
2919
3301
  return getInjectedSource(exports.ZenkyInjection.VariantOptionValueContext, exports.ZenkyInjection.VariantOptionValueContextNotFound, injected);
2920
3302
  default:
2921
3303
  return null;
@@ -3111,6 +3493,7 @@ exports.getApiErrorHandler = getApiErrorHandler;
3111
3493
  exports.getExistedAddress = getExistedAddress;
3112
3494
  exports.getExistedAddressDisplayValue = getExistedAddressDisplayValue;
3113
3495
  exports.getFirstMedium = getFirstMedium;
3496
+ exports.getProductVariantsPricesRange = getProductVariantsPricesRange;
3114
3497
  exports.getProductsListParamsFromQuery = getProductsListParamsFromQuery;
3115
3498
  exports.getProductsListQueryParams = getProductsListQueryParams;
3116
3499
  exports.getProductsPaginationRequest = getProductsPaginationRequest;
@@ -3162,6 +3545,8 @@ exports.useItemLoader = useItemLoader;
3162
3545
  exports.useListLoader = useListLoader;
3163
3546
  exports.useLogin = useLogin;
3164
3547
  exports.useLogout = useLogout;
3548
+ exports.useModifiers = useModifiers;
3549
+ exports.useModifiersGroup = useModifiersGroup;
3165
3550
  exports.useOfferItem = useOfferItem;
3166
3551
  exports.useOffersList = useOffersList;
3167
3552
  exports.useOrderCheckout = useOrderCheckout;
@@ -3174,6 +3559,8 @@ exports.usePasswordReset = usePasswordReset;
3174
3559
  exports.usePaymentMethodDestroyer = usePaymentMethodDestroyer;
3175
3560
  exports.usePaymentMethodsList = usePaymentMethodsList;
3176
3561
  exports.usePhoneConfirmation = usePhoneConfirmation;
3562
+ exports.useProductCard = useProductCard;
3563
+ exports.useProductItem = useProductItem;
3177
3564
  exports.useProductsList = useProductsList;
3178
3565
  exports.useProductsPricesRange = useProductsPricesRange;
3179
3566
  exports.useProductsPricesRangeFilters = useProductsPricesRangeFilters;
@@ -3181,10 +3568,13 @@ exports.usePromotionsStore = usePromotionsStore;
3181
3568
  exports.useRegistration = useRegistration;
3182
3569
  exports.useReversedTree = useReversedTree;
3183
3570
  exports.useRewardsSelector = useRewardsSelector;
3571
+ exports.useSingleModifier = useSingleModifier;
3184
3572
  exports.useSplittedCategoriesTree = useSplittedCategoriesTree;
3185
3573
  exports.useStateDataLoader = useStateDataLoader;
3186
3574
  exports.useStoreStore = useStoreStore;
3187
3575
  exports.useSuggestionsRestrictedToCity = useSuggestionsRestrictedToCity;
3188
3576
  exports.useTotalPrice = useTotalPrice;
3189
3577
  exports.useTotalQuantity = useTotalQuantity;
3578
+ exports.useVariant = useVariant;
3190
3579
  exports.useVariantControls = useVariantControls;
3580
+ exports.useVariantPrice = useVariantPrice;
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ref, computed, watch, unref, inject } from 'vue';
2
2
  import { debounce, isBoolean, cloneDeep } from 'lodash-es';
3
- import { getStore, getAddressSuggestions, getCategoriesTree, Visibility, getProductsCollections, getApiErrorMessage, getCategoryFeatures, getCategoryFeaturesGroups, getArticle, getArticles, getArticleCategories, getAuthenticationStatus, setAxiosToken, getCustomerProfile, login, requestPasswordResetCode, resetPassword, register, resendConfirmationCode, confirm, getApiErrorCode, getCustomerAddresses, deleteAddress, updateAddress, getOrder, getCustomerOrders, getCustomerPaymentMethods, deleteCustomerPaymentMethod, ImageType, getOffer, getOffers, setOrderCheckoutCustomer, getOrderSettings, createOrder, addOrderProductVariant, removeOrderProductVariant, confirmOrder, resendOrderConfirmationCode, setOrderCheckoutDelivery, setOrderCheckoutPayment, getOrderBonusesPaymentPreview, checkoutOrder, getOrderCheckoutTotal, getProductsPricesRange, getProducts, checkCompletedPromotions } from '@zenky/api';
3
+ import { getStore, getAddressSuggestions, getCategoriesTree, Visibility, getProductsCollections, getApiErrorMessage, getCategoryFeatures, getCategoryFeaturesGroups, getArticle, getArticles, getArticleCategories, getAuthenticationStatus, setAxiosToken, getCustomerProfile, login, requestPasswordResetCode, resetPassword, register, resendConfirmationCode, confirm, getApiErrorCode, getCustomerAddresses, deleteAddress, updateAddress, getOrder, getCustomerOrders, getCustomerPaymentMethods, deleteCustomerPaymentMethod, ImageType, getOffer, getOffers, setOrderCheckoutCustomer, getOrderSettings, createOrder, addOrderProductVariant, removeOrderProductVariant, confirmOrder, resendOrderConfirmationCode, setOrderCheckoutDelivery, setOrderCheckoutPayment, getOrderBonusesPaymentPreview, checkoutOrder, getOrderCheckoutTotal, getProductVariantPrice, getProduct, getProductsPricesRange, getProducts, checkCompletedPromotions } from '@zenky/api';
4
4
  import { defineStore, storeToRefs } from 'pinia';
5
5
  import { useNotification } from '@zenky/ui';
6
6
  import { useCustomerLoaded, useCustomerAuthenticated, useCustomerLoggedOut, useOrderLoaded, useProductQuantityIncreased, useProductQuantityDecreased, usePromotionsCheckerStarted, usePromotionsCheckerCompleted, useDisplayOrderPromotionRewardSelection, useOrderPromotionsNotFound, useOrderPriceRecalculated, useOrderShouldBeReloaded, useOrderPromotionRewardsShouldBeReloaded, useOrderSubmitted } from '@zenky/events';
@@ -2513,6 +2513,388 @@ function useCheckoutTotal() {
2513
2513
  };
2514
2514
  }
2515
2515
 
2516
+ function useSingleModifier(props, emit) {
2517
+ const value = computed({
2518
+ get: () => props.modelValue,
2519
+ set: (val) => emit('update:modelValue', val),
2520
+ });
2521
+ const checked = computed({
2522
+ get: () => value.value.quantity > 0,
2523
+ set: (val) => {
2524
+ value.value.quantity = val ? 1 : 0;
2525
+ },
2526
+ });
2527
+ const shouldUseQuantityControls = computed(() => props.modifier.max_quantity > 1);
2528
+ const increase = () => {
2529
+ if (props.limitReached) {
2530
+ return;
2531
+ }
2532
+ value.value.quantity = Math.min(value.value.quantity + 1, props.modifier.max_quantity);
2533
+ };
2534
+ const decrease = () => {
2535
+ value.value.quantity = Math.max(value.value.quantity - 1, props.modifier.min_quantity);
2536
+ };
2537
+ return {
2538
+ value,
2539
+ checked,
2540
+ shouldUseQuantityControls,
2541
+ increase,
2542
+ decrease,
2543
+ };
2544
+ }
2545
+
2546
+ function getModifierQuantity(modifier, value) {
2547
+ const index = value.value.findIndex((item) => item.modifier_id === modifier.modifier.id);
2548
+ if (index === -1) {
2549
+ return 0;
2550
+ }
2551
+ return value.value[index].quantity;
2552
+ }
2553
+ function getDefaultModifiersGroupModifiers(group, value) {
2554
+ const modifiers = {};
2555
+ group.modifiers.forEach((modifier) => {
2556
+ const quantity = Array.isArray(value.value) ? getModifierQuantity(modifier, value) : 0;
2557
+ modifiers[modifier.modifier.id] = {
2558
+ quantity,
2559
+ modifier_id: modifier.modifier.id,
2560
+ };
2561
+ });
2562
+ return modifiers;
2563
+ }
2564
+ function getSelectedModifiers$1(group, modifiers) {
2565
+ const selected = [];
2566
+ Object.keys(modifiers).forEach((modifierId) => {
2567
+ if (!modifiers[modifierId].quantity) {
2568
+ return;
2569
+ }
2570
+ selected.push({
2571
+ modifiers_group_id: group.group.id,
2572
+ modifier_id: modifierId,
2573
+ quantity: modifiers[modifierId].quantity,
2574
+ });
2575
+ });
2576
+ return selected;
2577
+ }
2578
+ function useModifiersGroup(props, emit) {
2579
+ const value = computed({
2580
+ get: () => props.modelValue,
2581
+ set: (val) => emit('update:modelValue', val),
2582
+ });
2583
+ const selectedModifier = ref('');
2584
+ const modifiers = ref(getDefaultModifiersGroupModifiers(props.group, value));
2585
+ const shouldUseQuantityControls = computed(() => props.group.max_quantity > 1);
2586
+ const totalSelectedCount = computed(() => {
2587
+ return value.value
2588
+ .map((modifier) => modifier.quantity)
2589
+ .reduce((current, total) => current + total, 0);
2590
+ });
2591
+ const limitReached = computed(() => {
2592
+ if (!shouldUseQuantityControls.value) {
2593
+ return selectedModifier.value !== '';
2594
+ }
2595
+ return totalSelectedCount.value >= props.group.max_quantity;
2596
+ });
2597
+ const requiredModifierIsMissing = computed(() => {
2598
+ if (!props.group.is_required) {
2599
+ return false;
2600
+ }
2601
+ else if (props.group.min_quantity === 0) {
2602
+ return false;
2603
+ }
2604
+ return totalSelectedCount.value < props.group.min_quantity;
2605
+ });
2606
+ watch(selectedModifier, (val) => {
2607
+ if (!val) {
2608
+ value.value = [];
2609
+ return;
2610
+ }
2611
+ value.value = [{
2612
+ modifiers_group_id: props.group.group.id,
2613
+ modifier_id: val,
2614
+ quantity: 1,
2615
+ }];
2616
+ });
2617
+ watch(modifiers, (val) => {
2618
+ value.value = getSelectedModifiers$1(props.group, val);
2619
+ }, { deep: true });
2620
+ return {
2621
+ selectedModifier,
2622
+ modifiers,
2623
+ shouldUseQuantityControls,
2624
+ requiredModifierIsMissing,
2625
+ limitReached,
2626
+ };
2627
+ }
2628
+
2629
+ function getModifiers(product, variant) {
2630
+ const modifiers = {};
2631
+ ((product === null || product === void 0 ? void 0 : product.modifiers) || []).forEach((modifier) => {
2632
+ modifiers[modifier.modifier.id] = {
2633
+ modifier_id: modifier.modifier.id,
2634
+ quantity: 0,
2635
+ };
2636
+ });
2637
+ ((product === null || product === void 0 ? void 0 : product.modifiers_groups) || []).forEach((group) => {
2638
+ modifiers[group.group.id] = [];
2639
+ });
2640
+ if (!variant.value || !variant.value.selected_modifiers || !variant.value.selected_modifiers.modifiers) {
2641
+ return modifiers;
2642
+ }
2643
+ else if (!variant.value.selected_modifiers.modifiers.length) {
2644
+ return modifiers;
2645
+ }
2646
+ variant.value.selected_modifiers.modifiers.forEach((modifier) => {
2647
+ if (typeof modifier.modifiers_group_id !== 'undefined' && modifier.modifiers_group_id) {
2648
+ modifiers[modifier.modifiers_group_id].push(modifier);
2649
+ }
2650
+ else if (typeof modifier.modifier_id !== 'undefined' && modifier.modifier_id) {
2651
+ modifiers[modifier.modifier_id] = {
2652
+ modifier_id: modifier.modifier_id,
2653
+ quantity: modifier.quantity,
2654
+ };
2655
+ }
2656
+ });
2657
+ return modifiers;
2658
+ }
2659
+ function getSelectedModifiers(modifiers) {
2660
+ const selected = [];
2661
+ Object.keys(modifiers.value).forEach((modifierId) => {
2662
+ const isGroup = Array.isArray(modifiers.value[modifierId]);
2663
+ if (!isGroup && !modifiers.value[modifierId].quantity) {
2664
+ return;
2665
+ }
2666
+ else if (!isGroup) {
2667
+ selected.push({
2668
+ modifier_id: modifierId,
2669
+ quantity: modifiers.value[modifierId].quantity,
2670
+ });
2671
+ return;
2672
+ }
2673
+ modifiers.value[modifierId].forEach((modifier) => {
2674
+ if (!modifier.modifier_id || !modifier.quantity || !modifier.modifiers_group_id) {
2675
+ return;
2676
+ }
2677
+ selected.push({
2678
+ modifiers_group_id: modifier.modifiers_group_id,
2679
+ modifier_id: modifier.modifier_id,
2680
+ quantity: modifier.quantity,
2681
+ });
2682
+ });
2683
+ });
2684
+ return selected;
2685
+ }
2686
+ function useModifiers(product, variant, recalculate) {
2687
+ var _a, _b;
2688
+ const modifiersHash = ref(((_b = (_a = variant.value) === null || _a === void 0 ? void 0 : _a.selected_modifiers) === null || _b === void 0 ? void 0 : _b.hash) || null);
2689
+ const modifiers = ref(getModifiers(product, variant));
2690
+ const selectedModifiers = computed(() => getSelectedModifiers(modifiers));
2691
+ watch(variant, () => {
2692
+ modifiers.value = getModifiers(product, variant);
2693
+ });
2694
+ watch(selectedModifiers, async () => {
2695
+ const hash = await recalculate(selectedModifiers);
2696
+ if (hash === null) {
2697
+ return;
2698
+ }
2699
+ modifiersHash.value = hash;
2700
+ });
2701
+ return {
2702
+ modifiers,
2703
+ selectedModifiers,
2704
+ modifiersHash,
2705
+ };
2706
+ }
2707
+
2708
+ async function recalculatePrice(variant, modifiers) {
2709
+ if (!variant.value) {
2710
+ return null;
2711
+ }
2712
+ else if (!modifiers.value.length) {
2713
+ return null;
2714
+ }
2715
+ const { cityId } = storeToRefs(useStoreStore());
2716
+ try {
2717
+ return await getProductVariantPrice(variant.value.product_id, variant.value.id, modifiers.value, {
2718
+ city_id: cityId.value || undefined,
2719
+ });
2720
+ }
2721
+ catch (e) {
2722
+ //
2723
+ }
2724
+ return null;
2725
+ }
2726
+ function getProductVariantsPricesRange(variants) {
2727
+ if (!variants.length) {
2728
+ return null;
2729
+ }
2730
+ const sorted = [...variants].sort((first, second) => Math.sign(first.price.value - second.price.value));
2731
+ return {
2732
+ min: sorted[0].price,
2733
+ max: sorted[sorted.length - 1].price,
2734
+ };
2735
+ }
2736
+ function useVariantPrice(variants, variant) {
2737
+ const result = ref(null);
2738
+ const recalculating = ref(false);
2739
+ const totalPrice = computed(() => {
2740
+ if (result.value !== null) {
2741
+ return {
2742
+ recalculated: true,
2743
+ recalculating: recalculating.value,
2744
+ price: result.value.price,
2745
+ original_price: result.value.original_price,
2746
+ has_discount: result.value.has_discount,
2747
+ discount_id: result.value.discount_id,
2748
+ discount_difference: result.value.discount_difference,
2749
+ discount_percentage: result.value.discount_percentage,
2750
+ };
2751
+ }
2752
+ else if (!variant.value) {
2753
+ return null;
2754
+ }
2755
+ return {
2756
+ recalculated: false,
2757
+ recalculating: recalculating.value,
2758
+ price: variant.value.price,
2759
+ original_price: variant.value.original_price,
2760
+ has_discount: variant.value.has_discount,
2761
+ discount_id: variant.value.discount_id,
2762
+ discount_difference: variant.value.discount_difference,
2763
+ discount_percentage: variant.value.discount_percentage,
2764
+ };
2765
+ });
2766
+ const pricesRange = computed(() => getProductVariantsPricesRange(variants));
2767
+ const recalculate = async (modifiers) => {
2768
+ if (recalculating.value) {
2769
+ return null;
2770
+ }
2771
+ recalculating.value = true;
2772
+ result.value = await recalculatePrice(variant, modifiers);
2773
+ recalculating.value = false;
2774
+ return result.value !== null ? result.value.modifiers_hash : null;
2775
+ };
2776
+ return {
2777
+ totalPrice,
2778
+ pricesRange,
2779
+ recalculating,
2780
+ recalculate,
2781
+ };
2782
+ }
2783
+
2784
+ function getOptionsList(variants) {
2785
+ const options = [];
2786
+ if (variants.length <= 1) {
2787
+ return options;
2788
+ }
2789
+ variants.forEach((variant) => {
2790
+ if (!variant.option_values || !variant.option_values.length) {
2791
+ return;
2792
+ }
2793
+ variant.option_values.forEach((optionValue) => {
2794
+ if (!optionValue.option || !optionValue.option.id) {
2795
+ return;
2796
+ }
2797
+ const optionIndex = options.findIndex((option) => { var _a; return option.id === ((_a = optionValue.option) === null || _a === void 0 ? void 0 : _a.id); });
2798
+ if (optionIndex === -1) {
2799
+ options.push({
2800
+ id: optionValue.option.id,
2801
+ name: optionValue.option.name,
2802
+ type: optionValue.option.type,
2803
+ values: [optionValue],
2804
+ });
2805
+ return;
2806
+ }
2807
+ const valueIndex = options[optionIndex].values.findIndex((item) => item.id === optionValue.id);
2808
+ if (valueIndex !== -1) {
2809
+ return;
2810
+ }
2811
+ options[optionIndex].values.push(optionValue);
2812
+ });
2813
+ });
2814
+ return options;
2815
+ }
2816
+ function useVariant(variants) {
2817
+ const options = ref(getOptionsList(variants));
2818
+ const selectedOptions = ref({});
2819
+ options.value.forEach((option) => {
2820
+ selectedOptions.value[option.id] = option.values.length > 0 ? option.values[0].id : null;
2821
+ });
2822
+ const variant = computed(() => {
2823
+ if (!Array.isArray(variants) || !variants.length) {
2824
+ return null;
2825
+ }
2826
+ else if (variants.length === 1) {
2827
+ return variants[0];
2828
+ }
2829
+ else if (!Object.keys(selectedOptions.value).length) {
2830
+ return variants[0];
2831
+ }
2832
+ const variantIndex = variants.findIndex((item) => {
2833
+ if (!item.option_values || !item.option_values.length) {
2834
+ return false;
2835
+ }
2836
+ return item.option_values.every((optionValue) => {
2837
+ if (!optionValue.option || !optionValue.option.id) {
2838
+ return false;
2839
+ }
2840
+ else if (typeof selectedOptions.value[optionValue.option.id] === 'undefined') {
2841
+ return false;
2842
+ }
2843
+ else if (selectedOptions.value[optionValue.option.id] !== optionValue.id) {
2844
+ return false;
2845
+ }
2846
+ return true;
2847
+ });
2848
+ });
2849
+ if (variantIndex === -1) {
2850
+ return null;
2851
+ }
2852
+ return variants[variantIndex];
2853
+ });
2854
+ return {
2855
+ variant,
2856
+ options,
2857
+ selectedOptions,
2858
+ };
2859
+ }
2860
+
2861
+ function useProductItem(errorHandler) {
2862
+ return useItemLoader(getProduct, getApiErrorHandler(errorHandler, function (e) {
2863
+ useNotification('error', 'Ошибка', getApiErrorMessage(e, 'Товар не найден.'));
2864
+ }));
2865
+ }
2866
+ function useProductCard(item) {
2867
+ var _a;
2868
+ const product = ref({
2869
+ id: item.id,
2870
+ short_id: item.short_id,
2871
+ category_id: Array.isArray(item.categories) && item.categories.length > 0 ? item.categories[0].id : null,
2872
+ slug: item.slug,
2873
+ name: item.name,
2874
+ description: item.description,
2875
+ images: item.media || [],
2876
+ modifiers: item.modifiers || [],
2877
+ modifiers_groups: item.modifiers_groups || [],
2878
+ variants_count: ((_a = item.variants) === null || _a === void 0 ? void 0 : _a.length) || 0,
2879
+ has_images: (item.media || []).length > 0,
2880
+ has_modifiers: (item.modifiers || []).length > 0 || (item.modifiers_groups || []).length > 0,
2881
+ });
2882
+ const { variant, options, selectedOptions, } = useVariant(item.variants || []);
2883
+ const { totalPrice, pricesRange, recalculate, } = useVariantPrice(item.variants || [], variant);
2884
+ const { modifiers, selectedModifiers, modifiersHash, } = useModifiers(item, variant, recalculate);
2885
+ return {
2886
+ product,
2887
+ variant,
2888
+ options,
2889
+ selectedOptions,
2890
+ pricesRange,
2891
+ totalPrice,
2892
+ modifiers,
2893
+ modifiersHash,
2894
+ selectedModifiers,
2895
+ };
2896
+ }
2897
+
2516
2898
  function useProductsPricesRange(categoryId, errorHandler) {
2517
2899
  return useDataLoader(async () => getProductsPricesRange(categoryId), getApiErrorHandler(errorHandler, function (e) {
2518
2900
  useNotification('error', 'Ошибка', getApiErrorMessage(e, 'Не удалось загрузить диапазон цен.'));
@@ -3096,4 +3478,4 @@ function subscribeToOrderEvents(order) {
3096
3478
  });
3097
3479
  }
3098
3480
 
3099
- export { AuthenticationEvent, AuthenticationResultType, AuthenticationStage, CheckoutStage, ZenkyInjection, ZenkyWebsocketEvent, createStorage, createWebsocketsConnection, getAddressForm, getApiErrorHandler, getExistedAddress, getExistedAddressDisplayValue, getFirstMedium, getProductsListParamsFromQuery, getProductsListQueryParams, getProductsPaginationRequest, getProductsSource, getSelectedAddress, getSelectedAddressDisplayValue, getStockAddress, getStockSchedule, getStorage, getUpdatedVariants, getWebsocketsConnection, initializeOrderCustomer, initializePromotions, subscribeToOrderEvents, useAddressFormValue, useArticleCategoriesList, useArticleItem, useArticlesList, useAuthenticationForm, useAuthenticationStatusChecker, useBillSuggestions, useCategories, useCategoriesStore, useCategoriesTree, useCategory, useCategoryFeaturesGroupsList, useCategoryFeaturesList, useCheckoutConfirmation, useCheckoutSummary, useCheckoutTotal, useCollection, useCollections, useCollectionsStore, useCustomer, useCustomerCheckoutForm, useCustomerStore, useDadata, useDataDestroyer, useDataLoader, useDeliveryAddressDestroyer, useDeliveryAddressesList, useDeliveryCheckoutForm, useDeliveryPaymentsForm, useEditAddressForm, useFeaturesFilters, useFeaturesGroupsFilters, useFlatCategoriesTree, useItemLoader, useListLoader, useLogin, useLogout, useOfferItem, useOffersList, useOrderCheckout, useOrderItem, useOrderStore, useOrderVariants, useOrdersList, usePaginatedLoader, usePasswordReset, usePaymentMethodDestroyer, usePaymentMethodsList, usePhoneConfirmation, useProductsList, useProductsPricesRange, useProductsPricesRangeFilters, usePromotionsStore, useRegistration, useReversedTree, useRewardsSelector, useSplittedCategoriesTree, useStateDataLoader, useStoreStore, useSuggestionsRestrictedToCity, useTotalPrice, useTotalQuantity, useVariantControls };
3481
+ export { AuthenticationEvent, AuthenticationResultType, AuthenticationStage, CheckoutStage, ProductsFiltersType, ProductsSorting, ProductsSourceType, ZenkyInjection, ZenkyWebsocketEvent, createStorage, createWebsocketsConnection, getAddressForm, getApiErrorHandler, getExistedAddress, getExistedAddressDisplayValue, getFirstMedium, getProductVariantsPricesRange, getProductsListParamsFromQuery, getProductsListQueryParams, getProductsPaginationRequest, getProductsSource, getSelectedAddress, getSelectedAddressDisplayValue, getStockAddress, getStockSchedule, getStorage, getUpdatedVariants, getWebsocketsConnection, initializeOrderCustomer, initializePromotions, subscribeToOrderEvents, useAddressFormValue, useArticleCategoriesList, useArticleItem, useArticlesList, useAuthenticationForm, useAuthenticationStatusChecker, useBillSuggestions, useCategories, useCategoriesStore, useCategoriesTree, useCategory, useCategoryFeaturesGroupsList, useCategoryFeaturesList, useCheckoutConfirmation, useCheckoutSummary, useCheckoutTotal, useCollection, useCollections, useCollectionsStore, useCustomer, useCustomerCheckoutForm, useCustomerStore, useDadata, useDataDestroyer, useDataLoader, useDeliveryAddressDestroyer, useDeliveryAddressesList, useDeliveryCheckoutForm, useDeliveryPaymentsForm, useEditAddressForm, useFeaturesFilters, useFeaturesGroupsFilters, useFlatCategoriesTree, useItemLoader, useListLoader, useLogin, useLogout, useModifiers, useModifiersGroup, useOfferItem, useOffersList, useOrderCheckout, useOrderItem, useOrderStore, useOrderVariants, useOrdersList, usePaginatedLoader, usePasswordReset, usePaymentMethodDestroyer, usePaymentMethodsList, usePhoneConfirmation, useProductCard, useProductItem, useProductsList, useProductsPricesRange, useProductsPricesRangeFilters, usePromotionsStore, useRegistration, useReversedTree, useRewardsSelector, useSingleModifier, useSplittedCategoriesTree, useStateDataLoader, useStoreStore, useSuggestionsRestrictedToCity, useTotalPrice, useTotalQuantity, useVariant, useVariantControls, useVariantPrice };
package/dist/zenky.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as vue from 'vue';
2
- import { Ref, ComputedRef } from 'vue';
2
+ import { Ref, ComputedRef, WritableComputedRef } from 'vue';
3
3
  import * as _zenky_api from '@zenky/api';
4
- import { PaginationRequest, Pagination, PaginatedResponse, ResourceRequest, Address, City, NestedCategory, ProductsCollection, Feature, FeaturesGroupContainer, Article, ArticlesPaginationRequest, ArticleCategory, ArticleCategoriesPaginationRequest, Customer, AuthenticationPhone, Order, OrderCredentials, CustomerPaymentMethod, Medium, Image, Offer, OffersPaginationRequest, OrderSettings, OrderCheckoutTotal, ProductVariant, OrderProductVariant, Product, ProductsPricesRange, ProductsPaginationRequest, Schedule, Stock, Store, StoreSettings } from '@zenky/api';
4
+ import { PaginationRequest, Pagination, PaginatedResponse, ResourceRequest, Address, City, NestedCategory, ProductsCollection, Feature, FeaturesGroupContainer, Article, ArticlesPaginationRequest, ArticleCategory, ArticleCategoriesPaginationRequest, Customer, AuthenticationPhone, Order, OrderCredentials, CustomerPaymentMethod, Medium, Image, Offer, OffersPaginationRequest, OrderSettings, OrderCheckoutTotal, ProductVariant, OrderProductVariant, ProductModifiersGroup, ProductModifier, ProductVariantPriceCalculation, Enum, VariantOptionValue, Product, ProductRequest, ProductsPaginationRequest, ProductsPricesRange, Schedule, Stock, Store, StoreSettings } from '@zenky/api';
5
5
  import * as pinia from 'pinia';
6
6
  import Pusher from 'pusher-js';
7
7
 
@@ -9991,6 +9991,122 @@ declare const useVariantControls: (variant: Ref<ProductVariant>, modifiers: Ref<
9991
9991
 
9992
9992
  declare function getUpdatedVariants(currentOrder: Order, order: Order): OrderProductVariant[];
9993
9993
 
9994
+ interface ProductModifierModel {
9995
+ quantity: number;
9996
+ modifier_id: string;
9997
+ }
9998
+ interface ModifiersGroupModifiersList {
9999
+ [x: string]: ProductModifierModel;
10000
+ }
10001
+ interface ProductModifiersGroupModifierModel {
10002
+ modifiers_group_id: string | null;
10003
+ modifier_id: string | null;
10004
+ quantity: number;
10005
+ }
10006
+ interface ModifiersGroupProps {
10007
+ modelValue: ProductModifiersGroupModifierModel[];
10008
+ group: ProductModifiersGroup;
10009
+ }
10010
+ interface SingleModifierProps {
10011
+ modelValue: ProductModifierModel;
10012
+ modifier: ProductModifier;
10013
+ limitReached: boolean;
10014
+ }
10015
+ interface ProductCardModifiersList {
10016
+ [x: string]: ProductModifierModel | ProductModifiersGroupModifierModel[];
10017
+ }
10018
+ interface SelectedProductModifier {
10019
+ modifier_id: string;
10020
+ quantity: number;
10021
+ modifiers_group_id?: string;
10022
+ }
10023
+ declare type ProductVariantPriceCalcuator = (modifiers: Ref<SelectedProductModifier[]>) => Promise<string | null>;
10024
+ interface CalculatedProductVariantPrice extends ProductVariantPriceCalculation {
10025
+ recalculated: boolean;
10026
+ recalculating: boolean;
10027
+ }
10028
+ interface ProductCardVariantOption {
10029
+ id: string;
10030
+ name: string | null;
10031
+ type: Enum | null;
10032
+ values: VariantOptionValue[];
10033
+ }
10034
+ interface SelectedVariantOptionsList {
10035
+ [x: string]: string | null;
10036
+ }
10037
+ interface ProductCardProduct {
10038
+ id: string;
10039
+ short_id: string | null;
10040
+ category_id: string | null;
10041
+ slug: string | null;
10042
+ name: string | null;
10043
+ description: string | null;
10044
+ images: Medium[];
10045
+ modifiers: ProductModifier[];
10046
+ modifiers_groups: ProductModifiersGroup[];
10047
+ variants_count: number;
10048
+ has_images: boolean;
10049
+ has_modifiers: boolean;
10050
+ }
10051
+
10052
+ declare function useSingleModifier(props: SingleModifierProps, emit: (event: string, data: any) => any): {
10053
+ value: WritableComputedRef<ProductModifierModel>;
10054
+ checked: WritableComputedRef<boolean>;
10055
+ shouldUseQuantityControls: ComputedRef<boolean>;
10056
+ increase: () => void;
10057
+ decrease: () => void;
10058
+ };
10059
+
10060
+ declare function useModifiersGroup(props: ModifiersGroupProps, emit: (event: string, data: any) => any): {
10061
+ selectedModifier: Ref<string>;
10062
+ modifiers: Ref<ModifiersGroupModifiersList>;
10063
+ shouldUseQuantityControls: ComputedRef<boolean>;
10064
+ requiredModifierIsMissing: ComputedRef<boolean>;
10065
+ limitReached: ComputedRef<boolean>;
10066
+ };
10067
+
10068
+ declare function useModifiers(product: Product, variant: ComputedRef<ProductVariant | null>, recalculate: ProductVariantPriceCalcuator): {
10069
+ modifiers: Ref<ProductCardModifiersList>;
10070
+ selectedModifiers: Ref<SelectedProductModifier[]>;
10071
+ modifiersHash: Ref<string | null>;
10072
+ };
10073
+
10074
+ declare function getProductVariantsPricesRange(variants: ProductVariant[]): {
10075
+ min: _zenky_api.Price;
10076
+ max: _zenky_api.Price;
10077
+ } | null;
10078
+ declare function useVariantPrice(variants: ProductVariant[], variant: ComputedRef<ProductVariant | null>): {
10079
+ totalPrice: ComputedRef<CalculatedProductVariantPrice | null>;
10080
+ pricesRange: ComputedRef<{
10081
+ min: _zenky_api.Price;
10082
+ max: _zenky_api.Price;
10083
+ } | null>;
10084
+ recalculating: Ref<boolean>;
10085
+ recalculate: ProductVariantPriceCalcuator;
10086
+ };
10087
+
10088
+ declare function useProductItem(errorHandler?: OptionalApiErrorHandler): ItemLoader<Product, string, ProductRequest>;
10089
+ declare function useProductCard(item: Product): {
10090
+ product: Ref<ProductCardProduct>;
10091
+ variant: vue.ComputedRef<_zenky_api.ProductVariant | null>;
10092
+ options: Ref<ProductCardVariantOption[]>;
10093
+ selectedOptions: Ref<SelectedVariantOptionsList>;
10094
+ pricesRange: vue.ComputedRef<{
10095
+ min: _zenky_api.Price;
10096
+ max: _zenky_api.Price;
10097
+ } | null>;
10098
+ totalPrice: vue.ComputedRef<CalculatedProductVariantPrice | null>;
10099
+ modifiers: Ref<ProductCardModifiersList>;
10100
+ modifiersHash: Ref<string | null>;
10101
+ selectedModifiers: Ref<SelectedProductModifier[]>;
10102
+ };
10103
+
10104
+ declare function useVariant(variants: ProductVariant[]): {
10105
+ variant: ComputedRef<ProductVariant | null>;
10106
+ options: Ref<ProductCardVariantOption[]>;
10107
+ selectedOptions: Ref<SelectedVariantOptionsList>;
10108
+ };
10109
+
9994
10110
  declare enum ProductsSourceType {
9995
10111
  Category = "category",
9996
10112
  Collection = "collection",
@@ -10011,6 +10127,9 @@ interface ProductsSource {
10011
10127
  id?: string;
10012
10128
  error?: boolean;
10013
10129
  }
10130
+ interface InjectedProductsSource {
10131
+ id: string;
10132
+ }
10014
10133
  interface ProductsFilters {
10015
10134
  [key: string]: string[];
10016
10135
  }
@@ -10188,4 +10307,4 @@ declare function createWebsocketsConnection(store: Store): Pusher;
10188
10307
  declare function getWebsocketsConnection(): Pusher;
10189
10308
  declare function subscribeToOrderEvents(order: Order): void;
10190
10309
 
10191
- export { AddressForm, AddressFormValue, AddressFormValueProvider, ApiErrorHandler, AuthenticationEvent, AuthenticationForm, AuthenticationFormProvider, AuthenticationResult, AuthenticationResultType, AuthenticationStage, AuthenticationStatusCheckerProvider, CategoriesProvider, CategoriesState, CategoriesTreeProvider, CategoryProvider, CheckoutStage, CollectionsState, ConfirmableDataDestroyer, ConfirmationProvider, CustomerStore, DadataProvider, DataDestroyer, DataDestroyerHandler, DataLoader, DataProvider, EditAddressFormProvider, EmitAuthenticationEvent, FlatCategoriesTreeProvider, FlattenNestedCategory, ItemLoader, ItemProvider, ListLoader, ListProvider, LoaderState, LoginProvider, LogoutProvider, OptionalApiErrorHandler, OrderInclusions, OrderProductVariantPromotion, OrderSettingsState, OrderStoreState, PaginatedItemsProvider, PaginatedLoader, PaginatedLoaderState, PasswordResetProvider, ProductsCollectionProvider, ProductsCollectionsProvider, PromotionsCheckerCompletedPayload, PromotionsCheckerSelector, PromotionsRewardsSelectorProvider, PromotionsSelector, PromotionsSelectorContext, PromotionsSelectorOffer, PromotionsStoreState, RegistrationProvider, ReversedTreeProvider, SplittedCategoriesTreeProvider, StateDataLoader, StateDataLoaderState, StoreState, ZenkyInjection, ZenkyStorage, ZenkyWebsocketEvent, createStorage, createWebsocketsConnection, getAddressForm, getApiErrorHandler, getExistedAddress, getExistedAddressDisplayValue, getFirstMedium, getProductsListParamsFromQuery, getProductsListQueryParams, getProductsPaginationRequest, getProductsSource, getSelectedAddress, getSelectedAddressDisplayValue, getStockAddress, getStockSchedule, getStorage, getUpdatedVariants, getWebsocketsConnection, initializeOrderCustomer, initializePromotions, subscribeToOrderEvents, useAddressFormValue, useArticleCategoriesList, useArticleItem, useArticlesList, useAuthenticationForm, useAuthenticationStatusChecker, useBillSuggestions, useCategories, useCategoriesStore, useCategoriesTree, useCategory, useCategoryFeaturesGroupsList, useCategoryFeaturesList, useCheckoutConfirmation, useCheckoutSummary, useCheckoutTotal, useCollection, useCollections, useCollectionsStore, useCustomer, useCustomerCheckoutForm, useCustomerStore, useDadata, useDataDestroyer, useDataLoader, useDeliveryAddressDestroyer, useDeliveryAddressesList, useDeliveryCheckoutForm, useDeliveryPaymentsForm, useEditAddressForm, useFeaturesFilters, useFeaturesGroupsFilters, useFlatCategoriesTree, useItemLoader, useListLoader, useLogin, useLogout, useOfferItem, useOffersList, useOrderCheckout, useOrderItem, useOrderStore, useOrderVariants, useOrdersList, usePaginatedLoader, usePasswordReset, usePaymentMethodDestroyer, usePaymentMethodsList, usePhoneConfirmation, useProductsList, useProductsPricesRange, useProductsPricesRangeFilters, usePromotionsStore, useRegistration, useReversedTree, useRewardsSelector, useSplittedCategoriesTree, useStateDataLoader, useStoreStore, useSuggestionsRestrictedToCity, useTotalPrice, useTotalQuantity, useVariantControls };
10310
+ export { AddressForm, AddressFormValue, AddressFormValueProvider, ApiErrorHandler, AuthenticationEvent, AuthenticationForm, AuthenticationFormProvider, AuthenticationResult, AuthenticationResultType, AuthenticationStage, AuthenticationStatusCheckerProvider, CalculatedProductVariantPrice, CategoriesProvider, CategoriesState, CategoriesTreeProvider, CategoryProvider, CheckoutStage, CollectionsState, ConfirmableDataDestroyer, ConfirmationProvider, CustomerStore, DadataProvider, DataDestroyer, DataDestroyerHandler, DataLoader, DataProvider, EditAddressFormProvider, EmitAuthenticationEvent, FlatCategoriesTreeProvider, FlattenNestedCategory, InjectedProductsSource, ItemLoader, ItemProvider, ListLoader, ListProvider, LoaderState, LoginProvider, LogoutProvider, ModifiersGroupModifiersList, ModifiersGroupProps, OptionalApiErrorHandler, OrderInclusions, OrderProductVariantPromotion, OrderSettingsState, OrderStoreState, PaginatedItemsProvider, PaginatedLoader, PaginatedLoaderState, PasswordResetProvider, ProductCardModifiersList, ProductCardProduct, ProductCardVariantOption, ProductModifierModel, ProductModifiersGroupModifierModel, ProductVariantPriceCalcuator, ProductsCollectionProvider, ProductsCollectionsProvider, ProductsFilters, ProductsFiltersType, ProductsListConfig, ProductsListProvider, ProductsLoader, ProductsPriceFilters, ProductsPromotion, ProductsRequestCallback, ProductsSorting, ProductsSource, ProductsSourceType, PromotionsCheckerCompletedPayload, PromotionsCheckerSelector, PromotionsRewardsSelectorProvider, PromotionsSelector, PromotionsSelectorContext, PromotionsSelectorOffer, PromotionsStoreState, RegistrationProvider, ReversedTreeProvider, SelectedProductModifier, SelectedVariantOptionsList, SingleModifierProps, SplittedCategoriesTreeProvider, StateDataLoader, StateDataLoaderState, StoreState, ZenkyInjection, ZenkyStorage, ZenkyWebsocketEvent, createStorage, createWebsocketsConnection, getAddressForm, getApiErrorHandler, getExistedAddress, getExistedAddressDisplayValue, getFirstMedium, getProductVariantsPricesRange, getProductsListParamsFromQuery, getProductsListQueryParams, getProductsPaginationRequest, getProductsSource, getSelectedAddress, getSelectedAddressDisplayValue, getStockAddress, getStockSchedule, getStorage, getUpdatedVariants, getWebsocketsConnection, initializeOrderCustomer, initializePromotions, subscribeToOrderEvents, useAddressFormValue, useArticleCategoriesList, useArticleItem, useArticlesList, useAuthenticationForm, useAuthenticationStatusChecker, useBillSuggestions, useCategories, useCategoriesStore, useCategoriesTree, useCategory, useCategoryFeaturesGroupsList, useCategoryFeaturesList, useCheckoutConfirmation, useCheckoutSummary, useCheckoutTotal, useCollection, useCollections, useCollectionsStore, useCustomer, useCustomerCheckoutForm, useCustomerStore, useDadata, useDataDestroyer, useDataLoader, useDeliveryAddressDestroyer, useDeliveryAddressesList, useDeliveryCheckoutForm, useDeliveryPaymentsForm, useEditAddressForm, useFeaturesFilters, useFeaturesGroupsFilters, useFlatCategoriesTree, useItemLoader, useListLoader, useLogin, useLogout, useModifiers, useModifiersGroup, useOfferItem, useOffersList, useOrderCheckout, useOrderItem, useOrderStore, useOrderVariants, useOrdersList, usePaginatedLoader, usePasswordReset, usePaymentMethodDestroyer, usePaymentMethodsList, usePhoneConfirmation, useProductCard, useProductItem, useProductsList, useProductsPricesRange, useProductsPricesRangeFilters, usePromotionsStore, useRegistration, useReversedTree, useRewardsSelector, useSingleModifier, useSplittedCategoriesTree, useStateDataLoader, useStoreStore, useSuggestionsRestrictedToCity, useTotalPrice, useTotalQuantity, useVariant, useVariantControls, useVariantPrice };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenky/storefront-vue",
3
- "version": "0.9.39",
3
+ "version": "0.9.40",
4
4
  "description": "Zenky Storefront library for Vue 3.",
5
5
  "author": "Timur Zurbaev <hello@zurbaev.ru>",
6
6
  "license": "MIT",
@@ -19,7 +19,7 @@
19
19
  "Zenky"
20
20
  ],
21
21
  "peerDependencies": {
22
- "@zenky/api": "^0.9.50",
22
+ "@zenky/api": "^0.9.51",
23
23
  "@zenky/events": "^1.0.2",
24
24
  "@zenky/ui": "^0.9.63",
25
25
  "date-fns": "^2.29.2",