@zenky/storefront-vue 0.10.0 → 0.10.4
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 +105 -0
- package/README.md +66 -6
- package/dist/cart/index.d.ts +31 -2
- package/dist/cart/index.js +6 -9
- package/dist/catalog/index.d.ts +1 -11
- package/dist/catalog/index.js +2 -2
- package/dist/chunk-2CI4RW7V.js +21 -0
- package/dist/chunk-2CI4RW7V.js.map +1 -0
- package/dist/{chunk-GW2QNTAD.js → chunk-4IFPVEO7.js} +3 -113
- package/dist/chunk-4IFPVEO7.js.map +1 -0
- package/dist/{chunk-EYRCAUUP.js → chunk-E3G7NGCH.js} +2 -2
- package/dist/chunk-E3G7NGCH.js.map +1 -0
- package/dist/{chunk-IGDDWGS4.js → chunk-IVG4FQE5.js} +21 -13
- package/dist/chunk-IVG4FQE5.js.map +1 -0
- package/dist/{chunk-PJ2LEKW6.js → chunk-MZ66ARDL.js} +18 -3
- package/dist/chunk-MZ66ARDL.js.map +1 -0
- package/dist/{chunk-2OD7CLKD.js → chunk-NG7RUIWW.js} +3 -13
- package/dist/chunk-NG7RUIWW.js.map +1 -0
- package/dist/{chunk-VL3T36VM.js → chunk-NIQFYJRP.js} +53 -9
- package/dist/chunk-NIQFYJRP.js.map +1 -0
- package/dist/{chunk-AL5W5JSD.js → chunk-OTSAR32A.js} +6 -3
- package/dist/chunk-OTSAR32A.js.map +1 -0
- package/dist/{chunk-BIGTKVC6.js → chunk-SS7B2NLF.js} +3 -3
- package/dist/{chunk-BIGTKVC6.js.map → chunk-SS7B2NLF.js.map} +1 -1
- package/dist/{chunk-PWHIDGKW.js → chunk-TB5TBJ4U.js} +53 -6
- package/dist/chunk-TB5TBJ4U.js.map +1 -0
- package/dist/{chunk-4MJKN7PL.js → chunk-YREGCQSB.js} +4 -6
- package/dist/chunk-YREGCQSB.js.map +1 -0
- package/dist/{chunk-OQLU7FSR.js → chunk-YS5DXYYV.js} +228 -51
- package/dist/chunk-YS5DXYYV.js.map +1 -0
- package/dist/index.d.ts +6 -8
- package/dist/index.js +14 -16
- package/dist/order/index.d.ts +2 -0
- package/dist/order/index.js +2 -5
- package/dist/order/index.js.map +1 -1
- package/dist/pagination/index.js.map +1 -1
- package/dist/ports/index.d.ts +12 -1
- package/dist/ports/index.js +1 -1
- package/dist/products/index.js +3 -4
- package/dist/promotions/index.js +3 -5
- package/dist/seo/index.d.ts +5 -11
- package/dist/seo/index.js +17 -27
- package/dist/seo/index.js.map +1 -1
- package/dist/snippets/index.d.ts +21 -15
- package/dist/snippets/index.js +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/index.js +3 -5
- package/dist/theme/index.d.ts +1 -11
- package/dist/theme/index.js +1 -1
- package/dist/utils/index.d.ts +28 -5
- package/dist/utils/index.js +1 -1
- package/dist/website-settings/index.d.ts +1 -1
- package/docs/consumer-setup.md +279 -0
- package/docs/ports.md +148 -0
- package/docs/releasing.md +53 -0
- package/package.json +27 -8
- package/dist/chunk-2OD7CLKD.js.map +0 -1
- package/dist/chunk-4MJKN7PL.js.map +0 -1
- package/dist/chunk-AL5W5JSD.js.map +0 -1
- package/dist/chunk-BWUKMWHL.js +0 -45
- package/dist/chunk-BWUKMWHL.js.map +0 -1
- package/dist/chunk-DKWDKVXQ.js +0 -91
- package/dist/chunk-DKWDKVXQ.js.map +0 -1
- package/dist/chunk-EYRCAUUP.js.map +0 -1
- package/dist/chunk-GW2QNTAD.js.map +0 -1
- package/dist/chunk-IGDDWGS4.js.map +0 -1
- package/dist/chunk-OQLU7FSR.js.map +0 -1
- package/dist/chunk-PJ2LEKW6.js.map +0 -1
- package/dist/chunk-PWHIDGKW.js.map +0 -1
- package/dist/chunk-V3VVDQIR.js +0 -27
- package/dist/chunk-V3VVDQIR.js.map +0 -1
- package/dist/chunk-VL3T36VM.js.map +0 -1
- package/dist/layout/index.d.ts +0 -54
- package/dist/layout/index.js +0 -102
- package/dist/layout/index.js.map +0 -1
- package/dist/schedule-Dd3zwHEb.d.ts +0 -27
- package/dist/snippets-BC5bkSjm.d.ts +0 -23
|
@@ -1,7 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ref, computed, inject, provide } from 'vue';
|
|
2
2
|
import { defineStore } from 'pinia';
|
|
3
|
-
import { ref, computed } from 'vue';
|
|
4
3
|
|
|
4
|
+
// src/ports/runtime.ts
|
|
5
|
+
var RUNTIME_KEY = /* @__PURE__ */ Symbol.for("zenky.storefront.runtime");
|
|
6
|
+
var REQUIRED_PORTS = [
|
|
7
|
+
"sdk",
|
|
8
|
+
"config",
|
|
9
|
+
"storage",
|
|
10
|
+
"notifier",
|
|
11
|
+
"activity",
|
|
12
|
+
"messages"
|
|
13
|
+
];
|
|
14
|
+
function assertRequiredPorts(runtime) {
|
|
15
|
+
const missing = REQUIRED_PORTS.filter((port) => runtime[port] == null);
|
|
16
|
+
if (missing.length > 0) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`[@zenky/storefront-vue] Runtime is missing required ports: ${missing.join(", ")}. See the Runtime Ports table in the README.`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function createStorefront(runtime) {
|
|
23
|
+
assertRequiredPorts(runtime);
|
|
24
|
+
return {
|
|
25
|
+
install(app) {
|
|
26
|
+
app.provide(RUNTIME_KEY, runtime);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function provideStorefront(runtime) {
|
|
31
|
+
assertRequiredPorts(runtime);
|
|
32
|
+
provide(RUNTIME_KEY, runtime);
|
|
33
|
+
}
|
|
34
|
+
function useRuntime() {
|
|
35
|
+
const runtime = inject(RUNTIME_KEY);
|
|
36
|
+
if (!runtime) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
"[@zenky/storefront-vue] Runtime was not provided. Install the plugin with app.use(createStorefront(runtime))."
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return runtime;
|
|
42
|
+
}
|
|
5
43
|
var useStoreProfileStore = defineStore("zenky-store-profile", () => {
|
|
6
44
|
const store = ref(null);
|
|
7
45
|
const city = ref(null);
|
|
@@ -89,9 +127,18 @@ var useAuthStore = defineStore("zenky-auth", () => {
|
|
|
89
127
|
phone.value = savedPhone;
|
|
90
128
|
}
|
|
91
129
|
}
|
|
92
|
-
return {
|
|
130
|
+
return {
|
|
131
|
+
token,
|
|
132
|
+
phone,
|
|
133
|
+
countryCode,
|
|
134
|
+
isAuthenticated,
|
|
135
|
+
initials,
|
|
136
|
+
setToken,
|
|
137
|
+
clearToken,
|
|
138
|
+
initFromCookie
|
|
139
|
+
};
|
|
93
140
|
});
|
|
94
141
|
|
|
95
|
-
export { useAuthStore, useStoreProfileStore };
|
|
96
|
-
//# sourceMappingURL=chunk-
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
142
|
+
export { createStorefront, provideStorefront, useAuthStore, useRuntime, useStoreProfileStore };
|
|
143
|
+
//# sourceMappingURL=chunk-TB5TBJ4U.js.map
|
|
144
|
+
//# sourceMappingURL=chunk-TB5TBJ4U.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ports/runtime.ts","../src/stores/store-profile.ts","../src/stores/auth.ts"],"names":["defineStore","ref","computed"],"mappings":";;;;AAOA,IAAM,WAAA,mBAAc,MAAA,CAAO,GAAA,CAAI,0BAA0B,CAAA;AAMzD,IAAM,cAAA,GAAiB;AAAA,EACnB,KAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA;AACJ,CAAA;AAQA,SAAS,oBAAoB,OAAA,EAAkC;AAC3D,EAAA,MAAM,OAAA,GAAU,eAAe,MAAA,CAAO,CAAC,SAAS,OAAA,CAAQ,IAAI,KAAK,IAAI,CAAA;AACrE,EAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,KAAA;AAAA,MACN,CAAA,2DAAA,EAA8D,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAC,CAAA,4CAAA;AAAA,KAEpF;AAAA,EACJ;AACJ;AAGO,SAAS,iBAAiB,OAAA,EAAoC;AACjE,EAAA,mBAAA,CAAoB,OAAO,CAAA;AAE3B,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,mBAAA,CAAoB,OAAO,CAAA;AAC3B,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;ACzCO,IAAM,oBAAA,GAAuB,WAAA,CAAY,qBAAA,EAAuB,MAAyB;AAC5F,EAAA,MAAM,KAAA,GAAQ,IAAkB,IAAI,CAAA;AACpC,EAAA,MAAM,IAAA,GAAO,IAAiB,IAAI,CAAA;AAClC,EAAA,MAAM,KAAA,GAAQ,IAAkB,IAAI,CAAA;AACpC,EAAA,MAAM,UAAA,GAAa,GAAA,CAAsB,EAAE,CAAA;AAC3C,EAAA,MAAM,OAAA,GAAU,IAAoB,IAAI,CAAA;AAExC,EAAA,SAAS,SAAA,CAAU,QAAA,EAAiB,OAAA,EAAe,QAAA,EAA8B;AAC7E,IAAA,KAAA,CAAM,KAAA,GAAQ,QAAA;AACd,IAAA,IAAA,CAAK,KAAA,GAAQ,OAAA;AACb,IAAA,KAAA,CAAM,KAAA,GAAQ,QAAA;AAAA,EAClB;AAEA,EAAA,SAAS,SAAS,QAAA,EAA8B;AAC5C,IAAA,KAAA,CAAM,KAAA,GAAQ,QAAA;AAAA,EAClB;AAEA,EAAA,SAAS,cAAc,aAAA,EAAuC;AAC1D,IAAA,UAAA,CAAW,KAAA,GAAQ,aAAA;AAAA,EACvB;AAEA,EAAA,SAAS,YAAY,UAAA,EAAkC;AACnD,IAAA,OAAA,CAAQ,KAAA,GAAQ,UAAA;AAAA,EACpB;AAEA,EAAA,MAAM,OAAA,GAAU,SAAS,MAAM,KAAA,CAAM,UAAU,IAAA,IAAQ,IAAA,CAAK,UAAU,IAAI,CAAA;AAC1E,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,MAAM,KAAA,CAAM,UAAU,IAAI,CAAA;AACpD,EAAA,MAAM,WAAW,QAAA,CAAiB,MAAM,MAAM,KAAA,EAAO,QAAA,EAAU,YAAY,KAAK,CAAA;AAEhF,EAAA,MAAM,aAAA,GAAgB,SAAwB,MAAM;AAChD,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,EAAO,WAAA,IAAe,MAAM,KAAA,EAAO,IAAA;AACtD,IAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,IAAA,OACI,IAAA,CAAK,EAAA,EAAI,GAAA,IACT,IAAA,CAAK,QAAQ,GAAA,IACb,IAAA,CAAK,KAAA,EAAO,GAAA,IACZ,IAAA,CAAK,MAAA,EAAQ,GAAA,IACb,IAAA,CAAK,aAAa,GAAA,IAClB,IAAA;AAAA,EAER,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACH,KAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA;AAAA,IACA,WAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACJ;AACJ,CAAC;AC5ED,IAAM,cAAA,GAAiB,kBAAA;AACvB,IAAM,cAAA,GAAiB,kBAAA;AACvB,IAAM,YAAA,GAAe,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAc7B,IAAM,YAAA,GAAeA,WAAAA,CAAY,YAAA,EAAc,MAAiB;AAInE,EAAA,MAAM,EAAE,OAAA,EAAS,GAAA,EAAI,GAAI,UAAA,EAAW;AAEpC,EAAA,MAAM,KAAA,GAAQC,IAAmB,IAAI,CAAA;AACrC,EAAA,MAAM,KAAA,GAAQA,IAAmB,IAAI,CAAA;AACrC,EAAA,MAAM,WAAA,GAAcA,IAAI,IAAI,CAAA;AAE5B,EAAA,MAAM,eAAA,GAAkBC,SAAS,MAAM,KAAA,CAAM,UAAU,IAAA,IAAQ,KAAA,CAAM,UAAU,EAAE,CAAA;AAEjF,EAAA,MAAM,QAAA,GAAWA,SAAS,MAAM;AAC5B,IAAA,IAAI,CAAC,KAAA,CAAM,KAAA,EAAO,OAAO,GAAA;AACzB,IAAA,OAAO,MAAM,KAAA,CAAM,OAAA,CAAQ,OAAO,EAAE,CAAA,CAAE,MAAM,EAAE,CAAA;AAAA,EAClD,CAAC,CAAA;AAED,EAAA,SAAS,QAAA,CAAS,SAAA,EAAmB,SAAA,EAAoB,eAAA,EAAgC;AACrF,IAAA,KAAA,CAAM,KAAA,GAAQ,SAAA;AACd,IAAA,OAAA,CAAQ,IAAI,cAAA,EAAgB,SAAA,EAAW,EAAE,MAAA,EAAQ,cAAc,CAAA;AAC/D,IAAA,GAAA,CAAI,YAAY,SAAS,CAAA;AAEzB,IAAA,IAAI,SAAA,EAAW;AACX,MAAA,KAAA,CAAM,KAAA,GAAQ,SAAA;AACd,MAAA,OAAA,CAAQ,IAAI,cAAA,EAAgB,SAAA,EAAW,EAAE,MAAA,EAAQ,cAAc,CAAA;AAAA,IACnE;AAEA,IAAA,IAAI,eAAA,EAAiB;AACjB,MAAA,WAAA,CAAY,KAAA,GAAQ,eAAA;AAAA,IACxB;AAAA,EACJ;AAEA,EAAA,SAAS,UAAA,GAAmB;AACxB,IAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,IAAA,KAAA,CAAM,KAAA,GAAQ,IAAA;AACd,IAAA,OAAA,CAAQ,OAAO,cAAc,CAAA;AAC7B,IAAA,OAAA,CAAQ,OAAO,cAAc,CAAA;AAC7B,IAAA,GAAA,CAAI,YAAY,IAAI,CAAA;AAAA,EACxB;AAEA,EAAA,SAAS,cAAA,GAAuB;AAC5B,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA;AAC7C,IAAA,IAAI,UAAA,EAAY;AACZ,MAAA,KAAA,CAAM,KAAA,GAAQ,UAAA;AACd,MAAA,GAAA,CAAI,YAAY,UAAU,CAAA;AAAA,IAC9B;AAEA,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA;AAC7C,IAAA,IAAI,UAAA,EAAY;AACZ,MAAA,KAAA,CAAM,KAAA,GAAQ,UAAA;AAAA,IAClB;AAAA,EACJ;AAEA,EAAA,OAAO;AAAA,IACH,KAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,eAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACJ;AACJ,CAAC","file":"chunk-TB5TBJ4U.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\ntype RequiredPort = {\n [K in keyof StorefrontRuntime]-?: undefined extends StorefrontRuntime[K] ? never : K\n}[keyof StorefrontRuntime]\n\nconst REQUIRED_PORTS = [\n 'sdk',\n 'config',\n 'storage',\n 'notifier',\n 'activity',\n 'messages',\n] as const satisfies readonly RequiredPort[]\n\ntype ListedPort = (typeof REQUIRED_PORTS)[number]\ntype UnlistedRequiredPort = Exclude<RequiredPort, ListedPort>\n\nconst _allRequiredPortsListed: UnlistedRequiredPort extends never ? true : never = true\nvoid _allRequiredPortsListed\n\nfunction assertRequiredPorts(runtime: StorefrontRuntime): void {\n const missing = REQUIRED_PORTS.filter((port) => runtime[port] == null)\n if (missing.length > 0) {\n throw new Error(\n `[@zenky/storefront-vue] Runtime is missing required ports: ${missing.join(', ')}. ` +\n 'See the Runtime Ports table in the README.'\n )\n }\n}\n\n/** Vue-плагин: app.use(createStorefront(runtime)). */\nexport function createStorefront(runtime: StorefrontRuntime): Plugin {\n assertRequiredPorts(runtime)\n\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 assertRequiredPorts(runtime)\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 '[@zenky/storefront-vue] Runtime was not provided. ' +\n 'Install the plugin with app.use(createStorefront(runtime)).'\n )\n }\n return runtime\n}\n","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"]}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { usePromotionsStore } from './chunk-
|
|
2
|
-
import { useAuthStore, useStoreProfileStore } from './chunk-
|
|
3
|
-
import { useCartStore } from './chunk-VL3T36VM.js';
|
|
4
|
-
import { useRuntime } from './chunk-V3VVDQIR.js';
|
|
1
|
+
import { useCartStore, usePromotionsStore } from './chunk-NIQFYJRP.js';
|
|
2
|
+
import { useRuntime, useAuthStore, useStoreProfileStore } from './chunk-TB5TBJ4U.js';
|
|
5
3
|
import { ref } from 'vue';
|
|
6
4
|
|
|
7
5
|
var KEY_ORDER_ID = "zenky_order_id";
|
|
@@ -107,5 +105,5 @@ function usePromotionsChecker() {
|
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
export { useCartCredentials, usePromotionsChecker };
|
|
110
|
-
//# sourceMappingURL=chunk-
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-YREGCQSB.js.map
|
|
109
|
+
//# sourceMappingURL=chunk-YREGCQSB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cart/useCartCredentials.ts","../src/promotions/usePromotionsChecker.ts"],"names":[],"mappings":"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","file":"chunk-YREGCQSB.js","sourcesContent":["import { ref, type Ref } from 'vue'\n\nimport type { Order, OrderCredentials } from '@zenky/storefront-api'\n\nimport { useRuntime } from '../ports/runtime'\nimport { useAuthStore } from '../stores/auth'\nimport { useCartStore } from '../stores/cart'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nconst KEY_ORDER_ID = 'zenky_order_id'\nconst KEY_ORDER_TOKEN = 'zenky_order_token'\nconst WEEK_SECONDS = 60 * 60 * 24 * 7\n\n// app-энум OrderStatusKind.Pending = 'pending'.\nconst ORDER_STATUS_PENDING = 'pending'\n\nexport interface CartCredentials {\n orderIdCookie: Ref<string | null>\n orderTokenCookie: Ref<string | null>\n getStoreId: () => string\n getCityId: () => string\n getApiToken: () => string | undefined\n buildCredentials: (orderId: string, orderToken: string) => OrderCredentials\n getCredentials: () => OrderCredentials\n persistCredentials: (savedOrder: Order) => void\n clearPersistedCredentials: () => void\n isOrderActive: (order: Order) => boolean\n}\n\n/**\n * Управление credentials заказа. Персистенс order-id/token — через порт `storage`\n * (ядро не знает про useCookie). Рефы инициализируются из storage, persist пишет в оба.\n */\nexport function useCartCredentials(): CartCredentials {\n const { storage } = useRuntime()\n const cartStore = useCartStore()\n const authStore = useAuthStore()\n const profileStore = useStoreProfileStore()\n\n const orderIdRef = ref<string | null>(storage.get(KEY_ORDER_ID))\n const orderTokenRef = ref<string | null>(storage.get(KEY_ORDER_TOKEN))\n\n function getStoreId(): string {\n if (!profileStore.store) {\n throw new Error('Store is not initialized.')\n }\n\n return profileStore.store.id\n }\n\n function getCityId(): string {\n if (!profileStore.city) {\n throw new Error('City is not initialized.')\n }\n\n return profileStore.city.id\n }\n\n function getApiToken(): string | undefined {\n return authStore.isAuthenticated ? (authStore.token ?? undefined) : undefined\n }\n\n function buildCredentials(orderId: string, orderToken: string): OrderCredentials {\n const credentials: OrderCredentials = {\n id: orderId,\n token: orderToken,\n }\n\n const apiToken = getApiToken()\n\n if (apiToken) {\n credentials.api_token = apiToken\n }\n\n return credentials\n }\n\n function getCredentials(): OrderCredentials {\n if (!cartStore.credentials) {\n throw new Error('Cart has no credentials.')\n }\n\n return buildCredentials(cartStore.credentials.id, cartStore.credentials.token)\n }\n\n function persistCredentials(savedOrder: Order): void {\n orderIdRef.value = savedOrder.id\n orderTokenRef.value = savedOrder.token\n storage.set(KEY_ORDER_ID, savedOrder.id, { maxAge: WEEK_SECONDS })\n storage.set(KEY_ORDER_TOKEN, savedOrder.token, { maxAge: WEEK_SECONDS })\n }\n\n function clearPersistedCredentials(): void {\n orderIdRef.value = null\n orderTokenRef.value = null\n storage.remove(KEY_ORDER_ID)\n storage.remove(KEY_ORDER_TOKEN)\n }\n\n function isOrderActive(existingOrder: Order): boolean {\n if (!existingOrder.status) return true\n\n return String(existingOrder.status.kind) === ORDER_STATUS_PENDING\n }\n\n return {\n orderIdCookie: orderIdRef,\n orderTokenCookie: orderTokenRef,\n getStoreId,\n getCityId,\n getApiToken,\n buildCredentials,\n getCredentials,\n persistCredentials,\n clearPersistedCredentials,\n isOrderActive,\n }\n}\n","import { useRuntime } from '../ports/runtime'\nimport { useCartCredentials } from '../cart/useCartCredentials'\nimport { useCartStore } from '../stores/cart'\nimport { usePromotionsStore } from '../stores/promotions'\nimport { useStoreProfileStore } from '../stores/store-profile'\n\nexport interface PromotionsChecker {\n dispatchCheck: () => Promise<void>\n}\n\n/** Таймаут — если WS не ответил, сбросить флаг checking. */\nconst WS_RESPONSE_TIMEOUT_MS = 5000\n\n/**\n * Проверка промо-акций. Вызывает dispatchPromotionsChecker после изменения корзины.\n * Результат приходит через WebSocket (обрабатывается в useOrderChannel).\n */\nexport function usePromotionsChecker(): PromotionsChecker {\n const { sdk, events } = useRuntime()\n const cartStore = useCartStore()\n const profileStore = useStoreProfileStore()\n const promotionsStore = usePromotionsStore()\n const credentials = useCartCredentials()\n\n async function dispatchCheck(): Promise<void> {\n if (!cartStore.hasOrder || promotionsStore.checking) return\n\n const storeId = profileStore.store?.id\n if (!storeId) return\n\n promotionsStore.setChecking(true)\n promotionsStore.clearRewards() // Очистить старые — WS заново наполнит актуальные\n events?.get()?.promotionsCheckerStarted({ order: cartStore.order })\n\n try {\n const creds = credentials.getCredentials()\n await sdk.orders.dispatchPromotionsChecker(storeId, creds)\n\n setTimeout(() => {\n if (promotionsStore.checking) promotionsStore.setChecking(false)\n }, WS_RESPONSE_TIMEOUT_MS)\n } catch (e: unknown) {\n console.error('[promotions] check failed', e)\n promotionsStore.setChecking(false)\n }\n }\n\n return { dispatchCheck }\n}\n"]}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { useCartCredentials, usePromotionsChecker } from './chunk-
|
|
2
|
-
import { createRuntimeState } from './chunk-5QCUH3FF.js';
|
|
1
|
+
import { useCartCredentials, usePromotionsChecker } from './chunk-YREGCQSB.js';
|
|
3
2
|
import { useCatalogStore } from './chunk-Z3IW4ODZ.js';
|
|
4
|
-
import { usePromotionsStore } from './chunk-
|
|
5
|
-
import {
|
|
6
|
-
import { getRemoteCatalog } from './chunk-EYRCAUUP.js';
|
|
7
|
-
import { useCartStore, useOrderSettingsStore } from './chunk-VL3T36VM.js';
|
|
8
|
-
import { useRuntime } from './chunk-V3VVDQIR.js';
|
|
3
|
+
import { useCartStore, useOrderSettingsStore, usePromotionsStore } from './chunk-NIQFYJRP.js';
|
|
4
|
+
import { getRemoteCatalog } from './chunk-E3G7NGCH.js';
|
|
9
5
|
import { minorToMajor, majorToMinor } from './chunk-RO25KNM5.js';
|
|
6
|
+
import { createRuntimeState } from './chunk-5QCUH3FF.js';
|
|
7
|
+
import { useRuntime, useStoreProfileStore, useAuthStore } from './chunk-TB5TBJ4U.js';
|
|
10
8
|
import { PaymentMethod, OrderAuthenticationMethod, DeliveryMethod, OrderCartCheckerResultAction, RecaptchaAction } from '@zenky/storefront-api';
|
|
11
|
-
import {
|
|
9
|
+
import { ref, computed, watch, watchEffect, getCurrentScope, onScopeDispose, toValue } from 'vue';
|
|
12
10
|
import { storeToRefs } from 'pinia';
|
|
13
11
|
|
|
14
12
|
// src/cart/constants.ts
|
|
@@ -95,16 +93,70 @@ function buildCashChangePresets({
|
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
// src/cart/logCartError.ts
|
|
96
|
+
var REDACTED = "[REDACTED]";
|
|
97
|
+
var MAX_LOG_DEPTH = 6;
|
|
98
|
+
var MAX_ARRAY_ITEMS = 25;
|
|
99
|
+
var MAX_OBJECT_KEYS = 50;
|
|
100
|
+
var SENSITIVE_KEY_PARTS = [
|
|
101
|
+
"authorization",
|
|
102
|
+
"cookie",
|
|
103
|
+
"credential",
|
|
104
|
+
"password",
|
|
105
|
+
"recaptcha",
|
|
106
|
+
"secret",
|
|
107
|
+
"token"
|
|
108
|
+
];
|
|
109
|
+
var SENSITIVE_EXACT_KEYS = /* @__PURE__ */ new Set(["cvc", "cvv", "otp", "pan", "pin"]);
|
|
110
|
+
var SENSITIVE_ASSIGNMENT = /((?:authorization|cookie|password|recaptcha|secret|(?:api|access|auth|card|order|refresh)[_-]?token|token)\s*[=:]\s*["']?)([^\s,"';&}\]]+)/gi;
|
|
111
|
+
var SENSITIVE_QUERY_PARAM = /([?&#](?:authorization|password|recaptcha|secret|(?:api|access|auth|card|order|refresh)[_-]?token|token)=)([^&#\s]+)/gi;
|
|
112
|
+
var BEARER_TOKEN = /(bearer\s+)[a-z0-9._~+/=-]+/gi;
|
|
113
|
+
function isSensitiveKey(key) {
|
|
114
|
+
const normalized = key.replace(/[^a-z0-9]/gi, "").toLowerCase();
|
|
115
|
+
return SENSITIVE_EXACT_KEYS.has(normalized) || normalized.includes("confirmationcode") || normalized.includes("verificationcode") || SENSITIVE_KEY_PARTS.some((part) => normalized.includes(part));
|
|
116
|
+
}
|
|
117
|
+
function sanitizeString(value) {
|
|
118
|
+
return value.replace(BEARER_TOKEN, `$1${REDACTED}`).replace(SENSITIVE_QUERY_PARAM, `$1${REDACTED}`).replace(SENSITIVE_ASSIGNMENT, `$1${REDACTED}`);
|
|
119
|
+
}
|
|
120
|
+
function sanitizeLogValue(value, depth = 0, seen = /* @__PURE__ */ new WeakSet()) {
|
|
121
|
+
if (typeof value === "string") return sanitizeString(value);
|
|
122
|
+
if (value === null || typeof value !== "object") return value;
|
|
123
|
+
if (depth >= MAX_LOG_DEPTH) return "[TRUNCATED]";
|
|
124
|
+
if (seen.has(value)) return "[CIRCULAR]";
|
|
125
|
+
seen.add(value);
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
const sanitized = value.slice(0, MAX_ARRAY_ITEMS).map((item) => sanitizeLogValue(item, depth + 1, seen));
|
|
128
|
+
if (value.length > MAX_ARRAY_ITEMS) sanitized.push("[TRUNCATED]");
|
|
129
|
+
return sanitized;
|
|
130
|
+
}
|
|
131
|
+
const result = {};
|
|
132
|
+
if (value instanceof Error) {
|
|
133
|
+
result.name = sanitizeString(value.name);
|
|
134
|
+
result.message = sanitizeString(value.message);
|
|
135
|
+
}
|
|
136
|
+
let allEntries;
|
|
137
|
+
try {
|
|
138
|
+
allEntries = Object.entries(value);
|
|
139
|
+
} catch {
|
|
140
|
+
return "[UNSERIALIZABLE]";
|
|
141
|
+
}
|
|
142
|
+
const entries = allEntries.slice(0, MAX_OBJECT_KEYS);
|
|
143
|
+
for (const [key, nestedValue] of entries) {
|
|
144
|
+
if (key === "name" || key === "message") continue;
|
|
145
|
+
result[key] = isSensitiveKey(key) ? REDACTED : sanitizeLogValue(nestedValue, depth + 1, seen);
|
|
146
|
+
}
|
|
147
|
+
if (allEntries.length > MAX_OBJECT_KEYS) result.__truncated__ = true;
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
98
150
|
function logCartError({ scope, context }, e) {
|
|
99
151
|
const err = e?.err;
|
|
152
|
+
const safeContext = sanitizeLogValue(context);
|
|
100
153
|
console.error(`[${scope}] failed`, {
|
|
101
|
-
...
|
|
154
|
+
...safeContext ?? {},
|
|
102
155
|
httpCode: err?.http_code,
|
|
103
156
|
errorCode: err?.error_code,
|
|
104
|
-
message: err?.message,
|
|
105
|
-
meta: err?.meta,
|
|
106
|
-
|
|
107
|
-
raw: e
|
|
157
|
+
message: sanitizeLogValue(err?.message),
|
|
158
|
+
meta: sanitizeLogValue(err?.meta),
|
|
159
|
+
error: sanitizeLogValue(e)
|
|
108
160
|
});
|
|
109
161
|
}
|
|
110
162
|
function getCartErrorCode(e) {
|
|
@@ -115,7 +167,7 @@ function getCartErrorHttpCode(e) {
|
|
|
115
167
|
}
|
|
116
168
|
function getValidationErrors(e) {
|
|
117
169
|
const err = e?.err;
|
|
118
|
-
if (
|
|
170
|
+
if (err?.error_code !== "validation") return {};
|
|
119
171
|
const meta = err.meta;
|
|
120
172
|
return meta?.errors ?? {};
|
|
121
173
|
}
|
|
@@ -337,7 +389,7 @@ function useCartAddressSync() {
|
|
|
337
389
|
const response = await sdk.customer.getAddresses(storeId, void 0, requestedToken);
|
|
338
390
|
addresses = response.items ?? [];
|
|
339
391
|
} catch (e) {
|
|
340
|
-
|
|
392
|
+
logCartError({ scope: "address-sync", context: { storeId } }, e);
|
|
341
393
|
return;
|
|
342
394
|
}
|
|
343
395
|
if (!authStore.isAuthenticated || authStore.token !== requestedToken) return;
|
|
@@ -381,9 +433,13 @@ var ORDER_INCLUDES = [
|
|
|
381
433
|
"variants.product.images",
|
|
382
434
|
"variants.product.categories",
|
|
383
435
|
"variants.modifiers.modifier",
|
|
384
|
-
"variants.modifiers.modifiers_group"
|
|
436
|
+
"variants.modifiers.modifiers_group",
|
|
437
|
+
// Ограничения позиций (#32): is_blocking для сообщений в корзине и блокировки чекаута.
|
|
438
|
+
"variants.restrictions"
|
|
385
439
|
].join(",");
|
|
386
440
|
var ORDER_WITH = { with: ORDER_INCLUDES };
|
|
441
|
+
var RUM_MARK_CART_INIT = "rum:cart:init";
|
|
442
|
+
var RUM_METRIC_CART_INIT = "rum_cart_init_seconds";
|
|
387
443
|
var getInitializationState = createRuntimeState(() => ({ promise: null }));
|
|
388
444
|
function useCartInitialization(credentials, sdk) {
|
|
389
445
|
const cartStore = useCartStore();
|
|
@@ -406,10 +462,17 @@ function useCartInitialization(credentials, sdk) {
|
|
|
406
462
|
const settings = await sdk.orders.getOrderSettings(storeId, orderCredentials);
|
|
407
463
|
cartStore.setOrderSettings(settings);
|
|
408
464
|
} catch (e) {
|
|
409
|
-
|
|
465
|
+
logCartError(
|
|
466
|
+
{
|
|
467
|
+
scope: "cart-load-order-settings",
|
|
468
|
+
context: { orderId: cartStore.credentials?.id }
|
|
469
|
+
},
|
|
470
|
+
e
|
|
471
|
+
);
|
|
410
472
|
}
|
|
411
473
|
}
|
|
412
474
|
async function _doInitialize() {
|
|
475
|
+
runtime.rum?.mark(RUM_MARK_CART_INIT);
|
|
413
476
|
cartStore.setInitializing(true);
|
|
414
477
|
try {
|
|
415
478
|
if (credentials.orderIdCookie.value && credentials.orderTokenCookie.value) {
|
|
@@ -448,6 +511,7 @@ function useCartInitialization(credentials, sdk) {
|
|
|
448
511
|
}
|
|
449
512
|
}
|
|
450
513
|
cartStore.setInitializing(false);
|
|
514
|
+
runtime.rum?.measure(RUM_METRIC_CART_INIT, RUM_MARK_CART_INIT);
|
|
451
515
|
}
|
|
452
516
|
}
|
|
453
517
|
function initializeOrder() {
|
|
@@ -493,9 +557,13 @@ function useOrderBonuses(deps = {}) {
|
|
|
493
557
|
activity.begin("bonuses");
|
|
494
558
|
try {
|
|
495
559
|
const orderCredentials = credentials.getCredentials();
|
|
496
|
-
const updatedOrder = await sdk.orders.setOrderPayments(
|
|
497
|
-
|
|
498
|
-
|
|
560
|
+
const updatedOrder = await sdk.orders.setOrderPayments(
|
|
561
|
+
storeId,
|
|
562
|
+
orderCredentials,
|
|
563
|
+
{
|
|
564
|
+
payments: [...additionalPayments, bonusesPayment]
|
|
565
|
+
}
|
|
566
|
+
);
|
|
499
567
|
if (isStale()) return;
|
|
500
568
|
if (Array.isArray(updatedOrder)) {
|
|
501
569
|
cartStore.setOrderPaymentsState(updatedOrder);
|
|
@@ -527,9 +595,13 @@ function useOrderBonuses(deps = {}) {
|
|
|
527
595
|
activity.begin("bonuses");
|
|
528
596
|
try {
|
|
529
597
|
const orderCredentials = credentials.getCredentials();
|
|
530
|
-
const updatedOrder = await sdk.orders.setOrderPayments(
|
|
531
|
-
|
|
532
|
-
|
|
598
|
+
const updatedOrder = await sdk.orders.setOrderPayments(
|
|
599
|
+
storeId,
|
|
600
|
+
orderCredentials,
|
|
601
|
+
{
|
|
602
|
+
payments: mainPayment ? [mainPayment] : []
|
|
603
|
+
}
|
|
604
|
+
);
|
|
533
605
|
if (isStale()) return;
|
|
534
606
|
if (Array.isArray(updatedOrder)) {
|
|
535
607
|
cartStore.setOrderPaymentsState(updatedOrder);
|
|
@@ -560,7 +632,7 @@ function useOrderBonuses(deps = {}) {
|
|
|
560
632
|
}
|
|
561
633
|
var PAYMENT_DEBOUNCE_MS = 300;
|
|
562
634
|
function usePaymentSelection() {
|
|
563
|
-
const { sdk, notifier, activity } = useRuntime();
|
|
635
|
+
const { sdk, notifier, messages, activity } = useRuntime();
|
|
564
636
|
const credentials = useCartCredentials();
|
|
565
637
|
const cartStore = useCartStore();
|
|
566
638
|
const profileStore = useStoreProfileStore();
|
|
@@ -597,7 +669,7 @@ function usePaymentSelection() {
|
|
|
597
669
|
},
|
|
598
670
|
e
|
|
599
671
|
);
|
|
600
|
-
notifier.error(getCartErrorMessage(e, "
|
|
672
|
+
notifier.error(getCartErrorMessage(e, messages.format("cart.payment.updateFailed")));
|
|
601
673
|
} finally {
|
|
602
674
|
activity.end("payment");
|
|
603
675
|
}
|
|
@@ -644,6 +716,7 @@ function usePaymentSelection() {
|
|
|
644
716
|
return { setPayment, syncPaymentNow, clearPayments };
|
|
645
717
|
}
|
|
646
718
|
function useBonusesReconciliation(deps) {
|
|
719
|
+
const { messages } = useRuntime();
|
|
647
720
|
const cartStore = useCartStore();
|
|
648
721
|
const profileStore = useStoreProfileStore();
|
|
649
722
|
const { maxAvailable, apply, remove } = useOrderBonuses({ activity: deps.activity });
|
|
@@ -696,8 +769,8 @@ function useBonusesReconciliation(deps) {
|
|
|
696
769
|
);
|
|
697
770
|
}
|
|
698
771
|
cartStore.setBonusesRequiresConfirmation(true);
|
|
699
|
-
deps.notifier.message("
|
|
700
|
-
description: "
|
|
772
|
+
deps.notifier.message(messages.format("cart.bonuses.changed.title"), {
|
|
773
|
+
description: messages.format("cart.bonuses.changed.description")
|
|
701
774
|
});
|
|
702
775
|
return;
|
|
703
776
|
}
|
|
@@ -733,7 +806,7 @@ function useCartRecalculation(deps) {
|
|
|
733
806
|
return { recalculateAfterOrderChange };
|
|
734
807
|
}
|
|
735
808
|
function useCustomerAttach(cache) {
|
|
736
|
-
const { sdk, notifier, activity } = useRuntime();
|
|
809
|
+
const { sdk, notifier, messages, activity } = useRuntime();
|
|
737
810
|
const credentials = useCartCredentials();
|
|
738
811
|
const cartStore = useCartStore();
|
|
739
812
|
const profileStore = useStoreProfileStore();
|
|
@@ -775,7 +848,7 @@ function useCustomerAttach(cache) {
|
|
|
775
848
|
},
|
|
776
849
|
e
|
|
777
850
|
);
|
|
778
|
-
notifier.error(getCartErrorMessage(e, "
|
|
851
|
+
notifier.error(getCartErrorMessage(e, messages.format("cart.customer.saveFailed")));
|
|
779
852
|
throw e;
|
|
780
853
|
}
|
|
781
854
|
}
|
|
@@ -787,7 +860,7 @@ function normalizePhone(phone) {
|
|
|
787
860
|
return digits || null;
|
|
788
861
|
}
|
|
789
862
|
function useCartCustomerAttachment(cache) {
|
|
790
|
-
const { sdk, notifier } = useRuntime();
|
|
863
|
+
const { sdk, notifier, messages } = useRuntime();
|
|
791
864
|
const authStore = useAuthStore();
|
|
792
865
|
const cartStore = useCartStore();
|
|
793
866
|
const profileStore = useStoreProfileStore();
|
|
@@ -807,7 +880,6 @@ function useCartCustomerAttachment(cache) {
|
|
|
807
880
|
await sdk.orders.setOrderCustomer(storeId, credentials, {
|
|
808
881
|
phone: { number: authStore.phone ?? "", country: authStore.countryCode }
|
|
809
882
|
});
|
|
810
|
-
console.log("[cart] customer attached to order");
|
|
811
883
|
const fresh = await sdk.orders.getOrder(storeId, credentials, ORDER_WITH);
|
|
812
884
|
if (!authStore.isAuthenticated || authStore.token !== requestedToken) return;
|
|
813
885
|
if (cartStore.order?.id !== requestedOrderId) return;
|
|
@@ -818,14 +890,20 @@ function useCartCustomerAttachment(cache) {
|
|
|
818
890
|
if (previousPhone && newPhone && previousPhone !== newPhone) {
|
|
819
891
|
const firstName = fresh.customer?.first_name;
|
|
820
892
|
notifier.success(
|
|
821
|
-
firstName ?
|
|
893
|
+
firstName ? messages.format("cart.customer.updatedWithName", { firstName }) : messages.format("cart.customer.updated")
|
|
822
894
|
);
|
|
823
895
|
}
|
|
824
896
|
}
|
|
825
897
|
} catch (e) {
|
|
826
|
-
|
|
898
|
+
logCartError(
|
|
899
|
+
{
|
|
900
|
+
scope: "cart-customer-attach",
|
|
901
|
+
context: { orderId: requestedOrderId }
|
|
902
|
+
},
|
|
903
|
+
e
|
|
904
|
+
);
|
|
827
905
|
if (notifyOnPhoneChange) {
|
|
828
|
-
notifier.error("
|
|
906
|
+
notifier.error(messages.format("cart.customer.updateAfterLoginFailed"));
|
|
829
907
|
}
|
|
830
908
|
}
|
|
831
909
|
}
|
|
@@ -843,7 +921,13 @@ function useCartCustomerAttachment(cache) {
|
|
|
843
921
|
cartStore.setOrder(fresh);
|
|
844
922
|
cache.clear();
|
|
845
923
|
} catch (e) {
|
|
846
|
-
|
|
924
|
+
logCartError(
|
|
925
|
+
{
|
|
926
|
+
scope: "cart-customer-refresh-after-logout",
|
|
927
|
+
context: { orderId: requestedOrderId }
|
|
928
|
+
},
|
|
929
|
+
e
|
|
930
|
+
);
|
|
847
931
|
}
|
|
848
932
|
}
|
|
849
933
|
watch(
|
|
@@ -869,7 +953,7 @@ function useCartCustomerAttachment(cache) {
|
|
|
869
953
|
var KEY_STOCK_ID = "zenky_stock_id";
|
|
870
954
|
var YEAR_SECONDS = 60 * 60 * 24 * 365;
|
|
871
955
|
function useCartStockWatcher() {
|
|
872
|
-
const { sdk, notifier, storage, catalogReloader } = useRuntime();
|
|
956
|
+
const { sdk, notifier, messages, storage, catalogReloader } = useRuntime();
|
|
873
957
|
const profileStore = useStoreProfileStore();
|
|
874
958
|
const catalogStore = useCatalogStore();
|
|
875
959
|
const cartStore = useCartStore();
|
|
@@ -904,7 +988,7 @@ function useCartStockWatcher() {
|
|
|
904
988
|
},
|
|
905
989
|
e
|
|
906
990
|
);
|
|
907
|
-
notifier.warning("
|
|
991
|
+
notifier.warning(messages.format("cart.stock.catalogReloadFailed"));
|
|
908
992
|
}
|
|
909
993
|
}
|
|
910
994
|
async function checkCartProducts() {
|
|
@@ -916,10 +1000,10 @@ function useCartStockWatcher() {
|
|
|
916
1000
|
const freshOrder = await sdk.orders.getOrder(storeId, orderCredentials, ORDER_WITH);
|
|
917
1001
|
cartStore.setOrder(freshOrder);
|
|
918
1002
|
await fetchTotal();
|
|
919
|
-
notifier.warning("
|
|
1003
|
+
notifier.warning(messages.format("cart.stock.itemsRemoved"));
|
|
920
1004
|
} else if (result.order_variants.length > 0) {
|
|
921
1005
|
await fetchTotal();
|
|
922
|
-
notifier.warning("
|
|
1006
|
+
notifier.warning(messages.format("cart.stock.pricesUpdated"));
|
|
923
1007
|
}
|
|
924
1008
|
} catch (e) {
|
|
925
1009
|
logCartError(
|
|
@@ -929,7 +1013,7 @@ function useCartStockWatcher() {
|
|
|
929
1013
|
},
|
|
930
1014
|
e
|
|
931
1015
|
);
|
|
932
|
-
notifier.warning("
|
|
1016
|
+
notifier.warning(messages.format("cart.stock.checkFailed"));
|
|
933
1017
|
}
|
|
934
1018
|
}
|
|
935
1019
|
return { handleStockChange };
|
|
@@ -1158,11 +1242,14 @@ function useOrderPromocode(deps = {}) {
|
|
|
1158
1242
|
}
|
|
1159
1243
|
});
|
|
1160
1244
|
} catch (e) {
|
|
1161
|
-
errorMessage.value = getCartErrorMessage(
|
|
1245
|
+
errorMessage.value = getCartErrorMessage(
|
|
1246
|
+
e,
|
|
1247
|
+
runtime.messages.format("cart.promocode.applyFailed")
|
|
1248
|
+
);
|
|
1162
1249
|
logCartError(
|
|
1163
1250
|
{
|
|
1164
1251
|
scope: "promocode-apply",
|
|
1165
|
-
context: {
|
|
1252
|
+
context: { codeLength: trimmed.length, orderId: cartStore.credentials?.id }
|
|
1166
1253
|
},
|
|
1167
1254
|
e
|
|
1168
1255
|
);
|
|
@@ -1190,12 +1277,15 @@ function useOrderPromocode(deps = {}) {
|
|
|
1190
1277
|
}
|
|
1191
1278
|
});
|
|
1192
1279
|
} catch (e) {
|
|
1193
|
-
errorMessage.value = getCartErrorMessage(
|
|
1280
|
+
errorMessage.value = getCartErrorMessage(
|
|
1281
|
+
e,
|
|
1282
|
+
runtime.messages.format("cart.promocode.removeFailed")
|
|
1283
|
+
);
|
|
1194
1284
|
logCartError(
|
|
1195
1285
|
{
|
|
1196
1286
|
scope: "promocode-remove",
|
|
1197
1287
|
context: {
|
|
1198
|
-
|
|
1288
|
+
codeLength: applied.value?.promocode?.length,
|
|
1199
1289
|
orderId: cartStore.credentials?.id
|
|
1200
1290
|
}
|
|
1201
1291
|
},
|
|
@@ -1293,7 +1383,13 @@ function useCartDeliveryAttachment() {
|
|
|
1293
1383
|
if (!recovered) orderSettings.setSelectedAddress(null, null, null);
|
|
1294
1384
|
return;
|
|
1295
1385
|
}
|
|
1296
|
-
|
|
1386
|
+
logCartError(
|
|
1387
|
+
{
|
|
1388
|
+
scope: "cart-delivery-attach",
|
|
1389
|
+
context: { orderId: cartStore.credentials?.id }
|
|
1390
|
+
},
|
|
1391
|
+
result.error
|
|
1392
|
+
);
|
|
1297
1393
|
}
|
|
1298
1394
|
}
|
|
1299
1395
|
watch(
|
|
@@ -1319,7 +1415,7 @@ var getOperationsState = createRuntimeState(() => ({
|
|
|
1319
1415
|
function useCartOperations(credentials, initialization, sdk, deps) {
|
|
1320
1416
|
const { notifier, activity } = deps;
|
|
1321
1417
|
const runtime = useRuntime();
|
|
1322
|
-
const { events, rum, commerceEvents } = runtime;
|
|
1418
|
+
const { events, rum, commerceEvents, messages } = runtime;
|
|
1323
1419
|
const { batches, inflight } = getOperationsState(runtime);
|
|
1324
1420
|
const cartStore = useCartStore();
|
|
1325
1421
|
const profileStore = useStoreProfileStore();
|
|
@@ -1438,7 +1534,9 @@ function useCartOperations(credentials, initialization, sdk, deps) {
|
|
|
1438
1534
|
await recalculateAfterOrderChange();
|
|
1439
1535
|
if (isAdd && productName) {
|
|
1440
1536
|
const parts = [productName, variantLabel].filter(Boolean);
|
|
1441
|
-
notifier.message(
|
|
1537
|
+
notifier.message(messages.format("cart.added.title"), {
|
|
1538
|
+
description: parts.join(", ")
|
|
1539
|
+
});
|
|
1442
1540
|
}
|
|
1443
1541
|
});
|
|
1444
1542
|
} catch (e) {
|
|
@@ -1463,7 +1561,7 @@ function useCartOperations(credentials, initialization, sdk, deps) {
|
|
|
1463
1561
|
} else {
|
|
1464
1562
|
integrations?.productQuantityDecreaseFailed({ order: cartStore.order });
|
|
1465
1563
|
}
|
|
1466
|
-
notifier.error(getCartErrorMessage(e, "
|
|
1564
|
+
notifier.error(getCartErrorMessage(e, messages.format("cart.updateFailed")));
|
|
1467
1565
|
try {
|
|
1468
1566
|
await refreshCart({ silent: true });
|
|
1469
1567
|
} catch (refreshErr) {
|
|
@@ -1835,7 +1933,86 @@ function useOrderChannel() {
|
|
|
1835
1933
|
});
|
|
1836
1934
|
}
|
|
1837
1935
|
}
|
|
1936
|
+
var getGateState = createRuntimeState(() => ({
|
|
1937
|
+
isOpen: ref(false),
|
|
1938
|
+
blocking: ref([]),
|
|
1939
|
+
product: ref(null),
|
|
1940
|
+
resolver: null
|
|
1941
|
+
}));
|
|
1942
|
+
function useRestrictionGate() {
|
|
1943
|
+
const state = getGateState(useRuntime());
|
|
1944
|
+
function settle(confirmed) {
|
|
1945
|
+
state.isOpen.value = false;
|
|
1946
|
+
const resolve = state.resolver;
|
|
1947
|
+
state.resolver = null;
|
|
1948
|
+
resolve?.(confirmed);
|
|
1949
|
+
}
|
|
1950
|
+
function confirmBlocking(items, gateProduct) {
|
|
1951
|
+
settle(false);
|
|
1952
|
+
state.blocking.value = items;
|
|
1953
|
+
state.product.value = gateProduct;
|
|
1954
|
+
state.isOpen.value = true;
|
|
1955
|
+
return new Promise((resolve) => {
|
|
1956
|
+
state.resolver = resolve;
|
|
1957
|
+
});
|
|
1958
|
+
}
|
|
1959
|
+
return {
|
|
1960
|
+
isOpen: state.isOpen,
|
|
1961
|
+
blocking: state.blocking,
|
|
1962
|
+
product: state.product,
|
|
1963
|
+
confirmBlocking,
|
|
1964
|
+
confirm: () => settle(true),
|
|
1965
|
+
cancel: () => settle(false)
|
|
1966
|
+
};
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
// src/cart/useRestrictedAddToCart.ts
|
|
1970
|
+
function useRestrictedAddToCart() {
|
|
1971
|
+
const { sdk } = useRuntime();
|
|
1972
|
+
const profileStore = useStoreProfileStore();
|
|
1973
|
+
const { addToCart } = useStorefrontCart();
|
|
1974
|
+
const { confirmBlocking, isOpen: gateIsOpen } = useRestrictionGate();
|
|
1975
|
+
async function checkRestrictionsAllowed(product, alreadyInCart) {
|
|
1976
|
+
if (alreadyInCart || !product.restrictions?.length) return true;
|
|
1977
|
+
const storeId = profileStore.store?.id;
|
|
1978
|
+
const cityId = profileStore.city?.id;
|
|
1979
|
+
if (!storeId || !cityId) return true;
|
|
1980
|
+
let blocking = [];
|
|
1981
|
+
try {
|
|
1982
|
+
const url = sdk.client.getStoreUrl(storeId, `/products/${product.id}/restrictions`, {
|
|
1983
|
+
city_id: cityId,
|
|
1984
|
+
stock_id: profileStore.stock?.id ?? void 0
|
|
1985
|
+
});
|
|
1986
|
+
const response = await sdk.client.request("GET", url);
|
|
1987
|
+
blocking = (response?.data ?? []).filter((item) => item.is_blocking);
|
|
1988
|
+
} catch (error) {
|
|
1989
|
+
logCartError({ scope: "restrictions-check", context: { productId: product.id } }, error);
|
|
1990
|
+
return true;
|
|
1991
|
+
}
|
|
1992
|
+
if (!blocking.length) return true;
|
|
1993
|
+
if (gateIsOpen.value) return false;
|
|
1994
|
+
return confirmBlocking(blocking, {
|
|
1995
|
+
name: product.name ?? "",
|
|
1996
|
+
image: product.images?.[0] ?? null
|
|
1997
|
+
});
|
|
1998
|
+
}
|
|
1999
|
+
async function addWithRestrictionCheck(product, request, alreadyInCart) {
|
|
2000
|
+
if (await checkRestrictionsAllowed(product, alreadyInCart)) {
|
|
2001
|
+
await addToCart(request);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
return { checkRestrictionsAllowed, addWithRestrictionCheck };
|
|
2005
|
+
}
|
|
2006
|
+
function useVisibleCartVariants() {
|
|
2007
|
+
const cartStore = useCartStore();
|
|
2008
|
+
return computed(
|
|
2009
|
+
() => cartStore.variants.filter((variant) => {
|
|
2010
|
+
const delta = cartStore.lineOptimistic[variantLineKey(variant)] ?? 0;
|
|
2011
|
+
return variant.quantity + delta > 0;
|
|
2012
|
+
})
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
1838
2015
|
|
|
1839
|
-
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, useStorefrontCart, variantLineKey };
|
|
1840
|
-
//# sourceMappingURL=chunk-
|
|
1841
|
-
//# sourceMappingURL=chunk-
|
|
2016
|
+
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 };
|
|
2017
|
+
//# sourceMappingURL=chunk-YS5DXYYV.js.map
|
|
2018
|
+
//# sourceMappingURL=chunk-YS5DXYYV.js.map
|