refactor: move spa to frontend folder
This commit is contained in:
165
frontend/spa/src/stores/CartStore.js
Normal file
165
frontend/spa/src/stores/CartStore.js
Normal file
@@ -0,0 +1,165 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {isNotEmpty} from "@/helpers.js";
|
||||
import {addToCart, cartEditItem, cartRemoveItem, getCart, setCoupon, setVoucher} from "@/utils/ftch.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
|
||||
export const useCartStore = defineStore('cart', {
|
||||
state: () => ({
|
||||
items: [],
|
||||
productsCount: 0,
|
||||
total: 0,
|
||||
isLoading: false,
|
||||
reason: null,
|
||||
error_warning: '',
|
||||
attention: '',
|
||||
success: '',
|
||||
coupon: '',
|
||||
voucher: '',
|
||||
}),
|
||||
|
||||
getters: {
|
||||
canCheckout: (state) => {
|
||||
if (state.isLoading || state.error_warning.length > 0) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
async getProducts() {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const {data} = await getCart();
|
||||
this.items = data.products;
|
||||
this.productsCount = data.total_products_count;
|
||||
this.totals = data.totals;
|
||||
this.error_warning = data.error_warning;
|
||||
this.attention = data.attention;
|
||||
this.success = data.success;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async addProduct(productId, productName, price, quantity = 1, options = []) {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const formData = new FormData();
|
||||
formData.append("product_id", productId);
|
||||
formData.append("quantity", quantity);
|
||||
|
||||
// TODO: Add support different types of options
|
||||
options.forEach((option) => {
|
||||
if (option.type === "checkbox" && Array.isArray(option.value)) {
|
||||
option.value.forEach(item => {
|
||||
formData.append(`option[${option.product_option_id}][]`, item.product_option_value_id);
|
||||
});
|
||||
} else if (option.type === "radio" && isNotEmpty(option.value)) {
|
||||
formData.append(`option[${option.product_option_id}]`, option.value.product_option_value_id);
|
||||
} else if (option.type === "select" && isNotEmpty(option.value)) {
|
||||
formData.append(`option[${option.product_option_id}]`, option.value.product_option_value_id);
|
||||
} else if ((option.type === "text" || option.type === 'textarea') && isNotEmpty(option.value)) {
|
||||
formData.append(`option[${option.product_option_id}]`, option.value);
|
||||
}
|
||||
})
|
||||
|
||||
const response = await addToCart(formData);
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(JSON.stringify(response.error));
|
||||
}
|
||||
|
||||
await this.getProducts();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
throw error;
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async removeItem(cartItem, rowId, index = 0) {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const formData = new FormData();
|
||||
formData.append('key', rowId);
|
||||
await cartRemoveItem(formData);
|
||||
useYaMetrikaStore().dataLayerPush({
|
||||
"ecommerce": {
|
||||
"currencyCode": useSettingsStore().currency_code,
|
||||
"remove": {
|
||||
"products": [
|
||||
{
|
||||
"id": cartItem.product_id,
|
||||
"name": cartItem.name,
|
||||
"quantity": cartItem.quantity,
|
||||
"position": index
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
await this.getProducts();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async setQuantity(cartId, quantity) {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const formData = new FormData();
|
||||
formData.append(`quantity[${cartId}]`, quantity);
|
||||
await cartEditItem(formData);
|
||||
await this.getProducts();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async applyCoupon() {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
this.error_warning = '';
|
||||
const response = await setCoupon(this.coupon);
|
||||
|
||||
if (response.error) {
|
||||
this.error_warning = response.error;
|
||||
} else {
|
||||
await this.getProducts();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this.error_warning = 'Возникла ошибка';
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async applyVoucher() {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
this.error_warning = '';
|
||||
const response = await setVoucher(this.voucher);
|
||||
|
||||
if (response.error) {
|
||||
this.error_warning = response.error;
|
||||
} else {
|
||||
await this.getProducts();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this.error_warning = 'Возникла ошибка';
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
61
frontend/spa/src/stores/CategoriesStore.js
Normal file
61
frontend/spa/src/stores/CategoriesStore.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import {defineStore} from "pinia";
|
||||
import ftch from "../utils/ftch.js";
|
||||
|
||||
export const useCategoriesStore = defineStore('categories', {
|
||||
state: () => ({
|
||||
topCategories: [],
|
||||
categories: [],
|
||||
isLoading: false,
|
||||
isCategoriesLoaded: false,
|
||||
}),
|
||||
|
||||
actions: {
|
||||
async fetchCategories() {
|
||||
if (this.isCategoriesLoaded === false && this.categories.length === 0) {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const {data} = await ftch('categoriesList');
|
||||
this.categories = data;
|
||||
this.isCategoriesLoaded = true;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async fetchTopCategories() {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const response = await ftch('categoriesList', {
|
||||
forMainPage: true,
|
||||
});
|
||||
this.topCategories = response.data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
async findCategoryById(id, list = []) {
|
||||
if (! id) return null;
|
||||
|
||||
if (list && list.length === 0) {
|
||||
await this.fetchCategories();
|
||||
list = this.categories;
|
||||
}
|
||||
|
||||
for (const cat of list) {
|
||||
if (parseInt(cat.id) === parseInt(id)) return cat;
|
||||
if (cat.children?.length) {
|
||||
const found = await this.findCategoryById(id, cat.children);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
114
frontend/spa/src/stores/CheckoutStore.js
Normal file
114
frontend/spa/src/stores/CheckoutStore.js
Normal file
@@ -0,0 +1,114 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {isNotEmpty} from "@/helpers.js";
|
||||
import {storeOrder} from "@/utils/ftch.js";
|
||||
import {useCartStore} from "@/stores/CartStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
|
||||
export const useCheckoutStore = defineStore('checkout', {
|
||||
state: () => ({
|
||||
customer: {
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
email: "",
|
||||
phone: "",
|
||||
address: "",
|
||||
comment: "",
|
||||
tgData: null,
|
||||
},
|
||||
|
||||
order: null,
|
||||
|
||||
isLoading: false,
|
||||
validationErrors: {},
|
||||
}),
|
||||
|
||||
getters: {
|
||||
hasError: (state) => {
|
||||
return (field) => isNotEmpty(state.validationErrors[field]);
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
async makeOrder() {
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const data = window.Telegram.WebApp.initDataUnsafe;
|
||||
|
||||
console.log("Allows write to PM: ", data.user.allows_write_to_pm);
|
||||
|
||||
if (! data.user.allows_write_to_pm) {
|
||||
console.log("Sending request");
|
||||
const granted = await new Promise(resolve => {
|
||||
window.Telegram.WebApp.requestWriteAccess((granted) => {
|
||||
resolve(granted);
|
||||
});
|
||||
});
|
||||
|
||||
if (granted) {
|
||||
data.user.allows_write_to_pm = true;
|
||||
console.log('Пользователь разрешил отправку сообщений');
|
||||
} else {
|
||||
alert('Вы не дали разрешение — бот не сможет отправлять вам уведомления');
|
||||
}
|
||||
}
|
||||
|
||||
this.customer.tgData = data;
|
||||
|
||||
const response = await storeOrder(this.customer);
|
||||
this.order = response.data;
|
||||
|
||||
if (! this.order.id) {
|
||||
console.debug(response.data);
|
||||
throw new Error('Ошибка создания заказа.');
|
||||
}
|
||||
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.ORDER_CREATED_SUCCESS, {
|
||||
price: this.order?.final_total_numeric,
|
||||
currency: this.order?.currency,
|
||||
});
|
||||
yaMetrika.dataLayerPush({
|
||||
"ecommerce": {
|
||||
"currencyCode": useSettingsStore().currency_code,
|
||||
"purchase": {
|
||||
"actionField": {
|
||||
"id": this.order.id,
|
||||
'revenue': this.order?.final_total_numeric,
|
||||
},
|
||||
"products": this.order.products ? this.order.products.map((product, index) => {
|
||||
return {
|
||||
id: product.product_id,
|
||||
name: product.name,
|
||||
price: product.total_numeric,
|
||||
position: index,
|
||||
quantity: product.quantity,
|
||||
};
|
||||
}) : [],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
|
||||
await useCartStore().getProducts();
|
||||
} catch (error) {
|
||||
if (error.response?.status === 422) {
|
||||
this.validationErrors = error.response._data.data;
|
||||
} else {
|
||||
console.error('Server error', error);
|
||||
}
|
||||
|
||||
window.Telegram.WebApp.HapticFeedback.notificationOccurred('error');
|
||||
|
||||
throw error;
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
clearError(field) {
|
||||
this.validationErrors[field] = null;
|
||||
},
|
||||
},
|
||||
});
|
||||
41
frontend/spa/src/stores/ProductFiltersStore.js
Normal file
41
frontend/spa/src/stores/ProductFiltersStore.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {getFiltersForMainPage} from "@/utils/ftch.js";
|
||||
import {md5} from "js-md5";
|
||||
|
||||
export const useProductFiltersStore = defineStore('product_filters', {
|
||||
state: () => ({
|
||||
isLoading: false,
|
||||
draft: {},
|
||||
applied: {},
|
||||
default: {},
|
||||
fullPath: '',
|
||||
}),
|
||||
|
||||
getters: {
|
||||
paramsHashForRouter: (state) => md5(JSON.stringify({ filters: state.applied })),
|
||||
|
||||
isFiltersChanged: (state) =>
|
||||
md5(JSON.stringify({ filters: state.applied })) !== md5(JSON.stringify({ filters: state.default })),
|
||||
},
|
||||
|
||||
actions: {
|
||||
async fetchFiltersForMainPage() {
|
||||
if (this.isLoading) return;
|
||||
|
||||
try {
|
||||
this.isLoading = true;
|
||||
const response = await getFiltersForMainPage();
|
||||
this.default = response.data;
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.filters = {};
|
||||
}
|
||||
},
|
||||
});
|
||||
122
frontend/spa/src/stores/ProductsStore.js
Normal file
122
frontend/spa/src/stores/ProductsStore.js
Normal file
@@ -0,0 +1,122 @@
|
||||
import {defineStore} from "pinia";
|
||||
import ftch from "@/utils/ftch.js";
|
||||
import {md5} from 'js-md5';
|
||||
import {toRaw} from "vue";
|
||||
|
||||
export const useProductsStore = defineStore('products', {
|
||||
state: () => ({
|
||||
products: {
|
||||
data: [],
|
||||
meta: {
|
||||
hasMore: true,
|
||||
},
|
||||
},
|
||||
filters: null,
|
||||
filtersFullUrl: '',
|
||||
search: '',
|
||||
page: 1,
|
||||
isLoading: false,
|
||||
isLoadingMore: false,
|
||||
loadFinished: false,
|
||||
savedScrollY: 0,
|
||||
currentLoadedParamsHash: null,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
paramsHash: (state) => md5(JSON.stringify(toRaw(state.getParams()))),
|
||||
paramsHashForRouter: (state) => md5(JSON.stringify({
|
||||
search: state.search,
|
||||
filters: toRaw(state.filters),
|
||||
})),
|
||||
},
|
||||
|
||||
actions: {
|
||||
getParams() {
|
||||
return {
|
||||
page: this.page,
|
||||
search: this.search,
|
||||
filters: toRaw(this.filters),
|
||||
};
|
||||
},
|
||||
|
||||
async fetchProducts() {
|
||||
try {
|
||||
console.debug('Current params hash: ', this.currentLoadedParamsHash);
|
||||
if (this.products.data.length > 0 && this.paramsHash === this.currentLoadedParamsHash) {
|
||||
console.debug('Loading products from cache');
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(this.products);
|
||||
});
|
||||
}
|
||||
|
||||
console.debug('Requested param cache: ', this.paramsHash);
|
||||
console.debug('Invalidate cache. Fetch products from server.', this.getParams());
|
||||
const response = await ftch('products', null, this.getParams());
|
||||
this.currentLoadedParamsHash = this.paramsHash;
|
||||
console.debug('Products loaded from server.');
|
||||
console.debug('New params hash: ', this.currentLoadedParamsHash);
|
||||
|
||||
return {
|
||||
meta: response.meta,
|
||||
data: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Failed to load products");
|
||||
console.error(error);
|
||||
} finally {
|
||||
}
|
||||
},
|
||||
|
||||
async loadProducts(filters = null) {
|
||||
if (this.isLoading) return;
|
||||
|
||||
try {
|
||||
console.debug('Load products with filters', filters);
|
||||
this.reset();
|
||||
this.isLoading = true;
|
||||
this.page = 1;
|
||||
this.loadFinished = false;
|
||||
this.search = '';
|
||||
this.filters = filters;
|
||||
this.products = await this.fetchProducts();
|
||||
} catch (e) {
|
||||
console.error('Ошибка загрузки', e);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
this.loadFinished = true;
|
||||
}
|
||||
},
|
||||
|
||||
async loadMore() {
|
||||
if (this.isLoading || this.isLoadingMore || this.products.meta.hasMore === false) return;
|
||||
|
||||
try {
|
||||
this.isLoadingMore = true;
|
||||
this.page++;
|
||||
console.debug('Load more products for page: ', this.page);
|
||||
const response = await this.fetchProducts();
|
||||
this.products.meta = response.meta;
|
||||
this.products.data.push(...response.data);
|
||||
} catch (e) {
|
||||
console.error('Ошибка загрузки', e);
|
||||
} finally {
|
||||
this.isLoadingMore = false;
|
||||
this.loadFinished = true;
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.isLoading = false;
|
||||
this.page = 1;
|
||||
this.loadFinished = false;
|
||||
this.search = '';
|
||||
this.products = {
|
||||
data: [],
|
||||
meta: {
|
||||
hasMore: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
56
frontend/spa/src/stores/SearchStore.js
Normal file
56
frontend/spa/src/stores/SearchStore.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import {defineStore} from "pinia";
|
||||
import ftch from "@/utils/ftch.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
|
||||
export const useSearchStore = defineStore('search', {
|
||||
state: () => ({
|
||||
search: '',
|
||||
page: 1,
|
||||
products: {
|
||||
data: [],
|
||||
meta: {},
|
||||
},
|
||||
|
||||
isLoading: false,
|
||||
isSearchPerformed: false,
|
||||
}),
|
||||
|
||||
actions: {
|
||||
reset() {
|
||||
this.search = '';
|
||||
this.isSearchPerformed = false;
|
||||
this.isLoading = false;
|
||||
this.page = 1;
|
||||
this.products = {
|
||||
data: [],
|
||||
meta: {},
|
||||
};
|
||||
},
|
||||
|
||||
async performSearch() {
|
||||
if (!this.search) {
|
||||
return this.reset();
|
||||
}
|
||||
|
||||
useYaMetrikaStore().reachGoal(YA_METRIKA_GOAL.PERFORM_SEARCH, {
|
||||
keyword: this.search,
|
||||
});
|
||||
|
||||
try {
|
||||
this.isLoading = true;
|
||||
this.products = await ftch('products', {
|
||||
page: this.page,
|
||||
perPage: 10,
|
||||
search: this.search,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
this.isSearchPerformed = true;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
});
|
||||
56
frontend/spa/src/stores/SettingsStore.js
Normal file
56
frontend/spa/src/stores/SettingsStore.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {fetchSettings} from "@/utils/ftch.js";
|
||||
|
||||
export const useSettingsStore = defineStore('settings', {
|
||||
state: () => ({
|
||||
app_enabled: true,
|
||||
app_debug: false,
|
||||
store_enabled: true,
|
||||
app_name: 'OpenCart Telegram магазин',
|
||||
app_icon: '',
|
||||
app_icon192: '',
|
||||
app_icon180: '',
|
||||
app_icon152: '',
|
||||
app_icon120: '',
|
||||
manifest_url: null,
|
||||
night_auto: true,
|
||||
ya_metrika_enabled: false,
|
||||
feature_coupons: false,
|
||||
feature_vouchers: false,
|
||||
currency_code: null,
|
||||
theme: {
|
||||
light: 'light', dark: 'dark', variables: {
|
||||
'--product_list_title_max_lines': 2,
|
||||
}
|
||||
},
|
||||
texts: {
|
||||
no_more_products: 'Нет товаров',
|
||||
empty_cart: 'Корзина пуста',
|
||||
order_created_success: 'Заказ успешно оформлен.',
|
||||
},
|
||||
}),
|
||||
|
||||
actions: {
|
||||
async load() {
|
||||
console.log('Load settings');
|
||||
const settings = await fetchSettings();
|
||||
this.manifest_url = settings.manifest_url;
|
||||
this.app_name = settings.app_name;
|
||||
this.app_icon = settings.app_icon;
|
||||
this.app_icon192 = settings.app_icon192;
|
||||
this.app_icon180 = settings.app_icon180;
|
||||
this.app_icon152 = settings.app_icon152;
|
||||
this.app_icon120 = settings.app_icon120;
|
||||
this.theme.light = settings.theme_light;
|
||||
this.theme.dark = settings.theme_dark;
|
||||
this.ya_metrika_enabled = settings.ya_metrika_enabled;
|
||||
this.app_enabled = settings.app_enabled;
|
||||
this.app_debug = settings.app_debug;
|
||||
this.store_enabled = settings.store_enabled;
|
||||
this.feature_coupons = settings.feature_coupons;
|
||||
this.feature_vouchers = settings.feature_vouchers;
|
||||
this.currency_code = settings.currency_code;
|
||||
this.texts = settings.texts;
|
||||
}
|
||||
}
|
||||
});
|
||||
130
frontend/spa/src/stores/yaMetrikaStore.js
Normal file
130
frontend/spa/src/stores/yaMetrikaStore.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
import sha256 from 'crypto-js/sha256';
|
||||
import {toRaw} from "vue";
|
||||
|
||||
export const useYaMetrikaStore = defineStore('ya_metrika', {
|
||||
state: () => ({
|
||||
queue: [],
|
||||
prevPath: null,
|
||||
}),
|
||||
|
||||
actions: {
|
||||
pushHit(url, params = {}) {
|
||||
if (!useSettingsStore().ya_metrika_enabled) {
|
||||
console.debug('[ym] Yandex Metrika disabled in settings.');
|
||||
return;
|
||||
}
|
||||
|
||||
const fullUrl = `/#${url}`;
|
||||
|
||||
params.referer = params.referer ?? this.prevPath;
|
||||
|
||||
if (typeof window.ym === 'function' && window.YA_METRIKA_ID !== undefined) {
|
||||
console.debug('[ym] Hit ', fullUrl);
|
||||
console.debug('[ym] ID ', window.YA_METRIKA_ID);
|
||||
console.debug('[ym] params ', params);
|
||||
window.ym(window.YA_METRIKA_ID, 'hit', fullUrl, params);
|
||||
} else {
|
||||
console.debug('[ym] Yandex Metrika is not initialized. Pushed to queue.');
|
||||
this.queue.push({
|
||||
event: 'hit',
|
||||
payload: {
|
||||
fullUrl,
|
||||
params,
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
reachGoal(target, params = {}) {
|
||||
if (!useSettingsStore().ya_metrika_enabled) {
|
||||
console.debug('[ym] Yandex Metrika disabled in settings.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window.ym === 'function' && window.YA_METRIKA_ID !== undefined) {
|
||||
console.debug('[ym] reachGoal ', target, ' params: ', params);
|
||||
window.ym(window.YA_METRIKA_ID, 'reachGoal', target, params);
|
||||
} else {
|
||||
console.debug('[ym] Yandex Metrika is not initialized. Pushed to queue.');
|
||||
this.queue.push({
|
||||
event: 'reachGoal',
|
||||
payload: {
|
||||
target,
|
||||
params
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
initUserParams() {
|
||||
if (!useSettingsStore().ya_metrika_enabled) {
|
||||
console.debug('[ym] Yandex Metrika disabled in settings.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof window.ym === 'function' && window.YA_METRIKA_ID !== undefined) {
|
||||
let tgID = null;
|
||||
|
||||
if (window?.Telegram?.WebApp?.initDataUnsafe?.user?.id) {
|
||||
tgID = sha256(window.Telegram.WebApp.initDataUnsafe.user.id).toString();
|
||||
}
|
||||
|
||||
const userParams = {
|
||||
tg_id: tgID,
|
||||
language: window.Telegram?.WebApp?.initDataUnsafe?.user?.language_code || 'unknown',
|
||||
platform: window.Telegram?.WebApp?.platform || 'unknown',
|
||||
};
|
||||
|
||||
window.ym(window.YA_METRIKA_ID, 'userParams', userParams);
|
||||
console.debug('[ym] User params initialized: ', userParams);
|
||||
} else {
|
||||
console.debug('[ym] Yandex Metrika is not initialized. Could not init user params.');
|
||||
}
|
||||
},
|
||||
|
||||
processQueue() {
|
||||
if (this.queue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('[ym] Start processing queue. Size: ', this.queue.length);
|
||||
|
||||
while (this.queue.length > 0) {
|
||||
const item = this.queue.shift();
|
||||
if (item.event === 'hit') {
|
||||
console.debug('[ym] Queue ', toRaw(item));
|
||||
window.ym(window.YA_METRIKA_ID, 'hit', item.payload.fullUrl, item.payload.params);
|
||||
} else if (item.event === 'reachGoal') {
|
||||
window.ym(window.YA_METRIKA_ID, 'reachGoal', item.payload.target, item.payload.params);
|
||||
} else if (item.event === 'dataLayer') {
|
||||
console.debug('[ym] queue dataLayer push: ', item.payload);
|
||||
window.dataLayer.push(item.payload);
|
||||
} else {
|
||||
console.error('[ym] Unsupported queue event: ', item.event);
|
||||
}
|
||||
}
|
||||
|
||||
console.debug('[ym] Queue processing complete. Size: ', this.queue.length);
|
||||
},
|
||||
|
||||
dataLayerPush(object) {
|
||||
if (!useSettingsStore().ya_metrika_enabled) {
|
||||
console.debug('[ym] Yandex Metrika disabled in settings.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(window.dataLayer)) {
|
||||
console.debug('[ym] dataLayer push: ', object);
|
||||
window.dataLayer.push(object);
|
||||
} else {
|
||||
console.debug('[ym] dataLayer inaccessible. Put to queue');
|
||||
this.queue.push({
|
||||
event: 'dataLayer',
|
||||
payload: object,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user