@zenky/storefront-vue 0.9.46 → 0.10.0
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/LICENSE.md +2 -2
- package/README.md +163 -6
- package/dist/cart/index.d.ts +559 -0
- package/dist/cart/index.js +13 -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-2OD7CLKD.js +102 -0
- package/dist/chunk-2OD7CLKD.js.map +1 -0
- package/dist/chunk-4MJKN7PL.js +111 -0
- package/dist/chunk-4MJKN7PL.js.map +1 -0
- package/dist/chunk-5QCUH3FF.js +15 -0
- package/dist/chunk-5QCUH3FF.js.map +1 -0
- package/dist/chunk-AL5W5JSD.js +41 -0
- package/dist/chunk-AL5W5JSD.js.map +1 -0
- package/dist/chunk-BIGTKVC6.js +38 -0
- package/dist/chunk-BIGTKVC6.js.map +1 -0
- package/dist/chunk-BWUKMWHL.js +45 -0
- package/dist/chunk-BWUKMWHL.js.map +1 -0
- package/dist/chunk-DKWDKVXQ.js +91 -0
- package/dist/chunk-DKWDKVXQ.js.map +1 -0
- package/dist/chunk-EMGQXBU3.js +3 -0
- package/dist/chunk-EMGQXBU3.js.map +1 -0
- package/dist/chunk-EYRCAUUP.js +45 -0
- package/dist/chunk-EYRCAUUP.js.map +1 -0
- package/dist/chunk-GW2QNTAD.js +327 -0
- package/dist/chunk-GW2QNTAD.js.map +1 -0
- package/dist/chunk-IGDDWGS4.js +557 -0
- package/dist/chunk-IGDDWGS4.js.map +1 -0
- package/dist/chunk-OQLU7FSR.js +1841 -0
- package/dist/chunk-OQLU7FSR.js.map +1 -0
- package/dist/chunk-PJ2LEKW6.js +229 -0
- package/dist/chunk-PJ2LEKW6.js.map +1 -0
- package/dist/chunk-PWHIDGKW.js +97 -0
- package/dist/chunk-PWHIDGKW.js.map +1 -0
- package/dist/chunk-RO25KNM5.js +36 -0
- package/dist/chunk-RO25KNM5.js.map +1 -0
- package/dist/chunk-V3VVDQIR.js +27 -0
- package/dist/chunk-V3VVDQIR.js.map +1 -0
- package/dist/chunk-VL3T36VM.js +386 -0
- package/dist/chunk-VL3T36VM.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 +102 -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/package.json +122 -41
- package/dist/esm/index.js +0 -3642
- package/dist/zenky.d.ts +0 -10377
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { ContactType, ZenkyError } from '@zenky/storefront-api';
|
|
2
|
+
|
|
3
|
+
// src/utils/createOperationChain.ts
|
|
4
|
+
function createOperationChain() {
|
|
5
|
+
const chains = /* @__PURE__ */ new Map();
|
|
6
|
+
async function execute(key, fn) {
|
|
7
|
+
const prev = chains.get(key) ?? Promise.resolve();
|
|
8
|
+
const current = prev.then(fn);
|
|
9
|
+
const safe = current.catch(() => {
|
|
10
|
+
});
|
|
11
|
+
chains.set(key, safe);
|
|
12
|
+
safe.finally(() => {
|
|
13
|
+
if (chains.get(key) === safe) {
|
|
14
|
+
chains.delete(key);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return current;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
execute,
|
|
21
|
+
get size() {
|
|
22
|
+
return chains.size;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/utils/phone.ts
|
|
28
|
+
function formatPhoneNational(phone) {
|
|
29
|
+
if (!phone) return null;
|
|
30
|
+
return phone.national || phone.number;
|
|
31
|
+
}
|
|
32
|
+
function getPhoneTelLink(phone) {
|
|
33
|
+
if (!phone) return null;
|
|
34
|
+
return `tel:${phone.number}`;
|
|
35
|
+
}
|
|
36
|
+
function formatPhoneSpaced(formatted) {
|
|
37
|
+
if (!formatted) return "";
|
|
38
|
+
return formatted.replace(/[()-]/g, " ").replace(/\s+/g, " ").trim();
|
|
39
|
+
}
|
|
40
|
+
var SOCIAL_TYPES = /* @__PURE__ */ new Set([
|
|
41
|
+
ContactType.Vk,
|
|
42
|
+
ContactType.Instagram,
|
|
43
|
+
ContactType.Facebook,
|
|
44
|
+
ContactType.Twitter,
|
|
45
|
+
ContactType.Ok,
|
|
46
|
+
ContactType.Tiktok,
|
|
47
|
+
ContactType.Telegram,
|
|
48
|
+
ContactType.Max
|
|
49
|
+
]);
|
|
50
|
+
var SOCIAL_LABELS = {
|
|
51
|
+
[ContactType.Vk]: "\u0412\u041A\u043E\u043D\u0442\u0430\u043A\u0442\u0435",
|
|
52
|
+
[ContactType.Instagram]: "Instagram",
|
|
53
|
+
[ContactType.Facebook]: "Facebook",
|
|
54
|
+
[ContactType.Twitter]: "Twitter",
|
|
55
|
+
[ContactType.Ok]: "\u041E\u0434\u043D\u043E\u043A\u043B\u0430\u0441\u0441\u043D\u0438\u043A\u0438",
|
|
56
|
+
[ContactType.Tiktok]: "TikTok",
|
|
57
|
+
[ContactType.Telegram]: "Telegram",
|
|
58
|
+
[ContactType.Max]: "Max"
|
|
59
|
+
};
|
|
60
|
+
function buildSocialUrl(type, value) {
|
|
61
|
+
if (value.startsWith("http://") || value.startsWith("https://")) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
const bases = {
|
|
65
|
+
[ContactType.Vk]: "https://vk.com/",
|
|
66
|
+
[ContactType.Instagram]: "https://instagram.com/",
|
|
67
|
+
[ContactType.Facebook]: "https://facebook.com/",
|
|
68
|
+
[ContactType.Twitter]: "https://x.com/",
|
|
69
|
+
[ContactType.Ok]: "https://ok.ru/",
|
|
70
|
+
[ContactType.Tiktok]: "https://tiktok.com/@",
|
|
71
|
+
[ContactType.Telegram]: "https://t.me/",
|
|
72
|
+
[ContactType.Max]: "https://max.ru/"
|
|
73
|
+
};
|
|
74
|
+
const base = bases[type];
|
|
75
|
+
return base ? `${base}${value}` : value;
|
|
76
|
+
}
|
|
77
|
+
function getSocialLinks(contacts) {
|
|
78
|
+
return contacts.filter((contact) => SOCIAL_TYPES.has(contact.type)).map((contact) => ({
|
|
79
|
+
type: contact.type,
|
|
80
|
+
url: buildSocialUrl(contact.type, contact.value),
|
|
81
|
+
label: SOCIAL_LABELS[contact.type] ?? contact.type
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
function getEmailLink(contacts) {
|
|
85
|
+
const email = contacts.find((c) => c.type === ContactType.Email);
|
|
86
|
+
return email?.value ?? null;
|
|
87
|
+
}
|
|
88
|
+
function getWebsiteLink(contacts) {
|
|
89
|
+
const website = contacts.find((c) => c.type === ContactType.Website);
|
|
90
|
+
return website?.value ?? null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/utils/schedule.ts
|
|
94
|
+
var DAY_TO_JS_INDEX = {
|
|
95
|
+
sunday: 0,
|
|
96
|
+
monday: 1,
|
|
97
|
+
tuesday: 2,
|
|
98
|
+
wednesday: 3,
|
|
99
|
+
thursday: 4,
|
|
100
|
+
friday: 5,
|
|
101
|
+
saturday: 6
|
|
102
|
+
};
|
|
103
|
+
var DAY_ORDER = [
|
|
104
|
+
"monday",
|
|
105
|
+
"tuesday",
|
|
106
|
+
"wednesday",
|
|
107
|
+
"thursday",
|
|
108
|
+
"friday",
|
|
109
|
+
"saturday",
|
|
110
|
+
"sunday"
|
|
111
|
+
];
|
|
112
|
+
function getDayName(dayKey, locale) {
|
|
113
|
+
const index = DAY_TO_JS_INDEX[dayKey];
|
|
114
|
+
if (index === void 0) {
|
|
115
|
+
return dayKey;
|
|
116
|
+
}
|
|
117
|
+
const date = new Date(2e3, 0, 2 + index);
|
|
118
|
+
return new Intl.DateTimeFormat(locale, { weekday: "long" }).format(date);
|
|
119
|
+
}
|
|
120
|
+
var DEFAULT_STATUS_LABELS = { open: "\u041E\u0442\u043A\u0440\u044B\u0442\u043E", closed: "\u0417\u0430\u043A\u0440\u044B\u0442\u043E" };
|
|
121
|
+
var STATUS_LABELS = {
|
|
122
|
+
"ru-RU": DEFAULT_STATUS_LABELS,
|
|
123
|
+
"en-US": { open: "Open", closed: "Closed" }
|
|
124
|
+
};
|
|
125
|
+
function getTodayInfo(schedule) {
|
|
126
|
+
if (!schedule) return null;
|
|
127
|
+
const todayDay = schedule.days[schedule.day_id];
|
|
128
|
+
return {
|
|
129
|
+
isOpenNow: schedule.is_open_now,
|
|
130
|
+
todayHours: todayDay?.hours ?? null,
|
|
131
|
+
openingAt: schedule.opening_at,
|
|
132
|
+
closingAt: schedule.closing_at
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function getWeeklySchedule(schedule, locale = "ru-RU") {
|
|
136
|
+
if (!schedule) return [];
|
|
137
|
+
return DAY_ORDER.map((dayKey) => ({
|
|
138
|
+
dayKey,
|
|
139
|
+
name: getDayName(dayKey, locale),
|
|
140
|
+
hours: schedule.days[dayKey]?.hours ?? null
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
function formatScheduleStatus(schedule, locale = "ru-RU") {
|
|
144
|
+
if (!schedule) return null;
|
|
145
|
+
const labels = STATUS_LABELS[locale] ?? DEFAULT_STATUS_LABELS;
|
|
146
|
+
return schedule.is_open_now ? labels.open : labels.closed;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/utils/qr.ts
|
|
150
|
+
function buildQrCodeUrl(target, apiBaseUrl, size = 200) {
|
|
151
|
+
if (!target) return "";
|
|
152
|
+
const utf8 = typeof window !== "undefined" ? window.btoa(unescape(encodeURIComponent(target))) : Buffer.from(target, "utf-8").toString("base64");
|
|
153
|
+
return `${apiBaseUrl}/media/qrcode?content=${utf8}&input=base64&size=${size}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/utils/date.ts
|
|
157
|
+
function formatDate(date) {
|
|
158
|
+
return new Date(date).toLocaleDateString("ru-RU", {
|
|
159
|
+
day: "numeric",
|
|
160
|
+
month: "long",
|
|
161
|
+
year: "numeric"
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function formatDateTime(date) {
|
|
165
|
+
const d = new Date(date);
|
|
166
|
+
const datePart = d.toLocaleDateString("ru-RU", {
|
|
167
|
+
day: "2-digit",
|
|
168
|
+
month: "2-digit",
|
|
169
|
+
year: "numeric"
|
|
170
|
+
});
|
|
171
|
+
const timePart = d.toLocaleTimeString("ru-RU", {
|
|
172
|
+
hour: "2-digit",
|
|
173
|
+
minute: "2-digit"
|
|
174
|
+
});
|
|
175
|
+
return `${datePart} ${timePart}`;
|
|
176
|
+
}
|
|
177
|
+
function toDateInputValue(value) {
|
|
178
|
+
if (!value) return "";
|
|
179
|
+
return value.slice(0, 10);
|
|
180
|
+
}
|
|
181
|
+
function todayInTimezone(timezone) {
|
|
182
|
+
const now = /* @__PURE__ */ new Date();
|
|
183
|
+
const options = {
|
|
184
|
+
year: "numeric",
|
|
185
|
+
month: "2-digit",
|
|
186
|
+
day: "2-digit"
|
|
187
|
+
};
|
|
188
|
+
if (timezone) {
|
|
189
|
+
options.timeZone = timezone;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
return new Intl.DateTimeFormat("en-CA", options).format(now);
|
|
193
|
+
} catch {
|
|
194
|
+
return new Intl.DateTimeFormat("en-CA").format(now);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/utils/pluralize.ts
|
|
199
|
+
function pluralize(count, one, few, many) {
|
|
200
|
+
const abs = Math.abs(count);
|
|
201
|
+
const mod10 = abs % 10;
|
|
202
|
+
const mod100 = abs % 100;
|
|
203
|
+
if (mod100 >= 11 && mod100 <= 19) return many;
|
|
204
|
+
if (mod10 === 1) return one;
|
|
205
|
+
if (mod10 >= 2 && mod10 <= 4) return few;
|
|
206
|
+
return many;
|
|
207
|
+
}
|
|
208
|
+
function getApiErrorMessage(e, fallback) {
|
|
209
|
+
if (e instanceof ZenkyError && e.err?.message) {
|
|
210
|
+
return e.err.message;
|
|
211
|
+
}
|
|
212
|
+
return fallback;
|
|
213
|
+
}
|
|
214
|
+
function getApiFieldErrors(e) {
|
|
215
|
+
if (e instanceof ZenkyError && e.err?.meta?.errors) {
|
|
216
|
+
return e.err.meta.errors;
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/utils/address.ts
|
|
222
|
+
function formatAddressCityLast(raw) {
|
|
223
|
+
const match = raw.match(/^(г\s[^,]+),\s*(.+)$/);
|
|
224
|
+
return match ? `${match[2]}, ${match[1]}` : raw;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export { buildQrCodeUrl, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, pluralize, toDateInputValue, todayInTimezone };
|
|
228
|
+
//# sourceMappingURL=chunk-PJ2LEKW6.js.map
|
|
229
|
+
//# sourceMappingURL=chunk-PJ2LEKW6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/createOperationChain.ts","../src/utils/phone.ts","../src/utils/contacts.ts","../src/utils/schedule.ts","../src/utils/qr.ts","../src/utils/date.ts","../src/utils/pluralize.ts","../src/utils/errors.ts","../src/utils/address.ts"],"names":[],"mappings":"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","file":"chunk-PJ2LEKW6.js","sourcesContent":["// Сериализует async-операции по ключу: для каждого key гарантирует,\n// что следующая операция начнётся только после завершения предыдущей.\n// Предотвращает гонки при параллельных запросах на один ресурс.\n\nexport interface OperationChain {\n execute: (key: string, fn: () => Promise<void>) => Promise<void>\n readonly size: number\n}\n\nexport function createOperationChain(): OperationChain {\n const chains = new Map<string, Promise<void>>()\n\n async function execute(key: string, fn: () => Promise<void>): Promise<void> {\n const prev = chains.get(key) ?? Promise.resolve()\n\n const current = prev.then(fn)\n\n // catch предотвращает unhandled rejection в цепочке\n const safe = current.catch(() => {})\n chains.set(key, safe)\n\n // Чистим запись, если после завершения не было новых операций\n safe.finally(() => {\n if (chains.get(key) === safe) {\n chains.delete(key)\n }\n })\n\n return current\n }\n\n return {\n execute,\n get size() {\n return chains.size\n },\n }\n}\n","import type { Phone } from '@zenky/storefront-api'\n\nexport function formatPhoneNational(phone: Phone | null | undefined): string | null {\n if (!phone) return null\n\n return phone.national || phone.number\n}\n\nexport function getPhoneTelLink(phone: Phone | null | undefined): string | null {\n if (!phone) return null\n\n return `tel:${phone.number}`\n}\n\n/**\n * «Воздушный» формат номера: `+7 (999) 999-99-99` → `+7 999 999 99 99`.\n * Скобки и дефисы заменяются на пробелы, лишние пробелы схлопываются.\n */\nexport function formatPhoneSpaced(formatted: string | null | undefined): string {\n if (!formatted) return ''\n\n return formatted.replace(/[()-]/g, ' ').replace(/\\s+/g, ' ').trim()\n}\n","import { ContactType } from '@zenky/storefront-api'\n\nimport type { Contact } from '@zenky/storefront-api'\n\nexport interface SocialLink {\n type: ContactType\n url: string\n label: string\n}\n\nconst SOCIAL_TYPES = new Set<ContactType>([\n ContactType.Vk,\n ContactType.Instagram,\n ContactType.Facebook,\n ContactType.Twitter,\n ContactType.Ok,\n ContactType.Tiktok,\n ContactType.Telegram,\n ContactType.Max,\n])\n\nconst SOCIAL_LABELS: Record<string, string> = {\n [ContactType.Vk]: 'ВКонтакте',\n [ContactType.Instagram]: 'Instagram',\n [ContactType.Facebook]: 'Facebook',\n [ContactType.Twitter]: 'Twitter',\n [ContactType.Ok]: 'Одноклассники',\n [ContactType.Tiktok]: 'TikTok',\n [ContactType.Telegram]: 'Telegram',\n [ContactType.Max]: 'Max',\n} as const\n\nfunction buildSocialUrl(type: ContactType, value: string): string {\n if (value.startsWith('http://') || value.startsWith('https://')) {\n return value\n }\n\n const bases: Partial<Record<ContactType, string>> = {\n [ContactType.Vk]: 'https://vk.com/',\n [ContactType.Instagram]: 'https://instagram.com/',\n [ContactType.Facebook]: 'https://facebook.com/',\n [ContactType.Twitter]: 'https://x.com/',\n [ContactType.Ok]: 'https://ok.ru/',\n [ContactType.Tiktok]: 'https://tiktok.com/@',\n [ContactType.Telegram]: 'https://t.me/',\n [ContactType.Max]: 'https://max.ru/',\n }\n\n const base = bases[type]\n\n return base ? `${base}${value}` : value\n}\n\nexport function getSocialLinks(contacts: Contact[]): SocialLink[] {\n return contacts\n .filter((contact) => SOCIAL_TYPES.has(contact.type))\n .map((contact) => ({\n type: contact.type,\n url: buildSocialUrl(contact.type, contact.value),\n label: SOCIAL_LABELS[contact.type] ?? contact.type,\n }))\n}\n\nexport function getEmailLink(contacts: Contact[]): string | null {\n const email = contacts.find((c) => c.type === ContactType.Email)\n\n return email?.value ?? null\n}\n\nexport function getWebsiteLink(contacts: Contact[]): string | null {\n const website = contacts.find((c) => c.type === ContactType.Website)\n\n return website?.value ?? null\n}\n","import type { Schedule } from '@zenky/storefront-api'\n\nexport interface DayScheduleInfo {\n dayKey: string\n name: string\n hours: string | null\n}\n\nexport interface TodayScheduleInfo {\n isOpenNow: boolean\n todayHours: string | null\n openingAt: string | null\n closingAt: string | null\n}\n\n// Маппинг ключей API → индекс дня JS (0=вс, 1=пн, ..., 6=сб)\nconst DAY_TO_JS_INDEX: Record<string, number> = {\n sunday: 0,\n monday: 1,\n tuesday: 2,\n wednesday: 3,\n thursday: 4,\n friday: 5,\n saturday: 6,\n} as const\n\nconst DAY_ORDER = [\n 'monday',\n 'tuesday',\n 'wednesday',\n 'thursday',\n 'friday',\n 'saturday',\n 'sunday',\n] as const\n\n// Опорная дата: 2 января 2000 — это воскресенье (JS index 0).\n// Для dayIndex=0 (вс) прибавляем 0, для 1 (пн) прибавляем 1, и т.д.\nfunction getDayName(dayKey: string, locale: string): string {\n const index = DAY_TO_JS_INDEX[dayKey]\n\n if (index === undefined) {\n return dayKey\n }\n\n const date = new Date(2000, 0, 2 + index)\n\n return new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(date)\n}\n\ninterface StatusLabels {\n open: string\n closed: string\n}\n\nconst DEFAULT_STATUS_LABELS: StatusLabels = { open: 'Открыто', closed: 'Закрыто' }\n\nconst STATUS_LABELS: Record<string, StatusLabels> = {\n 'ru-RU': DEFAULT_STATUS_LABELS,\n 'en-US': { open: 'Open', closed: 'Closed' },\n}\n\nexport function getTodayInfo(schedule: Schedule | null | undefined): TodayScheduleInfo | null {\n if (!schedule) return null\n\n const todayDay = schedule.days[schedule.day_id as keyof typeof schedule.days]\n\n return {\n isOpenNow: schedule.is_open_now,\n todayHours: todayDay?.hours ?? null,\n openingAt: schedule.opening_at,\n closingAt: schedule.closing_at,\n }\n}\n\nexport function getWeeklySchedule(\n schedule: Schedule | null | undefined,\n locale = 'ru-RU'\n): DayScheduleInfo[] {\n if (!schedule) return []\n\n return DAY_ORDER.map((dayKey) => ({\n dayKey,\n name: getDayName(dayKey, locale),\n hours: schedule.days[dayKey]?.hours ?? null,\n }))\n}\n\nexport function formatScheduleStatus(\n schedule: Schedule | null | undefined,\n locale = 'ru-RU'\n): string | null {\n if (!schedule) return null\n\n const labels = STATUS_LABELS[locale] ?? DEFAULT_STATUS_LABELS\n\n return schedule.is_open_now ? labels.open : labels.closed\n}\n","/**\n * Генерирует URL картинки QR-кода через Zenky media API.\n *\n * Контент кодируется в base64 и передаётся в query `content`.\n * `btoa` работает только с Latin-1 — для юникода предварительно прогоняем через\n * `encodeURIComponent` + `unescape`. На сервере используем Buffer.\n */\nexport function buildQrCodeUrl(target: string, apiBaseUrl: string, size = 200): string {\n if (!target) return ''\n\n const utf8 =\n typeof window !== 'undefined'\n ? window.btoa(unescape(encodeURIComponent(target)))\n : Buffer.from(target, 'utf-8').toString('base64')\n\n return `${apiBaseUrl}/media/qrcode?content=${utf8}&input=base64&size=${size}`\n}\n","export function formatDate(date: string): string {\n return new Date(date).toLocaleDateString('ru-RU', {\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n })\n}\n\nexport function formatDateTime(date: string): string {\n const d = new Date(date)\n const datePart = d.toLocaleDateString('ru-RU', {\n day: '2-digit',\n month: '2-digit',\n year: 'numeric',\n })\n const timePart = d.toLocaleTimeString('ru-RU', {\n hour: '2-digit',\n minute: '2-digit',\n })\n return `${datePart} ${timePart}`\n}\n\n/**\n * Извлекает YYYY-MM-DD из ISO-строки (например \"1998-06-02T03:00:00+03:00\" → \"1998-06-02\").\n * Для использования в <input type=\"date\">.\n */\nexport function toDateInputValue(value: string | null): string {\n if (!value) return ''\n return value.slice(0, 10)\n}\n\n/**\n * Сегодняшняя дата в указанном часовом поясе в формате YYYY-MM-DD.\n * Если TZ невалидный или не передан — возвращает дату в локальном TZ браузера.\n *\n * Используется, когда нужно сопоставить «сегодня» с датой из бэка, которая\n * приходит относительно TZ магазина (а не TZ пользователя).\n */\nexport function todayInTimezone(timezone?: string | null): string {\n const now = new Date()\n\n const options: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }\n\n // timeZone добавляем только если задан: под exactOptionalPropertyTypes\n // нельзя присвоить undefined опциональному свойству.\n if (timezone) {\n options.timeZone = timezone\n }\n\n try {\n return new Intl.DateTimeFormat('en-CA', options).format(now)\n } catch {\n // Невалидный TZ — fallback на локальный\n return new Intl.DateTimeFormat('en-CA').format(now)\n }\n}\n","/**\n * Склонение существительных по числу (русский язык).\n *\n * @example\n * pluralize(1, 'позиция', 'позиции', 'позиций') // 'позиция'\n * pluralize(3, 'позиция', 'позиции', 'позиций') // 'позиции'\n * pluralize(5, 'позиция', 'позиции', 'позиций') // 'позиций'\n */\nexport function pluralize(count: number, one: string, few: string, many: string): string {\n const abs = Math.abs(count)\n const mod10 = abs % 10\n const mod100 = abs % 100\n\n if (mod100 >= 11 && mod100 <= 19) return many\n if (mod10 === 1) return one\n if (mod10 >= 2 && mod10 <= 4) return few\n\n return many\n}\n","import { ZenkyError } from '@zenky/storefront-api'\n\n/** Сообщение из ZenkyError (или fallback). */\nexport function getApiErrorMessage(e: unknown, fallback: string): string {\n if (e instanceof ZenkyError && e.err?.message) {\n return e.err.message\n }\n\n return fallback\n}\n\n/** Field-level ошибки из `meta.errors` ответа API (422 validation). */\nexport function getApiFieldErrors(e: unknown): Record<string, string[]> | null {\n if (e instanceof ZenkyError && e.err?.meta?.errors) {\n return e.err.meta.errors as Record<string, string[]>\n }\n\n return null\n}\n","/**\n * Переносит город в конец строки адреса.\n * \"г Улан-Удэ, ул Ленина, д 29\" → \"ул Ленина, д 29, г Улан-Удэ\"\n */\nexport function formatAddressCityLast(raw: string): string {\n const match = raw.match(/^(г\\s[^,]+),\\s*(.+)$/)\n\n return match ? `${match[2]}, ${match[1]}` : raw\n}\n"]}
|
|
@@ -0,0 +1,97 @@
|
|
|
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 { token, phone, countryCode, isAuthenticated, initials, setToken, clearToken, initFromCookie };
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export { useAuthStore, useStoreProfileStore };
|
|
96
|
+
//# sourceMappingURL=chunk-PWHIDGKW.js.map
|
|
97
|
+
//# sourceMappingURL=chunk-PWHIDGKW.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-PWHIDGKW.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 { token, phone, countryCode, isAuthenticated, initials, setToken, clearToken, initFromCookie }\n})\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/money/money.ts
|
|
2
|
+
var asMinor = (value) => value;
|
|
3
|
+
var asMajor = (value) => value;
|
|
4
|
+
function getMinorFactor(currency) {
|
|
5
|
+
const fractionDigits = new Intl.NumberFormat("en", {
|
|
6
|
+
style: "currency",
|
|
7
|
+
currency
|
|
8
|
+
}).resolvedOptions().maximumFractionDigits ?? 2;
|
|
9
|
+
return 10 ** fractionDigits;
|
|
10
|
+
}
|
|
11
|
+
var DEFAULT_LOCALE = "ru-RU";
|
|
12
|
+
function formatPrice(value, currency = "RUB", locale = DEFAULT_LOCALE) {
|
|
13
|
+
if (!value && value !== 0) {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
return new Intl.NumberFormat(locale, {
|
|
17
|
+
style: "currency",
|
|
18
|
+
currency,
|
|
19
|
+
minimumFractionDigits: 0
|
|
20
|
+
}).format(value / getMinorFactor(currency));
|
|
21
|
+
}
|
|
22
|
+
function minorToMajor(value, currency = "RUB") {
|
|
23
|
+
return value / getMinorFactor(currency);
|
|
24
|
+
}
|
|
25
|
+
function majorToMinor(value, currency = "RUB") {
|
|
26
|
+
return Math.round(value * getMinorFactor(currency));
|
|
27
|
+
}
|
|
28
|
+
function minorToMajorString(value, currency = "RUB") {
|
|
29
|
+
const factor = getMinorFactor(currency);
|
|
30
|
+
const major = value / factor;
|
|
31
|
+
return major.toFixed(Math.log10(factor));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { asMajor, asMinor, formatPrice, majorToMinor, minorToMajor, minorToMajorString };
|
|
35
|
+
//# sourceMappingURL=chunk-RO25KNM5.js.map
|
|
36
|
+
//# sourceMappingURL=chunk-RO25KNM5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/money/money.ts"],"names":[],"mappings":";AAmBO,IAAM,OAAA,GAAU,CAAC,KAAA,KAAyB;AAE1C,IAAM,OAAA,GAAU,CAAC,KAAA,KAAyB;AAQjD,SAAS,eAAe,QAAA,EAA0B;AAC9C,EAAA,MAAM,cAAA,GACF,IAAI,IAAA,CAAK,YAAA,CAAa,IAAA,EAAM;AAAA,IACxB,KAAA,EAAO,UAAA;AAAA,IACP;AAAA,GACH,CAAA,CAAE,eAAA,EAAgB,CAAE,qBAAA,IAAyB,CAAA;AAClD,EAAA,OAAO,EAAA,IAAM,cAAA;AACjB;AAMA,IAAM,cAAA,GAAiB,OAAA;AAKhB,SAAS,WAAA,CACZ,KAAA,EACA,QAAA,GAAW,KAAA,EACX,SAAiB,cAAA,EACX;AACN,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,KAAU,CAAA,EAAG;AACvB,IAAA,OAAO,EAAA;AAAA,EACX;AAEA,EAAA,OAAO,IAAI,IAAA,CAAK,YAAA,CAAa,MAAA,EAAQ;AAAA,IACjC,KAAA,EAAO,UAAA;AAAA,IACP,QAAA;AAAA,IACA,qBAAA,EAAuB;AAAA,GAC1B,CAAA,CAAE,MAAA,CAAO,KAAA,GAAQ,cAAA,CAAe,QAAQ,CAAC,CAAA;AAC9C;AAGO,SAAS,YAAA,CAAa,KAAA,EAAe,QAAA,GAAW,KAAA,EAAe;AAClE,EAAA,OAAO,KAAA,GAAQ,eAAe,QAAQ,CAAA;AAC1C;AAGO,SAAS,YAAA,CAAa,KAAA,EAAe,QAAA,GAAW,KAAA,EAAe;AAClE,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,cAAA,CAAe,QAAQ,CAAC,CAAA;AACtD;AAKO,SAAS,kBAAA,CAAmB,KAAA,EAAe,QAAA,GAAW,KAAA,EAAe;AACxE,EAAA,MAAM,MAAA,GAAS,eAAe,QAAQ,CAAA;AACtC,EAAA,MAAM,QAAQ,KAAA,GAAQ,MAAA;AACtB,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,MAAM,CAAC,CAAA;AAC3C","file":"chunk-RO25KNM5.js","sourcesContent":["// Денежные единицы. Золотое правило Zenky:\n// • храним и считаем в МИНОРНЫХ единицах (копейки/тыйны/…) — так отдаёт API;\n// • на часть API-эндпоинтов шлём в МАЖОРНЫХ (рубли) числом или строкой.\n//\n// Compat-функции ниже имеют те же сигнатуры, что и app/storefront/utils/price.ts —\n// это drop-in замена (не ломает call-site при переносе).\n\n// ── Branded types (opt-in, для нового кода) ────────────────────────────────\n// Minor и Major — разные типы, компилятор не даст их перепутать:\n// sendToServer(bill: Minor) ← передать Major = ошибка компиляции.\ndeclare const MINOR: unique symbol\ndeclare const MAJOR: unique symbol\n\n/** Сумма в минорных единицах (копейки). Так хранит и отдаёт API. */\nexport type Minor = number & { readonly [MINOR]: true }\n/** Сумма в мажорных единицах (рубли). В таком виде их ждёт часть API. */\nexport type Major = number & { readonly [MAJOR]: true }\n\n/** Помечает сырое число с API как Minor (assert без рантайм-стоимости). */\nexport const asMinor = (value: number): Minor => value as Minor\n/** Помечает число как Major. */\nexport const asMajor = (value: number): Major => value as Major\n\n// ── Currency helpers ────────────────────────────────────────────────────────\n\n/**\n * Множитель минор→мажор по ISO-коду валюты через Intl (без хардкода справочников):\n * RUB/KZT/THB/EUR/USD = ×100, JPY/KRW = ×1, KWD/BHD/OMR = ×1000.\n */\nfunction getMinorFactor(currency: string): number {\n const fractionDigits =\n new Intl.NumberFormat('en', {\n style: 'currency',\n currency,\n }).resolvedOptions().maximumFractionDigits ?? 2\n return 10 ** fractionDigits\n}\n\n/**\n * Дефолтная локаль форматирования. Влияет на разделители (1 290 ₽ vs 1,290 ₽).\n * `ru-RU` подходит для RU/KZ/BY/UA. Для TH/JP/ENG передавай `locale` аргументом.\n */\nconst DEFAULT_LOCALE = 'ru-RU' as const\n\n// ── Compat API (прежние сигнатуры на number — drop-in) ──────────────────────\n\n/** Форматирует цену из минорных единиц в читаемый вид (`1 290 ₽`). */\nexport function formatPrice(\n value?: number | null,\n currency = 'RUB',\n locale: string = DEFAULT_LOCALE\n): string {\n if (!value && value !== 0) {\n return ''\n }\n\n return new Intl.NumberFormat(locale, {\n style: 'currency',\n currency,\n minimumFractionDigits: 0,\n }).format(value / getMinorFactor(currency))\n}\n\n/** Сырая конвертация минор → мажор (копейки → рубли) без форматирования. */\nexport function minorToMajor(value: number, currency = 'RUB'): number {\n return value / getMinorFactor(currency)\n}\n\n/** Сырая конвертация мажор → минор (рубли → копейки), округление до целого. */\nexport function majorToMinor(value: number, currency = 'RUB'): number {\n return Math.round(value * getMinorFactor(currency))\n}\n\n/**\n * Минор → мажор строкой. API payments/bonuses ждёт сумму строкой в рублях `\"103.50\"`.\n */\nexport function minorToMajorString(value: number, currency = 'RUB'): string {\n const factor = getMinorFactor(currency)\n const major = value / factor\n return major.toFixed(Math.log10(factor))\n}\n"]}
|
|
@@ -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"]}
|