@zenky/storefront-vue 0.9.47 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE.md +2 -2
  3. package/README.md +213 -6
  4. package/dist/cart/index.d.ts +588 -0
  5. package/dist/cart/index.js +12 -0
  6. package/dist/cart/index.js.map +1 -0
  7. package/dist/catalog/index.d.ts +73 -0
  8. package/dist/catalog/index.js +4 -0
  9. package/dist/catalog/index.js.map +1 -0
  10. package/dist/chunk-57IOMDAM.js +38 -0
  11. package/dist/chunk-57IOMDAM.js.map +1 -0
  12. package/dist/chunk-5QCUH3FF.js +15 -0
  13. package/dist/chunk-5QCUH3FF.js.map +1 -0
  14. package/dist/chunk-7FRMMCR5.js +93 -0
  15. package/dist/chunk-7FRMMCR5.js.map +1 -0
  16. package/dist/chunk-BWUKMWHL.js +45 -0
  17. package/dist/chunk-BWUKMWHL.js.map +1 -0
  18. package/dist/chunk-E3G7NGCH.js +45 -0
  19. package/dist/chunk-E3G7NGCH.js.map +1 -0
  20. package/dist/chunk-EMGQXBU3.js +3 -0
  21. package/dist/chunk-EMGQXBU3.js.map +1 -0
  22. package/dist/chunk-FFBZKQRV.js +393 -0
  23. package/dist/chunk-FFBZKQRV.js.map +1 -0
  24. package/dist/chunk-G2X4SBCO.js +2011 -0
  25. package/dist/chunk-G2X4SBCO.js.map +1 -0
  26. package/dist/chunk-GLTOJTZO.js +41 -0
  27. package/dist/chunk-GLTOJTZO.js.map +1 -0
  28. package/dist/chunk-GW2QNTAD.js +327 -0
  29. package/dist/chunk-GW2QNTAD.js.map +1 -0
  30. package/dist/chunk-JLFBAAFT.js +566 -0
  31. package/dist/chunk-JLFBAAFT.js.map +1 -0
  32. package/dist/chunk-MZ66ARDL.js +244 -0
  33. package/dist/chunk-MZ66ARDL.js.map +1 -0
  34. package/dist/chunk-N3NOTJUC.js +111 -0
  35. package/dist/chunk-N3NOTJUC.js.map +1 -0
  36. package/dist/chunk-RO25KNM5.js +36 -0
  37. package/dist/chunk-RO25KNM5.js.map +1 -0
  38. package/dist/chunk-RYYY7MVP.js +102 -0
  39. package/dist/chunk-RYYY7MVP.js.map +1 -0
  40. package/dist/chunk-TEG7EL4N.js +106 -0
  41. package/dist/chunk-TEG7EL4N.js.map +1 -0
  42. package/dist/chunk-V3VVDQIR.js +27 -0
  43. package/dist/chunk-V3VVDQIR.js.map +1 -0
  44. package/dist/chunk-XUGXLJZB.js +14 -0
  45. package/dist/chunk-XUGXLJZB.js.map +1 -0
  46. package/dist/chunk-Z3IW4ODZ.js +36 -0
  47. package/dist/chunk-Z3IW4ODZ.js.map +1 -0
  48. package/dist/index.d.ts +26 -0
  49. package/dist/index.js +21 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/layout/index.d.ts +54 -0
  52. package/dist/layout/index.js +106 -0
  53. package/dist/layout/index.js.map +1 -0
  54. package/dist/money/index.d.ts +26 -0
  55. package/dist/money/index.js +3 -0
  56. package/dist/money/index.js.map +1 -0
  57. package/dist/order/index.d.ts +34 -0
  58. package/dist/order/index.js +209 -0
  59. package/dist/order/index.js.map +1 -0
  60. package/dist/pagination/index.d.ts +87 -0
  61. package/dist/pagination/index.js +97 -0
  62. package/dist/pagination/index.js.map +1 -0
  63. package/dist/ports/index.d.ts +124 -0
  64. package/dist/ports/index.js +3 -0
  65. package/dist/ports/index.js.map +1 -0
  66. package/dist/products/index.d.ts +105 -0
  67. package/dist/products/index.js +7 -0
  68. package/dist/products/index.js.map +1 -0
  69. package/dist/promotions/index.d.ts +10 -0
  70. package/dist/promotions/index.js +7 -0
  71. package/dist/promotions/index.js.map +1 -0
  72. package/dist/schedule-Dd3zwHEb.d.ts +27 -0
  73. package/dist/seo/index.d.ts +91 -0
  74. package/dist/seo/index.js +289 -0
  75. package/dist/seo/index.js.map +1 -0
  76. package/dist/snippets/index.d.ts +17 -0
  77. package/dist/snippets/index.js +3 -0
  78. package/dist/snippets/index.js.map +1 -0
  79. package/dist/snippets-BC5bkSjm.d.ts +23 -0
  80. package/dist/stores/index.d.ts +196 -0
  81. package/dist/stores/index.js +8 -0
  82. package/dist/stores/index.js.map +1 -0
  83. package/dist/theme/index.d.ts +60 -0
  84. package/dist/theme/index.js +3 -0
  85. package/dist/theme/index.js.map +1 -0
  86. package/dist/utils/index.d.ts +66 -0
  87. package/dist/utils/index.js +4 -0
  88. package/dist/utils/index.js.map +1 -0
  89. package/dist/website-settings/index.d.ts +38 -0
  90. package/dist/website-settings/index.js +3 -0
  91. package/dist/website-settings/index.js.map +1 -0
  92. package/docs/consumer-setup.md +275 -0
  93. package/docs/ports.md +144 -0
  94. package/docs/releasing.md +46 -0
  95. package/package.json +143 -47
  96. package/dist/cjs/index.cjs +0 -3742
  97. package/dist/esm/index.mjs +0 -3642
  98. package/dist/zenky.d.ts +0 -10377
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/products/formatWeight.ts","../src/products/useProductsByCategory.ts","../src/products/useProductVariantModifiers.ts","../src/products/useProductPricing.ts","../src/products/useProductVariant.ts","../src/products/usePriceRecalculation.ts","../src/products/useProductVariantSelector.ts","../src/products/useRelatedProducts.ts","../src/products/findProductInCatalog.ts"],"names":["computed","ref","watch"],"mappings":"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","file":"chunk-JLFBAAFT.js","sourcesContent":["import { UnitType } from '@zenky/storefront-api'\n\nimport type { Product, ProductVariant } from '@zenky/storefront-api'\n\nconst UNIT_LABELS: Record<UnitType, string> = {\n [UnitType.Gram]: 'г',\n [UnitType.Kilogram]: 'кг',\n [UnitType.Meter]: 'м',\n [UnitType.Piece]: 'г',\n} as const\n\nfunction getWeightFromDimensions(variants: ProductVariant[] | undefined): number | null {\n if (!variants?.length) return null\n\n const dimension = variants[0]?.dimensions?.find((d) => d.dimension === 'weight')\n\n return dimension?.value ?? null\n}\n\nexport function getVariantWeight(variant: ProductVariant | null | undefined): number | null {\n if (!variant) return null\n\n return variant.dimensions?.find((d) => d.dimension === 'weight')?.value ?? null\n}\n\nexport function getProductWeight(product: Product): number | null {\n return product.weight ?? getWeightFromDimensions(product.variants) ?? null\n}\n\nexport function toGrams(weight: number | null, unitType: UnitType): number | null {\n if (!weight) {\n return null\n }\n\n if (unitType === UnitType.Kilogram) {\n return weight * 1000\n }\n\n if (unitType === UnitType.Meter) {\n return null\n }\n\n return weight\n}\n\nexport function formatWeight(weight: number | null, unitType: UnitType): string | null {\n if (!weight) {\n return null\n }\n\n const label = UNIT_LABELS[unitType]\n\n return `${weight} ${label}`\n}\n","import { computed, type ComputedRef } from 'vue'\n\nimport type { NestedCategory, Product } from '@zenky/storefront-api'\n\nexport interface CategoryWithProducts {\n id: string\n shortId: string\n slug: string | null\n name: string | null\n products: Product[]\n}\n\nexport function useProductsByCategory(\n products: ComputedRef<Product[]>,\n categories: ComputedRef<NestedCategory[]>\n): {\n grouped: ComputedRef<CategoryWithProducts[]>\n} {\n const grouped = computed<CategoryWithProducts[]>(() => {\n if (!categories.value.length || !products.value.length) {\n return []\n }\n\n const productsByCategory = new Map<string, Product[]>()\n\n for (const product of products.value) {\n for (const category of product.categories) {\n const existing = productsByCategory.get(category.id) ?? []\n existing.push(product)\n productsByCategory.set(category.id, existing)\n }\n }\n\n return flattenCategories(categories.value)\n .filter((category) => productsByCategory.has(category.id))\n .map((category) => ({\n id: category.id,\n shortId: category.short_id,\n slug: category.slug,\n name: category.name,\n products: productsByCategory.get(category.id) ?? [],\n }))\n })\n\n return { grouped }\n}\n\nfunction flattenCategories(categories: NestedCategory[]): NestedCategory[] {\n const result: NestedCategory[] = []\n\n for (const category of categories) {\n result.push(category)\n\n if (category.children?.length) {\n result.push(...flattenCategories(category.children))\n }\n }\n\n return result\n}\n","import { computed, ref, watch, type ComputedRef, type Ref } from 'vue'\n\nimport type { ProductModifiersRequest, ProductVariant } from '@zenky/storefront-api'\n\nfunction getInitialModifiersModel(variant: ProductVariant | null): ProductModifiersRequest[] {\n if (!variant?.default_modifiers?.modifiers.length) {\n return []\n }\n\n return variant.default_modifiers.modifiers.map((modifier) => ({\n modifier_id: modifier.modifier_id,\n modifiers_group_id: modifier.modifiers_group_id,\n quantity: modifier.quantity,\n }))\n}\n\nexport function useProductVariantModifiers(variant: ComputedRef<ProductVariant | null>): {\n modifiersModel: Ref<ProductModifiersRequest[]>\n selectedModifiersHash: Ref<string | null>\n hasAnyModifier: ComputedRef<boolean>\n} {\n const modifiersModel: Ref<ProductModifiersRequest[]> = ref([\n ...getInitialModifiersModel(variant.value),\n ])\n const selectedModifiersHash: Ref<string | null> = ref(null)\n const hasAnyModifier = computed<boolean>(() => modifiersModel.value.length > 0)\n\n watch(variant, () => {\n const newDefaults = getInitialModifiersModel(variant.value)\n\n // Сохраняем standalone модификаторы (без группы) — они продуктовые, не зависят от варианта.\n // Групповые модификаторы сбрасываются до дефолтов нового варианта.\n const userStandalone = modifiersModel.value.filter((m) => !m.modifiers_group_id)\n const defaultStandaloneIds = new Set(\n newDefaults.filter((d) => !d.modifiers_group_id).map((d) => d.modifier_id)\n )\n const preservedStandalone = userStandalone.filter(\n (m) => !defaultStandaloneIds.has(m.modifier_id)\n )\n\n modifiersModel.value = [...preservedStandalone, ...newDefaults]\n })\n\n return { modifiersModel, selectedModifiersHash, hasAnyModifier }\n}\n","import { computed, type ComputedRef } from 'vue'\n\nimport type { Discount, Product, ProductVariant } from '@zenky/storefront-api'\n\nexport interface ResolvedPrice {\n price: number\n originalPrice: number | null\n discount: Discount | null\n}\n\n/**\n * Определяет цену варианта с учётом склада.\n * Приоритет: prices[stockId] → prices[null] → top-level price.\n */\nexport function resolveVariantPrice(\n variant: ProductVariant,\n stockId?: string | null\n): ResolvedPrice {\n if (variant.prices?.length) {\n // 1. Точное совпадение по складу\n if (stockId) {\n const stockEntry = variant.prices.find((p) => p.stock_id === stockId)\n\n if (stockEntry) {\n return {\n price: stockEntry.price,\n originalPrice: stockEntry.original_price,\n discount: stockEntry.discount,\n }\n }\n }\n\n // 2. Глобальная цена (stock_id = null)\n const globalEntry = variant.prices.find((p) => p.stock_id === null)\n\n if (globalEntry) {\n return {\n price: globalEntry.price,\n originalPrice: globalEntry.original_price,\n discount: globalEntry.discount,\n }\n }\n }\n\n // 3. Fallback — top-level поля варианта\n return {\n price: variant.price,\n originalPrice: variant.original_price ?? null,\n discount: variant.discount ?? null,\n }\n}\n\nexport function useProductPricing(\n product: ComputedRef<Product>,\n stockId?: ComputedRef<string | null | undefined>\n): {\n displayPrice: ComputedRef<number>\n originalDisplayPrice: ComputedRef<number | null>\n hasDifferentPrices: ComputedRef<boolean>\n needsSelection: ComputedRef<boolean>\n} {\n const variants = computed(() => product.value.variants ?? [])\n const currentStockId = computed(() => stockId?.value ?? null)\n\n // Цены всех вариантов с учётом склада\n const resolvedPrices = computed(() =>\n variants.value.map((v) => resolveVariantPrice(v, currentStockId.value))\n )\n\n // Минимальная обязательная стоимость модификаторов, которая всегда добавляется к цене:\n // 1. modEntry.is_required — модификатор всегда присылается в API (нельзя убрать)\n // 2. groupEntry.is_required — пользователь обязан выбрать хотя бы один из группы →\n // добавляем минимальную цену из группы (если группа не покрыта is_required-модификатором)\n const minRequiredModifiersCost = computed<number>(() => {\n let total = 0\n\n for (const groupEntry of product.value.modifiers_groups ?? []) {\n const group = groupEntry.group\n\n // Обязательные модификаторы внутри группы — всегда добавляются в заказ\n for (const modEntry of group.modifiers) {\n if (modEntry.is_required && modEntry.modifier.price) {\n total += modEntry.modifier.price * Math.max(modEntry.min_quantity ?? 0, 1)\n }\n }\n\n if (\n groupEntry.is_required &&\n group.modifiers.length &&\n !group.modifiers.some((m) => m.is_required)\n ) {\n const cheapest = group.modifiers.reduce((min, m) =>\n (m.modifier.price ?? 0) < (min.modifier.price ?? 0) ? m : min\n )\n total += (cheapest.modifier.price ?? 0) * Math.max(cheapest.min_quantity ?? 0, 1)\n }\n }\n\n return total\n })\n\n const displayPrice = computed<number>(() => {\n if (!resolvedPrices.value.length) {\n return 0\n }\n\n return (\n Math.min(...resolvedPrices.value.map((r) => r.price)) + minRequiredModifiersCost.value\n )\n })\n\n // Цена без скидки: original_price минимального по цене варианта + обязательные модификаторы.\n // null если скидки нет.\n // original_price может быть null даже при наличии скидки — тогда вычисляем через discount.difference.\n const originalDisplayPrice = computed<number | null>(() => {\n if (!resolvedPrices.value.length) return null\n\n // Находим вариант с минимальной ценой (тот же, что определяет displayPrice)\n const cheapest = resolvedPrices.value.reduce((min, r) => (r.price < min.price ? r : min))\n\n // Приоритет: original_price, затем вычисление через discount\n let originalVariantPrice: number | null = null\n\n if (cheapest.originalPrice && cheapest.originalPrice > cheapest.price) {\n originalVariantPrice = cheapest.originalPrice\n } else if (cheapest.discount && cheapest.discount.difference > 0) {\n originalVariantPrice = cheapest.price + cheapest.discount.difference\n }\n\n if (!originalVariantPrice) return null\n\n return originalVariantPrice + minRequiredModifiersCost.value\n })\n\n const hasDifferentPrices = computed<boolean>(() => {\n if (resolvedPrices.value.length <= 1) {\n return false\n }\n\n const prices = new Set(resolvedPrices.value.map((r) => r.price))\n\n return prices.size > 1\n })\n\n const needsSelection = computed<boolean>(() => {\n if (variants.value.length > 1) {\n return true\n }\n\n const mods = product.value.modifiers\n const groups = product.value.modifiers_groups\n\n return (\n (Array.isArray(mods) && mods.length > 0) || (Array.isArray(groups) && groups.length > 0)\n )\n })\n\n return { displayPrice, originalDisplayPrice, hasDifferentPrices, needsSelection }\n}\n","import { computed, ref, watch, type ComputedRef, type Ref } from 'vue'\n\nimport type {\n Product,\n ProductVariant,\n ProductVariantOption,\n ProductVariantOptionValue,\n} from '@zenky/storefront-api'\n\nexport interface ProductVariantOptionListItem {\n id: string\n name: string | null\n values: ProductVariantOptionValue[]\n}\n\nfunction getDefaultOptionsModel(product: Product): Record<string, string> {\n const model: Record<string, string> = {}\n\n if (!product.variants?.length) {\n return model\n }\n\n const firstVariantOptions = product.variants.find(\n (variant: ProductVariant) => variant.options?.length\n )?.options\n\n if (!firstVariantOptions) {\n return model\n }\n\n firstVariantOptions.forEach((option: ProductVariantOption) => {\n model[option.id] = option.value.id\n })\n\n return model\n}\n\nfunction getProductVariantOptionsList(product: Product): ProductVariantOptionListItem[] {\n const list: ProductVariantOptionListItem[] = []\n\n if (!product.variants?.length) {\n return list\n }\n\n product.variants.forEach((variant: ProductVariant) => {\n if (!variant.options?.length) {\n return\n }\n\n variant.options.forEach((option: ProductVariantOption) => {\n let index = list.findIndex(\n (item: ProductVariantOptionListItem) => item.id === option.id\n )\n\n if (index === -1) {\n index = list.push({\n id: option.id,\n name: option.name,\n values: [],\n })\n\n index--\n }\n\n const valueIndex = list[index]!.values.findIndex(\n (value: ProductVariantOptionValue) => value.id === option.value.id\n )\n\n if (valueIndex === -1) {\n list[index]!.values.push(option.value)\n }\n })\n })\n\n return list\n}\n\nfunction computeDisabledValues(\n variants: ProductVariant[],\n optionsList: ProductVariantOptionListItem[],\n optionsModel: Record<string, string>\n): Record<string, Set<string>> {\n if (!variants.length) return {}\n\n const result: Record<string, Set<string>> = {}\n\n for (const option of optionsList) {\n const disabled = new Set<string>()\n\n for (const value of option.values) {\n const hasMatch = variants.some((variant) => {\n if (!variant.options?.length) return false\n\n const variantMap: Record<string, string> = {}\n for (const opt of variant.options) {\n variantMap[opt.id] = opt.value.id\n }\n\n // Variant must have this specific value for this option\n if (variantMap[option.id] !== value.id) return false\n\n // Variant must match all OTHER currently-selected values\n for (const [otherId, selectedId] of Object.entries(optionsModel)) {\n if (otherId === option.id) continue\n if (variantMap[otherId] !== selectedId) return false\n }\n\n return true\n })\n\n if (!hasMatch) {\n disabled.add(value.id)\n }\n }\n\n result[option.id] = disabled\n }\n\n return result\n}\n\nexport function useProductVariant(product: ComputedRef<Product>): {\n optionsModel: Ref<Record<string, string>>\n optionsList: Ref<ProductVariantOptionListItem[]>\n selectedVariant: ComputedRef<ProductVariant | null>\n disabledValues: ComputedRef<Record<string, Set<string>>>\n} {\n const optionsModel = ref({ ...getDefaultOptionsModel(product.value) })\n const optionsList = ref([...getProductVariantOptionsList(product.value)])\n\n const selectedVariant = computed<ProductVariant | null>(() => {\n if (!product.value.variants?.length) {\n return null\n } else if (product.value.variants.length === 1 || !Object.keys(optionsModel.value).length) {\n return product.value.variants[0] ?? null\n }\n\n return (\n product.value.variants.find((variant: ProductVariant) => {\n if (!variant.options?.length) {\n return false\n }\n\n return variant.options.every(\n (option: ProductVariantOption) =>\n optionsModel.value[option.id] === option.value.id\n )\n }) ?? null\n )\n })\n\n const disabledValues = computed<Record<string, Set<string>>>(() =>\n computeDisabledValues(product.value.variants ?? [], optionsList.value, optionsModel.value)\n )\n\n watch(product, () => {\n optionsModel.value = { ...getDefaultOptionsModel(product.value) }\n optionsList.value = [...getProductVariantOptionsList(product.value)]\n })\n\n return { optionsModel, optionsList, selectedVariant, disabledValues }\n}\n","import { computed, ref, watch, type ComputedRef, type Ref } from 'vue'\n\nimport type { Product, ProductModifiersRequest, ProductVariant } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { useStoreProfileStore } from '../stores/store-profile'\nimport { createDebounce } from '../utils/debounce'\nimport { resolveVariantPrice } from './useProductPricing'\n\ninterface PriceRecalculationOptions {\n product: ComputedRef<Product>\n selectedVariant: ComputedRef<ProductVariant | null>\n modifiersModel: Ref<ProductModifiersRequest[]>\n requiredModifiersGroupIsMissing: ComputedRef<boolean>\n selectedModifiersHash: Ref<string | null>\n}\n\nexport function usePriceRecalculation({\n product,\n selectedVariant,\n modifiersModel,\n requiredModifiersGroupIsMissing,\n selectedModifiersHash,\n}: PriceRecalculationOptions): {\n price: ComputedRef<number>\n originalPrice: ComputedRef<number | null>\n priceWasModified: ComputedRef<boolean>\n priceIsRecalculating: Ref<boolean>\n} {\n // SDK берём из рантайма (DI-порт), а не из Nuxt-специфичного useStorefrontApi().\n const sdk = useRuntime().sdk\n const profileStore = useStoreProfileStore()\n\n // -------------------------------------------------------------------------\n // Computed: stock-aware variant pricing\n // -------------------------------------------------------------------------\n\n const currentStockId = computed(() => profileStore.stock?.id ?? null)\n\n const resolvedVariant = computed(() => {\n if (!selectedVariant.value) return null\n\n return resolveVariantPrice(selectedVariant.value, currentStockId.value)\n })\n\n // -------------------------------------------------------------------------\n // Computed: modifier price helpers\n // -------------------------------------------------------------------------\n\n const modifierPriceMap = computed<Map<string, number>>(() => {\n const map = new Map<string, number>()\n\n for (const item of product.value.modifiers ?? []) {\n if (item.modifier.price) {\n map.set(item.modifier.id, item.modifier.price)\n }\n }\n\n for (const group of product.value.modifiers_groups ?? []) {\n for (const item of group.group.modifiers ?? []) {\n if (item.modifier.price) {\n map.set(item.modifier.id, item.modifier.price)\n }\n }\n }\n\n return map\n })\n\n // Сумма цен выбранных модификаторов (включая дефолтные — они в modifiersModel)\n const selectedModifierTotal = computed<number>(() =>\n modifiersModel.value.reduce(\n (sum, req) => sum + (modifierPriceMap.value.get(req.modifier_id) ?? 0) * req.quantity,\n 0\n )\n )\n\n // -------------------------------------------------------------------------\n // Computed: optimistic price (мгновенный, без API)\n // -------------------------------------------------------------------------\n\n // variant.price — базовая цена варианта (stock-specific или fallback),\n // НЕ включает модификаторы. selectedModifierTotal добавляет все выбранные\n // (дефолтные + обязательные + пользовательские).\n const optimisticPrice = computed<number>(() => {\n if (!resolvedVariant.value) return 0\n\n return resolvedVariant.value.price + selectedModifierTotal.value\n })\n\n const optimisticOriginalPrice = computed<number | null>(() => {\n if (!resolvedVariant.value) return null\n\n const r = resolvedVariant.value\n\n if (r.originalPrice && r.originalPrice > r.price) return r.originalPrice\n if (r.discount && r.discount.difference > 0) return r.price + r.discount.difference\n\n return null\n })\n\n // -------------------------------------------------------------------------\n // API-confirmed price (перезаписывает optimistic после ответа)\n // -------------------------------------------------------------------------\n\n const apiPrice = ref<number | null>(null)\n const apiOriginalPrice = ref<number | null>(null)\n const priceIsRecalculating = ref(false)\n let requestId = 0\n\n // -------------------------------------------------------------------------\n // Final displayed price: API > optimistic\n // -------------------------------------------------------------------------\n\n const price = computed<number>(() => apiPrice.value ?? optimisticPrice.value)\n const originalPrice = computed<number | null>(\n () => apiOriginalPrice.value ?? optimisticOriginalPrice.value\n )\n const priceWasModified = computed<boolean>(() => apiPrice.value !== null)\n\n // -------------------------------------------------------------------------\n // API recalculation (подтверждает / корректирует optimistic)\n // -------------------------------------------------------------------------\n\n async function recalculatePrice(): Promise<void> {\n if (requiredModifiersGroupIsMissing.value) return\n if (!modifiersModel.value.length || !selectedVariant.value) return\n\n const currentRequestId = ++requestId\n priceIsRecalculating.value = true\n\n try {\n const response = await sdk.products.getProductVariantPrice(\n profileStore.store!.id,\n product.value.id,\n selectedVariant.value.id,\n {\n modifiers: modifiersModel.value,\n // exactOptionalPropertyTypes: stock_id включаем только если есть\n ...(currentStockId.value ? { stock_id: currentStockId.value } : {}),\n }\n )\n\n if (currentRequestId !== requestId) return\n\n apiPrice.value = response.price\n apiOriginalPrice.value = response.original_price\n selectedModifiersHash.value = response.modifiers_hash\n } catch (e) {\n console.error('[usePriceRecalculation] price recalculation failed', e)\n } finally {\n if (currentRequestId === requestId) {\n priceIsRecalculating.value = false\n }\n }\n }\n\n const debouncedRecalculate = createDebounce(() => recalculatePrice(), 300)\n\n // -------------------------------------------------------------------------\n // Watcher: сброс API-цены + пересчёт при смене варианта/модификаторов\n // -------------------------------------------------------------------------\n\n watch(selectedVariant, () => {\n apiPrice.value = null\n apiOriginalPrice.value = null\n requestId++\n selectedModifiersHash.value = selectedVariant.value?.default_modifiers?.hash ?? null\n })\n\n watch(\n modifiersModel,\n () => {\n apiPrice.value = null\n apiOriginalPrice.value = null\n requestId++\n\n if (modifiersModel.value.length && selectedVariant.value) {\n debouncedRecalculate()\n } else {\n selectedModifiersHash.value = selectedVariant.value?.default_modifiers?.hash ?? null\n }\n },\n { deep: true }\n )\n\n return { price, originalPrice, priceWasModified, priceIsRecalculating }\n}\n","import { computed, watch, type ComputedRef, type Ref } from 'vue'\n\nimport type { Product, ProductModifiersRequest, ProductVariant } from '@zenky/storefront-api'\n\nimport { usePriceRecalculation } from './usePriceRecalculation'\nimport { useProductVariant, type ProductVariantOptionListItem } from './useProductVariant'\nimport { useProductVariantModifiers } from './useProductVariantModifiers'\n\n// SDK-поле min_quantity опционально (number | null); нормализуем в положительное количество.\nfunction resolveQuantity(minQuantity: number | null): number {\n return minQuantity && minQuantity > 0 ? minQuantity : 1\n}\n\nexport function useProductVariantSelector(product: ComputedRef<Product>): {\n optionsModel: Ref<Record<string, string>>\n optionsList: Ref<ProductVariantOptionListItem[]>\n disabledValues: ComputedRef<Record<string, Set<string>>>\n modifiersModel: Ref<ProductModifiersRequest[]>\n selectedVariant: ComputedRef<ProductVariant | null>\n price: ComputedRef<number>\n originalPrice: ComputedRef<number | null>\n priceWasModified: ComputedRef<boolean>\n priceIsRecalculating: Ref<boolean>\n selectedModifiersHash: Ref<string | null>\n requiredModifiersGroupIsMissing: ComputedRef<boolean>\n} {\n const { optionsModel, optionsList, selectedVariant, disabledValues } =\n useProductVariant(product)\n const { modifiersModel, selectedModifiersHash } = useProductVariantModifiers(selectedVariant)\n\n // Обязательные модификаторы — всегда должны быть в модели.\n // 1) modEntry.is_required — индивидуальный обязательный модификатор\n // 2) groupEntry.is_required — обязательная группа: если в ней нет is_required-модификаторов,\n // автоматически выбираем самый дешёвый (зеркалит minRequiredModifiersCost в useProductPricing)\n const requiredModifierEntries = computed<ProductModifiersRequest[]>(() => {\n const result: ProductModifiersRequest[] = []\n\n for (const groupEntry of product.value.modifiers_groups ?? []) {\n const group = groupEntry.group\n const hasIndividualRequired = group.modifiers.some((m) => m.is_required)\n\n // 1. Индивидуальные обязательные модификаторы\n for (const modEntry of group.modifiers) {\n if (modEntry.is_required) {\n result.push({\n modifier_id: modEntry.modifier.id,\n modifiers_group_id: group.id,\n quantity: resolveQuantity(modEntry.min_quantity),\n })\n }\n }\n\n // 2. Обязательная группа без is_required-модификаторов →\n // пользователь должен выбрать хотя бы один; берём самый дешёвый\n if (groupEntry.is_required && !hasIndividualRequired) {\n const sorted = [...group.modifiers].sort(\n (a, b) => (a.modifier.price ?? 0) - (b.modifier.price ?? 0)\n )\n const cheapest = sorted[0]\n\n if (cheapest) {\n result.push({\n modifier_id: cheapest.modifier.id,\n modifiers_group_id: group.id,\n quantity: resolveQuantity(cheapest.min_quantity),\n })\n }\n }\n }\n\n return result\n })\n\n // Добавляет обязательные модификаторы в модель (для UI и API).\n // Одна мутация — без лишних реактивных перерасчётов.\n function seedRequiredModifiers(): void {\n const missing = requiredModifierEntries.value.filter(\n (req) => !modifiersModel.value.some((m) => m.modifier_id === req.modifier_id)\n )\n\n if (missing.length) {\n modifiersModel.value = [...modifiersModel.value, ...missing]\n }\n }\n\n // Синхронная инициализация — до регистрации любых watchers в usePriceRecalculation,\n // чтобы первый рендер сразу видел корректную цену.\n seedRequiredModifiers()\n\n // При смене варианта: useProductVariantModifiers watcher сбрасывает модель до дефолтов,\n // затем мы добавляем обязательные обратно. Оба watcher'а flush: 'pre' — отрабатывают\n // в порядке регистрации до рендера.\n watch(selectedVariant, seedRequiredModifiers)\n\n const requiredModifiersGroupIsMissing = computed<boolean>(() => {\n const requiredGroups = (product.value.modifiers_groups ?? [])\n .filter((group) => group.is_required)\n .map((group) => group.group.id)\n\n if (!requiredGroups.length) return false\n\n return requiredGroups.some(\n (groupId) =>\n !modifiersModel.value.find(\n (m) => m.modifiers_group_id === groupId && m.quantity > 0\n )\n )\n })\n\n const { price, originalPrice, priceWasModified, priceIsRecalculating } = usePriceRecalculation({\n product,\n selectedVariant,\n modifiersModel,\n requiredModifiersGroupIsMissing,\n selectedModifiersHash,\n })\n\n return {\n optionsModel,\n optionsList,\n disabledValues,\n modifiersModel,\n selectedVariant,\n price,\n originalPrice,\n priceWasModified,\n priceIsRecalculating,\n selectedModifiersHash,\n requiredModifiersGroupIsMissing,\n }\n}\n","// Запросы рекомендованных товаров. SDK не предоставляет типизированных методов\n// related.products.list — идём через публичный sdk.client.request.\nimport type { Product } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { createRuntimeState } from '../ports/runtimeState'\nimport { useAuthStore } from '../stores/auth'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nexport interface OrderCredentials {\n id: string\n token: string\n}\n\ninterface UseRelatedProductsApi {\n fetchForProduct: (\n productId: string,\n orderCredentials: OrderCredentials | null,\n signal?: AbortSignal\n ) => Promise<Product[]>\n fetchForOrder: (orderId: string, orderToken: string, signal?: AbortSignal) => Promise<Product[]>\n}\n\n/**\n * Один из вариантов товара и ни одного модификатора — такой товар можно класть\n * в корзину одним кликом по рекомендации, минуя открытие карточки.\n */\nexport function canAddDirectly(product: Product): boolean {\n const variantsCount = product.variants?.length ?? 0\n const hasModifiers = (product.modifiers?.length ?? 0) > 0\n const hasModifierGroups = (product.modifiers_groups?.length ?? 0) > 0\n return variantsCount === 1 && !hasModifiers && !hasModifierGroups\n}\n\n// Без `variants.prices` приходят 0₽ (цены живут на variants). Без modifiers/groups\n// сломается canAddDirectly — посчитает товар «прямым добавлением», хотя модификаторы есть.\nconst RELATED_PRODUCT_INCLUDES = 'variants.prices,modifiers,modifiers_groups'\n\ninterface RelatedProductsState {\n productInFlight: Map<string, Promise<Product[]>>\n}\n\nconst getRelatedProductsState = createRuntimeState<RelatedProductsState>(() => ({\n productInFlight: new Map<string, Promise<Product[]>>(),\n}))\n\nexport function useRelatedProducts(): UseRelatedProductsApi {\n const runtime = useRuntime()\n const { sdk } = runtime\n const { productInFlight } = getRelatedProductsState(runtime)\n const profileStore = useStoreProfileStore()\n const authStore = useAuthStore()\n\n function getStoreId(): string {\n const id = profileStore.store?.id\n if (!id) throw new Error('Store is not initialized')\n return id\n }\n\n async function fetchForProduct(\n productId: string,\n orderCredentials: OrderCredentials | null,\n signal?: AbortSignal\n ): Promise<Product[]> {\n if (signal?.aborted) return []\n\n const key = orderCredentials ? `${productId}:${orderCredentials.id}` : productId\n\n let promise = productInFlight.get(key)\n if (!promise) {\n promise = (async (): Promise<Product[]> => {\n try {\n const storeId = getStoreId()\n const query: Record<string, string> = { with: RELATED_PRODUCT_INCLUDES }\n if (orderCredentials) {\n query.order_id = orderCredentials.id\n query.order_token = orderCredentials.token\n }\n const url = sdk.client.getStoreUrl(\n storeId,\n `/products/${productId}/related/products`,\n query\n )\n const response = await sdk.client.request(\n 'GET',\n url,\n undefined,\n authStore.token\n )\n return (response?.data as Product[] | undefined) ?? []\n } catch (e: unknown) {\n // По ТЗ при ошибке/пустом ответе никаких сообщений покупателю —\n // блок просто не появляется. Лог нужен разработчику.\n console.warn('[recommendations:product] fetch failed', e)\n return []\n }\n })().finally(() => productInFlight.delete(key))\n productInFlight.set(key, promise)\n }\n\n const result = await promise\n return signal?.aborted ? [] : result\n }\n\n async function fetchForOrder(\n orderId: string,\n orderToken: string,\n signal?: AbortSignal\n ): Promise<Product[]> {\n if (signal?.aborted) return []\n\n try {\n const storeId = getStoreId()\n const url = sdk.client.getStoreUrl(storeId, `/orders/${orderId}/related/products`, {\n token: orderToken,\n with: RELATED_PRODUCT_INCLUDES,\n })\n const response = await sdk.client.request('GET', url, undefined, authStore.token)\n if (signal?.aborted) return []\n return (response?.data as Product[] | undefined) ?? []\n } catch (e: unknown) {\n console.warn('[recommendations:order] fetch failed', e)\n return []\n }\n }\n\n return { fetchForProduct, fetchForOrder }\n}\n","import type { CatalogItem, Product } from '@zenky/storefront-api'\n\nexport interface CatalogProductMatch {\n product: Product\n catalogItem: CatalogItem\n}\n\n/** Поиск товара по short_id в статичном каталоге. null — если не найден. */\nexport function findProductInCatalog(\n catalog: CatalogItem[],\n shortId: string\n): CatalogProductMatch | null {\n for (const item of catalog) {\n if (!item.products.length) continue\n\n const found = item.products.find((p) => p.short_id === shortId)\n if (found) return { product: found, catalogItem: item }\n }\n\n return null\n}\n"]}
@@ -0,0 +1,244 @@
1
+ import { ContactType, ZenkyError } from '@zenky/storefront-api';
2
+
3
+ // src/utils/createOperationChain.ts
4
+ function createOperationChain() {
5
+ const chains = /* @__PURE__ */ new Map();
6
+ async function execute(key, fn) {
7
+ const prev = chains.get(key) ?? Promise.resolve();
8
+ const current = prev.then(fn);
9
+ const safe = current.catch(() => {
10
+ });
11
+ chains.set(key, safe);
12
+ safe.finally(() => {
13
+ if (chains.get(key) === safe) {
14
+ chains.delete(key);
15
+ }
16
+ });
17
+ return current;
18
+ }
19
+ return {
20
+ execute,
21
+ get size() {
22
+ return chains.size;
23
+ }
24
+ };
25
+ }
26
+
27
+ // src/utils/phone.ts
28
+ function formatPhoneNational(phone) {
29
+ if (!phone) return null;
30
+ return phone.national || phone.number;
31
+ }
32
+ function getPhoneTelLink(phone) {
33
+ if (!phone) return null;
34
+ return `tel:${phone.number}`;
35
+ }
36
+ function formatPhoneSpaced(formatted) {
37
+ if (!formatted) return "";
38
+ return formatted.replace(/[()-]/g, " ").replace(/\s+/g, " ").trim();
39
+ }
40
+ var SOCIAL_TYPES = /* @__PURE__ */ new Set([
41
+ ContactType.Vk,
42
+ ContactType.Instagram,
43
+ ContactType.Facebook,
44
+ ContactType.Twitter,
45
+ ContactType.Ok,
46
+ ContactType.Tiktok,
47
+ ContactType.Telegram,
48
+ ContactType.Max
49
+ ]);
50
+ var SOCIAL_LABELS = {
51
+ [ContactType.Vk]: "\u0412\u041A\u043E\u043D\u0442\u0430\u043A\u0442\u0435",
52
+ [ContactType.Instagram]: "Instagram",
53
+ [ContactType.Facebook]: "Facebook",
54
+ [ContactType.Twitter]: "Twitter",
55
+ [ContactType.Ok]: "\u041E\u0434\u043D\u043E\u043A\u043B\u0430\u0441\u0441\u043D\u0438\u043A\u0438",
56
+ [ContactType.Tiktok]: "TikTok",
57
+ [ContactType.Telegram]: "Telegram",
58
+ [ContactType.Max]: "Max"
59
+ };
60
+ function buildSocialUrl(type, value) {
61
+ if (value.startsWith("http://") || value.startsWith("https://")) {
62
+ return value;
63
+ }
64
+ const bases = {
65
+ [ContactType.Vk]: "https://vk.com/",
66
+ [ContactType.Instagram]: "https://instagram.com/",
67
+ [ContactType.Facebook]: "https://facebook.com/",
68
+ [ContactType.Twitter]: "https://x.com/",
69
+ [ContactType.Ok]: "https://ok.ru/",
70
+ [ContactType.Tiktok]: "https://tiktok.com/@",
71
+ [ContactType.Telegram]: "https://t.me/",
72
+ [ContactType.Max]: "https://max.ru/"
73
+ };
74
+ const base = bases[type];
75
+ return base ? `${base}${value}` : value;
76
+ }
77
+ function getSocialLinks(contacts) {
78
+ return contacts.filter((contact) => SOCIAL_TYPES.has(contact.type)).map((contact) => ({
79
+ type: contact.type,
80
+ url: buildSocialUrl(contact.type, contact.value),
81
+ label: SOCIAL_LABELS[contact.type] ?? contact.type
82
+ }));
83
+ }
84
+ function getEmailLink(contacts) {
85
+ const email = contacts.find((c) => c.type === ContactType.Email);
86
+ return email?.value ?? null;
87
+ }
88
+ function getWebsiteLink(contacts) {
89
+ const website = contacts.find((c) => c.type === ContactType.Website);
90
+ return website?.value ?? null;
91
+ }
92
+
93
+ // src/utils/schedule.ts
94
+ var DAY_TO_JS_INDEX = {
95
+ sunday: 0,
96
+ monday: 1,
97
+ tuesday: 2,
98
+ wednesday: 3,
99
+ thursday: 4,
100
+ friday: 5,
101
+ saturday: 6
102
+ };
103
+ var DAY_ORDER = [
104
+ "monday",
105
+ "tuesday",
106
+ "wednesday",
107
+ "thursday",
108
+ "friday",
109
+ "saturday",
110
+ "sunday"
111
+ ];
112
+ function getDayName(dayKey, locale) {
113
+ const index = DAY_TO_JS_INDEX[dayKey];
114
+ if (index === void 0) {
115
+ return dayKey;
116
+ }
117
+ const date = new Date(2e3, 0, 2 + index);
118
+ return new Intl.DateTimeFormat(locale, { weekday: "long" }).format(date);
119
+ }
120
+ var DEFAULT_STATUS_LABELS = { open: "\u041E\u0442\u043A\u0440\u044B\u0442\u043E", closed: "\u0417\u0430\u043A\u0440\u044B\u0442\u043E" };
121
+ var STATUS_LABELS = {
122
+ "ru-RU": DEFAULT_STATUS_LABELS,
123
+ "en-US": { open: "Open", closed: "Closed" }
124
+ };
125
+ function getTodayInfo(schedule) {
126
+ if (!schedule) return null;
127
+ const todayDay = schedule.days[schedule.day_id];
128
+ return {
129
+ isOpenNow: schedule.is_open_now,
130
+ todayHours: todayDay?.hours ?? null,
131
+ openingAt: schedule.opening_at,
132
+ closingAt: schedule.closing_at
133
+ };
134
+ }
135
+ function getWeeklySchedule(schedule, locale = "ru-RU") {
136
+ if (!schedule) return [];
137
+ return DAY_ORDER.map((dayKey) => ({
138
+ dayKey,
139
+ name: getDayName(dayKey, locale),
140
+ hours: schedule.days[dayKey]?.hours ?? null
141
+ }));
142
+ }
143
+ function formatScheduleStatus(schedule, locale = "ru-RU") {
144
+ if (!schedule) return null;
145
+ const labels = STATUS_LABELS[locale] ?? DEFAULT_STATUS_LABELS;
146
+ return schedule.is_open_now ? labels.open : labels.closed;
147
+ }
148
+
149
+ // src/utils/qr.ts
150
+ function buildQrCodeUrl(target, apiBaseUrl, size = 200) {
151
+ if (!target) return "";
152
+ const utf8 = encodeBase64(new TextEncoder().encode(target));
153
+ return `${apiBaseUrl}/media/qrcode?content=${utf8}&input=base64&size=${size}`;
154
+ }
155
+ var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
156
+ function encodeBase64(bytes) {
157
+ let output = "";
158
+ for (let index = 0; index < bytes.length; index += 3) {
159
+ const first = bytes[index] ?? 0;
160
+ const second = bytes[index + 1];
161
+ const third = bytes[index + 2];
162
+ const group = first << 16 | (second ?? 0) << 8 | (third ?? 0);
163
+ output += BASE64_ALPHABET[group >> 18 & 63];
164
+ output += BASE64_ALPHABET[group >> 12 & 63];
165
+ output += second === void 0 ? "=" : BASE64_ALPHABET[group >> 6 & 63];
166
+ output += third === void 0 ? "=" : BASE64_ALPHABET[group & 63];
167
+ }
168
+ return output;
169
+ }
170
+
171
+ // src/utils/date.ts
172
+ function formatDate(date) {
173
+ return new Date(date).toLocaleDateString("ru-RU", {
174
+ day: "numeric",
175
+ month: "long",
176
+ year: "numeric"
177
+ });
178
+ }
179
+ function formatDateTime(date) {
180
+ const d = new Date(date);
181
+ const datePart = d.toLocaleDateString("ru-RU", {
182
+ day: "2-digit",
183
+ month: "2-digit",
184
+ year: "numeric"
185
+ });
186
+ const timePart = d.toLocaleTimeString("ru-RU", {
187
+ hour: "2-digit",
188
+ minute: "2-digit"
189
+ });
190
+ return `${datePart} ${timePart}`;
191
+ }
192
+ function toDateInputValue(value) {
193
+ if (!value) return "";
194
+ return value.slice(0, 10);
195
+ }
196
+ function todayInTimezone(timezone) {
197
+ const now = /* @__PURE__ */ new Date();
198
+ const options = {
199
+ year: "numeric",
200
+ month: "2-digit",
201
+ day: "2-digit"
202
+ };
203
+ if (timezone) {
204
+ options.timeZone = timezone;
205
+ }
206
+ try {
207
+ return new Intl.DateTimeFormat("en-CA", options).format(now);
208
+ } catch {
209
+ return new Intl.DateTimeFormat("en-CA").format(now);
210
+ }
211
+ }
212
+
213
+ // src/utils/pluralize.ts
214
+ function pluralize(count, one, few, many) {
215
+ const abs = Math.abs(count);
216
+ const mod10 = abs % 10;
217
+ const mod100 = abs % 100;
218
+ if (mod100 >= 11 && mod100 <= 19) return many;
219
+ if (mod10 === 1) return one;
220
+ if (mod10 >= 2 && mod10 <= 4) return few;
221
+ return many;
222
+ }
223
+ function getApiErrorMessage(e, fallback) {
224
+ if (e instanceof ZenkyError && e.err?.message) {
225
+ return e.err.message;
226
+ }
227
+ return fallback;
228
+ }
229
+ function getApiFieldErrors(e) {
230
+ if (e instanceof ZenkyError && e.err?.meta?.errors) {
231
+ return e.err.meta.errors;
232
+ }
233
+ return null;
234
+ }
235
+
236
+ // src/utils/address.ts
237
+ function formatAddressCityLast(raw) {
238
+ const match = raw.match(/^(г\s[^,]+),\s*(.+)$/);
239
+ return match ? `${match[2]}, ${match[1]}` : raw;
240
+ }
241
+
242
+ export { buildQrCodeUrl, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, pluralize, toDateInputValue, todayInTimezone };
243
+ //# sourceMappingURL=chunk-MZ66ARDL.js.map
244
+ //# sourceMappingURL=chunk-MZ66ARDL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/createOperationChain.ts","../src/utils/phone.ts","../src/utils/contacts.ts","../src/utils/schedule.ts","../src/utils/qr.ts","../src/utils/date.ts","../src/utils/pluralize.ts","../src/utils/errors.ts","../src/utils/address.ts"],"names":[],"mappings":"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","file":"chunk-MZ66ARDL.js","sourcesContent":["// Сериализует async-операции по ключу: для каждого key гарантирует,\n// что следующая операция начнётся только после завершения предыдущей.\n// Предотвращает гонки при параллельных запросах на один ресурс.\n\nexport interface OperationChain {\n execute: (key: string, fn: () => Promise<void>) => Promise<void>\n readonly size: number\n}\n\nexport function createOperationChain(): OperationChain {\n const chains = new Map<string, Promise<void>>()\n\n async function execute(key: string, fn: () => Promise<void>): Promise<void> {\n const prev = chains.get(key) ?? Promise.resolve()\n\n const current = prev.then(fn)\n\n // catch предотвращает unhandled rejection в цепочке\n const safe = current.catch(() => {})\n chains.set(key, safe)\n\n // Чистим запись, если после завершения не было новых операций\n safe.finally(() => {\n if (chains.get(key) === safe) {\n chains.delete(key)\n }\n })\n\n return current\n }\n\n return {\n execute,\n get size() {\n return chains.size\n },\n }\n}\n","import type { Phone } from '@zenky/storefront-api'\n\nexport function formatPhoneNational(phone: Phone | null | undefined): string | null {\n if (!phone) return null\n\n return phone.national || phone.number\n}\n\nexport function getPhoneTelLink(phone: Phone | null | undefined): string | null {\n if (!phone) return null\n\n return `tel:${phone.number}`\n}\n\n/**\n * «Воздушный» формат номера: `+7 (999) 999-99-99` → `+7 999 999 99 99`.\n * Скобки и дефисы заменяются на пробелы, лишние пробелы схлопываются.\n */\nexport function formatPhoneSpaced(formatted: string | null | undefined): string {\n if (!formatted) return ''\n\n return formatted.replace(/[()-]/g, ' ').replace(/\\s+/g, ' ').trim()\n}\n","import { ContactType } from '@zenky/storefront-api'\n\nimport type { Contact } from '@zenky/storefront-api'\n\nexport interface SocialLink {\n type: ContactType\n url: string\n label: string\n}\n\nconst SOCIAL_TYPES = new Set<ContactType>([\n ContactType.Vk,\n ContactType.Instagram,\n ContactType.Facebook,\n ContactType.Twitter,\n ContactType.Ok,\n ContactType.Tiktok,\n ContactType.Telegram,\n ContactType.Max,\n])\n\nconst SOCIAL_LABELS: Record<string, string> = {\n [ContactType.Vk]: 'ВКонтакте',\n [ContactType.Instagram]: 'Instagram',\n [ContactType.Facebook]: 'Facebook',\n [ContactType.Twitter]: 'Twitter',\n [ContactType.Ok]: 'Одноклассники',\n [ContactType.Tiktok]: 'TikTok',\n [ContactType.Telegram]: 'Telegram',\n [ContactType.Max]: 'Max',\n} as const\n\nfunction buildSocialUrl(type: ContactType, value: string): string {\n if (value.startsWith('http://') || value.startsWith('https://')) {\n return value\n }\n\n const bases: Partial<Record<ContactType, string>> = {\n [ContactType.Vk]: 'https://vk.com/',\n [ContactType.Instagram]: 'https://instagram.com/',\n [ContactType.Facebook]: 'https://facebook.com/',\n [ContactType.Twitter]: 'https://x.com/',\n [ContactType.Ok]: 'https://ok.ru/',\n [ContactType.Tiktok]: 'https://tiktok.com/@',\n [ContactType.Telegram]: 'https://t.me/',\n [ContactType.Max]: 'https://max.ru/',\n }\n\n const base = bases[type]\n\n return base ? `${base}${value}` : value\n}\n\nexport function getSocialLinks(contacts: Contact[]): SocialLink[] {\n return contacts\n .filter((contact) => SOCIAL_TYPES.has(contact.type))\n .map((contact) => ({\n type: contact.type,\n url: buildSocialUrl(contact.type, contact.value),\n label: SOCIAL_LABELS[contact.type] ?? contact.type,\n }))\n}\n\nexport function getEmailLink(contacts: Contact[]): string | null {\n const email = contacts.find((c) => c.type === ContactType.Email)\n\n return email?.value ?? null\n}\n\nexport function getWebsiteLink(contacts: Contact[]): string | null {\n const website = contacts.find((c) => c.type === ContactType.Website)\n\n return website?.value ?? null\n}\n","import type { Schedule } from '@zenky/storefront-api'\n\nexport interface DayScheduleInfo {\n dayKey: string\n name: string\n hours: string | null\n}\n\nexport interface TodayScheduleInfo {\n isOpenNow: boolean\n todayHours: string | null\n openingAt: string | null\n closingAt: string | null\n}\n\n// Маппинг ключей API → индекс дня JS (0=вс, 1=пн, ..., 6=сб)\nconst DAY_TO_JS_INDEX: Record<string, number> = {\n sunday: 0,\n monday: 1,\n tuesday: 2,\n wednesday: 3,\n thursday: 4,\n friday: 5,\n saturday: 6,\n} as const\n\nconst DAY_ORDER = [\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n 'sunday',\n] as const\n\n// Опорная дата: 2 января 2000 — это воскресенье (JS index 0).\n// Для dayIndex=0 (вс) прибавляем 0, для 1 (пн) прибавляем 1, и т.д.\nfunction getDayName(dayKey: string, locale: string): string {\n const index = DAY_TO_JS_INDEX[dayKey]\n\n if (index === undefined) {\n return dayKey\n }\n\n const date = new Date(2000, 0, 2 + index)\n\n return new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(date)\n}\n\ninterface StatusLabels {\n open: string\n closed: string\n}\n\nconst DEFAULT_STATUS_LABELS: StatusLabels = { open: 'Открыто', closed: 'Закрыто' }\n\nconst STATUS_LABELS: Record<string, StatusLabels> = {\n 'ru-RU': DEFAULT_STATUS_LABELS,\n 'en-US': { open: 'Open', closed: 'Closed' },\n}\n\nexport function getTodayInfo(schedule: Schedule | null | undefined): TodayScheduleInfo | null {\n if (!schedule) return null\n\n const todayDay = schedule.days[schedule.day_id as keyof typeof schedule.days]\n\n return {\n isOpenNow: schedule.is_open_now,\n todayHours: todayDay?.hours ?? null,\n openingAt: schedule.opening_at,\n closingAt: schedule.closing_at,\n }\n}\n\nexport function getWeeklySchedule(\n schedule: Schedule | null | undefined,\n locale = 'ru-RU'\n): DayScheduleInfo[] {\n if (!schedule) return []\n\n return DAY_ORDER.map((dayKey) => ({\n dayKey,\n name: getDayName(dayKey, locale),\n hours: schedule.days[dayKey]?.hours ?? null,\n }))\n}\n\nexport function formatScheduleStatus(\n schedule: Schedule | null | undefined,\n locale = 'ru-RU'\n): string | null {\n if (!schedule) return null\n\n const labels = STATUS_LABELS[locale] ?? DEFAULT_STATUS_LABELS\n\n return schedule.is_open_now ? labels.open : labels.closed\n}\n","/**\n * Генерирует URL картинки QR-кода через Zenky media API.\n *\n * Контент кодируется в base64 и передаётся в query `content`.\n * Реализация не зависит от `window`, `btoa` или Node.js `Buffer`, поэтому один\n * и тот же код работает в браузере, Node SSR и edge runtimes.\n */\nexport function buildQrCodeUrl(target: string, apiBaseUrl: string, size = 200): string {\n if (!target) return ''\n\n const utf8 = encodeBase64(new TextEncoder().encode(target))\n\n return `${apiBaseUrl}/media/qrcode?content=${utf8}&input=base64&size=${size}`\n}\n\nconst BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'\n\nfunction encodeBase64(bytes: Uint8Array): string {\n let output = ''\n\n for (let index = 0; index < bytes.length; index += 3) {\n const first = bytes[index] ?? 0\n const second = bytes[index + 1]\n const third = bytes[index + 2]\n const group = (first << 16) | ((second ?? 0) << 8) | (third ?? 0)\n\n output += BASE64_ALPHABET[(group >> 18) & 63]\n output += BASE64_ALPHABET[(group >> 12) & 63]\n output += second === undefined ? '=' : BASE64_ALPHABET[(group >> 6) & 63]\n output += third === undefined ? '=' : BASE64_ALPHABET[group & 63]\n }\n\n return output\n}\n","export function formatDate(date: string): string {\n return new Date(date).toLocaleDateString('ru-RU', {\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n })\n}\n\nexport function formatDateTime(date: string): string {\n const d = new Date(date)\n const datePart = d.toLocaleDateString('ru-RU', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n })\n const timePart = d.toLocaleTimeString('ru-RU', {\n hour: '2-digit',\n minute: '2-digit',\n })\n return `${datePart} ${timePart}`\n}\n\n/**\n * Извлекает YYYY-MM-DD из ISO-строки (например \"1998-06-02T03:00:00+03:00\" → \"1998-06-02\").\n * Для использования в <input type=\"date\">.\n */\nexport function toDateInputValue(value: string | null): string {\n if (!value) return ''\n return value.slice(0, 10)\n}\n\n/**\n * Сегодняшняя дата в указанном часовом поясе в формате YYYY-MM-DD.\n * Если TZ невалидный или не передан — возвращает дату в локальном TZ браузера.\n *\n * Используется, когда нужно сопоставить «сегодня» с датой из бэка, которая\n * приходит относительно TZ магазина (а не TZ пользователя).\n */\nexport function todayInTimezone(timezone?: string | null): string {\n const now = new Date()\n\n const options: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }\n\n // timeZone добавляем только если задан: под exactOptionalPropertyTypes\n // нельзя присвоить undefined опциональному свойству.\n if (timezone) {\n options.timeZone = timezone\n }\n\n try {\n return new Intl.DateTimeFormat('en-CA', options).format(now)\n } catch {\n // Невалидный TZ — fallback на локальный\n return new Intl.DateTimeFormat('en-CA').format(now)\n }\n}\n","/**\n * Склонение существительных по числу (русский язык).\n *\n * @example\n * pluralize(1, 'позиция', 'позиции', 'позиций') // 'позиция'\n * pluralize(3, 'позиция', 'позиции', 'позиций') // 'позиции'\n * pluralize(5, 'позиция', 'позиции', 'позиций') // 'позиций'\n */\nexport function pluralize(count: number, one: string, few: string, many: string): string {\n const abs = Math.abs(count)\n const mod10 = abs % 10\n const mod100 = abs % 100\n\n if (mod100 >= 11 && mod100 <= 19) return many\n if (mod10 === 1) return one\n if (mod10 >= 2 && mod10 <= 4) return few\n\n return many\n}\n","import { ZenkyError } from '@zenky/storefront-api'\n\n/** Сообщение из ZenkyError (или fallback). */\nexport function getApiErrorMessage(e: unknown, fallback: string): string {\n if (e instanceof ZenkyError && e.err?.message) {\n return e.err.message\n }\n\n return fallback\n}\n\n/** Field-level ошибки из `meta.errors` ответа API (422 validation). */\nexport function getApiFieldErrors(e: unknown): Record<string, string[]> | null {\n if (e instanceof ZenkyError && e.err?.meta?.errors) {\n return e.err.meta.errors as Record<string, string[]>\n }\n\n return null\n}\n","/**\n * Переносит город в конец строки адреса.\n * \"г Улан-Удэ, ул Ленина, д 29\" → \"ул Ленина, д 29, г Улан-Удэ\"\n */\nexport function formatAddressCityLast(raw: string): string {\n const match = raw.match(/^(г\\s[^,]+),\\s*(.+)$/)\n\n return match ? `${match[2]}, ${match[1]}` : raw\n}\n"]}
@@ -0,0 +1,111 @@
1
+ import { usePromotionsStore } from './chunk-BWUKMWHL.js';
2
+ import { useAuthStore, useStoreProfileStore } from './chunk-TEG7EL4N.js';
3
+ import { useCartStore } from './chunk-FFBZKQRV.js';
4
+ import { useRuntime } from './chunk-V3VVDQIR.js';
5
+ import { ref } from 'vue';
6
+
7
+ var KEY_ORDER_ID = "zenky_order_id";
8
+ var KEY_ORDER_TOKEN = "zenky_order_token";
9
+ var WEEK_SECONDS = 60 * 60 * 24 * 7;
10
+ var ORDER_STATUS_PENDING = "pending";
11
+ function useCartCredentials() {
12
+ const { storage } = useRuntime();
13
+ const cartStore = useCartStore();
14
+ const authStore = useAuthStore();
15
+ const profileStore = useStoreProfileStore();
16
+ const orderIdRef = ref(storage.get(KEY_ORDER_ID));
17
+ const orderTokenRef = ref(storage.get(KEY_ORDER_TOKEN));
18
+ function getStoreId() {
19
+ if (!profileStore.store) {
20
+ throw new Error("Store is not initialized.");
21
+ }
22
+ return profileStore.store.id;
23
+ }
24
+ function getCityId() {
25
+ if (!profileStore.city) {
26
+ throw new Error("City is not initialized.");
27
+ }
28
+ return profileStore.city.id;
29
+ }
30
+ function getApiToken() {
31
+ return authStore.isAuthenticated ? authStore.token ?? void 0 : void 0;
32
+ }
33
+ function buildCredentials(orderId, orderToken) {
34
+ const credentials = {
35
+ id: orderId,
36
+ token: orderToken
37
+ };
38
+ const apiToken = getApiToken();
39
+ if (apiToken) {
40
+ credentials.api_token = apiToken;
41
+ }
42
+ return credentials;
43
+ }
44
+ function getCredentials() {
45
+ if (!cartStore.credentials) {
46
+ throw new Error("Cart has no credentials.");
47
+ }
48
+ return buildCredentials(cartStore.credentials.id, cartStore.credentials.token);
49
+ }
50
+ function persistCredentials(savedOrder) {
51
+ orderIdRef.value = savedOrder.id;
52
+ orderTokenRef.value = savedOrder.token;
53
+ storage.set(KEY_ORDER_ID, savedOrder.id, { maxAge: WEEK_SECONDS });
54
+ storage.set(KEY_ORDER_TOKEN, savedOrder.token, { maxAge: WEEK_SECONDS });
55
+ }
56
+ function clearPersistedCredentials() {
57
+ orderIdRef.value = null;
58
+ orderTokenRef.value = null;
59
+ storage.remove(KEY_ORDER_ID);
60
+ storage.remove(KEY_ORDER_TOKEN);
61
+ }
62
+ function isOrderActive(existingOrder) {
63
+ if (!existingOrder.status) return true;
64
+ return String(existingOrder.status.kind) === ORDER_STATUS_PENDING;
65
+ }
66
+ return {
67
+ orderIdCookie: orderIdRef,
68
+ orderTokenCookie: orderTokenRef,
69
+ getStoreId,
70
+ getCityId,
71
+ getApiToken,
72
+ buildCredentials,
73
+ getCredentials,
74
+ persistCredentials,
75
+ clearPersistedCredentials,
76
+ isOrderActive
77
+ };
78
+ }
79
+
80
+ // src/promotions/usePromotionsChecker.ts
81
+ var WS_RESPONSE_TIMEOUT_MS = 5e3;
82
+ function usePromotionsChecker() {
83
+ const { sdk, events } = useRuntime();
84
+ const cartStore = useCartStore();
85
+ const profileStore = useStoreProfileStore();
86
+ const promotionsStore = usePromotionsStore();
87
+ const credentials = useCartCredentials();
88
+ async function dispatchCheck() {
89
+ if (!cartStore.hasOrder || promotionsStore.checking) return;
90
+ const storeId = profileStore.store?.id;
91
+ if (!storeId) return;
92
+ promotionsStore.setChecking(true);
93
+ promotionsStore.clearRewards();
94
+ events?.get()?.promotionsCheckerStarted({ order: cartStore.order });
95
+ try {
96
+ const creds = credentials.getCredentials();
97
+ await sdk.orders.dispatchPromotionsChecker(storeId, creds);
98
+ setTimeout(() => {
99
+ if (promotionsStore.checking) promotionsStore.setChecking(false);
100
+ }, WS_RESPONSE_TIMEOUT_MS);
101
+ } catch (e) {
102
+ console.error("[promotions] check failed", e);
103
+ promotionsStore.setChecking(false);
104
+ }
105
+ }
106
+ return { dispatchCheck };
107
+ }
108
+
109
+ export { useCartCredentials, usePromotionsChecker };
110
+ //# sourceMappingURL=chunk-N3NOTJUC.js.map
111
+ //# sourceMappingURL=chunk-N3NOTJUC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cart/useCartCredentials.ts","../src/promotions/usePromotionsChecker.ts"],"names":[],"mappings":"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","file":"chunk-N3NOTJUC.js","sourcesContent":["import { ref, type Ref } from 'vue'\n\nimport type { Order, OrderCredentials } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { useAuthStore } from '../stores/auth'\nimport { useCartStore } from '../stores/cart'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nconst KEY_ORDER_ID = 'zenky_order_id'\nconst KEY_ORDER_TOKEN = 'zenky_order_token'\nconst WEEK_SECONDS = 60 * 60 * 24 * 7\n\n// app-энум OrderStatusKind.Pending = 'pending'.\nconst ORDER_STATUS_PENDING = 'pending'\n\nexport interface CartCredentials {\n orderIdCookie: Ref<string | null>\n orderTokenCookie: Ref<string | null>\n getStoreId: () => string\n getCityId: () => string\n getApiToken: () => string | undefined\n buildCredentials: (orderId: string, orderToken: string) => OrderCredentials\n getCredentials: () => OrderCredentials\n persistCredentials: (savedOrder: Order) => void\n clearPersistedCredentials: () => void\n isOrderActive: (order: Order) => boolean\n}\n\n/**\n * Управление credentials заказа. Персистенс order-id/token — через порт `storage`\n * (ядро не знает про useCookie). Рефы инициализируются из storage, persist пишет в оба.\n */\nexport function useCartCredentials(): CartCredentials {\n const { storage } = useRuntime()\n const cartStore = useCartStore()\n const authStore = useAuthStore()\n const profileStore = useStoreProfileStore()\n\n const orderIdRef = ref<string | null>(storage.get(KEY_ORDER_ID))\n const orderTokenRef = ref<string | null>(storage.get(KEY_ORDER_TOKEN))\n\n function getStoreId(): string {\n if (!profileStore.store) {\n throw new Error('Store is not initialized.')\n }\n\n return profileStore.store.id\n }\n\n function getCityId(): string {\n if (!profileStore.city) {\n throw new Error('City is not initialized.')\n }\n\n return profileStore.city.id\n }\n\n function getApiToken(): string | undefined {\n return authStore.isAuthenticated ? (authStore.token ?? undefined) : undefined\n }\n\n function buildCredentials(orderId: string, orderToken: string): OrderCredentials {\n const credentials: OrderCredentials = {\n id: orderId,\n token: orderToken,\n }\n\n const apiToken = getApiToken()\n\n if (apiToken) {\n credentials.api_token = apiToken\n }\n\n return credentials\n }\n\n function getCredentials(): OrderCredentials {\n if (!cartStore.credentials) {\n throw new Error('Cart has no credentials.')\n }\n\n return buildCredentials(cartStore.credentials.id, cartStore.credentials.token)\n }\n\n function persistCredentials(savedOrder: Order): void {\n orderIdRef.value = savedOrder.id\n orderTokenRef.value = savedOrder.token\n storage.set(KEY_ORDER_ID, savedOrder.id, { maxAge: WEEK_SECONDS })\n storage.set(KEY_ORDER_TOKEN, savedOrder.token, { maxAge: WEEK_SECONDS })\n }\n\n function clearPersistedCredentials(): void {\n orderIdRef.value = null\n orderTokenRef.value = null\n storage.remove(KEY_ORDER_ID)\n storage.remove(KEY_ORDER_TOKEN)\n }\n\n function isOrderActive(existingOrder: Order): boolean {\n if (!existingOrder.status) return true\n\n return String(existingOrder.status.kind) === ORDER_STATUS_PENDING\n }\n\n return {\n orderIdCookie: orderIdRef,\n orderTokenCookie: orderTokenRef,\n getStoreId,\n getCityId,\n getApiToken,\n buildCredentials,\n getCredentials,\n persistCredentials,\n clearPersistedCredentials,\n isOrderActive,\n }\n}\n","import { useRuntime } from '../ports/runtime'\nimport { useCartCredentials } from '../cart/useCartCredentials'\nimport { useCartStore } from '../stores/cart'\nimport { usePromotionsStore } from '../stores/promotions'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nexport interface PromotionsChecker {\n dispatchCheck: () => Promise<void>\n}\n\n/** Таймаут — если WS не ответил, сбросить флаг checking. */\nconst WS_RESPONSE_TIMEOUT_MS = 5000\n\n/**\n * Проверка промо-акций. Вызывает dispatchPromotionsChecker после изменения корзины.\n * Результат приходит через WebSocket (обрабатывается в useOrderChannel).\n */\nexport function usePromotionsChecker(): PromotionsChecker {\n const { sdk, events } = useRuntime()\n const cartStore = useCartStore()\n const profileStore = useStoreProfileStore()\n const promotionsStore = usePromotionsStore()\n const credentials = useCartCredentials()\n\n async function dispatchCheck(): Promise<void> {\n if (!cartStore.hasOrder || promotionsStore.checking) return\n\n const storeId = profileStore.store?.id\n if (!storeId) return\n\n promotionsStore.setChecking(true)\n promotionsStore.clearRewards() // Очистить старые — WS заново наполнит актуальные\n events?.get()?.promotionsCheckerStarted({ order: cartStore.order })\n\n try {\n const creds = credentials.getCredentials()\n await sdk.orders.dispatchPromotionsChecker(storeId, creds)\n\n setTimeout(() => {\n if (promotionsStore.checking) promotionsStore.setChecking(false)\n }, WS_RESPONSE_TIMEOUT_MS)\n } catch (e: unknown) {\n console.error('[promotions] check failed', e)\n promotionsStore.setChecking(false)\n }\n }\n\n return { dispatchCheck }\n}\n"]}
@@ -0,0 +1,36 @@
1
+ // src/money/money.ts
2
+ var asMinor = (value) => value;
3
+ var asMajor = (value) => value;
4
+ function getMinorFactor(currency) {
5
+ const fractionDigits = new Intl.NumberFormat("en", {
6
+ style: "currency",
7
+ currency
8
+ }).resolvedOptions().maximumFractionDigits ?? 2;
9
+ return 10 ** fractionDigits;
10
+ }
11
+ var DEFAULT_LOCALE = "ru-RU";
12
+ function formatPrice(value, currency = "RUB", locale = DEFAULT_LOCALE) {
13
+ if (!value && value !== 0) {
14
+ return "";
15
+ }
16
+ return new Intl.NumberFormat(locale, {
17
+ style: "currency",
18
+ currency,
19
+ minimumFractionDigits: 0
20
+ }).format(value / getMinorFactor(currency));
21
+ }
22
+ function minorToMajor(value, currency = "RUB") {
23
+ return value / getMinorFactor(currency);
24
+ }
25
+ function majorToMinor(value, currency = "RUB") {
26
+ return Math.round(value * getMinorFactor(currency));
27
+ }
28
+ function minorToMajorString(value, currency = "RUB") {
29
+ const factor = getMinorFactor(currency);
30
+ const major = value / factor;
31
+ return major.toFixed(Math.log10(factor));
32
+ }
33
+
34
+ export { asMajor, asMinor, formatPrice, majorToMinor, minorToMajor, minorToMajorString };
35
+ //# sourceMappingURL=chunk-RO25KNM5.js.map
36
+ //# sourceMappingURL=chunk-RO25KNM5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/money/money.ts"],"names":[],"mappings":";AAmBO,IAAM,OAAA,GAAU,CAAC,KAAA,KAAyB;AAE1C,IAAM,OAAA,GAAU,CAAC,KAAA,KAAyB;AAQjD,SAAS,eAAe,QAAA,EAA0B;AAC9C,EAAA,MAAM,cAAA,GACF,IAAI,IAAA,CAAK,YAAA,CAAa,IAAA,EAAM;AAAA,IACxB,KAAA,EAAO,UAAA;AAAA,IACP;AAAA,GACH,CAAA,CAAE,eAAA,EAAgB,CAAE,qBAAA,IAAyB,CAAA;AAClD,EAAA,OAAO,EAAA,IAAM,cAAA;AACjB;AAMA,IAAM,cAAA,GAAiB,OAAA;AAKhB,SAAS,WAAA,CACZ,KAAA,EACA,QAAA,GAAW,KAAA,EACX,SAAiB,cAAA,EACX;AACN,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,KAAU,CAAA,EAAG;AACvB,IAAA,OAAO,EAAA;AAAA,EACX;AAEA,EAAA,OAAO,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ;AAAA,IACjC,KAAA,EAAO,UAAA;AAAA,IACP,QAAA;AAAA,IACA,qBAAA,EAAuB;AAAA,GAC1B,CAAA,CAAE,MAAA,CAAO,KAAA,GAAQ,cAAA,CAAe,QAAQ,CAAC,CAAA;AAC9C;AAGO,SAAS,YAAA,CAAa,KAAA,EAAe,QAAA,GAAW,KAAA,EAAe;AAClE,EAAA,OAAO,KAAA,GAAQ,eAAe,QAAQ,CAAA;AAC1C;AAGO,SAAS,YAAA,CAAa,KAAA,EAAe,QAAA,GAAW,KAAA,EAAe;AAClE,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,cAAA,CAAe,QAAQ,CAAC,CAAA;AACtD;AAKO,SAAS,kBAAA,CAAmB,KAAA,EAAe,QAAA,GAAW,KAAA,EAAe;AACxE,EAAA,MAAM,MAAA,GAAS,eAAe,QAAQ,CAAA;AACtC,EAAA,MAAM,QAAQ,KAAA,GAAQ,MAAA;AACtB,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAA;AAC3C","file":"chunk-RO25KNM5.js","sourcesContent":["// Денежные единицы. Золотое правило Zenky:\n// • храним и считаем в МИНОРНЫХ единицах (копейки/тыйны/…) — так отдаёт API;\n// • на часть API-эндпоинтов шлём в МАЖОРНЫХ (рубли) числом или строкой.\n//\n// Compat-функции ниже имеют те же сигнатуры, что и app/storefront/utils/price.ts —\n// это drop-in замена (не ломает call-site при переносе).\n\n// ── Branded types (opt-in, для нового кода) ────────────────────────────────\n// Minor и Major — разные типы, компилятор не даст их перепутать:\n// sendToServer(bill: Minor) ← передать Major = ошибка компиляции.\ndeclare const MINOR: unique symbol\ndeclare const MAJOR: unique symbol\n\n/** Сумма в минорных единицах (копейки). Так хранит и отдаёт API. */\nexport type Minor = number & { readonly [MINOR]: true }\n/** Сумма в мажорных единицах (рубли). В таком виде их ждёт часть API. */\nexport type Major = number & { readonly [MAJOR]: true }\n\n/** Помечает сырое число с API как Minor (assert без рантайм-стоимости). */\nexport const asMinor = (value: number): Minor => value as Minor\n/** Помечает число как Major. */\nexport const asMajor = (value: number): Major => value as Major\n\n// ── Currency helpers ────────────────────────────────────────────────────────\n\n/**\n * Множитель минор→мажор по ISO-коду валюты через Intl (без хардкода справочников):\n * RUB/KZT/THB/EUR/USD = ×100, JPY/KRW = ×1, KWD/BHD/OMR = ×1000.\n */\nfunction getMinorFactor(currency: string): number {\n const fractionDigits =\n new Intl.NumberFormat('en', {\n style: 'currency',\n currency,\n }).resolvedOptions().maximumFractionDigits ?? 2\n return 10 ** fractionDigits\n}\n\n/**\n * Дефолтная локаль форматирования. Влияет на разделители (1 290 ₽ vs 1,290 ₽).\n * `ru-RU` подходит для RU/KZ/BY/UA. Для TH/JP/ENG передавай `locale` аргументом.\n */\nconst DEFAULT_LOCALE = 'ru-RU' as const\n\n// ── Compat API (прежние сигнатуры на number — drop-in) ──────────────────────\n\n/** Форматирует цену из минорных единиц в читаемый вид (`1 290 ₽`). */\nexport function formatPrice(\n value?: number | null,\n currency = 'RUB',\n locale: string = DEFAULT_LOCALE\n): string {\n if (!value && value !== 0) {\n return ''\n }\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n }).format(value / getMinorFactor(currency))\n}\n\n/** Сырая конвертация минор → мажор (копейки → рубли) без форматирования. */\nexport function minorToMajor(value: number, currency = 'RUB'): number {\n return value / getMinorFactor(currency)\n}\n\n/** Сырая конвертация мажор → минор (рубли → копейки), округление до целого. */\nexport function majorToMinor(value: number, currency = 'RUB'): number {\n return Math.round(value * getMinorFactor(currency))\n}\n\n/**\n * Минор → мажор строкой. API payments/bonuses ждёт сумму строкой в рублях `\"103.50\"`.\n */\nexport function minorToMajorString(value: number, currency = 'RUB'): string {\n const factor = getMinorFactor(currency)\n const major = value / factor\n return major.toFixed(Math.log10(factor))\n}\n"]}