@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.
- package/CHANGELOG.md +46 -0
- package/LICENSE.md +2 -2
- package/README.md +213 -6
- package/dist/cart/index.d.ts +588 -0
- package/dist/cart/index.js +12 -0
- package/dist/cart/index.js.map +1 -0
- package/dist/catalog/index.d.ts +73 -0
- package/dist/catalog/index.js +4 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/chunk-57IOMDAM.js +38 -0
- package/dist/chunk-57IOMDAM.js.map +1 -0
- package/dist/chunk-5QCUH3FF.js +15 -0
- package/dist/chunk-5QCUH3FF.js.map +1 -0
- package/dist/chunk-7FRMMCR5.js +93 -0
- package/dist/chunk-7FRMMCR5.js.map +1 -0
- package/dist/chunk-BWUKMWHL.js +45 -0
- package/dist/chunk-BWUKMWHL.js.map +1 -0
- package/dist/chunk-E3G7NGCH.js +45 -0
- package/dist/chunk-E3G7NGCH.js.map +1 -0
- package/dist/chunk-EMGQXBU3.js +3 -0
- package/dist/chunk-EMGQXBU3.js.map +1 -0
- package/dist/chunk-FFBZKQRV.js +393 -0
- package/dist/chunk-FFBZKQRV.js.map +1 -0
- package/dist/chunk-G2X4SBCO.js +2011 -0
- package/dist/chunk-G2X4SBCO.js.map +1 -0
- package/dist/chunk-GLTOJTZO.js +41 -0
- package/dist/chunk-GLTOJTZO.js.map +1 -0
- package/dist/chunk-GW2QNTAD.js +327 -0
- package/dist/chunk-GW2QNTAD.js.map +1 -0
- package/dist/chunk-JLFBAAFT.js +566 -0
- package/dist/chunk-JLFBAAFT.js.map +1 -0
- package/dist/chunk-MZ66ARDL.js +244 -0
- package/dist/chunk-MZ66ARDL.js.map +1 -0
- package/dist/chunk-N3NOTJUC.js +111 -0
- package/dist/chunk-N3NOTJUC.js.map +1 -0
- package/dist/chunk-RO25KNM5.js +36 -0
- package/dist/chunk-RO25KNM5.js.map +1 -0
- package/dist/chunk-RYYY7MVP.js +102 -0
- package/dist/chunk-RYYY7MVP.js.map +1 -0
- package/dist/chunk-TEG7EL4N.js +106 -0
- package/dist/chunk-TEG7EL4N.js.map +1 -0
- package/dist/chunk-V3VVDQIR.js +27 -0
- package/dist/chunk-V3VVDQIR.js.map +1 -0
- package/dist/chunk-XUGXLJZB.js +14 -0
- package/dist/chunk-XUGXLJZB.js.map +1 -0
- package/dist/chunk-Z3IW4ODZ.js +36 -0
- package/dist/chunk-Z3IW4ODZ.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/index.d.ts +54 -0
- package/dist/layout/index.js +106 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/money/index.d.ts +26 -0
- package/dist/money/index.js +3 -0
- package/dist/money/index.js.map +1 -0
- package/dist/order/index.d.ts +34 -0
- package/dist/order/index.js +209 -0
- package/dist/order/index.js.map +1 -0
- package/dist/pagination/index.d.ts +87 -0
- package/dist/pagination/index.js +97 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/ports/index.d.ts +124 -0
- package/dist/ports/index.js +3 -0
- package/dist/ports/index.js.map +1 -0
- package/dist/products/index.d.ts +105 -0
- package/dist/products/index.js +7 -0
- package/dist/products/index.js.map +1 -0
- package/dist/promotions/index.d.ts +10 -0
- package/dist/promotions/index.js +7 -0
- package/dist/promotions/index.js.map +1 -0
- package/dist/schedule-Dd3zwHEb.d.ts +27 -0
- package/dist/seo/index.d.ts +91 -0
- package/dist/seo/index.js +289 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/snippets/index.d.ts +17 -0
- package/dist/snippets/index.js +3 -0
- package/dist/snippets/index.js.map +1 -0
- package/dist/snippets-BC5bkSjm.d.ts +23 -0
- package/dist/stores/index.d.ts +196 -0
- package/dist/stores/index.js +8 -0
- package/dist/stores/index.js.map +1 -0
- package/dist/theme/index.d.ts +60 -0
- package/dist/theme/index.js +3 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/utils/index.d.ts +66 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/website-settings/index.d.ts +38 -0
- package/dist/website-settings/index.js +3 -0
- package/dist/website-settings/index.js.map +1 -0
- package/docs/consumer-setup.md +275 -0
- package/docs/ports.md +144 -0
- package/docs/releasing.md +46 -0
- package/package.json +143 -47
- package/dist/cjs/index.cjs +0 -3742
- package/dist/esm/index.mjs +0 -3642
- 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"]}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|