@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,102 @@
1
+ // src/catalog/findCategory.ts
2
+ function findCategoryByShortId(tree, shortId) {
3
+ for (const cat of tree) {
4
+ if (cat.short_id === shortId) return cat;
5
+ if (cat.children && cat.children.length > 0) {
6
+ const found = findCategoryByShortId(cat.children, shortId);
7
+ if (found) return found;
8
+ }
9
+ }
10
+ return null;
11
+ }
12
+ function findRootAncestor(tree, category) {
13
+ if (!category.parent_id) {
14
+ return tree.find((c) => c.id === category.id) ?? category;
15
+ }
16
+ const parent = findCategoryById(tree, category.parent_id);
17
+ if (!parent) return null;
18
+ return findRootAncestor(tree, parent);
19
+ }
20
+ function findCategoryById(tree, id) {
21
+ for (const cat of tree) {
22
+ if (cat.id === id) return cat;
23
+ if (cat.children && cat.children.length > 0) {
24
+ const found = findCategoryById(cat.children, id);
25
+ if (found) return found;
26
+ }
27
+ }
28
+ return null;
29
+ }
30
+ function getCategoryPath(tree, target) {
31
+ const path = [];
32
+ let current = target;
33
+ while (current) {
34
+ path.unshift(current);
35
+ if (!current.parent_id) break;
36
+ current = findCategoryById(tree, current.parent_id);
37
+ }
38
+ return path;
39
+ }
40
+
41
+ // src/catalog/groupBySubcategory.ts
42
+ function collectDescendantIds(category) {
43
+ const ids = [category.id];
44
+ for (const child of category.children ?? []) ids.push(...collectDescendantIds(child));
45
+ return ids;
46
+ }
47
+ function productCategoryIds(product) {
48
+ const categories = product.categories;
49
+ return categories?.map((c) => c.id) ?? [];
50
+ }
51
+ function collectSubtreeProducts(category, products, order) {
52
+ const seen = /* @__PURE__ */ new Set();
53
+ const out = [];
54
+ const pushUnique = (list) => {
55
+ for (const p of list) {
56
+ if (!seen.has(p.id)) {
57
+ seen.add(p.id);
58
+ out.push(p);
59
+ }
60
+ }
61
+ };
62
+ pushUnique(
63
+ products.filter((p) => productCategoryIds(p).includes(category.id)).sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0))
64
+ );
65
+ for (const child of category.children ?? []) {
66
+ pushUnique(collectSubtreeProducts(child, products, order));
67
+ }
68
+ return out;
69
+ }
70
+ function groupProductsBySubcategory(rootCategory, products) {
71
+ const order = new Map(products.map((p, i) => [p.id, i]));
72
+ const rootDirect = products.filter((p) => productCategoryIds(p).includes(rootCategory.id));
73
+ const groups = [];
74
+ for (const child of rootCategory.children ?? []) {
75
+ const groupProducts = collectSubtreeProducts(child, products, order);
76
+ if (groupProducts.length > 0) groups.push({ category: child, products: groupProducts });
77
+ }
78
+ return { rootDirect, groups };
79
+ }
80
+
81
+ // src/catalog/useCollections.ts
82
+ function useCollections(sdk) {
83
+ async function loadCollections(storeId, request) {
84
+ const response = await sdk.collections.getCollections(storeId, request);
85
+ return response.items;
86
+ }
87
+ return { loadCollections };
88
+ }
89
+
90
+ // src/catalog/routes.ts
91
+ var catalogRoutes = {
92
+ /** Корневая страница каталога: список категорий + коллекций */
93
+ index: () => "/catalog",
94
+ /** Страница конкретной категории */
95
+ category: (shortId, slug) => `/catalog/${shortId}/${slug || shortId}`,
96
+ /** Страница конкретной коллекции */
97
+ collection: (id) => `/collections/${id}`
98
+ };
99
+
100
+ export { catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections };
101
+ //# sourceMappingURL=chunk-RYYY7MVP.js.map
102
+ //# sourceMappingURL=chunk-RYYY7MVP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/catalog/findCategory.ts","../src/catalog/groupBySubcategory.ts","../src/catalog/useCollections.ts","../src/catalog/routes.ts"],"names":[],"mappings":"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","file":"chunk-RYYY7MVP.js","sourcesContent":["import type { NestedCategory } from '@zenky/storefront-api'\n\n/**\n * Рекурсивный поиск категории в дереве по `short_id`.\n *\n * `NestedCategory[]` — это дерево: корневые категории на верхнем уровне,\n * вложенные — внутри `children[]`. Простой `tree.find()` найдёт только\n * корневые. Для вложенных (например «Куртки» внутри «Мужская» внутри «Одежда»)\n * нужно рекурсивно обойти все ветки.\n *\n * Возвращает первое совпадение (DFS pre-order).\n */\nexport function findCategoryByShortId(\n tree: NestedCategory[],\n shortId: string\n): NestedCategory | null {\n for (const cat of tree) {\n if (cat.short_id === shortId) return cat\n if (cat.children && cat.children.length > 0) {\n const found = findCategoryByShortId(cat.children, shortId)\n if (found) return found\n }\n }\n return null\n}\n\n/**\n * Находит корневого предка категории по `parent_id`.\n *\n * Для вложенной «Куртки» (parent: «Мужская») вернёт «Одежда» (корень ветки).\n * Для корневой «Одежда» вернёт саму себя.\n *\n * Используется в `CategoryTabs`, чтобы подсветить корневой таб когда юзер\n * находится на вложенной категории.\n */\nexport function findRootAncestor(\n tree: NestedCategory[],\n category: NestedCategory\n): NestedCategory | null {\n if (!category.parent_id) {\n // Уже корневая — возвращаем её саму если она есть в tree на верхнем уровне\n return tree.find((c) => c.id === category.id) ?? category\n }\n\n // Ищем родителя\n const parent = findCategoryById(tree, category.parent_id)\n if (!parent) return null\n return findRootAncestor(tree, parent)\n}\n\n/** Рекурсивный поиск по `id` (не `short_id`). Используется в findRootAncestor. */\nexport function findCategoryById(tree: NestedCategory[], id: string): NestedCategory | null {\n for (const cat of tree) {\n if (cat.id === id) return cat\n if (cat.children && cat.children.length > 0) {\n const found = findCategoryById(cat.children, id)\n if (found) return found\n }\n }\n return null\n}\n\n/**\n * Возвращает путь от корневой категории до указанной (включительно).\n *\n * Пример для «Куртки» в ветке «Одежда → Мужская → Куртки»:\n * → [Одежда, Мужская, Куртки]\n *\n * Используется для построения хлебных крошек.\n */\nexport function getCategoryPath(tree: NestedCategory[], target: NestedCategory): NestedCategory[] {\n const path: NestedCategory[] = []\n let current: NestedCategory | null = target\n\n while (current) {\n path.unshift(current)\n if (!current.parent_id) break\n current = findCategoryById(tree, current.parent_id)\n }\n\n return path\n}\n","import type { NestedCategory, Product } from '@zenky/storefront-api'\n\nexport interface SubcategoryGroup {\n category: NestedCategory\n products: Product[]\n}\n\nexport interface GroupedProducts {\n rootDirect: Product[]\n groups: SubcategoryGroup[]\n}\n\nexport function collectDescendantIds(category: NestedCategory): string[] {\n const ids = [category.id]\n for (const child of category.children ?? []) ids.push(...collectDescendantIds(child))\n return ids\n}\n\nfunction productCategoryIds(product: Product): string[] {\n const categories = (product as unknown as { categories?: Array<{ id: string }> }).categories\n return categories?.map((c) => c.id) ?? []\n}\n\n/**\n * Товары поддерева в порядке дерева (DFS): сперва товары самой категории\n * (в порядке каталога), затем рекурсивно товары дочерних категорий.\n * Дубли (товар в нескольких категориях) отбрасываем, оставляя первое вхождение.\n */\nfunction collectSubtreeProducts(\n category: NestedCategory,\n products: Product[],\n order: Map<string, number>\n): Product[] {\n const seen = new Set<string>()\n const out: Product[] = []\n\n const pushUnique = (list: Product[]): void => {\n for (const p of list) {\n if (!seen.has(p.id)) {\n seen.add(p.id)\n out.push(p)\n }\n }\n }\n\n pushUnique(\n products\n .filter((p) => productCategoryIds(p).includes(category.id))\n .sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0))\n )\n for (const child of category.children ?? []) {\n pushUnique(collectSubtreeProducts(child, products, order))\n }\n\n return out\n}\n\nexport function groupProductsBySubcategory(\n rootCategory: NestedCategory,\n products: Product[]\n): GroupedProducts {\n const order = new Map(products.map((p, i) => [p.id, i]))\n\n const rootDirect = products.filter((p) => productCategoryIds(p).includes(rootCategory.id))\n\n const groups: SubcategoryGroup[] = []\n for (const child of rootCategory.children ?? []) {\n const groupProducts = collectSubtreeProducts(child, products, order)\n if (groupProducts.length > 0) groups.push({ category: child, products: groupProducts })\n }\n\n return { rootDirect, groups }\n}\n","import type {\n CollectionsListRequest,\n ProductsCollection,\n ZenkyStorefront,\n} from '@zenky/storefront-api'\n\n/**\n * Загрузка списка коллекций товаров магазина.\n * Pure composable — SDK передаётся параметром (DI), Nuxt не нужен.\n *\n * NOTE: одиночный `getCollection(id)` в storefront API не предусмотрен,\n * для получения товаров коллекции используется `GET /products?collection_id=...`.\n * Чтобы получить метаданные коллекции — ищем в списке через `loadCollections`.\n */\nexport function useCollections(sdk: ZenkyStorefront): {\n loadCollections: (\n storeId: string,\n request?: CollectionsListRequest\n ) => Promise<ProductsCollection[]>\n} {\n async function loadCollections(\n storeId: string,\n request?: CollectionsListRequest\n ): Promise<ProductsCollection[]> {\n const response = await sdk.collections.getCollections(storeId, request)\n return response.items\n }\n\n return { loadCollections }\n}\n","/** URL-хелперы каталога — единая точка правды для путей категорий/коллекций. */\nexport const catalogRoutes = {\n /** Корневая страница каталога: список категорий + коллекций */\n index: (): string => '/catalog',\n\n /** Страница конкретной категории */\n category: (shortId: string, slug: string | null): string =>\n `/catalog/${shortId}/${slug || shortId}`,\n\n /** Страница конкретной коллекции */\n collection: (id: string): string => `/collections/${id}`,\n} as const\n"]}
@@ -0,0 +1,106 @@
1
+ import { useRuntime } from './chunk-V3VVDQIR.js';
2
+ import { defineStore } from 'pinia';
3
+ import { ref, computed } from 'vue';
4
+
5
+ var useStoreProfileStore = defineStore("zenky-store-profile", () => {
6
+ const store = ref(null);
7
+ const city = ref(null);
8
+ const stock = ref(null);
9
+ const categories = ref([]);
10
+ const website = ref(null);
11
+ function initStore(newStore, newCity, newStock) {
12
+ store.value = newStore;
13
+ city.value = newCity;
14
+ stock.value = newStock;
15
+ }
16
+ function setStock(newStock) {
17
+ stock.value = newStock;
18
+ }
19
+ function setCategories(newCategories) {
20
+ categories.value = newCategories;
21
+ }
22
+ function initWebsite(newWebsite) {
23
+ website.value = newWebsite;
24
+ }
25
+ const isReady = computed(() => store.value !== null && city.value !== null);
26
+ const hasStock = computed(() => stock.value !== null);
27
+ const currency = computed(() => store.value?.settings?.currency ?? "RUB");
28
+ const squareLogoUrl = computed(() => {
29
+ const logo = store.value?.square_logo ?? store.value?.logo;
30
+ if (!logo) return null;
31
+ return logo.hd?.url ?? logo.xlarge?.url ?? logo.large?.url ?? logo.medium?.url ?? logo.placeholder?.url ?? null;
32
+ });
33
+ return {
34
+ store,
35
+ city,
36
+ stock,
37
+ categories,
38
+ website,
39
+ initStore,
40
+ setStock,
41
+ setCategories,
42
+ initWebsite,
43
+ isReady,
44
+ hasStock,
45
+ currency,
46
+ squareLogoUrl
47
+ };
48
+ });
49
+ var AUTH_TOKEN_KEY = "zenky_auth_token";
50
+ var AUTH_PHONE_KEY = "zenky_auth_phone";
51
+ var YEAR_SECONDS = 60 * 60 * 24 * 365;
52
+ var useAuthStore = defineStore("zenky-auth", () => {
53
+ const { storage, sdk } = useRuntime();
54
+ const token = ref(null);
55
+ const phone = ref(null);
56
+ const countryCode = ref("RU");
57
+ const isAuthenticated = computed(() => token.value !== null && token.value !== "");
58
+ const initials = computed(() => {
59
+ if (!phone.value) return "?";
60
+ return phone.value.replace(/\D/g, "").slice(-4);
61
+ });
62
+ function setToken(nextToken, nextPhone, nextCountryCode) {
63
+ token.value = nextToken;
64
+ storage.set(AUTH_TOKEN_KEY, nextToken, { maxAge: YEAR_SECONDS });
65
+ sdk.setApiToken(nextToken);
66
+ if (nextPhone) {
67
+ phone.value = nextPhone;
68
+ storage.set(AUTH_PHONE_KEY, nextPhone, { maxAge: YEAR_SECONDS });
69
+ }
70
+ if (nextCountryCode) {
71
+ countryCode.value = nextCountryCode;
72
+ }
73
+ }
74
+ function clearToken() {
75
+ token.value = null;
76
+ phone.value = null;
77
+ storage.remove(AUTH_TOKEN_KEY);
78
+ storage.remove(AUTH_PHONE_KEY);
79
+ sdk.setApiToken(null);
80
+ }
81
+ function initFromCookie() {
82
+ const savedToken = storage.get(AUTH_TOKEN_KEY);
83
+ if (savedToken) {
84
+ token.value = savedToken;
85
+ sdk.setApiToken(savedToken);
86
+ }
87
+ const savedPhone = storage.get(AUTH_PHONE_KEY);
88
+ if (savedPhone) {
89
+ phone.value = savedPhone;
90
+ }
91
+ }
92
+ return {
93
+ token,
94
+ phone,
95
+ countryCode,
96
+ isAuthenticated,
97
+ initials,
98
+ setToken,
99
+ clearToken,
100
+ initFromCookie
101
+ };
102
+ });
103
+
104
+ export { useAuthStore, useStoreProfileStore };
105
+ //# sourceMappingURL=chunk-TEG7EL4N.js.map
106
+ //# sourceMappingURL=chunk-TEG7EL4N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stores/store-profile.ts","../src/stores/auth.ts"],"names":["defineStore","ref","computed"],"mappings":"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","file":"chunk-TEG7EL4N.js","sourcesContent":["import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { City, NestedCategory, Stock, Store } from '@zenky/storefront-api'\n\nimport type { Website } from '../website-settings'\n\n// Именованный return-тип (правило dts) — иначе Pinia-инференс развернёт SDK-типы в .d.ts.\nexport interface StoreProfileStore {\n store: Ref<Store | null>\n city: Ref<City | null>\n stock: Ref<Stock | null>\n categories: Ref<NestedCategory[]>\n website: Ref<Website | null>\n initStore: (store: Store, city: City, stock: Stock | null) => void\n setStock: (stock: Stock | null) => void\n setCategories: (categories: NestedCategory[]) => void\n initWebsite: (website: Website | null) => void\n isReady: ComputedRef<boolean>\n hasStock: ComputedRef<boolean>\n currency: ComputedRef<string>\n squareLogoUrl: ComputedRef<string | null>\n}\n\nexport const useStoreProfileStore = defineStore('zenky-store-profile', (): StoreProfileStore => {\n const store = ref<Store | null>(null)\n const city = ref<City | null>(null)\n const stock = ref<Stock | null>(null)\n const categories = ref<NestedCategory[]>([])\n const website = ref<Website | null>(null)\n\n function initStore(newStore: Store, newCity: City, newStock: Stock | null): void {\n store.value = newStore\n city.value = newCity\n stock.value = newStock\n }\n\n function setStock(newStock: Stock | null): void {\n stock.value = newStock\n }\n\n function setCategories(newCategories: NestedCategory[]): void {\n categories.value = newCategories\n }\n\n function initWebsite(newWebsite: Website | null): void {\n website.value = newWebsite\n }\n\n const isReady = computed(() => store.value !== null && city.value !== null)\n const hasStock = computed(() => stock.value !== null)\n const currency = computed<string>(() => store.value?.settings?.currency ?? 'RUB')\n\n const squareLogoUrl = computed<string | null>(() => {\n const logo = store.value?.square_logo ?? store.value?.logo\n if (!logo) return null\n\n return (\n logo.hd?.url ??\n logo.xlarge?.url ??\n logo.large?.url ??\n logo.medium?.url ??\n logo.placeholder?.url ??\n null\n )\n })\n\n return {\n store,\n city,\n stock,\n categories,\n website,\n initStore,\n setStock,\n setCategories,\n initWebsite,\n isReady,\n hasStock,\n currency,\n squareLogoUrl,\n }\n})\n","import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport { useRuntime } from '../ports/runtime'\n\n// Ключи совпадают с прежними CookieKey.AuthToken/AuthPhone — чтобы не разлогинить юзеров.\nconst AUTH_TOKEN_KEY = 'zenky_auth_token'\nconst AUTH_PHONE_KEY = 'zenky_auth_phone'\nconst YEAR_SECONDS = 60 * 60 * 24 * 365\n\n// Именованный return-тип (правило dts).\nexport interface AuthStore {\n token: Ref<string | null>\n phone: Ref<string | null>\n countryCode: Ref<string>\n isAuthenticated: ComputedRef<boolean>\n initials: ComputedRef<string>\n setToken: (token: string, phone?: string, countryCode?: string) => void\n clearToken: () => void\n initFromCookie: () => void\n}\n\nexport const useAuthStore = defineStore('zenky-auth', (): AuthStore => {\n // Рантайм захватываем на верхнем уровне setup (стор впервые создаётся в контексте\n // setup app.vue) — actions потом используют замыкание, не завися от inject после await.\n // SameSite/iframe-логика кук — целиком в cookie-адаптере приложения.\n const { storage, sdk } = useRuntime()\n\n const token = ref<string | null>(null)\n const phone = ref<string | null>(null)\n const countryCode = ref('RU')\n\n const isAuthenticated = computed(() => token.value !== null && token.value !== '')\n\n const initials = computed(() => {\n if (!phone.value) return '?'\n return phone.value.replace(/\\D/g, '').slice(-4)\n })\n\n function setToken(nextToken: string, nextPhone?: string, nextCountryCode?: string): void {\n token.value = nextToken\n storage.set(AUTH_TOKEN_KEY, nextToken, { maxAge: YEAR_SECONDS })\n sdk.setApiToken(nextToken)\n\n if (nextPhone) {\n phone.value = nextPhone\n storage.set(AUTH_PHONE_KEY, nextPhone, { maxAge: YEAR_SECONDS })\n }\n\n if (nextCountryCode) {\n countryCode.value = nextCountryCode\n }\n }\n\n function clearToken(): void {\n token.value = null\n phone.value = null\n storage.remove(AUTH_TOKEN_KEY)\n storage.remove(AUTH_PHONE_KEY)\n sdk.setApiToken(null)\n }\n\n function initFromCookie(): void {\n const savedToken = storage.get(AUTH_TOKEN_KEY)\n if (savedToken) {\n token.value = savedToken\n sdk.setApiToken(savedToken)\n }\n\n const savedPhone = storage.get(AUTH_PHONE_KEY)\n if (savedPhone) {\n phone.value = savedPhone\n }\n }\n\n return {\n token,\n phone,\n countryCode,\n isAuthenticated,\n initials,\n setToken,\n clearToken,\n initFromCookie,\n }\n})\n"]}
@@ -0,0 +1,27 @@
1
+ import { provide, inject } from 'vue';
2
+
3
+ // src/ports/runtime.ts
4
+ var RUNTIME_KEY = /* @__PURE__ */ Symbol.for("zenky.storefront.runtime");
5
+ function createStorefront(runtime) {
6
+ return {
7
+ install(app) {
8
+ app.provide(RUNTIME_KEY, runtime);
9
+ }
10
+ };
11
+ }
12
+ function provideStorefront(runtime) {
13
+ provide(RUNTIME_KEY, runtime);
14
+ }
15
+ function useRuntime() {
16
+ const runtime = inject(RUNTIME_KEY);
17
+ if (!runtime) {
18
+ throw new Error(
19
+ "[storefront-core] Runtime \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D. \u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438 \u043F\u043B\u0430\u0433\u0438\u043D: app.use(createStorefront(runtime))."
20
+ );
21
+ }
22
+ return runtime;
23
+ }
24
+
25
+ export { createStorefront, provideStorefront, useRuntime };
26
+ //# sourceMappingURL=chunk-V3VVDQIR.js.map
27
+ //# sourceMappingURL=chunk-V3VVDQIR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ports/runtime.ts"],"names":[],"mappings":";;;AAOA,IAAM,WAAA,mBAAc,MAAA,CAAO,GAAA,CAAI,0BAA0B,CAAA;AAGlD,SAAS,iBAAiB,OAAA,EAAoC;AACjE,EAAA,OAAO;AAAA,IACH,QAAQ,GAAA,EAAU;AACd,MAAA,GAAA,CAAI,OAAA,CAAQ,aAAa,OAAO,CAAA;AAAA,IACpC;AAAA,GACJ;AACJ;AAGO,SAAS,kBAAkB,OAAA,EAAkC;AAChE,EAAA,OAAA,CAAQ,aAAa,OAAO,CAAA;AAChC;AAGO,SAAS,UAAA,GAAgC;AAC5C,EAAA,MAAM,OAAA,GAAU,OAAO,WAAW,CAAA;AAClC,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACN;AAAA,KAEJ;AAAA,EACJ;AACA,EAAA,OAAO,OAAA;AACX","file":"chunk-V3VVDQIR.js","sourcesContent":["import { inject, provide, type App, type InjectionKey, type Plugin } from 'vue'\n\nimport type { StorefrontRuntime } from './index'\n\n// Composition root. Потребитель собирает рантайм (адаптеры) один раз и ставит плагин,\n// доменные composables берут его через useRuntime() вместо прямых Nuxt-вызовов.\n\nconst RUNTIME_KEY = Symbol.for('zenky.storefront.runtime') as InjectionKey<StorefrontRuntime>\n\n/** Vue-плагин: app.use(createStorefront(runtime)). */\nexport function createStorefront(runtime: StorefrontRuntime): Plugin {\n return {\n install(app: App) {\n app.provide(RUNTIME_KEY, runtime)\n },\n }\n}\n\n/** Альтернатива плагину — provide внутри setup (напр. в изолированном виджете). */\nexport function provideStorefront(runtime: StorefrontRuntime): void {\n provide(RUNTIME_KEY, runtime)\n}\n\n/** Доступ к рантайму из любого composable/стора ядра. */\nexport function useRuntime(): StorefrontRuntime {\n const runtime = inject(RUNTIME_KEY)\n if (!runtime) {\n throw new Error(\n '[storefront-core] Runtime не найден. ' +\n 'Установи плагин: app.use(createStorefront(runtime)).'\n )\n }\n return runtime\n}\n"]}
@@ -0,0 +1,14 @@
1
+ // src/utils/debounce.ts
2
+ function createDebounce(fn, delay) {
3
+ let timeout = null;
4
+ return () => {
5
+ if (timeout) {
6
+ clearTimeout(timeout);
7
+ }
8
+ timeout = setTimeout(fn, delay);
9
+ };
10
+ }
11
+
12
+ export { createDebounce };
13
+ //# sourceMappingURL=chunk-XUGXLJZB.js.map
14
+ //# sourceMappingURL=chunk-XUGXLJZB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/debounce.ts"],"names":[],"mappings":";AAAO,SAAS,cAAA,CAAe,IAAgB,KAAA,EAA2B;AACtE,EAAA,IAAI,OAAA,GAAgD,IAAA;AAEpD,EAAA,OAAO,MAAM;AACT,IAAA,IAAI,OAAA,EAAS;AACT,MAAA,YAAA,CAAa,OAAO,CAAA;AAAA,IACxB;AAEA,IAAA,OAAA,GAAU,UAAA,CAAW,IAAI,KAAK,CAAA;AAAA,EAClC,CAAA;AACJ","file":"chunk-XUGXLJZB.js","sourcesContent":["export function createDebounce(fn: () => void, delay: number): () => void {\n let timeout: ReturnType<typeof setTimeout> | null = null\n\n return () => {\n if (timeout) {\n clearTimeout(timeout)\n }\n\n timeout = setTimeout(fn, delay)\n }\n}\n"]}
@@ -0,0 +1,36 @@
1
+ import { defineStore } from 'pinia';
2
+ import { ref, computed } from 'vue';
3
+
4
+ // src/stores/catalog.ts
5
+ var useCatalogStore = defineStore("zenky-catalog", () => {
6
+ const catalog = ref([]);
7
+ const currentHash = ref(null);
8
+ const reloading = ref(false);
9
+ const loadError = ref(false);
10
+ function initCatalog(items, hash) {
11
+ catalog.value = items;
12
+ currentHash.value = hash ?? null;
13
+ loadError.value = false;
14
+ }
15
+ function setLoadError() {
16
+ loadError.value = true;
17
+ }
18
+ function setReloading(value) {
19
+ reloading.value = value;
20
+ }
21
+ const hasCatalog = computed(() => catalog.value.length > 0);
22
+ return {
23
+ catalog,
24
+ currentHash,
25
+ reloading,
26
+ loadError,
27
+ initCatalog,
28
+ setLoadError,
29
+ setReloading,
30
+ hasCatalog
31
+ };
32
+ });
33
+
34
+ export { useCatalogStore };
35
+ //# sourceMappingURL=chunk-Z3IW4ODZ.js.map
36
+ //# sourceMappingURL=chunk-Z3IW4ODZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stores/catalog.ts"],"names":[],"mappings":";;;;AAoBO,IAAM,eAAA,GAAkB,WAAA,CAAY,eAAA,EAAiB,MAAoB;AAC5E,EAAA,MAAM,OAAA,GAAU,GAAA,CAAmB,EAAE,CAAA;AACrC,EAAA,MAAM,WAAA,GAAc,IAAmB,IAAI,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,IAAI,KAAK,CAAA;AAC3B,EAAA,MAAM,SAAA,GAAY,IAAI,KAAK,CAAA;AAE3B,EAAA,SAAS,WAAA,CAAY,OAAsB,IAAA,EAA4B;AACnE,IAAA,OAAA,CAAQ,KAAA,GAAQ,KAAA;AAChB,IAAA,WAAA,CAAY,QAAQ,IAAA,IAAQ,IAAA;AAC5B,IAAA,SAAA,CAAU,KAAA,GAAQ,KAAA;AAAA,EACtB;AAEA,EAAA,SAAS,YAAA,GAAqB;AAC1B,IAAA,SAAA,CAAU,KAAA,GAAQ,IAAA;AAAA,EACtB;AAEA,EAAA,SAAS,aAAa,KAAA,EAAsB;AACxC,IAAA,SAAA,CAAU,KAAA,GAAQ,KAAA;AAAA,EACtB;AAEA,EAAA,MAAM,aAAa,QAAA,CAAS,MAAM,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAC,CAAA;AAE1D,EAAA,OAAO;AAAA,IACH,OAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACJ;AACJ,CAAC","file":"chunk-Z3IW4ODZ.js","sourcesContent":["import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { CatalogItem } from '@zenky/storefront-api'\n\n// Явный тип возврата (а не выведенный) — иначе Pinia-инференс структурно разворачивает\n// SDK-типы в .d.ts и раздувает его. Заодно соответствует правилу «явные return types».\nexport interface CatalogStore {\n catalog: Ref<CatalogItem[]>\n currentHash: Ref<string | null>\n reloading: Ref<boolean>\n loadError: Ref<boolean>\n initCatalog: (items: CatalogItem[], hash?: string | null) => void\n setLoadError: () => void\n setReloading: (value: boolean) => void\n hasCatalog: ComputedRef<boolean>\n}\n\n// Setup-стор (док 05): id с префиксом zenky-*, чтобы не столкнуться со сторами потребителя.\n// Чистый контейнер состояния — API/куки живут в composables/bootstrap, которые зовут actions.\nexport const useCatalogStore = defineStore('zenky-catalog', (): CatalogStore => {\n const catalog = ref<CatalogItem[]>([])\n const currentHash = ref<string | null>(null)\n const reloading = ref(false)\n const loadError = ref(false)\n\n function initCatalog(items: CatalogItem[], hash?: string | null): void {\n catalog.value = items\n currentHash.value = hash ?? null\n loadError.value = false\n }\n\n function setLoadError(): void {\n loadError.value = true\n }\n\n function setReloading(value: boolean): void {\n reloading.value = value\n }\n\n const hasCatalog = computed(() => catalog.value.length > 0)\n\n return {\n catalog,\n currentHash,\n reloading,\n loadError,\n initCatalog,\n setLoadError,\n setReloading,\n hasCatalog,\n }\n})\n"]}
@@ -0,0 +1,26 @@
1
+ import { StorefrontRuntime } from './ports/index.js';
2
+ export { ActivityReporter, CatalogReloader, CommerceAddedToCartPayload, CommerceEventIdentity, CommerceEventsPort, CommerceRemovedFromCartPayload, EventsPort, NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, Notifier, RealtimeAdapter, RealtimeChannel, RealtimePort, Result, RumReporter, StorageAdapter, StorageOptions, StorefrontConfig, createMemoryStorage, err, ok } from './ports/index.js';
3
+ import { Plugin } from 'vue';
4
+ export { Major, Minor, asMajor, asMinor, formatPrice, majorToMinor, minorToMajor, minorToMajorString } from './money/index.js';
5
+ export { DARK_THEME_PRESETS, FontConfig, PrimaryShades, THEME_PRESETS, ThemeColorConfig, ThemeData, ThemePreset, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme } from './theme/index.js';
6
+ export { OperationChain, buildQrCodeUrl, createDebounce, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, getApiErrorMessage, getApiFieldErrors, getPhoneTelLink, pluralize, toDateInputValue, todayInTimezone } from './utils/index.js';
7
+ export { D as DayScheduleInfo, S as SocialLink, T as TodayScheduleInfo, f as formatScheduleStatus, g as getEmailLink, a as getSocialLinks, b as getTodayInfo, c as getWebsiteLink, d as getWeeklySchedule } from './schedule-Dd3zwHEb.js';
8
+ export { CatalogProductMatch, CategoryWithProducts, OrderCredentials, ProductVariantOptionListItem, ResolvedPrice, canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts } from './products/index.js';
9
+ export { GroupedProducts, SubcategoryGroup, catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, getCity, getRemoteCatalog, getStock, groupProductsBySubcategory, useCollections } from './catalog/index.js';
10
+ export { AttachedCustomerCache, BonusesReconciliation, BonusesReconciliationDeps, CASH_DENOMINATIONS_MAJOR, CachedCustomerView, CartCredentials, CartDependencies, CartErrorScope, CartInitialization, CartItemRequest, CartLineKeyParams, CartMutationComposable, CartOperations, CartQuantities, CartRecalculation, CartRecalculationDeps, CartStockWatcher, CashChangePresetsOptions, CheckoutFlowFlags, CheckoutSubmitComposable, CustomerAttachComposable, DEFAULT_ROUND_STEPS_MAJOR, MainPaymentRequestParams, MutationKind, MutationOptions, ORDER_EVENTS, ORDER_WITH, OrderBonusesComposable, OrderBonusesDeps, OrderCredentialsLike, OrderDelivery, OrderDeliveryDeps, OrderPromocodeComposable, OrderPromocodeDeps, OrderSettingsComposable, OrderTotal, PaymentSelection, PaymentSelectionComposable, RecaptchaPayloadProvider, RestrictedAddToCart, RestrictionGate, RestrictionGateProduct, RetryOptions, StorefrontCart, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCredentials, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from './cart/index.js';
11
+ export { R as RawSnippetItem, S as Snippet, a as SnippetGroup, b as SnippetLanguage, c as SnippetPosition, n as normalizeSnippets } from './snippets-BC5bkSjm.js';
12
+ export { SnippetHead, buildSnippetHead } from './snippets/index.js';
13
+ export { SettingValue, Website, WebsitePage, WebsitePageListItem, WebsitePageSeo, WebsitePageType, WebsiteSettingsValues } from './website-settings/index.js';
14
+ export { AppliedBonusesIntent, AuthStore, CartStore, MinPriceViolation, OrderSettingsStore, PromotionsStore, RewardSelection, RewardSelectionContext, StoreProfileStore, useAuthStore, useCartStore, useCatalogStore, useOrderSettingsStore, useProductsStore, usePromotionsStore, useStore, useStoreProfileStore, useStorefrontProfile } from './stores/index.js';
15
+ import '@zenky/integrations-sdk';
16
+ import '@zenky/storefront-api';
17
+ import 'pinia';
18
+
19
+ /** Vue-плагин: app.use(createStorefront(runtime)). */
20
+ declare function createStorefront(runtime: StorefrontRuntime): Plugin;
21
+ /** Альтернатива плагину — provide внутри setup (напр. в изолированном виджете). */
22
+ declare function provideStorefront(runtime: StorefrontRuntime): void;
23
+ /** Доступ к рантайму из любого composable/стора ядра. */
24
+ declare function useRuntime(): StorefrontRuntime;
25
+
26
+ export { StorefrontRuntime, createStorefront, provideStorefront, useRuntime };
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
1
+ export { canAddDirectly, findProductInCatalog, formatWeight, getProductWeight, getVariantWeight, resolveVariantPrice, toGrams, usePriceRecalculation, useProductPricing, useProductVariant, useProductVariantModifiers, useProductVariantSelector, useProductsByCategory, useRelatedProducts } from './chunk-JLFBAAFT.js';
2
+ export { buildSnippetHead, normalizeSnippets } from './chunk-7FRMMCR5.js';
3
+ export { useProductsStore, useStore, useStorefrontProfile } from './chunk-57IOMDAM.js';
4
+ export { DARK_THEME_PRESETS, THEME_PRESETS, buildCssVariableMap, generatePrimaryShades, generateShades, useTheme } from './chunk-GW2QNTAD.js';
5
+ import './chunk-EMGQXBU3.js';
6
+ export { CASH_DENOMINATIONS_MAJOR, DEFAULT_ROUND_STEPS_MAJOR, ORDER_EVENTS, ORDER_WITH, buildCartLineKey, buildCashChangePresets, buildMainPaymentRequest, getCartErrorCode, getCartErrorHttpCode, getCartErrorMessage, getCashDenominationsMinor, getDefaultRoundStepsMinor, getValidationErrors, logCartError, normalizeAddress, useBonusesReconciliation, useCartAddressSync, useCartCustomerAttachment, useCartDeliveryAttachment, useCartInitialization, useCartMutation, useCartOperations, useCartQuantities, useCartRecalculation, useCartStockWatcher, useCheckoutFlow, useCheckoutSubmit, useCustomerAttach, useOnlinePaymentRetry, useOrderBonuses, useOrderChannel, useOrderDelivery, useOrderPromocode, useOrderSettings, useOrderTotal, usePaymentSelection, useRestrictedAddToCart, useRestrictionGate, useStorefrontCart, useVisibleCartVariants, variantLineKey } from './chunk-G2X4SBCO.js';
7
+ export { useCartCredentials } from './chunk-N3NOTJUC.js';
8
+ import './chunk-5QCUH3FF.js';
9
+ export { useCatalogStore } from './chunk-Z3IW4ODZ.js';
10
+ export { usePromotionsStore } from './chunk-BWUKMWHL.js';
11
+ export { useAuthStore, useStoreProfileStore } from './chunk-TEG7EL4N.js';
12
+ export { catalogRoutes, collectDescendantIds, findCategoryById, findCategoryByShortId, findRootAncestor, getCategoryPath, groupProductsBySubcategory, useCollections } from './chunk-RYYY7MVP.js';
13
+ export { getCity, getRemoteCatalog, getStock } from './chunk-E3G7NGCH.js';
14
+ export { buildQrCodeUrl, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, pluralize, toDateInputValue, todayInTimezone } from './chunk-MZ66ARDL.js';
15
+ export { createDebounce } from './chunk-XUGXLJZB.js';
16
+ export { useCartStore, useOrderSettingsStore } from './chunk-FFBZKQRV.js';
17
+ export { createStorefront, provideStorefront, useRuntime } from './chunk-V3VVDQIR.js';
18
+ export { asMajor, asMinor, formatPrice, majorToMinor, minorToMajor, minorToMajorString } from './chunk-RO25KNM5.js';
19
+ export { NOOP_ACTIVITY_REPORTER, NOOP_NOTIFIER, NOOP_RUM, createMemoryStorage, err, ok } from './chunk-GLTOJTZO.js';
20
+ //# sourceMappingURL=index.js.map
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,54 @@
1
+ import { ComputedRef } from 'vue';
2
+ import { City, Phone, Store, Stock } from '@zenky/storefront-api';
3
+ import { T as TodayScheduleInfo, D as DayScheduleInfo, S as SocialLink } from '../schedule-Dd3zwHEb.js';
4
+
5
+ interface LegalLink {
6
+ label: string;
7
+ to: string;
8
+ }
9
+ interface FormattedPhone {
10
+ formatted: string;
11
+ telLink: string;
12
+ }
13
+ /** App-специфичные значения для шапки (из Website Builder / app.config). */
14
+ interface HeaderDataOptions {
15
+ showStoreName: boolean;
16
+ logoOverride: string | null;
17
+ }
18
+ /** App-специфичные значения для футера (logo-override + правовые ссылки фичи). */
19
+ interface FooterDataOptions {
20
+ logoOverride: string | null;
21
+ legalLinks: ComputedRef<LegalLink[]>;
22
+ }
23
+ interface HeaderData {
24
+ storeName: ComputedRef<string>;
25
+ showStoreName: ComputedRef<boolean>;
26
+ logoUrl: ComputedRef<string | null>;
27
+ cityName: ComputedRef<string | null>;
28
+ cities: ComputedRef<City[]>;
29
+ phone: ComputedRef<Phone | null>;
30
+ phoneFormatted: ComputedRef<string | null>;
31
+ phoneTelLink: ComputedRef<string | null>;
32
+ schedule: ComputedRef<TodayScheduleInfo | null>;
33
+ scheduleHours: ComputedRef<string | null>;
34
+ cartCount: ComputedRef<number>;
35
+ }
36
+ interface FooterData {
37
+ storeName: ComputedRef<string>;
38
+ logoUrl: ComputedRef<string | null>;
39
+ phones: ComputedRef<FormattedPhone[]>;
40
+ todaySchedule: ComputedRef<TodayScheduleInfo | null>;
41
+ weeklySchedule: ComputedRef<DayScheduleInfo[]>;
42
+ address: ComputedRef<string | null>;
43
+ socialLinks: ComputedRef<SocialLink[]>;
44
+ legalLinks: ComputedRef<LegalLink[]>;
45
+ copyrightYear: ComputedRef<number>;
46
+ appStoreUrl: ComputedRef<string | null>;
47
+ googlePlayUrl: ComputedRef<string | null>;
48
+ }
49
+
50
+ declare function useHeaderData(store: ComputedRef<Store>, city: ComputedRef<City>, stock: ComputedRef<Stock | null>, options: HeaderDataOptions): HeaderData;
51
+
52
+ declare function useFooterData(store: ComputedRef<Store>, city: ComputedRef<City>, stock: ComputedRef<Stock | null>, options: FooterDataOptions): FooterData;
53
+
54
+ export { type FooterData, type FooterDataOptions, type FormattedPhone, type HeaderData, type HeaderDataOptions, type LegalLink, useFooterData, useHeaderData };
@@ -0,0 +1,106 @@
1
+ import { formatPhoneNational, getPhoneTelLink, getTodayInfo, getWeeklySchedule, getSocialLinks } from '../chunk-MZ66ARDL.js';
2
+ import '../chunk-XUGXLJZB.js';
3
+ import { useCartStore } from '../chunk-FFBZKQRV.js';
4
+ import '../chunk-V3VVDQIR.js';
5
+ import { computed } from 'vue';
6
+
7
+ function useHeaderData(store, city, stock, options) {
8
+ const storeName = computed(() => store.value.name);
9
+ const showStoreName = computed(() => options.showStoreName);
10
+ const logoUrl = computed(() => {
11
+ if (options.logoOverride) return options.logoOverride;
12
+ const logo = store.value.logo;
13
+ return logo?.medium?.url ?? logo?.large?.url ?? null;
14
+ });
15
+ const cityName = computed(() => city.value.name);
16
+ const cities = computed(() => store.value.cities);
17
+ const phone = computed(() => {
18
+ const cityPhones = city.value.phones;
19
+ if (cityPhones && cityPhones.length > 0) {
20
+ return cityPhones[0] ?? null;
21
+ }
22
+ return store.value.phones.length > 0 ? store.value.phones[0] ?? null : null;
23
+ });
24
+ const phoneFormatted = computed(() => formatPhoneNational(phone.value));
25
+ const phoneTelLink = computed(() => getPhoneTelLink(phone.value));
26
+ const schedule = computed(
27
+ () => getTodayInfo(stock.value?.schedule ?? city.value.schedule)
28
+ );
29
+ const scheduleHours = computed(() => {
30
+ const info = schedule.value;
31
+ if (!info) return null;
32
+ if (info.todayHours) return info.todayHours;
33
+ if (info.openingAt && info.closingAt) return `${info.openingAt}\u2013${info.closingAt}`;
34
+ return null;
35
+ });
36
+ const cartStore = useCartStore();
37
+ const cartCount = computed(() => cartStore.itemCount);
38
+ return {
39
+ storeName,
40
+ showStoreName,
41
+ logoUrl,
42
+ cityName,
43
+ cities,
44
+ phone,
45
+ phoneFormatted,
46
+ phoneTelLink,
47
+ schedule,
48
+ scheduleHours,
49
+ cartCount
50
+ };
51
+ }
52
+ function useFooterData(store, city, stock, options) {
53
+ const storeName = computed(() => store.value.name);
54
+ const logoUrl = computed(() => {
55
+ if (options.logoOverride) return options.logoOverride;
56
+ const logo = store.value.logo;
57
+ return logo?.medium?.url ?? logo?.large?.url ?? null;
58
+ });
59
+ const phones = computed(() => {
60
+ const cityPhones = city.value.phones;
61
+ const rawPhones = cityPhones && cityPhones.length > 0 ? cityPhones : store.value.phones;
62
+ return rawPhones.map((p) => {
63
+ const formatted = formatPhoneNational(p);
64
+ const telLink = getPhoneTelLink(p);
65
+ if (!formatted || !telLink) return null;
66
+ return { formatted, telLink };
67
+ }).filter((p) => p !== null);
68
+ });
69
+ const activeSchedule = computed(() => stock.value?.schedule ?? city.value.schedule);
70
+ const todaySchedule = computed(
71
+ () => getTodayInfo(activeSchedule.value)
72
+ );
73
+ const weeklySchedule = computed(
74
+ () => getWeeklySchedule(activeSchedule.value)
75
+ );
76
+ const address = computed(() => {
77
+ if (stock.value?.address) return stock.value.address;
78
+ const cityStocks = city.value.stocks;
79
+ if (cityStocks && cityStocks.length > 0) {
80
+ return cityStocks[0]?.address ?? null;
81
+ }
82
+ return null;
83
+ });
84
+ const socialLinks = computed(() => getSocialLinks(store.value.links));
85
+ const legalLinks = options.legalLinks;
86
+ const copyrightYear = computed(() => (/* @__PURE__ */ new Date()).getFullYear());
87
+ const appStoreUrl = computed(() => store.value.app_store_url);
88
+ const googlePlayUrl = computed(() => store.value.google_play_url);
89
+ return {
90
+ storeName,
91
+ logoUrl,
92
+ phones,
93
+ todaySchedule,
94
+ weeklySchedule,
95
+ address,
96
+ socialLinks,
97
+ legalLinks,
98
+ copyrightYear,
99
+ appStoreUrl,
100
+ googlePlayUrl
101
+ };
102
+ }
103
+
104
+ export { useFooterData, useHeaderData };
105
+ //# sourceMappingURL=index.js.map
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/layout/useHeaderData.ts","../../src/layout/useFooterData.ts"],"names":["computed"],"mappings":"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","file":"index.js","sourcesContent":["import { computed, type ComputedRef } from 'vue'\n\nimport type { City, Phone, Stock, Store } from '@zenky/storefront-api'\n\nimport { formatPhoneNational, getPhoneTelLink, getTodayInfo } from '../utils'\nimport type { TodayScheduleInfo } from '../utils'\nimport { useCartStore } from '../stores/cart'\nimport type { HeaderData, HeaderDataOptions } from './types'\n\nexport function useHeaderData(\n store: ComputedRef<Store>,\n city: ComputedRef<City>,\n stock: ComputedRef<Stock | null>,\n options: HeaderDataOptions\n): HeaderData {\n const storeName = computed<string>(() => store.value.name)\n const showStoreName = computed<boolean>(() => options.showStoreName)\n\n const logoUrl = computed<string | null>(() => {\n if (options.logoOverride) return options.logoOverride\n const logo = store.value.logo\n return logo?.medium?.url ?? logo?.large?.url ?? null\n })\n\n const cityName = computed<string | null>(() => city.value.name)\n const cities = computed<City[]>(() => store.value.cities)\n\n const phone = computed<Phone | null>(() => {\n const cityPhones = city.value.phones\n\n if (cityPhones && cityPhones.length > 0) {\n return cityPhones[0] ?? null\n }\n\n return store.value.phones.length > 0 ? (store.value.phones[0] ?? null) : null\n })\n\n const phoneFormatted = computed<string | null>(() => formatPhoneNational(phone.value))\n const phoneTelLink = computed<string | null>(() => getPhoneTelLink(phone.value))\n // Режим работы привязан к складу; если склад выбран — его расписание, иначе city.schedule.\n const schedule = computed<TodayScheduleInfo | null>(() =>\n getTodayInfo(stock.value?.schedule ?? city.value.schedule)\n )\n\n const scheduleHours = computed<string | null>(() => {\n const info = schedule.value\n\n if (!info) return null\n\n if (info.todayHours) return info.todayHours\n if (info.openingAt && info.closingAt) return `${info.openingAt}–${info.closingAt}`\n\n return null\n })\n\n const cartStore = useCartStore()\n const cartCount = computed<number>(() => cartStore.itemCount)\n\n return {\n storeName,\n showStoreName,\n logoUrl,\n cityName,\n cities,\n phone,\n phoneFormatted,\n phoneTelLink,\n schedule,\n scheduleHours,\n cartCount,\n }\n}\n","import { computed, type ComputedRef } from 'vue'\n\nimport type { City, Stock, Store } from '@zenky/storefront-api'\n\nimport {\n formatPhoneNational,\n getPhoneTelLink,\n getSocialLinks,\n getTodayInfo,\n getWeeklySchedule,\n} from '../utils'\nimport type { DayScheduleInfo, SocialLink, TodayScheduleInfo } from '../utils'\nimport type { FooterData, FooterDataOptions, FormattedPhone } from './types'\n\nexport function useFooterData(\n store: ComputedRef<Store>,\n city: ComputedRef<City>,\n stock: ComputedRef<Stock | null>,\n options: FooterDataOptions\n): FooterData {\n const storeName = computed<string>(() => store.value.name)\n\n const logoUrl = computed<string | null>(() => {\n if (options.logoOverride) return options.logoOverride\n const logo = store.value.logo\n return logo?.medium?.url ?? logo?.large?.url ?? null\n })\n\n const phones = computed<FormattedPhone[]>(() => {\n const cityPhones = city.value.phones\n const rawPhones = cityPhones && cityPhones.length > 0 ? cityPhones : store.value.phones\n\n return rawPhones\n .map((p) => {\n const formatted = formatPhoneNational(p)\n const telLink = getPhoneTelLink(p)\n\n if (!formatted || !telLink) return null\n\n return { formatted, telLink }\n })\n .filter((p): p is FormattedPhone => p !== null)\n })\n\n const activeSchedule = computed(() => stock.value?.schedule ?? city.value.schedule)\n\n const todaySchedule = computed<TodayScheduleInfo | null>(() =>\n getTodayInfo(activeSchedule.value)\n )\n\n const weeklySchedule = computed<DayScheduleInfo[]>(() =>\n getWeeklySchedule(activeSchedule.value)\n )\n\n const address = computed<string | null>(() => {\n if (stock.value?.address) return stock.value.address\n\n const cityStocks = city.value.stocks\n\n if (cityStocks && cityStocks.length > 0) {\n return cityStocks[0]?.address ?? null\n }\n\n return null\n })\n\n const socialLinks = computed<SocialLink[]>(() => getSocialLinks(store.value.links))\n\n const legalLinks = options.legalLinks\n\n const copyrightYear = computed<number>(() => new Date().getFullYear())\n\n const appStoreUrl = computed<string | null>(() => store.value.app_store_url)\n const googlePlayUrl = computed<string | null>(() => store.value.google_play_url)\n\n return {\n storeName,\n logoUrl,\n phones,\n todaySchedule,\n weeklySchedule,\n address,\n socialLinks,\n legalLinks,\n copyrightYear,\n appStoreUrl,\n googlePlayUrl,\n }\n}\n"]}
@@ -0,0 +1,26 @@
1
+ declare const MINOR: unique symbol;
2
+ declare const MAJOR: unique symbol;
3
+ /** Сумма в минорных единицах (копейки). Так хранит и отдаёт API. */
4
+ type Minor = number & {
5
+ readonly [MINOR]: true;
6
+ };
7
+ /** Сумма в мажорных единицах (рубли). В таком виде их ждёт часть API. */
8
+ type Major = number & {
9
+ readonly [MAJOR]: true;
10
+ };
11
+ /** Помечает сырое число с API как Minor (assert без рантайм-стоимости). */
12
+ declare const asMinor: (value: number) => Minor;
13
+ /** Помечает число как Major. */
14
+ declare const asMajor: (value: number) => Major;
15
+ /** Форматирует цену из минорных единиц в читаемый вид (`1 290 ₽`). */
16
+ declare function formatPrice(value?: number | null, currency?: string, locale?: string): string;
17
+ /** Сырая конвертация минор → мажор (копейки → рубли) без форматирования. */
18
+ declare function minorToMajor(value: number, currency?: string): number;
19
+ /** Сырая конвертация мажор → минор (рубли → копейки), округление до целого. */
20
+ declare function majorToMinor(value: number, currency?: string): number;
21
+ /**
22
+ * Минор → мажор строкой. API payments/bonuses ждёт сумму строкой в рублях `"103.50"`.
23
+ */
24
+ declare function minorToMajorString(value: number, currency?: string): string;
25
+
26
+ export { type Major, type Minor, asMajor, asMinor, formatPrice, majorToMinor, minorToMajor, minorToMajorString };
@@ -0,0 +1,3 @@
1
+ export { asMajor, asMinor, formatPrice, majorToMinor, minorToMajor, minorToMajorString } from '../chunk-RO25KNM5.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}