@zenky/storefront-vue 0.10.9 → 0.10.11
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 +162 -0
- package/README.md +1 -1
- package/dist/auth/index.d.ts +14 -0
- package/dist/auth/index.js +4 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cart/index.d.ts +3 -28
- package/dist/cart/index.js +9 -7
- package/dist/catalog/index.d.ts +5 -3
- package/dist/catalog/index.js +2 -2
- package/dist/catalogEntity-DgrPsJpf.d.ts +44 -0
- package/dist/{chunk-AVES4WJZ.js → chunk-5CNL24PI.js} +11 -108
- package/dist/chunk-5CNL24PI.js.map +1 -0
- package/dist/{chunk-RF4ML3Q3.js → chunk-6FVXAF7L.js} +5 -4
- package/dist/chunk-6FVXAF7L.js.map +1 -0
- package/dist/chunk-AK4276ND.js +67 -0
- package/dist/chunk-AK4276ND.js.map +1 -0
- package/dist/{chunk-KFCO46RB.js → chunk-FS2UNPTY.js} +2 -2
- package/dist/chunk-FS2UNPTY.js.map +1 -0
- package/dist/chunk-IOYYCA75.js +52 -0
- package/dist/chunk-IOYYCA75.js.map +1 -0
- package/dist/chunk-KX7KXN3W.js +529 -0
- package/dist/chunk-KX7KXN3W.js.map +1 -0
- package/dist/{chunk-6QCFHSLX.js → chunk-NSOIL7PW.js} +2 -2
- package/dist/chunk-NSOIL7PW.js.map +1 -0
- package/dist/{chunk-RK5CGOM7.js → chunk-OBNMXLJO.js} +19 -3
- package/dist/chunk-OBNMXLJO.js.map +1 -0
- package/dist/{chunk-GXDTRTUT.js → chunk-RURXGVWW.js} +35 -6
- package/dist/chunk-RURXGVWW.js.map +1 -0
- package/dist/{chunk-XULHV6SS.js → chunk-TE2QPH74.js} +3 -3
- package/dist/{chunk-XULHV6SS.js.map → chunk-TE2QPH74.js.map} +1 -1
- package/dist/chunk-TE42OCFK.js +102 -0
- package/dist/chunk-TE42OCFK.js.map +1 -0
- package/dist/{chunk-GILJFP55.js → chunk-VTZYJ6OZ.js} +2 -2
- package/dist/chunk-VTZYJ6OZ.js.map +1 -0
- package/dist/{chunk-46FNHMWC.js → chunk-W43D7JYV.js} +5 -4
- package/dist/chunk-W43D7JYV.js.map +1 -0
- package/dist/{chunk-QZ3S3NN3.js → chunk-WTZXTBF6.js} +3 -47
- package/dist/chunk-WTZXTBF6.js.map +1 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.js +16 -13
- package/dist/ports/index.d.ts +1 -1
- package/dist/ports/index.js +1 -1
- package/dist/products/index.d.ts +4 -3
- package/dist/products/index.js +4 -3
- package/dist/promotions/index.js +4 -3
- package/dist/seo/index.d.ts +5 -7
- package/dist/seo/index.js +16 -9
- package/dist/seo/index.js.map +1 -1
- package/dist/stores/index.d.ts +60 -4
- package/dist/stores/index.js +7 -4
- package/dist/types-CXm2F6Hz.d.ts +55 -0
- package/dist/useCheckoutSubmit-Be-lQd60.d.ts +30 -0
- package/dist/utils/index.d.ts +6 -1
- package/dist/utils/index.js +1 -1
- package/docs/architecture.md +81 -4
- package/package.json +7 -3
- package/dist/chunk-46FNHMWC.js.map +0 -1
- package/dist/chunk-6QCFHSLX.js.map +0 -1
- package/dist/chunk-AVES4WJZ.js.map +0 -1
- package/dist/chunk-FXKG5TFQ.js +0 -38
- package/dist/chunk-FXKG5TFQ.js.map +0 -1
- package/dist/chunk-GILJFP55.js.map +0 -1
- package/dist/chunk-GXDTRTUT.js.map +0 -1
- package/dist/chunk-KFCO46RB.js.map +0 -1
- package/dist/chunk-QZ3S3NN3.js.map +0 -1
- package/dist/chunk-RF4ML3Q3.js.map +0 -1
- package/dist/chunk-RK5CGOM7.js.map +0 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { OrderCheckoutResult, RecaptchaAction } from '@zenky/storefront-api';
|
|
3
|
+
|
|
4
|
+
/** reCAPTCHA payload provider (implemented by the consumer app — Google reCAPTCHA v3). */
|
|
5
|
+
type RecaptchaPayloadProvider = (action: RecaptchaAction) => Promise<{
|
|
6
|
+
token: string;
|
|
7
|
+
} | undefined>;
|
|
8
|
+
interface CheckoutSubmitComposable {
|
|
9
|
+
/** Last `checkoutOrder` result — needed by the UI (ConfirmationModal / online redirect) */
|
|
10
|
+
result: Ref<OrderCheckoutResult | null>;
|
|
11
|
+
submitting: Ref<boolean>;
|
|
12
|
+
/**
|
|
13
|
+
* Collects `OrderCheckoutRequest` from `cartStore` (notes + persons_count).
|
|
14
|
+
* Returns `OrderCheckoutResult` with confirmation/online_payment flags.
|
|
15
|
+
*/
|
|
16
|
+
submit: () => Promise<OrderCheckoutResult | null>;
|
|
17
|
+
/** Confirm the SMS code (after checkoutOrder returned confirmation.required) */
|
|
18
|
+
confirm: (code: string) => Promise<boolean>;
|
|
19
|
+
/** Resend the code (with backoff — the UI is responsible for that) */
|
|
20
|
+
resendCode: () => Promise<boolean>;
|
|
21
|
+
cancel: () => Promise<boolean>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Final order submit + SMS confirmation.
|
|
25
|
+
*
|
|
26
|
+
* @param getRecaptchaPayload reCAPTCHA token provider (app-specific, injected).
|
|
27
|
+
*/
|
|
28
|
+
declare function useCheckoutSubmit(getRecaptchaPayload: RecaptchaPayloadProvider): CheckoutSubmitComposable;
|
|
29
|
+
|
|
30
|
+
export { type CheckoutSubmitComposable as C, type RecaptchaPayloadProvider as R, useCheckoutSubmit as u };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -39,6 +39,11 @@ interface TodayScheduleInfo {
|
|
|
39
39
|
declare function getTodayInfo(schedule: Schedule | null | undefined): TodayScheduleInfo | null;
|
|
40
40
|
declare function getWeeklySchedule(schedule: Schedule | null | undefined, locale?: string): DayScheduleInfo[];
|
|
41
41
|
declare function formatScheduleStatus(schedule: Schedule | null | undefined, locale?: string): string | null;
|
|
42
|
+
interface ScheduleRow {
|
|
43
|
+
label: string;
|
|
44
|
+
hours: string | null;
|
|
45
|
+
}
|
|
46
|
+
declare function groupScheduleDays(schedule: Schedule | null | undefined, locale?: string): ScheduleRow[];
|
|
42
47
|
|
|
43
48
|
/**
|
|
44
49
|
* Builds a QR code image URL through the Zenky media API.
|
|
@@ -86,4 +91,4 @@ declare function getApiFieldErrors(e: unknown): Record<string, string[]> | null;
|
|
|
86
91
|
*/
|
|
87
92
|
declare function formatAddressCityLast(raw: string): string;
|
|
88
93
|
|
|
89
|
-
export { type DayScheduleInfo, type OperationChain, type SocialLink, type TodayScheduleInfo, buildQrCodeUrl, createDebounce, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, pluralize, toDateInputValue, todayInTimezone };
|
|
94
|
+
export { type DayScheduleInfo, type OperationChain, type ScheduleRow, type SocialLink, type TodayScheduleInfo, buildQrCodeUrl, createDebounce, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, groupScheduleDays, pluralize, toDateInputValue, todayInTimezone };
|
package/dist/utils/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { buildQrCodeUrl, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, pluralize, toDateInputValue, todayInTimezone } from '../chunk-
|
|
1
|
+
export { buildQrCodeUrl, createOperationChain, formatAddressCityLast, formatDate, formatDateTime, formatPhoneNational, formatPhoneSpaced, formatScheduleStatus, getApiErrorMessage, getApiFieldErrors, getEmailLink, getPhoneTelLink, getSocialLinks, getTodayInfo, getWebsiteLink, getWeeklySchedule, groupScheduleDays, pluralize, toDateInputValue, todayInTimezone } from '../chunk-RURXGVWW.js';
|
|
2
2
|
export { createDebounce } from '../chunk-XUGXLJZB.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/docs/architecture.md
CHANGED
|
@@ -9,12 +9,17 @@ the consumer app.
|
|
|
9
9
|
Each folder under `src/` is one subpath export (see the README's Subpath Imports
|
|
10
10
|
section). This list says what each one owns.
|
|
11
11
|
|
|
12
|
+
- **`auth/`** — the authentication flow's shared types and channel-selection logic
|
|
13
|
+
(`AUTH_STEP`, `ConfirmationChannel`, `useAvailableConfirmationChannels`). The step
|
|
14
|
+
machine itself (`checkPhone`/`login`/`register`/`resendCode`/`dispatchReset`/
|
|
15
|
+
`resetPassword`) is the `authFlow` store in `stores/` — see below.
|
|
12
16
|
- **`cart/`** — the largest domain. Cart mutation and quantities, checkout submission
|
|
13
17
|
and confirmation, delivery and payment selection, bonuses, promocodes, customer
|
|
14
18
|
attachment, and the credentials (order id/token) every cart request needs. Most
|
|
15
19
|
checkout logic lives here.
|
|
16
20
|
- **`catalog/`** — resolving which remote catalog snapshot applies to a city and stock,
|
|
17
|
-
|
|
21
|
+
resolving what a catalog item is about (a category or a products collection), and pure
|
|
22
|
+
lookup helpers (find a category, group products by subcategory).
|
|
18
23
|
- **`money/`** — converting between minor units (kopecks) and major units (rubles).
|
|
19
24
|
Nothing else in the package divides or multiplies a price by 100; everything else
|
|
20
25
|
calls these functions.
|
|
@@ -34,12 +39,14 @@ section). This list says what each one owns.
|
|
|
34
39
|
into `<head>` tags is the consumer's job (see the README's note on `useHead`).
|
|
35
40
|
- **`snippets/`** — normalizing the snippet records a website carries (tracking scripts,
|
|
36
41
|
custom CSS) into a consistent shape.
|
|
37
|
-
- **`stores/`** — the
|
|
38
|
-
`promotions`, `store-profile`, `order-settings`. State and business logic
|
|
42
|
+
- **`stores/`** — the eight Pinia stores: `auth`, `authFlow`, `cart`, `catalog`,
|
|
43
|
+
`products`, `promotions`, `store-profile`, `order-settings`. State and business logic
|
|
44
|
+
only, no UI.
|
|
39
45
|
- **`theme/`** — generating a full color palette from one brand hex value, and the CSS
|
|
40
46
|
variable map the consumer injects into `<head>`.
|
|
41
47
|
- **`utils/`** — small pure helpers with no domain attached: phone/date/address
|
|
42
|
-
formatting,
|
|
48
|
+
formatting, reading a store schedule (today's status, the week, grouped rows),
|
|
49
|
+
debouncing, pluralization, an operation chain for sequencing async work.
|
|
43
50
|
- **`website-settings/`** — only the **runtime** shape of a website (what the storefront
|
|
44
51
|
reads and renders: settings values, pages, snippets, integrations). The website
|
|
45
52
|
builder's admin schema is a different concern — see below.
|
|
@@ -82,3 +89,73 @@ passed as an argument to that one function. `sdk`, `storage`, and the rest of th
|
|
|
82
89
|
are the port case: dozens of composables across every domain need them, so they are
|
|
83
90
|
resolved once through `useRuntime()` instead of being passed down through every caller in
|
|
84
91
|
between.
|
|
92
|
+
|
|
93
|
+
`cart/useCheckoutSubmit.ts`'s `RecaptchaPayloadProvider` type is reused as-is by the
|
|
94
|
+
`authFlow` store (`stores/authFlow.ts`) instead of being redeclared — both domains need
|
|
95
|
+
the exact same shape at the exact same "parameter, not port" surface. If a third domain
|
|
96
|
+
ever needs it, this is the point to promote it into a shared location (e.g. `utils/`)
|
|
97
|
+
rather than adding a third copy.
|
|
98
|
+
|
|
99
|
+
## Guarding async state against out-of-order responses
|
|
100
|
+
|
|
101
|
+
A store with several actions that can each be re-triggered before the previous call
|
|
102
|
+
settles (`authFlow`'s `checkPhone`/`login`/`register`/`resendCode`/`dispatchReset`, all
|
|
103
|
+
gated behind recaptcha and network round-trips a user can outrun by clicking again or
|
|
104
|
+
navigating away) needs to answer one question after every `await`: is this response
|
|
105
|
+
still the one the user is waiting for? Without that check, a slow, abandoned attempt
|
|
106
|
+
that finally resolves can overwrite state a newer attempt already set — the classic
|
|
107
|
+
last-write-doesn't-win race.
|
|
108
|
+
|
|
109
|
+
`authFlow` answers it with a single `operationRevision` counter plus four helpers:
|
|
110
|
+
|
|
111
|
+
- `invalidatePendingOperation()` — bumps the counter, nothing else. The primitive the
|
|
112
|
+
other three build on.
|
|
113
|
+
- `beginOperation()` — bumps the counter **and** sets `loading` to `false`, then returns
|
|
114
|
+
the new revision. Called once at the top of every **top-level** action (a call the UI
|
|
115
|
+
can trigger directly). Setting `loading` here — not leaving it to "the action's own
|
|
116
|
+
next line" — matters because that next line often isn't next: `register`/`resendCode`/
|
|
117
|
+
`dispatchReset` have a channel gate, and every request-making action checks `storeId`,
|
|
118
|
+
both of which can `return` before `loading.value = true` is ever reached. Without this,
|
|
119
|
+
a `checkPhone` in flight when the user triggers a `register()` that immediately exits
|
|
120
|
+
on the channel gate would invalidate `checkPhone`'s revision (so its own `finally`
|
|
121
|
+
loses the right to clear `loading`) while never reaching the line that would clear it
|
|
122
|
+
itself — `loading` stuck at `true` forever. An action that *does* reach its request
|
|
123
|
+
sets `loading.value = true` again a few lines later, in the same synchronous stretch
|
|
124
|
+
(no `await` in between), so this reads as one transition from the outside, not a
|
|
125
|
+
flicker.
|
|
126
|
+
- `isStale(revision)` — `true` once the counter has moved past the value an action
|
|
127
|
+
captured at its start. Checked after every `await` (recaptcha included) before the
|
|
128
|
+
action touches `currentStep`, `error`, `confirmationMethod`, or `loading` — if stale,
|
|
129
|
+
the action returns without touching state, including in `finally`.
|
|
130
|
+
- `cancelPendingOperation()` — same as `beginOperation()`, just for call sites that
|
|
131
|
+
don't need the revision because they aren't starting a new operation, only cancelling
|
|
132
|
+
the current one: every `goTo*`, `reset()`, `changeChannel()`. Separate name for
|
|
133
|
+
readability at the call site, not separate behavior: both clearing `loading` matters
|
|
134
|
+
in two distinct failure shapes — navigation cancelling an in-flight request with
|
|
135
|
+
nothing to replace it, and a fresh action's own early return doing the same before it
|
|
136
|
+
ever reaches its request. Diverging behavior here (one clearing `loading`, the other
|
|
137
|
+
assuming it doesn't need to) reintroduces the bug this guard exists to prevent.
|
|
138
|
+
|
|
139
|
+
A nested call that's a *continuation* of the same attempt rather than a new one
|
|
140
|
+
(`checkPhone`/`login`'s internal auto-resend, `register`'s 0-channel `login` fallback,
|
|
141
|
+
`selectChannel`'s dispatch) receives the parent's revision as an internal, non-public
|
|
142
|
+
parameter instead of calling `beginOperation()` — otherwise a parent would invalidate
|
|
143
|
+
itself the moment its own nested call started.
|
|
144
|
+
|
|
145
|
+
Two more things can go stale besides the revision counter itself. First, request inputs
|
|
146
|
+
read from mutable refs (`phone`, `country`, the channel an action is attempting) are
|
|
147
|
+
captured into local values before the first `await`, and that snapshot — not a live
|
|
148
|
+
read — is what the rest of the action uses, including any success or error handling
|
|
149
|
+
after the request resolves: reading `phone.value` or `confirmationMethod.value` again
|
|
150
|
+
after an `await` would pick up whatever the user (or unrelated code) changed it to
|
|
151
|
+
since, not what was actually submitted. Second, `phone`/`countryCode` invalidate the
|
|
152
|
+
revision on direct assignment too, via a small `customRef` (`invalidatingRef()`) instead
|
|
153
|
+
of a plain `ref()` — transparent to `v-model`, so the public type is still `Ref<string>`
|
|
154
|
+
and nothing about consuming it changes. This matters because those two are usually bound
|
|
155
|
+
straight to a form input: a user can edit the field without ever calling a store action,
|
|
156
|
+
and the revision counter alone — tied only to explicit action/navigation calls — would
|
|
157
|
+
never see that edit. Without it, a slow response for the phone number the user has since
|
|
158
|
+
changed could still land as if it were current.
|
|
159
|
+
|
|
160
|
+
This pattern is local to `authFlow` for now. If a second store grows the same shape of
|
|
161
|
+
problem, promote the counter/guard pair into `utils/` rather than re-deriving it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenky/storefront-vue",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.11",
|
|
4
4
|
"description": "Zenky Storefront SDK for Vue 3.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zenky",
|
|
@@ -90,6 +90,10 @@
|
|
|
90
90
|
"types": "./dist/stores/index.d.ts",
|
|
91
91
|
"import": "./dist/stores/index.js"
|
|
92
92
|
},
|
|
93
|
+
"./auth": {
|
|
94
|
+
"types": "./dist/auth/index.d.ts",
|
|
95
|
+
"import": "./dist/auth/index.js"
|
|
96
|
+
},
|
|
93
97
|
"./package.json": "./package.json"
|
|
94
98
|
},
|
|
95
99
|
"scripts": {
|
|
@@ -115,7 +119,7 @@
|
|
|
115
119
|
},
|
|
116
120
|
"peerDependencies": {
|
|
117
121
|
"@zenky/integrations-sdk": ">=0.1.3",
|
|
118
|
-
"@zenky/storefront-api": "^1.0
|
|
122
|
+
"@zenky/storefront-api": "^1.1.0",
|
|
119
123
|
"pinia": "^3.0.0",
|
|
120
124
|
"vue": "^3.5.0"
|
|
121
125
|
},
|
|
@@ -125,7 +129,7 @@
|
|
|
125
129
|
"@types/node": "^22.10.0",
|
|
126
130
|
"@vitest/coverage-v8": "^4.1.10",
|
|
127
131
|
"@zenky/integrations-sdk": "^0.1.3",
|
|
128
|
-
"@zenky/storefront-api": "^1.0
|
|
132
|
+
"@zenky/storefront-api": "^1.1.0",
|
|
129
133
|
"pinia": "^3.0.4",
|
|
130
134
|
"publint": "^0.3.21",
|
|
131
135
|
"tsup": "^8.3.5",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cart/useCartCredentials.ts","../src/promotions/usePromotionsChecker.ts"],"names":[],"mappings":"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","file":"chunk-46FNHMWC.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-level enum: 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 * Manages order credentials. Order id/token persistence goes through the `storage`\n * port (the core doesn't know about useCookie). The refs are initialized from\n * storage; persisting writes to both.\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.apiToken\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/** Timeout — if the WS never responds, reset the checking flag. */\nconst WS_RESPONSE_TIMEOUT_MS = 5000\n\n/**\n * Checks promotions. Calls dispatchPromotionsChecker after the cart changes.\n * The result arrives over WebSocket (handled in useOrderChannel).\n *\n * Resolve this synchronously in setup, and call only `dispatchCheck` after an\n * await — like any core composable, see \"Call composables and stores\n * synchronously in setup\" in the README.\n *\n * ```ts\n * const { dispatchCheck } = usePromotionsChecker()\n *\n * async function addGift() {\n * await addVariantToOrder()\n * dispatchCheck()\n * }\n * ```\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() // Clear old ones — WS will refill with current ones\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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stores/catalog.ts"],"names":[],"mappings":";;;;AAsBO,IAAM,eAAA,GAAkB,WAAA,CAAY,eAAA,EAAiB,MAAoB;AAC5E,EAAA,MAAM,OAAA,GAAU,GAAA,CAAmB,EAAE,CAAA;AACrC,EAAA,MAAM,WAAA,GAAc,IAAmB,IAAI,CAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,IAAI,KAAK,CAAA;AAC3B,EAAA,MAAM,SAAA,GAAY,IAAI,KAAK,CAAA;AAE3B,EAAA,SAAS,WAAA,CAAY,OAAsB,IAAA,EAA4B;AACnE,IAAA,OAAA,CAAQ,KAAA,GAAQ,KAAA;AAChB,IAAA,WAAA,CAAY,QAAQ,IAAA,IAAQ,IAAA;AAC5B,IAAA,SAAA,CAAU,KAAA,GAAQ,KAAA;AAAA,EACtB;AAEA,EAAA,SAAS,YAAA,GAAqB;AAC1B,IAAA,SAAA,CAAU,KAAA,GAAQ,IAAA;AAAA,EACtB;AAEA,EAAA,SAAS,aAAa,KAAA,EAAsB;AACxC,IAAA,SAAA,CAAU,KAAA,GAAQ,KAAA;AAAA,EACtB;AAEA,EAAA,MAAM,aAAa,QAAA,CAAS,MAAM,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAC,CAAA;AAE1D,EAAA,OAAO;AAAA,IACH,OAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACJ;AACJ,CAAC","file":"chunk-6QCFHSLX.js","sourcesContent":["import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { CatalogItem } from '@zenky/storefront-api'\n\n// Explicit return type (not inferred): otherwise Pinia's inference structurally\n// expands the SDK types in the .d.ts and bloats it. This also satisfies the\n// \"explicit return types\" rule.\nexport interface CatalogStore {\n catalog: Ref<CatalogItem[]>\n currentHash: Ref<string | null>\n reloading: Ref<boolean>\n loadError: Ref<boolean>\n initCatalog: (items: CatalogItem[], hash?: string | null) => void\n setLoadError: () => void\n setReloading: (value: boolean) => void\n hasCatalog: ComputedRef<boolean>\n}\n\n// Setup store (doc 05): id prefixed with zenky-* to avoid colliding with the\n// consumer's own stores. A plain state container — API calls and cookies live in\n// the composables/bootstrap layer, which calls these actions.\nexport const useCatalogStore = defineStore('zenky-catalog', (): CatalogStore => {\n const catalog = ref<CatalogItem[]>([])\n const currentHash = ref<string | null>(null)\n const reloading = ref(false)\n const loadError = ref(false)\n\n function initCatalog(items: CatalogItem[], hash?: string | null): void {\n catalog.value = items\n currentHash.value = hash ?? null\n loadError.value = false\n }\n\n function setLoadError(): void {\n loadError.value = true\n }\n\n function setReloading(value: boolean): void {\n reloading.value = value\n }\n\n const hasCatalog = computed(() => catalog.value.length > 0)\n\n return {\n catalog,\n currentHash,\n reloading,\n loadError,\n initCatalog,\n setLoadError,\n setReloading,\n hasCatalog,\n }\n})\n"]}
|