@zenky/storefront-vue 0.10.10 → 0.10.12
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 +139 -0
- package/README.md +1 -1
- package/dist/auth/index.d.ts +14 -0
- package/dist/auth/index.js +5 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/cart/index.d.ts +4 -28
- package/dist/cart/index.js +9 -6
- package/dist/chunk-5B2P5W3E.js +20 -0
- package/dist/chunk-5B2P5W3E.js.map +1 -0
- package/dist/{chunk-32SLDGE5.js → chunk-6FVXAF7L.js} +4 -3
- package/dist/chunk-6FVXAF7L.js.map +1 -0
- package/dist/{chunk-4UMDIBW5.js → chunk-EM6H5WFS.js} +19 -110
- package/dist/chunk-EM6H5WFS.js.map +1 -0
- package/dist/chunk-IOYYCA75.js +52 -0
- package/dist/chunk-IOYYCA75.js.map +1 -0
- package/dist/chunk-LUJSF6V7.js +530 -0
- package/dist/chunk-LUJSF6V7.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-TIQ7AJLY.js +52 -0
- package/dist/chunk-TIQ7AJLY.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 +5 -3
- package/dist/index.js +15 -11
- package/dist/ports/index.d.ts +1 -1
- package/dist/ports/index.js +1 -1
- package/dist/products/index.js +3 -2
- package/dist/promotions/index.js +4 -3
- package/dist/seo/index.js +5 -4
- package/dist/seo/index.js.map +1 -1
- package/dist/stores/index.d.ts +56 -1
- package/dist/stores/index.js +7 -3
- package/dist/types-CXm2F6Hz.d.ts +55 -0
- package/dist/useCheckoutSubmit-C934F26-.d.ts +34 -0
- package/dist/utils/index.d.ts +6 -1
- package/dist/utils/index.js +1 -1
- package/docs/architecture.md +79 -3
- package/package.json +7 -3
- package/dist/chunk-32SLDGE5.js.map +0 -1
- package/dist/chunk-46FNHMWC.js.map +0 -1
- package/dist/chunk-4UMDIBW5.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-QZ3S3NN3.js.map +0 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { ref, computed } from 'vue';
|
|
3
|
+
|
|
4
|
+
// src/stores/store-profile.ts
|
|
5
|
+
var useStoreProfileStore = defineStore("zenky-store-profile", () => {
|
|
6
|
+
const store = ref(null);
|
|
7
|
+
const city = ref(null);
|
|
8
|
+
const stock = ref(null);
|
|
9
|
+
const categories = ref([]);
|
|
10
|
+
const website = ref(null);
|
|
11
|
+
function initStore(newStore, newCity, newStock) {
|
|
12
|
+
store.value = newStore;
|
|
13
|
+
city.value = newCity;
|
|
14
|
+
stock.value = newStock;
|
|
15
|
+
}
|
|
16
|
+
function setStock(newStock) {
|
|
17
|
+
stock.value = newStock;
|
|
18
|
+
}
|
|
19
|
+
function setCategories(newCategories) {
|
|
20
|
+
categories.value = newCategories;
|
|
21
|
+
}
|
|
22
|
+
function initWebsite(newWebsite) {
|
|
23
|
+
website.value = newWebsite;
|
|
24
|
+
}
|
|
25
|
+
const isReady = computed(() => store.value !== null && city.value !== null);
|
|
26
|
+
const hasStock = computed(() => stock.value !== null);
|
|
27
|
+
const currency = computed(() => store.value?.settings?.currency ?? "RUB");
|
|
28
|
+
const squareLogoUrl = computed(() => {
|
|
29
|
+
const logo = store.value?.square_logo ?? store.value?.logo;
|
|
30
|
+
if (!logo) return null;
|
|
31
|
+
return logo.hd?.url ?? logo.xlarge?.url ?? logo.large?.url ?? logo.medium?.url ?? logo.placeholder?.url ?? null;
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
store,
|
|
35
|
+
city,
|
|
36
|
+
stock,
|
|
37
|
+
categories,
|
|
38
|
+
website,
|
|
39
|
+
initStore,
|
|
40
|
+
setStock,
|
|
41
|
+
setCategories,
|
|
42
|
+
initWebsite,
|
|
43
|
+
isReady,
|
|
44
|
+
hasStock,
|
|
45
|
+
currency,
|
|
46
|
+
squareLogoUrl
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export { useStoreProfileStore };
|
|
51
|
+
//# sourceMappingURL=chunk-IOYYCA75.js.map
|
|
52
|
+
//# sourceMappingURL=chunk-IOYYCA75.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stores/store-profile.ts"],"names":[],"mappings":";;;;AAwBO,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","file":"chunk-IOYYCA75.js","sourcesContent":["import { defineStore } from 'pinia'\nimport { computed, ref, type ComputedRef, type Ref } from 'vue'\n\nimport type { City, NestedCategory, Stock, Store } from '@zenky/storefront-api'\n\nimport type { Website } from '../website-settings'\n\n// Named return type (the dts rule) — otherwise Pinia's inference would expand the SDK types in the .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"]}
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import { useAvailableConfirmationChannels } from './chunk-5B2P5W3E.js';
|
|
2
|
+
import { getCartErrorCode, logCartError, getValidationErrors, getCartErrorMessage } from './chunk-TE42OCFK.js';
|
|
3
|
+
import { useRuntime, useAuthStore } from './chunk-WTZXTBF6.js';
|
|
4
|
+
import { AUTH_STEP, CODE_CONTEXT, CHANNEL_INTENT, toConfirmationChannel, toRequestedMethod, CONFIRMATION_CHANNEL } from './chunk-TIQ7AJLY.js';
|
|
5
|
+
import { useStoreProfileStore } from './chunk-IOYYCA75.js';
|
|
6
|
+
import { defineStore, storeToRefs } from 'pinia';
|
|
7
|
+
import { ref, computed, customRef } from 'vue';
|
|
8
|
+
import { RecaptchaAction } from '@zenky/storefront-api';
|
|
9
|
+
|
|
10
|
+
var useProductsStore = defineStore("zenky-products", () => {
|
|
11
|
+
const products = ref([]);
|
|
12
|
+
function setProducts(list) {
|
|
13
|
+
products.value = list;
|
|
14
|
+
}
|
|
15
|
+
const hasProducts = computed(() => products.value.length > 0);
|
|
16
|
+
return { products, setProducts, hasProducts };
|
|
17
|
+
});
|
|
18
|
+
var RESEND_TIMER_SECONDS = 60;
|
|
19
|
+
var AUTH_ERROR_CODE = {
|
|
20
|
+
ConfirmationRequired: "auth.registration.confirmation_required",
|
|
21
|
+
InvalidCode: "auth.confirmation.invalid_code",
|
|
22
|
+
InvalidRegistrationCode: "auth.registration.invalid_confirmation_code",
|
|
23
|
+
InvalidResetCode: "auth.password_reset.invalid_code",
|
|
24
|
+
ExpiredCode: "auth.confirmation.expired_code",
|
|
25
|
+
OtpRequestFailed: "auth.otp_request.failed"
|
|
26
|
+
};
|
|
27
|
+
var useAuthFlowStore = defineStore("zenky-auth-flow", () => {
|
|
28
|
+
const { sdk, notifier, messages } = useRuntime();
|
|
29
|
+
const authStore = useAuthStore();
|
|
30
|
+
const profileStore = useStoreProfileStore();
|
|
31
|
+
const currentStep = ref(AUTH_STEP.Phone);
|
|
32
|
+
const phone = invalidatingRef("");
|
|
33
|
+
const countryCode = invalidatingRef("RU");
|
|
34
|
+
const loading = ref(false);
|
|
35
|
+
const error = ref(null);
|
|
36
|
+
const codeContext = ref(CODE_CONTEXT.Register);
|
|
37
|
+
const confirmationMethod = ref(null);
|
|
38
|
+
const resetCode = ref("");
|
|
39
|
+
const registerCode = ref("");
|
|
40
|
+
const resendTimerEndsAt = ref(0);
|
|
41
|
+
const fieldErrors = ref({});
|
|
42
|
+
const pendingPassword = ref("");
|
|
43
|
+
const channelIntent = ref(null);
|
|
44
|
+
const lastFailedChannel = ref(null);
|
|
45
|
+
const operationRevision = ref(0);
|
|
46
|
+
function invalidatePendingOperation() {
|
|
47
|
+
operationRevision.value += 1;
|
|
48
|
+
}
|
|
49
|
+
function beginOperation() {
|
|
50
|
+
invalidatePendingOperation();
|
|
51
|
+
loading.value = false;
|
|
52
|
+
return operationRevision.value;
|
|
53
|
+
}
|
|
54
|
+
function cancelPendingOperation() {
|
|
55
|
+
beginOperation();
|
|
56
|
+
}
|
|
57
|
+
function isStale(revision) {
|
|
58
|
+
return revision !== operationRevision.value;
|
|
59
|
+
}
|
|
60
|
+
function invalidatingRef(initial) {
|
|
61
|
+
let value = initial;
|
|
62
|
+
return customRef((track, trigger) => ({
|
|
63
|
+
get() {
|
|
64
|
+
track();
|
|
65
|
+
return value;
|
|
66
|
+
},
|
|
67
|
+
set(newValue) {
|
|
68
|
+
if (newValue === value) return;
|
|
69
|
+
value = newValue;
|
|
70
|
+
cancelPendingOperation();
|
|
71
|
+
trigger();
|
|
72
|
+
}
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
const availableChannels = useAvailableConfirmationChannels();
|
|
76
|
+
function resolveOutgoingMethod() {
|
|
77
|
+
const channel = confirmationMethod.value ?? (availableChannels.value.length === 1 ? availableChannels.value[0] : void 0);
|
|
78
|
+
return toRequestedMethod(channel);
|
|
79
|
+
}
|
|
80
|
+
function getStoreId() {
|
|
81
|
+
return profileStore.store?.id ?? null;
|
|
82
|
+
}
|
|
83
|
+
function phoneRequest() {
|
|
84
|
+
return { number: phone.value, country: countryCode.value };
|
|
85
|
+
}
|
|
86
|
+
function clearError() {
|
|
87
|
+
error.value = null;
|
|
88
|
+
fieldErrors.value = {};
|
|
89
|
+
}
|
|
90
|
+
function handleAuthError(e, fallbackKey, scope) {
|
|
91
|
+
logCartError({ scope: `auth-${scope}`, context: { step: currentStep.value } }, e);
|
|
92
|
+
const fallback = messages.format(fallbackKey);
|
|
93
|
+
const validationErrors = getValidationErrors(e);
|
|
94
|
+
if (Object.keys(validationErrors).length > 0) {
|
|
95
|
+
notifier.error(getCartErrorMessage(e, fallback));
|
|
96
|
+
fieldErrors.value = validationErrors;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
error.value = getCartErrorMessage(e, fallback);
|
|
100
|
+
}
|
|
101
|
+
function handleOtpDispatchError(e, intent, scope, attemptedChannel) {
|
|
102
|
+
if (getCartErrorCode(e) === AUTH_ERROR_CODE.OtpRequestFailed && availableChannels.value.length >= 2) {
|
|
103
|
+
logCartError({ scope: `auth-${scope}`, context: { step: currentStep.value } }, e);
|
|
104
|
+
lastFailedChannel.value = attemptedChannel && attemptedChannel !== CONFIRMATION_CHANNEL.Call ? attemptedChannel : null;
|
|
105
|
+
confirmationMethod.value = null;
|
|
106
|
+
error.value = messages.format("auth.otpUnavailable");
|
|
107
|
+
channelIntent.value = intent;
|
|
108
|
+
currentStep.value = AUTH_STEP.Channel;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
function changeChannel() {
|
|
114
|
+
cancelPendingOperation();
|
|
115
|
+
confirmationMethod.value = null;
|
|
116
|
+
lastFailedChannel.value = null;
|
|
117
|
+
}
|
|
118
|
+
function reset() {
|
|
119
|
+
cancelPendingOperation();
|
|
120
|
+
currentStep.value = AUTH_STEP.Phone;
|
|
121
|
+
phone.value = "";
|
|
122
|
+
countryCode.value = "RU";
|
|
123
|
+
error.value = null;
|
|
124
|
+
fieldErrors.value = {};
|
|
125
|
+
codeContext.value = CODE_CONTEXT.Register;
|
|
126
|
+
confirmationMethod.value = null;
|
|
127
|
+
resetCode.value = "";
|
|
128
|
+
registerCode.value = "";
|
|
129
|
+
resendTimerEndsAt.value = 0;
|
|
130
|
+
pendingPassword.value = "";
|
|
131
|
+
channelIntent.value = null;
|
|
132
|
+
lastFailedChannel.value = null;
|
|
133
|
+
}
|
|
134
|
+
async function checkPhone(getRecaptchaPayload) {
|
|
135
|
+
const revision = beginOperation();
|
|
136
|
+
clearError();
|
|
137
|
+
codeContext.value = CODE_CONTEXT.Register;
|
|
138
|
+
resendTimerEndsAt.value = 0;
|
|
139
|
+
confirmationMethod.value = null;
|
|
140
|
+
lastFailedChannel.value = null;
|
|
141
|
+
pendingPassword.value = "";
|
|
142
|
+
channelIntent.value = null;
|
|
143
|
+
resetCode.value = "";
|
|
144
|
+
registerCode.value = "";
|
|
145
|
+
const storeId = getStoreId();
|
|
146
|
+
if (!storeId) return;
|
|
147
|
+
const phoneSnapshot = phoneRequest();
|
|
148
|
+
loading.value = true;
|
|
149
|
+
try {
|
|
150
|
+
const result = await sdk.auth.checkPhone(storeId, { phone: phoneSnapshot });
|
|
151
|
+
if (isStale(revision)) return;
|
|
152
|
+
if (result.registered && result.confirmed) {
|
|
153
|
+
currentStep.value = AUTH_STEP.Login;
|
|
154
|
+
} else if (result.registered && !result.confirmed) {
|
|
155
|
+
codeContext.value = CODE_CONTEXT.Register;
|
|
156
|
+
await resendCode(getRecaptchaPayload, revision);
|
|
157
|
+
if (isStale(revision)) return;
|
|
158
|
+
if (currentStep.value !== AUTH_STEP.Channel) currentStep.value = AUTH_STEP.Code;
|
|
159
|
+
} else {
|
|
160
|
+
currentStep.value = AUTH_STEP.Register;
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
if (!isStale(revision)) handleAuthError(e, "auth.checkPhoneFailed", "check-phone");
|
|
164
|
+
} finally {
|
|
165
|
+
if (!isStale(revision)) loading.value = false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function login(password, getRecaptchaPayload, parentRevision) {
|
|
169
|
+
const revision = parentRevision ?? beginOperation();
|
|
170
|
+
clearError();
|
|
171
|
+
const storeId = getStoreId();
|
|
172
|
+
if (!storeId) return false;
|
|
173
|
+
const phoneSnapshot = phoneRequest();
|
|
174
|
+
loading.value = true;
|
|
175
|
+
try {
|
|
176
|
+
const result = await sdk.auth.login(storeId, { phone: phoneSnapshot, password });
|
|
177
|
+
if (isStale(revision)) return false;
|
|
178
|
+
authStore.setToken(result.token, phoneSnapshot.number, phoneSnapshot.country);
|
|
179
|
+
pendingPassword.value = "";
|
|
180
|
+
return true;
|
|
181
|
+
} catch (e) {
|
|
182
|
+
if (isStale(revision)) return false;
|
|
183
|
+
if (getCartErrorCode(e) === AUTH_ERROR_CODE.ConfirmationRequired) {
|
|
184
|
+
pendingPassword.value = password;
|
|
185
|
+
codeContext.value = CODE_CONTEXT.Register;
|
|
186
|
+
loading.value = false;
|
|
187
|
+
await resendCode(getRecaptchaPayload, revision);
|
|
188
|
+
if (isStale(revision)) return false;
|
|
189
|
+
if (currentStep.value !== AUTH_STEP.Channel) currentStep.value = AUTH_STEP.Code;
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
handleAuthError(e, "auth.invalidPassword", "login");
|
|
193
|
+
return false;
|
|
194
|
+
} finally {
|
|
195
|
+
if (!isStale(revision)) loading.value = false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function register(password, getRecaptchaPayload, parentRevision) {
|
|
199
|
+
const revision = parentRevision ?? beginOperation();
|
|
200
|
+
clearError();
|
|
201
|
+
pendingPassword.value = password;
|
|
202
|
+
if (confirmationMethod.value === null && availableChannels.value.length >= 2) {
|
|
203
|
+
channelIntent.value = CHANNEL_INTENT.Register;
|
|
204
|
+
currentStep.value = AUTH_STEP.Channel;
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
const storeId = getStoreId();
|
|
208
|
+
if (!storeId) return false;
|
|
209
|
+
const phoneSnapshot = phoneRequest();
|
|
210
|
+
const method = resolveOutgoingMethod();
|
|
211
|
+
const attemptedChannel = confirmationMethod.value;
|
|
212
|
+
loading.value = true;
|
|
213
|
+
try {
|
|
214
|
+
const recaptcha = await getRecaptchaPayload(RecaptchaAction.Registration);
|
|
215
|
+
if (isStale(revision)) return false;
|
|
216
|
+
const result = await sdk.auth.register(storeId, {
|
|
217
|
+
phone: phoneSnapshot,
|
|
218
|
+
password,
|
|
219
|
+
recaptcha,
|
|
220
|
+
method
|
|
221
|
+
});
|
|
222
|
+
if (isStale(revision)) return false;
|
|
223
|
+
if (result.confirmation_required) {
|
|
224
|
+
codeContext.value = CODE_CONTEXT.Register;
|
|
225
|
+
confirmationMethod.value = toConfirmationChannel(result.method);
|
|
226
|
+
resendTimerEndsAt.value = Date.now() + RESEND_TIMER_SECONDS * 1e3;
|
|
227
|
+
currentStep.value = AUTH_STEP.Code;
|
|
228
|
+
channelIntent.value = null;
|
|
229
|
+
lastFailedChannel.value = null;
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
channelIntent.value = null;
|
|
233
|
+
lastFailedChannel.value = null;
|
|
234
|
+
return await login(password, getRecaptchaPayload, revision);
|
|
235
|
+
} catch (e) {
|
|
236
|
+
if (isStale(revision)) return false;
|
|
237
|
+
if (!handleOtpDispatchError(e, CHANNEL_INTENT.Register, "register", attemptedChannel)) {
|
|
238
|
+
handleAuthError(e, "auth.registerFailed", "register");
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
} finally {
|
|
242
|
+
if (!isStale(revision)) loading.value = false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function confirmRegistration(code, password) {
|
|
246
|
+
const revision = beginOperation();
|
|
247
|
+
clearError();
|
|
248
|
+
const storeId = getStoreId();
|
|
249
|
+
if (!storeId) return false;
|
|
250
|
+
const phoneSnapshot = phoneRequest();
|
|
251
|
+
const passwordSnapshot = password || pendingPassword.value || void 0;
|
|
252
|
+
loading.value = true;
|
|
253
|
+
try {
|
|
254
|
+
const result = await sdk.auth.confirmRegistration(storeId, {
|
|
255
|
+
phone: phoneSnapshot,
|
|
256
|
+
code,
|
|
257
|
+
password: passwordSnapshot
|
|
258
|
+
});
|
|
259
|
+
if (isStale(revision)) return false;
|
|
260
|
+
authStore.setToken(result.token, phoneSnapshot.number, phoneSnapshot.country);
|
|
261
|
+
pendingPassword.value = "";
|
|
262
|
+
return true;
|
|
263
|
+
} catch (e) {
|
|
264
|
+
if (isStale(revision)) return false;
|
|
265
|
+
handleAuthError(e, "auth.invalidCode", "confirm-registration");
|
|
266
|
+
return false;
|
|
267
|
+
} finally {
|
|
268
|
+
if (!isStale(revision)) loading.value = false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async function resendCode(getRecaptchaPayload, parentRevision) {
|
|
272
|
+
const revision = parentRevision ?? beginOperation();
|
|
273
|
+
clearError();
|
|
274
|
+
if (confirmationMethod.value === null && availableChannels.value.length >= 2) {
|
|
275
|
+
channelIntent.value = CHANNEL_INTENT.Resend;
|
|
276
|
+
currentStep.value = AUTH_STEP.Channel;
|
|
277
|
+
return 0;
|
|
278
|
+
}
|
|
279
|
+
const storeId = getStoreId();
|
|
280
|
+
if (!storeId) return 0;
|
|
281
|
+
const phoneSnapshot = phoneRequest();
|
|
282
|
+
const method = resolveOutgoingMethod();
|
|
283
|
+
const context = codeContext.value;
|
|
284
|
+
const attemptedChannel = confirmationMethod.value;
|
|
285
|
+
loading.value = true;
|
|
286
|
+
try {
|
|
287
|
+
const recaptcha = await getRecaptchaPayload(
|
|
288
|
+
context === CODE_CONTEXT.Reset ? RecaptchaAction.ResetPassword : RecaptchaAction.ResendRegistrationCode
|
|
289
|
+
);
|
|
290
|
+
if (isStale(revision)) return 0;
|
|
291
|
+
const result = context === CODE_CONTEXT.Reset ? await sdk.auth.dispatchPasswordReset(storeId, {
|
|
292
|
+
phone: phoneSnapshot,
|
|
293
|
+
recaptcha,
|
|
294
|
+
method
|
|
295
|
+
}) : await sdk.auth.resendRegistrationConfirmation(storeId, {
|
|
296
|
+
phone: phoneSnapshot,
|
|
297
|
+
recaptcha,
|
|
298
|
+
method
|
|
299
|
+
});
|
|
300
|
+
if (isStale(revision)) return 0;
|
|
301
|
+
confirmationMethod.value = toConfirmationChannel(result.method);
|
|
302
|
+
resendTimerEndsAt.value = Date.now() + RESEND_TIMER_SECONDS * 1e3;
|
|
303
|
+
lastFailedChannel.value = null;
|
|
304
|
+
if (currentStep.value === AUTH_STEP.Channel) {
|
|
305
|
+
channelIntent.value = null;
|
|
306
|
+
currentStep.value = AUTH_STEP.Code;
|
|
307
|
+
}
|
|
308
|
+
return RESEND_TIMER_SECONDS;
|
|
309
|
+
} catch (e) {
|
|
310
|
+
if (isStale(revision)) return 0;
|
|
311
|
+
if (!handleOtpDispatchError(e, CHANNEL_INTENT.Resend, "resend-code", attemptedChannel)) {
|
|
312
|
+
handleAuthError(e, "auth.resendCodeFailed", "resend-code");
|
|
313
|
+
}
|
|
314
|
+
return 0;
|
|
315
|
+
} finally {
|
|
316
|
+
if (!isStale(revision)) loading.value = false;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
async function dispatchReset(getRecaptchaPayload, parentRevision) {
|
|
320
|
+
const revision = parentRevision ?? beginOperation();
|
|
321
|
+
clearError();
|
|
322
|
+
if (confirmationMethod.value === null && availableChannels.value.length >= 2) {
|
|
323
|
+
channelIntent.value = CHANNEL_INTENT.DispatchReset;
|
|
324
|
+
currentStep.value = AUTH_STEP.Channel;
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const storeId = getStoreId();
|
|
328
|
+
if (!storeId) return;
|
|
329
|
+
const phoneSnapshot = phoneRequest();
|
|
330
|
+
const method = resolveOutgoingMethod();
|
|
331
|
+
const attemptedChannel = confirmationMethod.value;
|
|
332
|
+
loading.value = true;
|
|
333
|
+
try {
|
|
334
|
+
const recaptcha = await getRecaptchaPayload(RecaptchaAction.ResetPassword);
|
|
335
|
+
if (isStale(revision)) return;
|
|
336
|
+
const result = await sdk.auth.dispatchPasswordReset(storeId, {
|
|
337
|
+
phone: phoneSnapshot,
|
|
338
|
+
recaptcha,
|
|
339
|
+
method
|
|
340
|
+
});
|
|
341
|
+
if (isStale(revision)) return;
|
|
342
|
+
codeContext.value = CODE_CONTEXT.Reset;
|
|
343
|
+
confirmationMethod.value = toConfirmationChannel(result.method);
|
|
344
|
+
resendTimerEndsAt.value = Date.now() + RESEND_TIMER_SECONDS * 1e3;
|
|
345
|
+
currentStep.value = AUTH_STEP.Code;
|
|
346
|
+
channelIntent.value = null;
|
|
347
|
+
lastFailedChannel.value = null;
|
|
348
|
+
} catch (e) {
|
|
349
|
+
if (isStale(revision)) return;
|
|
350
|
+
if (!handleOtpDispatchError(
|
|
351
|
+
e,
|
|
352
|
+
CHANNEL_INTENT.DispatchReset,
|
|
353
|
+
"dispatch-reset",
|
|
354
|
+
attemptedChannel
|
|
355
|
+
)) {
|
|
356
|
+
handleAuthError(e, "auth.dispatchResetFailed", "dispatch-reset");
|
|
357
|
+
}
|
|
358
|
+
} finally {
|
|
359
|
+
if (!isStale(revision)) loading.value = false;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async function resetPassword(code, password) {
|
|
363
|
+
const revision = beginOperation();
|
|
364
|
+
clearError();
|
|
365
|
+
const storeId = getStoreId();
|
|
366
|
+
if (!storeId) return false;
|
|
367
|
+
const phoneSnapshot = phoneRequest();
|
|
368
|
+
loading.value = true;
|
|
369
|
+
try {
|
|
370
|
+
const result = await sdk.auth.resetPassword(storeId, {
|
|
371
|
+
phone: phoneSnapshot,
|
|
372
|
+
code,
|
|
373
|
+
password
|
|
374
|
+
});
|
|
375
|
+
if (isStale(revision)) return false;
|
|
376
|
+
authStore.setToken(result.token, phoneSnapshot.number, phoneSnapshot.country);
|
|
377
|
+
return true;
|
|
378
|
+
} catch (e) {
|
|
379
|
+
if (isStale(revision)) return false;
|
|
380
|
+
const errorCode = getCartErrorCode(e);
|
|
381
|
+
if (errorCode === AUTH_ERROR_CODE.InvalidCode || errorCode === AUTH_ERROR_CODE.InvalidRegistrationCode || errorCode === AUTH_ERROR_CODE.InvalidResetCode || errorCode === AUTH_ERROR_CODE.ExpiredCode) {
|
|
382
|
+
handleAuthError(e, "auth.invalidCode", "reset-password");
|
|
383
|
+
resetCode.value = "";
|
|
384
|
+
currentStep.value = AUTH_STEP.Code;
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
handleAuthError(e, "auth.resetPasswordFailed", "reset-password");
|
|
388
|
+
return false;
|
|
389
|
+
} finally {
|
|
390
|
+
if (!isStale(revision)) loading.value = false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function selectChannel(channel, getRecaptchaPayload) {
|
|
394
|
+
if (!availableChannels.value.includes(channel)) return false;
|
|
395
|
+
const revision = beginOperation();
|
|
396
|
+
confirmationMethod.value = channel;
|
|
397
|
+
const intent = channelIntent.value;
|
|
398
|
+
if (intent === CHANNEL_INTENT.Register)
|
|
399
|
+
return register(pendingPassword.value, getRecaptchaPayload, revision);
|
|
400
|
+
if (intent === CHANNEL_INTENT.Resend) {
|
|
401
|
+
await resendCode(getRecaptchaPayload, revision);
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
if (intent === CHANNEL_INTENT.DispatchReset) {
|
|
405
|
+
await dispatchReset(getRecaptchaPayload, revision);
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
function goToChannelBack() {
|
|
411
|
+
cancelPendingOperation();
|
|
412
|
+
clearError();
|
|
413
|
+
const intent = channelIntent.value;
|
|
414
|
+
channelIntent.value = null;
|
|
415
|
+
if (intent === CHANNEL_INTENT.Register) currentStep.value = AUTH_STEP.Register;
|
|
416
|
+
else if (intent === CHANNEL_INTENT.Resend) currentStep.value = AUTH_STEP.Code;
|
|
417
|
+
else if (intent === CHANNEL_INTENT.DispatchReset) currentStep.value = AUTH_STEP.Reset;
|
|
418
|
+
else currentStep.value = AUTH_STEP.Phone;
|
|
419
|
+
}
|
|
420
|
+
function goToReset() {
|
|
421
|
+
cancelPendingOperation();
|
|
422
|
+
clearError();
|
|
423
|
+
if (codeContext.value === CODE_CONTEXT.Reset && resendTimerEndsAt.value > Date.now()) {
|
|
424
|
+
currentStep.value = AUTH_STEP.Code;
|
|
425
|
+
} else {
|
|
426
|
+
currentStep.value = AUTH_STEP.Reset;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function goToPhone() {
|
|
430
|
+
cancelPendingOperation();
|
|
431
|
+
clearError();
|
|
432
|
+
currentStep.value = AUTH_STEP.Phone;
|
|
433
|
+
}
|
|
434
|
+
function goToMethod() {
|
|
435
|
+
cancelPendingOperation();
|
|
436
|
+
clearError();
|
|
437
|
+
currentStep.value = AUTH_STEP.Method;
|
|
438
|
+
}
|
|
439
|
+
function goToLogin() {
|
|
440
|
+
cancelPendingOperation();
|
|
441
|
+
clearError();
|
|
442
|
+
currentStep.value = AUTH_STEP.Login;
|
|
443
|
+
}
|
|
444
|
+
function goToNewPassword(code) {
|
|
445
|
+
cancelPendingOperation();
|
|
446
|
+
clearError();
|
|
447
|
+
resetCode.value = code;
|
|
448
|
+
currentStep.value = AUTH_STEP.NewPassword;
|
|
449
|
+
}
|
|
450
|
+
function goToResetCode() {
|
|
451
|
+
cancelPendingOperation();
|
|
452
|
+
clearError();
|
|
453
|
+
resetCode.value = "";
|
|
454
|
+
currentStep.value = AUTH_STEP.Code;
|
|
455
|
+
}
|
|
456
|
+
function goToRegisterPassword(code) {
|
|
457
|
+
cancelPendingOperation();
|
|
458
|
+
clearError();
|
|
459
|
+
registerCode.value = code;
|
|
460
|
+
currentStep.value = AUTH_STEP.RegisterPassword;
|
|
461
|
+
}
|
|
462
|
+
function goToRegisterCode() {
|
|
463
|
+
cancelPendingOperation();
|
|
464
|
+
clearError();
|
|
465
|
+
registerCode.value = "";
|
|
466
|
+
currentStep.value = AUTH_STEP.Code;
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
currentStep,
|
|
470
|
+
phone,
|
|
471
|
+
countryCode,
|
|
472
|
+
loading,
|
|
473
|
+
error,
|
|
474
|
+
fieldErrors,
|
|
475
|
+
codeContext,
|
|
476
|
+
confirmationMethod,
|
|
477
|
+
channelIntent,
|
|
478
|
+
lastFailedChannel,
|
|
479
|
+
resetCode,
|
|
480
|
+
registerCode,
|
|
481
|
+
resendTimerEndsAt,
|
|
482
|
+
pendingPassword,
|
|
483
|
+
availableChannels,
|
|
484
|
+
checkPhone,
|
|
485
|
+
login,
|
|
486
|
+
register,
|
|
487
|
+
confirmRegistration,
|
|
488
|
+
resendCode,
|
|
489
|
+
dispatchReset,
|
|
490
|
+
resetPassword,
|
|
491
|
+
selectChannel,
|
|
492
|
+
changeChannel,
|
|
493
|
+
goToChannelBack,
|
|
494
|
+
goToReset,
|
|
495
|
+
goToPhone,
|
|
496
|
+
goToMethod,
|
|
497
|
+
goToLogin,
|
|
498
|
+
goToNewPassword,
|
|
499
|
+
goToResetCode,
|
|
500
|
+
goToRegisterPassword,
|
|
501
|
+
goToRegisterCode,
|
|
502
|
+
reset
|
|
503
|
+
};
|
|
504
|
+
});
|
|
505
|
+
function useStore() {
|
|
506
|
+
const profileStore = useStoreProfileStore();
|
|
507
|
+
return {
|
|
508
|
+
store: computed(() => profileStore.store),
|
|
509
|
+
city: computed(() => profileStore.city),
|
|
510
|
+
stock: computed(() => profileStore.stock)
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
function useStorefrontProfile() {
|
|
514
|
+
const profileStore = useStoreProfileStore();
|
|
515
|
+
const { store, city, stock, categories } = storeToRefs(profileStore);
|
|
516
|
+
const isReady = computed(() => profileStore.isReady);
|
|
517
|
+
const hasStock = computed(() => profileStore.hasStock);
|
|
518
|
+
return {
|
|
519
|
+
store,
|
|
520
|
+
city,
|
|
521
|
+
stock,
|
|
522
|
+
categories,
|
|
523
|
+
isReady,
|
|
524
|
+
hasStock
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
export { RESEND_TIMER_SECONDS, useAuthFlowStore, useProductsStore, useStore, useStorefrontProfile };
|
|
529
|
+
//# sourceMappingURL=chunk-LUJSF6V7.js.map
|
|
530
|
+
//# sourceMappingURL=chunk-LUJSF6V7.js.map
|