@zenky/storefront-vue 0.10.3 → 0.10.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +90 -1
  2. package/README.md +76 -6
  3. package/dist/cart/index.js +5 -7
  4. package/dist/catalog/index.d.ts +1 -11
  5. package/dist/catalog/index.js +1 -1
  6. package/dist/chunk-2CI4RW7V.js +21 -0
  7. package/dist/chunk-2CI4RW7V.js.map +1 -0
  8. package/dist/{chunk-GW2QNTAD.js → chunk-4IFPVEO7.js} +3 -113
  9. package/dist/chunk-4IFPVEO7.js.map +1 -0
  10. package/dist/{chunk-N3NOTJUC.js → chunk-4YAEIKLA.js} +4 -6
  11. package/dist/chunk-4YAEIKLA.js.map +1 -0
  12. package/dist/{chunk-TEG7EL4N.js → chunk-CUSQYIEU.js} +46 -17
  13. package/dist/chunk-CUSQYIEU.js.map +1 -0
  14. package/dist/{chunk-57IOMDAM.js → chunk-CY6LA6C7.js} +3 -3
  15. package/dist/{chunk-57IOMDAM.js.map → chunk-CY6LA6C7.js.map} +1 -1
  16. package/dist/{chunk-GLTOJTZO.js → chunk-MOG6UMFM.js} +6 -3
  17. package/dist/chunk-MOG6UMFM.js.map +1 -0
  18. package/dist/{chunk-RYYY7MVP.js → chunk-NG7RUIWW.js} +3 -13
  19. package/dist/chunk-NG7RUIWW.js.map +1 -0
  20. package/dist/{chunk-JLFBAAFT.js → chunk-Q2TVQ3BG.js} +4 -5
  21. package/dist/chunk-Q2TVQ3BG.js.map +1 -0
  22. package/dist/{chunk-FFBZKQRV.js → chunk-SHASMBMV.js} +42 -5
  23. package/dist/chunk-SHASMBMV.js.map +1 -0
  24. package/dist/{chunk-G2X4SBCO.js → chunk-SPMUTUNX.js} +50 -50
  25. package/dist/chunk-SPMUTUNX.js.map +1 -0
  26. package/dist/index.d.ts +5 -7
  27. package/dist/index.js +13 -15
  28. package/dist/order/index.d.ts +2 -0
  29. package/dist/order/index.js +2 -5
  30. package/dist/order/index.js.map +1 -1
  31. package/dist/ports/index.d.ts +14 -2
  32. package/dist/ports/index.js +1 -1
  33. package/dist/products/index.js +3 -4
  34. package/dist/promotions/index.d.ts +13 -0
  35. package/dist/promotions/index.js +3 -5
  36. package/dist/seo/index.d.ts +5 -11
  37. package/dist/seo/index.js +14 -24
  38. package/dist/seo/index.js.map +1 -1
  39. package/dist/snippets/index.d.ts +21 -15
  40. package/dist/snippets/index.js +1 -1
  41. package/dist/stores/index.d.ts +1 -1
  42. package/dist/stores/index.js +3 -5
  43. package/dist/theme/index.d.ts +1 -11
  44. package/dist/theme/index.js +1 -1
  45. package/dist/utils/index.d.ts +26 -3
  46. package/dist/website-settings/index.d.ts +1 -1
  47. package/docs/consumer-setup.md +15 -4
  48. package/docs/ports.md +5 -1
  49. package/docs/releasing.md +10 -2
  50. package/package.json +8 -10
  51. package/dist/chunk-7FRMMCR5.js +0 -93
  52. package/dist/chunk-7FRMMCR5.js.map +0 -1
  53. package/dist/chunk-BWUKMWHL.js +0 -45
  54. package/dist/chunk-BWUKMWHL.js.map +0 -1
  55. package/dist/chunk-FFBZKQRV.js.map +0 -1
  56. package/dist/chunk-G2X4SBCO.js.map +0 -1
  57. package/dist/chunk-GLTOJTZO.js.map +0 -1
  58. package/dist/chunk-GW2QNTAD.js.map +0 -1
  59. package/dist/chunk-JLFBAAFT.js.map +0 -1
  60. package/dist/chunk-N3NOTJUC.js.map +0 -1
  61. package/dist/chunk-RYYY7MVP.js.map +0 -1
  62. package/dist/chunk-TEG7EL4N.js.map +0 -1
  63. package/dist/chunk-V3VVDQIR.js +0 -27
  64. package/dist/chunk-V3VVDQIR.js.map +0 -1
  65. package/dist/layout/index.d.ts +0 -54
  66. package/dist/layout/index.js +0 -106
  67. package/dist/layout/index.js.map +0 -1
  68. package/dist/schedule-Dd3zwHEb.d.ts +0 -27
  69. package/dist/snippets-BC5bkSjm.d.ts +0 -23
@@ -11,7 +11,7 @@ Use an exact version while integrating or testing a prerelease. Upgrade delibera
11
11
  after the consumer quality gate is green.
12
12
 
13
13
  ```bash
14
- npm install --save-exact @zenky/storefront-vue@0.10.0
14
+ npm install --save-exact @zenky/storefront-vue@0.10.5
15
15
  ```
16
16
 
17
17
  The consumer must also provide compatible peer dependencies:
@@ -39,7 +39,7 @@ import { useCartStore } from '@zenky/storefront-vue/stores'
39
39
  A read-only menu normally needs `catalog`, `products`, `theme`, `utils`, and selected
40
40
  stores. It does not need cart, checkout, auth, delivery, or payment modules.
41
41
 
42
- A full storefront can additionally use `cart`, `order`, `promotions`, `seo`, `layout`,
42
+ A full storefront can additionally use `cart`, `order`, `promotions`, `seo`,
43
43
  `pagination`, `snippets`, and `website-settings`.
44
44
 
45
45
  Never import from `@zenky/storefront-vue/dist/*` or from this repository's `src/*`.
@@ -80,6 +80,9 @@ const runtime: StorefrontRuntime = {
80
80
  warning: (message) => notifications.warning(message),
81
81
  message: (title, options) => notifications.message(title, options),
82
82
  },
83
+ messages: {
84
+ format: (key, params) => i18n.t(key, params),
85
+ },
83
86
  activity: {
84
87
  begin: (kind) => busy.begin(kind),
85
88
  end: (kind) => busy.end(kind),
@@ -107,8 +110,13 @@ import type { StorefrontRuntime } from '@zenky/storefront-vue/ports'
107
110
  export default defineNuxtPlugin((nuxtApp) => {
108
111
  const config = useRuntimeConfig()
109
112
 
113
+ // One SDK client per request. The client is mutable — auth stores call
114
+ // `setApiToken()` on it — so a process-wide instance leaks one user's Bearer
115
+ // into other SSR requests. This plugin runs per request, so build it here.
116
+ const sdk = new ZenkyStorefront({ baseUrl, baseAuthUrl, client: 'web' })
117
+
110
118
  const runtime: StorefrontRuntime = {
111
- sdk: useStorefrontApi(),
119
+ sdk,
112
120
  config: {
113
121
  baseUrl: config.public.storefrontBaseUrl,
114
122
  baseAuthUrl: config.public.storefrontAuthUrl,
@@ -123,6 +131,7 @@ export default defineNuxtPlugin((nuxtApp) => {
123
131
  },
124
132
  },
125
133
  notifier: createNotifierAdapter(),
134
+ messages: createMessageFormatter(),
126
135
  activity: createActivityAdapter(),
127
136
  }
128
137
 
@@ -170,7 +179,9 @@ For every server request, create a new:
170
179
  1. Vue application;
171
180
  2. Pinia instance;
172
181
  3. `StorefrontRuntime`;
173
- 4. storage adapter.
182
+ 4. storage adapter;
183
+ 5. **SDK client** — it holds a mutable auth token, so sharing one across requests
184
+ leaks credentials between users.
174
185
 
175
186
  Do not keep runtime or Pinia instances in module-global server state. Runtime-owned
176
187
  mutation versions, request deduplication, restriction gates, and related-product state
package/docs/ports.md CHANGED
@@ -33,6 +33,7 @@ const runtime: StorefrontRuntime = {
33
33
  },
34
34
  storage,
35
35
  notifier,
36
+ messages,
36
37
  activity,
37
38
  }
38
39
 
@@ -48,18 +49,21 @@ scope instead of installing the plugin globally.
48
49
  | Port | Contract | Responsibility |
49
50
  | --- | --- | --- |
50
51
  | `sdk` | `ZenkyStorefront` | Typed access to Zenky Storefront API resources. The consumer owns configuration and request transport. |
51
- | `config` | `StorefrontConfig` | Public storefront and auth base URLs plus an optional sales channel id. |
52
52
  | `storage` | `StorageAdapter` | Synchronous key/value persistence used for order/auth state and lightweight preferences. |
53
53
  | `notifier` | `Notifier` | User-facing `error`, `success`, `warning`, and generic message notifications. |
54
+ | `messages` | `MessageFormatter` | Maps stable domain message keys and parameters to localized consumer copy. |
54
55
  | `activity` | `ActivityReporter` | Balanced `begin(kind)` / `end(kind)` signals for long-running operations. |
55
56
 
56
57
  Required ports are intentionally small. If an application has no UI for notifications or
57
58
  activity, use `NOOP_NOTIFIER` and `NOOP_ACTIVITY_REPORTER` explicitly.
59
+ For tests that do not render messages, use `KEY_MESSAGE_FORMATTER`. Production consumers
60
+ should provide a locale-aware formatter.
58
61
 
59
62
  ## Optional ports
60
63
 
61
64
  | Port | Contract | Behavior when absent |
62
65
  | --- | --- | --- |
66
+ | `config` | `StorefrontConfig` | No behavior changes; the current core does not read this reserved consumer configuration. |
63
67
  | `events` | Lazy `EventsPort.get()` returning `ZenkyIntegrationsSDK` | Integration events are skipped. |
64
68
  | `realtime` | Lazy `RealtimePort.get()` returning `RealtimeAdapter` | Realtime order updates are skipped. |
65
69
  | `catalogReloader` | `CatalogReloader.reload()` | Stock changes do not trigger an external catalog reload. |
package/docs/releasing.md CHANGED
@@ -13,8 +13,15 @@ from the release tag.
13
13
  - patch for compatible fixes and security hardening;
14
14
  - minor for backward-compatible public features;
15
15
  - major for breaking exports, port contracts, behavior, or support changes.
16
+
17
+ While the package is below `1.0.0`, SemVer does not reserve any component for
18
+ stability ([SemVer §4](https://semver.org/spec/v2.0.0.html#spec-item-4)). A breaking
19
+ release may stay inside the current `0.x.y` range when every consumer is known and
20
+ migrated in the same change. State it explicitly at the top of the changelog section
21
+ and write the migration steps. Once `1.0.0` ships, the table above is binding.
16
22
  5. Verify migrations and compatibility notes are explicit for any consumer-visible change.
17
- 6. Run `npm run check:release` and inspect `npm pack --dry-run` locally.
23
+ 6. Update the version referenced in `docs/consumer-setup.md` to the one being released.
24
+ 7. Run `npm run check:release` and inspect `npm pack --dry-run` locally.
18
25
 
19
26
  ## Publish
20
27
 
@@ -34,7 +41,8 @@ The npm package must have a trusted publisher configured for this GitHub reposit
34
41
 
35
42
  ## Verify
36
43
 
37
- - Confirm the workflow completed and the package has npm provenance.
44
+ - Confirm the workflow completed. This private repository intentionally publishes without
45
+ npm provenance; enable and verify provenance only after the source repository is public.
38
46
  - Inspect `npm view @zenky/storefront-vue@X.Y.Z` metadata and dist-tags.
39
47
  - Install the exact version into a clean consumer and import both the root and one subpath.
40
48
  - Confirm the GitHub release links to the correct tag and changelog section.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenky/storefront-vue",
3
- "version": "0.10.3",
3
+ "version": "0.10.5",
4
4
  "description": "Zenky Storefront SDK for Vue 3.",
5
5
  "keywords": [
6
6
  "zenky",
@@ -70,10 +70,6 @@
70
70
  "types": "./dist/seo/index.d.ts",
71
71
  "import": "./dist/seo/index.js"
72
72
  },
73
- "./layout": {
74
- "types": "./dist/layout/index.d.ts",
75
- "import": "./dist/layout/index.js"
76
- },
77
73
  "./pagination": {
78
74
  "types": "./dist/pagination/index.d.ts",
79
75
  "import": "./dist/pagination/index.js"
@@ -108,16 +104,18 @@
108
104
  "test:coverage": "vitest run --coverage",
109
105
  "test:watch": "vitest",
110
106
  "check:exports": "publint --strict && attw --pack . --profile esm-only",
107
+ "check:boundaries": "node scripts/check-boundaries.mjs",
108
+ "check:context": "node scripts/check-context.mjs",
111
109
  "check:runtime": "node scripts/check-runtime-compat.mjs",
112
110
  "check:size": "node scripts/check-bundle-size.mjs",
113
- "check": "npm run format:check && npm run lint && npm run typecheck && npm run test && npm run build && npm run check:exports && npm run check:runtime && npm run check:size",
114
- "check:ci": "npm run format:check && npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run check:exports && npm run check:runtime && npm run check:size",
115
- "check:release": "npm run typecheck && npm run test && npm run build && npm run check:exports && npm run check:runtime && npm run check:size",
111
+ "check": "npm run format:check && npm run lint && npm run typecheck && npm run test && npm run check:boundaries && npm run check:context && npm run build && npm run check:exports && npm run check:runtime && npm run check:size",
112
+ "check:ci": "npm run format:check && npm run lint && npm run typecheck && npm run test:coverage && npm run check:boundaries && npm run check:context && npm run build && npm run check:exports && npm run check:runtime && npm run check:size",
113
+ "check:release": "npm run typecheck && npm run test && npm run check:boundaries && npm run check:context && npm run build && npm run check:exports && npm run check:runtime && npm run check:size",
116
114
  "prepublishOnly": "npm run check:release"
117
115
  },
118
116
  "peerDependencies": {
119
117
  "@zenky/integrations-sdk": ">=0.1.3",
120
- "@zenky/storefront-api": ">=0.0.68",
118
+ "@zenky/storefront-api": "^1.0.1",
121
119
  "pinia": "^3.0.0",
122
120
  "vue": "^3.5.0"
123
121
  },
@@ -127,7 +125,7 @@
127
125
  "@types/node": "^22.10.0",
128
126
  "@vitest/coverage-v8": "^4.1.10",
129
127
  "@zenky/integrations-sdk": "^0.1.3",
130
- "@zenky/storefront-api": "^0.0.68",
128
+ "@zenky/storefront-api": "^1.0.1",
131
129
  "pinia": "^3.0.4",
132
130
  "publint": "^0.3.21",
133
131
  "tsup": "^8.3.5",
@@ -1,93 +0,0 @@
1
- // src/snippets/snippets.ts
2
- function normalizeSnippets(groups) {
3
- if (!Array.isArray(groups)) return [];
4
- return groups.flatMap(
5
- (group, groupIndex) => (group.snippets ?? []).filter((item) => !!item.content?.trim()).map((item, itemIndex) => {
6
- const snippet = {
7
- id: `${group.region}-${groupIndex}-${itemIndex}`,
8
- position: group.region,
9
- language: item.language,
10
- code: item.content,
11
- enabled: item.enabled ?? true
12
- };
13
- if (item.name !== void 0) snippet.name = item.name;
14
- return snippet;
15
- })
16
- );
17
- }
18
-
19
- // src/snippets/buildSnippetHead.ts
20
- function wrapSnippetJs(snippet) {
21
- const id = JSON.stringify(snippet.id);
22
- return `;(() => {
23
- try {
24
- ${snippet.code}
25
- } catch (error) {
26
- console.error('[snippet:error]', { id: ${id}, error });
27
- window.dispatchEvent(new CustomEvent('zenky:snippet-error', {
28
- detail: { id: ${id}, message: error instanceof Error ? error.message : String(error) },
29
- }));
30
- }
31
- })();`;
32
- }
33
- function parseTagAttributes(raw) {
34
- const attrs = {};
35
- const re = /([a-zA-Z][\w:-]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
36
- for (const match of raw.matchAll(re)) {
37
- const name = match[1];
38
- if (name) attrs[name] = match[2] ?? match[3] ?? match[4] ?? true;
39
- }
40
- return attrs;
41
- }
42
- function parseHeadHtml(html) {
43
- const result = { meta: [], link: [], script: [] };
44
- const metaRe = /<meta\b([^>]*)>/gi;
45
- for (const match of html.matchAll(metaRe)) {
46
- result.meta.push(parseTagAttributes(match[1] ?? ""));
47
- }
48
- const linkRe = /<link\b([^>]*)>/gi;
49
- for (const match of html.matchAll(linkRe)) {
50
- result.link.push(parseTagAttributes(match[1] ?? ""));
51
- }
52
- const scriptRe = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
53
- for (const match of html.matchAll(scriptRe)) {
54
- const attrs = parseTagAttributes(match[1] ?? "");
55
- const inner = (match[2] ?? "").trim();
56
- result.script.push(inner ? { ...attrs, innerHTML: inner } : attrs);
57
- }
58
- return result;
59
- }
60
- function buildSnippetHead(snippets) {
61
- const enabled = snippets.filter((s) => s.enabled);
62
- const jsSnippets = enabled.filter((s) => s.language === "javascript");
63
- const cssSnippets = enabled.filter((s) => s.language === "css");
64
- const headHtmlSnippets = enabled.filter(
65
- (s) => s.language === "html" && s.position.startsWith("head")
66
- );
67
- const parsedHead = headHtmlSnippets.map((s) => parseHeadHtml(s.code));
68
- const headMeta = parsedHead.flatMap((p) => p.meta);
69
- const headLink = parsedHead.flatMap((p) => p.link);
70
- const headScripts = parsedHead.flatMap((p) => p.script);
71
- return {
72
- meta: headMeta,
73
- link: headLink,
74
- script: [
75
- ...jsSnippets.map((snippet) => ({
76
- key: `snippet-js-${snippet.id}`,
77
- innerHTML: wrapSnippetJs(snippet),
78
- body: snippet.position.startsWith("body"),
79
- "data-snippet-id": snippet.id
80
- })),
81
- ...headScripts
82
- ],
83
- style: cssSnippets.map((snippet) => ({
84
- key: `snippet-css-${snippet.id}`,
85
- innerHTML: snippet.code,
86
- "data-snippet-id": snippet.id
87
- }))
88
- };
89
- }
90
-
91
- export { buildSnippetHead, normalizeSnippets };
92
- //# sourceMappingURL=chunk-7FRMMCR5.js.map
93
- //# sourceMappingURL=chunk-7FRMMCR5.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/snippets/snippets.ts","../src/snippets/buildSnippetHead.ts"],"names":[],"mappings":"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","file":"chunk-7FRMMCR5.js","sourcesContent":["export type SnippetPosition = 'head_start' | 'head_end' | 'body_start' | 'body_end'\nexport type SnippetLanguage = 'html' | 'css' | 'javascript'\n\nexport interface Snippet {\n id: string\n name?: string\n position: SnippetPosition\n language: SnippetLanguage\n code: string\n enabled: boolean\n}\n\nexport interface RawSnippetItem {\n language: SnippetLanguage\n content: string\n enabled?: boolean\n name?: string\n}\n\nexport interface SnippetGroup {\n region: SnippetPosition\n snippets: RawSnippetItem[]\n}\n\nexport function normalizeSnippets(groups: SnippetGroup[] | null | undefined): Snippet[] {\n if (!Array.isArray(groups)) return []\n\n return groups.flatMap((group, groupIndex) =>\n (group.snippets ?? [])\n .filter((item) => !!item.content?.trim())\n .map((item, itemIndex): Snippet => {\n const snippet: Snippet = {\n id: `${group.region}-${groupIndex}-${itemIndex}`,\n position: group.region,\n language: item.language,\n code: item.content,\n enabled: item.enabled ?? true,\n }\n // exactOptionalPropertyTypes: name задаём только если оно есть\n if (item.name !== undefined) snippet.name = item.name\n return snippet\n })\n )\n}\n","import type { Snippet } from './snippets'\n\n/** Head-нагрузка для инъекции сниппетов (потребитель отдаёт её в useHead). */\nexport interface SnippetHead {\n meta: Record<string, string | boolean>[]\n link: Record<string, string | boolean>[]\n script: Record<string, unknown>[]\n style: Record<string, string | boolean>[]\n}\n\n/** JS-сниппет в try/catch с dispatch `zenky:snippet-error` при падении. */\nfunction wrapSnippetJs(snippet: Snippet): string {\n const id = JSON.stringify(snippet.id)\n return `;(() => {\n try {\n ${snippet.code}\n } catch (error) {\n console.error('[snippet:error]', { id: ${id}, error });\n window.dispatchEvent(new CustomEvent('zenky:snippet-error', {\n detail: { id: ${id}, message: error instanceof Error ? error.message : String(error) },\n }));\n }\n})();`\n}\n\ntype HeadAttrs = Record<string, string | boolean>\n\ninterface ParsedHeadHtml {\n meta: HeadAttrs[]\n link: HeadAttrs[]\n script: Array<HeadAttrs & { innerHTML?: string }>\n}\n\nfunction parseTagAttributes(raw: string): HeadAttrs {\n const attrs: HeadAttrs = {}\n const re = /([a-zA-Z][\\w:-]*)(?:\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s\"'=<>`]+)))?/g\n for (const match of raw.matchAll(re)) {\n const name = match[1]\n if (name) attrs[name] = match[2] ?? match[3] ?? match[4] ?? true\n }\n return attrs\n}\n\nfunction parseHeadHtml(html: string): ParsedHeadHtml {\n const result: ParsedHeadHtml = { meta: [], link: [], script: [] }\n\n const metaRe = /<meta\\b([^>]*)>/gi\n for (const match of html.matchAll(metaRe)) {\n result.meta.push(parseTagAttributes(match[1] ?? ''))\n }\n\n const linkRe = /<link\\b([^>]*)>/gi\n for (const match of html.matchAll(linkRe)) {\n result.link.push(parseTagAttributes(match[1] ?? ''))\n }\n\n const scriptRe = /<script\\b([^>]*)>([\\s\\S]*?)<\\/script>/gi\n for (const match of html.matchAll(scriptRe)) {\n const attrs = parseTagAttributes(match[1] ?? '')\n const inner = (match[2] ?? '').trim()\n result.script.push(inner ? { ...attrs, innerHTML: inner } : attrs)\n }\n\n return result\n}\n\n/**\n * Раскладывает сниппеты магазина в head-нагрузку: JS (обёрнут в try/catch),\n * CSS (style), head-HTML (распарсенные meta/link/script). Инъекция — у потребителя.\n */\nexport function buildSnippetHead(snippets: Snippet[]): SnippetHead {\n const enabled = snippets.filter((s) => s.enabled)\n\n const jsSnippets = enabled.filter((s) => s.language === 'javascript')\n const cssSnippets = enabled.filter((s) => s.language === 'css')\n const headHtmlSnippets = enabled.filter(\n (s) => s.language === 'html' && s.position.startsWith('head')\n )\n\n const parsedHead = headHtmlSnippets.map((s) => parseHeadHtml(s.code))\n const headMeta = parsedHead.flatMap((p) => p.meta)\n const headLink = parsedHead.flatMap((p) => p.link)\n const headScripts = parsedHead.flatMap((p) => p.script)\n\n return {\n meta: headMeta,\n link: headLink,\n script: [\n ...jsSnippets.map((snippet) => ({\n key: `snippet-js-${snippet.id}`,\n innerHTML: wrapSnippetJs(snippet),\n body: snippet.position.startsWith('body'),\n 'data-snippet-id': snippet.id,\n })),\n ...headScripts,\n ],\n style: cssSnippets.map((snippet) => ({\n key: `snippet-css-${snippet.id}`,\n innerHTML: snippet.code,\n 'data-snippet-id': snippet.id,\n })),\n }\n}\n"]}
@@ -1,45 +0,0 @@
1
- import { defineStore } from 'pinia';
2
- import { ref, computed } from 'vue';
3
-
4
- // src/stores/promotions.ts
5
- var usePromotionsStore = defineStore("zenky-promotions", () => {
6
- const rewards = ref([]);
7
- const checking = ref(false);
8
- function addOrUpdateReward(selection) {
9
- const index = rewards.value.findIndex((r) => r.promotionId === selection.promotionId);
10
- if (index >= 0) {
11
- rewards.value[index] = selection;
12
- } else {
13
- rewards.value.push(selection);
14
- }
15
- }
16
- function removeRewardByPromotion(promotionId) {
17
- rewards.value = rewards.value.filter((r) => r.promotionId !== promotionId);
18
- }
19
- function clearRewards() {
20
- rewards.value = [];
21
- }
22
- function setChecking(value) {
23
- checking.value = value;
24
- }
25
- const hasRewards = computed(() => rewards.value.length > 0);
26
- const totalEmptySlots = computed(() => rewards.value.reduce((sum, r) => sum + r.limit, 0));
27
- const rewardSelection = computed(() => rewards.value[0] ?? null);
28
- const needsSelection = computed(() => rewards.value.some((r) => r.context !== null));
29
- return {
30
- rewards,
31
- checking,
32
- addOrUpdateReward,
33
- removeRewardByPromotion,
34
- clearRewards,
35
- setChecking,
36
- hasRewards,
37
- totalEmptySlots,
38
- rewardSelection,
39
- needsSelection
40
- };
41
- });
42
-
43
- export { usePromotionsStore };
44
- //# sourceMappingURL=chunk-BWUKMWHL.js.map
45
- //# sourceMappingURL=chunk-BWUKMWHL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/stores/promotions.ts"],"names":[],"mappings":";;;;AA6BO,IAAM,kBAAA,GAAqB,WAAA,CAAY,kBAAA,EAAoB,MAAuB;AAErF,EAAA,MAAM,OAAA,GAAU,GAAA,CAAuB,EAAE,CAAA;AAEzC,EAAA,MAAM,QAAA,GAAW,IAAI,KAAK,CAAA;AAE1B,EAAA,SAAS,kBAAkB,SAAA,EAAkC;AACzD,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,CAAM,SAAA,CAAU,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB,SAAA,CAAU,WAAW,CAAA;AACpF,IAAA,IAAI,SAAS,CAAA,EAAG;AACZ,MAAA,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,GAAI,SAAA;AAAA,IAC3B,CAAA,MAAO;AACH,MAAA,OAAA,CAAQ,KAAA,CAAM,KAAK,SAAS,CAAA;AAAA,IAChC;AAAA,EACJ;AAEA,EAAA,SAAS,wBAAwB,WAAA,EAA2B;AACxD,IAAA,OAAA,CAAQ,KAAA,GAAQ,QAAQ,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,WAAW,CAAA;AAAA,EAC7E;AAEA,EAAA,SAAS,YAAA,GAAqB;AAC1B,IAAA,OAAA,CAAQ,QAAQ,EAAC;AAAA,EACrB;AAEA,EAAA,SAAS,YAAY,KAAA,EAAsB;AACvC,IAAA,QAAA,CAAS,KAAA,GAAQ,KAAA;AAAA,EACrB;AAEA,EAAA,MAAM,aAAa,QAAA,CAAS,MAAM,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAC,CAAA;AAE1D,EAAA,MAAM,eAAA,GAAkB,QAAA,CAAS,MAAM,OAAA,CAAQ,KAAA,CAAM,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,KAAA,EAAO,CAAC,CAAC,CAAA;AAEzF,EAAA,MAAM,kBAAkB,QAAA,CAAiC,MAAM,QAAQ,KAAA,CAAM,CAAC,KAAK,IAAI,CAAA;AACvF,EAAA,MAAM,cAAA,GAAiB,QAAA,CAAS,MAAM,OAAA,CAAQ,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,IAAI,CAAC,CAAA;AAEnF,EAAA,OAAO;AAAA,IACH,OAAA;AAAA,IACA,QAAA;AAAA,IACA,iBAAA;AAAA,IACA,uBAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,IACA,eAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACJ;AACJ,CAAC","file":"chunk-BWUKMWHL.js","sourcesContent":["import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nexport interface RewardSelectionContext {\n type: string\n id: string\n}\n\nexport interface RewardSelection {\n offerId: string\n promotionId: string\n rewardId: string\n context: RewardSelectionContext | null\n limit: number\n}\n\nexport interface PromotionsStore {\n rewards: Ref<RewardSelection[]>\n checking: Ref<boolean>\n addOrUpdateReward: (selection: RewardSelection) => void\n removeRewardByPromotion: (promotionId: string) => void\n clearRewards: () => void\n setChecking: (value: boolean) => void\n hasRewards: ComputedRef<boolean>\n totalEmptySlots: ComputedRef<number>\n rewardSelection: ComputedRef<RewardSelection | null>\n needsSelection: ComputedRef<boolean>\n}\n\nexport const usePromotionsStore = defineStore('zenky-promotions', (): PromotionsStore => {\n /** Доступные награды (может быть несколько акций одновременно) */\n const rewards = ref<RewardSelection[]>([])\n /** Идёт проверка промо-акций */\n const checking = ref(false)\n\n function addOrUpdateReward(selection: RewardSelection): void {\n const index = rewards.value.findIndex((r) => r.promotionId === selection.promotionId)\n if (index >= 0) {\n rewards.value[index] = selection\n } else {\n rewards.value.push(selection)\n }\n }\n\n function removeRewardByPromotion(promotionId: string): void {\n rewards.value = rewards.value.filter((r) => r.promotionId !== promotionId)\n }\n\n function clearRewards(): void {\n rewards.value = []\n }\n\n function setChecking(value: boolean): void {\n checking.value = value\n }\n\n const hasRewards = computed(() => rewards.value.length > 0)\n /** Общее количество пустых слотов по всем акциям */\n const totalEmptySlots = computed(() => rewards.value.reduce((sum, r) => sum + r.limit, 0))\n /** Для обратной совместимости — первая награда */\n const rewardSelection = computed<RewardSelection | null>(() => rewards.value[0] ?? null)\n const needsSelection = computed(() => rewards.value.some((r) => r.context !== null))\n\n return {\n rewards,\n checking,\n addOrUpdateReward,\n removeRewardByPromotion,\n clearRewards,\n setChecking,\n hasRewards,\n totalEmptySlots,\n rewardSelection,\n needsSelection,\n }\n})\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/stores/order-settings.ts","../src/stores/cart.ts"],"names":["defineStore","ref","raw","computed"],"mappings":"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","file":"chunk-FFBZKQRV.js","sourcesContent":["import { DeliveryMethod } from '@zenky/storefront-api'\nimport { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { City, Stock } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\n\n// Ключи совпадают с прежними CookieKey.* — чтобы не потерять сохранённые настройки.\nconst KEY_DELIVERY_METHOD = 'zenky_delivery_method'\nconst KEY_ON_PREMISE_TABLE = 'zenky_on_premise_table'\nconst KEY_SELECTED_STOCK_ID = 'zenky_selected_stock_id'\nconst KEY_SELECTED_ADDRESS = 'zenky_selected_address'\nconst KEY_SELECTED_ADDRESS_ID = 'zenky_selected_address_id'\nconst KEY_SELECTED_ADDRESS_NAME = 'zenky_selected_address_name'\n\nconst VALID_DELIVERY_METHODS = new Set<string>(Object.values(DeliveryMethod))\n\nexport interface OrderSettingsStore {\n deliveryMethod: Ref<DeliveryMethod>\n onPremiseTable: Ref<string | null>\n selectedStock: Ref<Stock | null>\n selectedAddress: Ref<string | null>\n selectedAddressId: Ref<string | null>\n selectedAddressName: Ref<string | null>\n setDeliveryMethod: (method: DeliveryMethod) => void\n setOnPremiseTable: (table: string | null) => void\n setSelectedStock: (stock: Stock | null) => void\n setSelectedAddress: (\n address: string | null,\n addressId?: string | null,\n addressName?: string | null\n ) => void\n validateDeliveryMethod: (availableMethods: DeliveryMethod[]) => void\n restoreFromCookies: (city: City) => void\n isDelivery: ComputedRef<boolean>\n isPickup: ComputedRef<boolean>\n isOnPremise: ComputedRef<boolean>\n needsAddress: ComputedRef<boolean>\n needsStock: ComputedRef<boolean>\n needsTable: ComputedRef<boolean>\n}\n\nexport const useOrderSettingsStore = defineStore('zenky-order-settings', (): OrderSettingsStore => {\n const { storage } = useRuntime()\n\n const deliveryMethod = ref<DeliveryMethod>(DeliveryMethod.Delivery)\n const onPremiseTable = ref<string | null>(null)\n const selectedStock = ref<Stock | null>(null)\n const selectedAddress = ref<string | null>(null)\n const selectedAddressId = ref<string | null>(null)\n const selectedAddressName = ref<string | null>(null)\n\n function setDeliveryMethod(method: DeliveryMethod): void {\n deliveryMethod.value = method\n storage.set(KEY_DELIVERY_METHOD, method)\n }\n\n function setOnPremiseTable(table: string | null): void {\n onPremiseTable.value = table\n if (table) storage.set(KEY_ON_PREMISE_TABLE, table)\n else storage.remove(KEY_ON_PREMISE_TABLE)\n }\n\n function setSelectedStock(stock: Stock | null): void {\n selectedStock.value = stock\n if (stock) storage.set(KEY_SELECTED_STOCK_ID, stock.id)\n else storage.remove(KEY_SELECTED_STOCK_ID)\n }\n\n function setSelectedAddress(\n address: string | null,\n addressId?: string | null,\n addressName?: string | null\n ): void {\n selectedAddress.value = address\n selectedAddressId.value = addressId ?? null\n selectedAddressName.value = addressName ?? null\n writeOrRemove(KEY_SELECTED_ADDRESS, address)\n writeOrRemove(KEY_SELECTED_ADDRESS_ID, addressId ?? null)\n writeOrRemove(KEY_SELECTED_ADDRESS_NAME, addressName ?? null)\n }\n\n function writeOrRemove(key: string, value: string | null): void {\n if (value) storage.set(key, value)\n else storage.remove(key)\n }\n\n /** Если текущий метод не входит в доступные — переключить на первый доступный. */\n function validateDeliveryMethod(availableMethods: DeliveryMethod[]): void {\n const first = availableMethods[0]\n if (!first) return\n\n if (!availableMethods.includes(deliveryMethod.value)) {\n deliveryMethod.value = first\n storage.set(KEY_DELIVERY_METHOD, first)\n }\n }\n\n /** Восстановить настройки из cookies. Вызывать после загрузки города. */\n function restoreFromCookies(city: City): void {\n const savedMethod = storage.get(KEY_DELIVERY_METHOD)\n if (savedMethod && VALID_DELIVERY_METHODS.has(savedMethod)) {\n deliveryMethod.value = savedMethod as DeliveryMethod\n }\n\n const savedStockId = storage.get(KEY_SELECTED_STOCK_ID)\n const stocks = city.stocks ?? []\n if (savedStockId && stocks.length) {\n const stock = stocks.find((s) => s.id === savedStockId) ?? null\n selectedStock.value = stock\n if (!stock) storage.remove(KEY_SELECTED_STOCK_ID)\n }\n\n const savedAddress = storage.get(KEY_SELECTED_ADDRESS)\n if (savedAddress) selectedAddress.value = savedAddress\n\n const savedAddressId = storage.get(KEY_SELECTED_ADDRESS_ID)\n if (savedAddressId) selectedAddressId.value = savedAddressId\n\n const savedAddressName = storage.get(KEY_SELECTED_ADDRESS_NAME)\n if (savedAddressName) selectedAddressName.value = savedAddressName\n\n const savedTable = storage.get(KEY_ON_PREMISE_TABLE)\n if (savedTable) onPremiseTable.value = savedTable\n }\n\n const isDelivery = computed(() => deliveryMethod.value === DeliveryMethod.Delivery)\n const isPickup = computed(() => deliveryMethod.value === DeliveryMethod.Pickup)\n const isOnPremise = computed(() => deliveryMethod.value === DeliveryMethod.OnPremise)\n const needsAddress = computed(() => deliveryMethod.value === DeliveryMethod.Delivery)\n const needsStock = computed(\n () =>\n deliveryMethod.value === DeliveryMethod.Pickup ||\n deliveryMethod.value === DeliveryMethod.OnPremise\n )\n const needsTable = computed(() => deliveryMethod.value === DeliveryMethod.OnPremise)\n\n return {\n deliveryMethod,\n onPremiseTable,\n selectedStock,\n selectedAddress,\n selectedAddressId,\n selectedAddressName,\n setDeliveryMethod,\n setOnPremiseTable,\n setSelectedStock,\n setSelectedAddress,\n validateDeliveryMethod,\n restoreFromCookies,\n isDelivery,\n isPickup,\n isOnPremise,\n needsAddress,\n needsStock,\n needsTable,\n }\n})\n","import { PaymentMethod } from '@zenky/storefront-api'\nimport { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type {\n DeliveryMethod,\n Order,\n OrderCheckoutTotal,\n OrderDeliveryMethod,\n OrderPaymentMethod,\n OrderPaymentTransaction,\n OrderProductVariant,\n OrderSettings,\n} from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { useOrderSettingsStore } from './order-settings'\n\n// Ключи совпадают с прежними CookieKey.* — чтобы не потерять сохранённое.\nconst KEY_COMMENT = 'zenky_order_comment'\nconst KEY_PERSONS_COUNT = 'zenky_order_persons_count'\n\nexport interface CartCredentials {\n id: string\n token: string\n}\n\n/** Намерение по бонусам (business-state) — для headless-reconciliation. */\nexport interface AppliedBonusesIntent {\n enabled: boolean\n /** null = «списать максимум». */\n desiredAmountMinor: number | null\n /** PIN-flow: бонусы сняты, нужно подтвердить заново. */\n requiresConfirmation: boolean\n}\n\nexport interface MinPriceViolation {\n remaining: number\n progress: number\n minPrice: number\n}\n\nfunction emptyBonusesIntent(): AppliedBonusesIntent {\n return { enabled: false, desiredAmountMinor: null, requiresConfirmation: false }\n}\n\nfunction parsePersonsCount(raw: string | null): number {\n const parsed = raw ? Number.parseInt(raw, 10) : NaN\n return Number.isFinite(parsed) && parsed > 0 ? parsed : 0\n}\n\nexport interface CartStore {\n order: Ref<Order | null>\n credentials: Ref<CartCredentials | null>\n loading: Ref<boolean>\n initializing: Ref<boolean>\n optimisticAdjustments: Ref<Record<string, number>>\n lineOptimistic: Ref<Record<string, number>>\n deliveryMethods: Ref<OrderDeliveryMethod[]>\n orderSettings: Ref<OrderSettings | null>\n comment: Ref<string>\n personsCount: Ref<number>\n checkoutTotal: Ref<OrderCheckoutTotal | null>\n selectedPaymentMethod: Ref<PaymentMethod | null>\n selectedPaymentBill: Ref<number | null>\n selectedCardTokenId: Ref<string | null>\n selectedSaveCard: Ref<boolean>\n bonusesIntent: Ref<AppliedBonusesIntent>\n deliveryTimeIntent: Ref<string | null>\n minPriceViolation: Ref<MinPriceViolation | null>\n setOrder: (order: Order) => void\n patchOrder: (partial: Order) => void\n setCredentials: (credentials: CartCredentials) => void\n setLoading: (value: boolean) => void\n setInitializing: (value: boolean) => void\n adjustOptimistic: (productId: string, delta: number) => void\n clearOptimistic: (productId: string) => void\n adjustLineOptimistic: (lineKey: string, delta: number) => void\n setDeliveryMethods: (methods: OrderDeliveryMethod[]) => void\n setOrderSettings: (settings: OrderSettings) => void\n setComment: (value: string) => void\n setPersonsCount: (value: number) => void\n setSelectedPaymentMethod: (method: PaymentMethod | null) => void\n setSelectedPaymentBill: (bill: number | null) => void\n setSelectedCardTokenId: (id: string | null) => void\n setSelectedSaveCard: (value: boolean) => void\n setBonusesIntentEnabled: (value: boolean) => void\n setDesiredBonusesAmount: (value: number | null) => void\n setBonusesRequiresConfirmation: (value: boolean) => void\n clearBonusesIntent: () => void\n setDeliveryTimeIntent: (value: string | null) => void\n restorePaymentSelection: (payments: OrderPaymentTransaction[]) => void\n validatePaymentSelection: () => void\n setOrderPaymentsState: (payments: OrderPaymentTransaction[]) => void\n setCheckoutTotal: (value: OrderCheckoutTotal) => void\n clearCart: () => void\n hasOrder: ComputedRef<boolean>\n hasCredentials: ComputedRef<boolean>\n variants: ComputedRef<OrderProductVariant[]>\n totalPrice: ComputedRef<number>\n itemCount: ComputedRef<number>\n availableDeliveryMethodIds: ComputedRef<DeliveryMethod[]>\n paymentMethods: ComputedRef<OrderPaymentMethod[]>\n hasBonusesApplied: ComputedRef<boolean>\n productQuantities: ComputedRef<Record<string, number>>\n}\n\nexport const useCartStore = defineStore('zenky-cart', (): CartStore => {\n const { storage } = useRuntime()\n\n const order = ref<Order | null>(null)\n const credentials = ref<CartCredentials | null>(null)\n const loading = ref(false)\n const initializing = ref(false)\n const optimisticAdjustments = ref<Record<string, number>>({})\n const lineOptimistic = ref<Record<string, number>>({})\n const deliveryMethods = ref<OrderDeliveryMethod[]>([])\n const orderSettings = ref<OrderSettings | null>(null)\n const comment = ref(storage.get(KEY_COMMENT) ?? '')\n const personsCount = ref(parsePersonsCount(storage.get(KEY_PERSONS_COUNT)))\n const checkoutTotal = ref<OrderCheckoutTotal | null>(null)\n const selectedPaymentMethod = ref<PaymentMethod | null>(null)\n const selectedPaymentBill = ref<number | null>(null)\n const selectedCardTokenId = ref<string | null>(null)\n const selectedSaveCard = ref(false)\n const bonusesIntent = ref<AppliedBonusesIntent>(emptyBonusesIntent())\n const deliveryTimeIntent = ref<string | null>(null)\n const minPriceViolation = ref<MinPriceViolation | null>(null)\n\n function restorePaymentSelection(payments: OrderPaymentTransaction[]): void {\n const restored = payments.find((p) => {\n const raw = p.method as unknown\n const id = typeof raw === 'string' ? raw : ((raw as { id?: string } | null)?.id ?? null)\n return id !== PaymentMethod.Bonuses\n })\n if (!restored) return\n\n const raw = restored.method as unknown\n const methodId = (\n typeof raw === 'string' ? raw : ((raw as { id?: PaymentMethod } | null)?.id ?? null)\n ) as PaymentMethod | null\n if (!methodId || selectedPaymentMethod.value === methodId) return\n\n selectedPaymentMethod.value = methodId\n\n const meta = restored.transaction_meta as { bill?: number | null } | null | undefined\n const billMinor = meta?.bill ?? null\n const newBill = billMinor != null && billMinor > 0 ? billMinor : null\n if (selectedPaymentBill.value !== newBill) {\n selectedPaymentBill.value = newBill\n }\n }\n\n function validatePaymentSelection(): void {\n if (!selectedPaymentMethod.value) return\n const methods = orderSettings.value?.payment_methods ?? []\n if (!methods.some((m) => m.id === selectedPaymentMethod.value)) {\n selectedPaymentMethod.value = null\n selectedPaymentBill.value = null\n }\n }\n\n function setOrder(next: Order): void {\n if (!next?.id || !next.token) {\n console.warn('[cart] setOrder ignored — missing id/token', {\n hasId: Boolean(next?.id),\n hasToken: Boolean(next?.token),\n })\n return\n }\n\n order.value = next\n credentials.value = { id: next.id, token: next.token }\n\n if (Array.isArray(next.payments) && next.payments.length > 0) {\n restorePaymentSelection(next.payments as unknown as OrderPaymentTransaction[])\n }\n }\n\n function patchOrder(partial: Order): void {\n if (!partial?.id || !partial.token) {\n console.warn('[cart] patchOrder ignored — missing id/token', {\n hasId: Boolean(partial?.id),\n hasToken: Boolean(partial?.token),\n })\n return\n }\n\n if (!order.value) {\n order.value = partial\n } else {\n const merged: Order = { ...order.value }\n for (const key of Object.keys(partial) as (keyof Order)[]) {\n const value = partial[key]\n if (value !== undefined) {\n ;(merged as unknown as Record<string, unknown>)[key as string] = value\n }\n }\n order.value = merged\n }\n\n credentials.value = { id: partial.id, token: partial.token }\n\n if (Array.isArray(partial.payments) && partial.payments.length > 0) {\n restorePaymentSelection(partial.payments as unknown as OrderPaymentTransaction[])\n }\n }\n\n function setCredentials(next: CartCredentials): void {\n credentials.value = next\n }\n\n function setLoading(value: boolean): void {\n loading.value = value\n }\n\n function setInitializing(value: boolean): void {\n initializing.value = value\n }\n\n function adjustOptimistic(productId: string, delta: number): void {\n const next = (optimisticAdjustments.value[productId] ?? 0) + delta\n if (next === 0) delete optimisticAdjustments.value[productId]\n else optimisticAdjustments.value[productId] = next\n }\n\n function clearOptimistic(productId: string): void {\n delete optimisticAdjustments.value[productId]\n }\n\n function adjustLineOptimistic(lineKey: string, delta: number): void {\n const next = (lineOptimistic.value[lineKey] ?? 0) + delta\n if (next === 0) delete lineOptimistic.value[lineKey]\n else lineOptimistic.value[lineKey] = next\n }\n\n function setDeliveryMethods(methods: OrderDeliveryMethod[]): void {\n deliveryMethods.value = methods\n const settingsStore = useOrderSettingsStore()\n settingsStore.validateDeliveryMethod(methods.map((m) => m.id))\n }\n\n function setOrderSettings(settings: OrderSettings): void {\n orderSettings.value = settings\n setDeliveryMethods(settings.delivery_methods)\n validatePaymentSelection()\n }\n\n function setComment(value: string): void {\n comment.value = value\n if (value) storage.set(KEY_COMMENT, value)\n else storage.remove(KEY_COMMENT)\n }\n\n function setPersonsCount(value: number): void {\n personsCount.value = value\n if (value > 0) storage.set(KEY_PERSONS_COUNT, String(value))\n else storage.remove(KEY_PERSONS_COUNT)\n }\n\n function setSelectedPaymentMethod(method: PaymentMethod | null): void {\n selectedPaymentMethod.value = method\n }\n\n function setSelectedPaymentBill(bill: number | null): void {\n selectedPaymentBill.value = bill\n }\n\n function setSelectedCardTokenId(id: string | null): void {\n selectedCardTokenId.value = id\n }\n\n function setSelectedSaveCard(value: boolean): void {\n selectedSaveCard.value = value\n }\n\n function setBonusesIntentEnabled(value: boolean): void {\n bonusesIntent.value.enabled = value\n if (!value) {\n bonusesIntent.value.desiredAmountMinor = null\n bonusesIntent.value.requiresConfirmation = false\n }\n }\n\n function setDesiredBonusesAmount(value: number | null): void {\n bonusesIntent.value.desiredAmountMinor = value\n }\n\n function setBonusesRequiresConfirmation(value: boolean): void {\n bonusesIntent.value.requiresConfirmation = value\n }\n\n function clearBonusesIntent(): void {\n bonusesIntent.value = emptyBonusesIntent()\n }\n\n function setDeliveryTimeIntent(value: string | null): void {\n deliveryTimeIntent.value = value\n }\n\n function setOrderPaymentsState(payments: OrderPaymentTransaction[]): void {\n if (order.value) {\n order.value = { ...order.value, payments } as Order\n }\n restorePaymentSelection(payments)\n }\n\n function setCheckoutTotal(value: OrderCheckoutTotal): void {\n checkoutTotal.value = value\n\n const min = value.min_price\n // Пустой заказ (нет variants) с ненулевой доставкой в total — не нарушение минималки.\n const hasItems = (order.value?.variants?.length ?? 0) > 0\n minPriceViolation.value =\n hasItems && min != null && value.total > 0 && value.total < min\n ? {\n remaining: Math.max(0, min - value.total),\n progress: Math.min(1, value.total / min),\n minPrice: min,\n }\n : null\n }\n\n function clearCart(): void {\n order.value = null\n credentials.value = null\n checkoutTotal.value = null\n optimisticAdjustments.value = {}\n lineOptimistic.value = {}\n orderSettings.value = null\n comment.value = ''\n personsCount.value = 0\n storage.remove(KEY_COMMENT)\n storage.remove(KEY_PERSONS_COUNT)\n selectedPaymentMethod.value = null\n selectedPaymentBill.value = null\n selectedCardTokenId.value = null\n selectedSaveCard.value = false\n bonusesIntent.value = emptyBonusesIntent()\n deliveryTimeIntent.value = null\n minPriceViolation.value = null\n }\n\n const hasOrder = computed(() => order.value !== null)\n const hasCredentials = computed(() => credentials.value !== null)\n const variants = computed<OrderProductVariant[]>(() => order.value?.variants ?? [])\n const totalPrice = computed(() => order.value?.total_price ?? 0)\n const itemCount = computed(() => variants.value.reduce((sum, v) => sum + v.quantity, 0))\n const availableDeliveryMethodIds = computed<DeliveryMethod[]>(() =>\n deliveryMethods.value.map((m) => m.id)\n )\n const paymentMethods = computed<OrderPaymentMethod[]>(\n () => orderSettings.value?.payment_methods ?? []\n )\n const hasBonusesApplied = computed(() => {\n const payments = order.value?.payments ?? []\n return (payments as unknown as Array<{ method: unknown }>).some((p) => {\n const raw = p.method\n const id = typeof raw === 'string' ? raw : ((raw as { id?: string } | null)?.id ?? null)\n return id === PaymentMethod.Bonuses\n })\n })\n const productQuantities = computed<Record<string, number>>(() => {\n const map: Record<string, number> = {}\n for (const variant of variants.value) {\n const pid = variant.product_id\n map[pid] = (map[pid] ?? 0) + variant.quantity\n }\n return map\n })\n\n return {\n order,\n credentials,\n loading,\n initializing,\n optimisticAdjustments,\n lineOptimistic,\n deliveryMethods,\n orderSettings,\n comment,\n personsCount,\n checkoutTotal,\n selectedPaymentMethod,\n selectedPaymentBill,\n selectedCardTokenId,\n selectedSaveCard,\n bonusesIntent,\n deliveryTimeIntent,\n minPriceViolation,\n setOrder,\n patchOrder,\n setCredentials,\n setLoading,\n setInitializing,\n adjustOptimistic,\n clearOptimistic,\n adjustLineOptimistic,\n setDeliveryMethods,\n setOrderSettings,\n setComment,\n setPersonsCount,\n setSelectedPaymentMethod,\n setSelectedPaymentBill,\n setSelectedCardTokenId,\n setSelectedSaveCard,\n setBonusesIntentEnabled,\n setDesiredBonusesAmount,\n setBonusesRequiresConfirmation,\n clearBonusesIntent,\n setDeliveryTimeIntent,\n restorePaymentSelection,\n validatePaymentSelection,\n setOrderPaymentsState,\n setCheckoutTotal,\n clearCart,\n hasOrder,\n hasCredentials,\n variants,\n totalPrice,\n itemCount,\n availableDeliveryMethodIds,\n paymentMethods,\n hasBonusesApplied,\n productQuantities,\n }\n})\n"]}