feat: WIP add yandex metrika goals
This commit is contained in:
@@ -547,17 +547,18 @@ HTML,
|
||||
],
|
||||
|
||||
'orders' => [
|
||||
'module_tgshop_order_customer_group_id' => [
|
||||
'type' => 'select',
|
||||
'options' => $this->getCustomerGroups(),
|
||||
'help' => 'Группа покупателей, которая будет назначена для заказов, оформленных через Telegram-магазин.',
|
||||
],
|
||||
|
||||
'module_tgshop_order_default_status_id' => [
|
||||
'type' => 'select',
|
||||
'options' => $this->getOrderStatuses(),
|
||||
'help' => 'Статус, с которым будут создаваться заказы через Telegram по умолчанию.',
|
||||
],
|
||||
|
||||
'module_tgshop_order_customer_group_id' => [
|
||||
'hidden' => true,
|
||||
'type' => 'select',
|
||||
'options' => $this->getCustomerGroups(),
|
||||
'help' => 'Группа покупателей, которая будет назначена для заказов, оформленных через Telegram-магазин.',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ class ControllerExtensionTgshopHandle extends Controller
|
||||
'app_debug' => $appDebug,
|
||||
'oc_config_tax' => $this->config->get('config_tax'),
|
||||
'oc_default_currency' => $this->config->get('config_currency'),
|
||||
// ID группы покупателей, которая будет использоаваться в заказах через Телеграм.
|
||||
'oc_customer_group_id' => $this->config->get('module_tgshop_order_customer_group_id'),
|
||||
'oc_customer_group_id' => $this->config->get('config_customer_group_id'),
|
||||
// ID магазина, для которого будут создаваться заказы из Телеграм
|
||||
'oc_store_id' => 0,
|
||||
// Название магазина, для которого будут создаваться заказы из Телеграм
|
||||
|
||||
@@ -177,6 +177,7 @@ class OrderCreateService
|
||||
$this->cartService->flush();
|
||||
|
||||
$orderData['order_id'] = $orderId;
|
||||
$orderData['total_numeric'] = $orderData['total'] ?? 0;
|
||||
$orderData['total'] = $cart['total_text'] ?? '';
|
||||
|
||||
$this->sendNotifications($orderData, $data['tgData']);
|
||||
@@ -192,6 +193,8 @@ class OrderCreateService
|
||||
'id' => $orderData['order_id'],
|
||||
'created_at' => $dateTimeFormatted,
|
||||
'total' => $orderData['total'],
|
||||
'final_total_numeric' => $orderData['total_numeric'],
|
||||
'currency' => $currencyCode,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -214,6 +214,7 @@ class ProductsService
|
||||
$configTax = $this->oc->config->get('config_tax');
|
||||
|
||||
$product_info = $this->oc->model_catalog_product->getProduct($productId);
|
||||
$currency = $this->oc->session->data['currency'];
|
||||
|
||||
if (! $product_info) {
|
||||
throw new EntityNotFoundException('Product with id ' . $productId . ' not found');
|
||||
@@ -280,24 +281,24 @@ class ProductsService
|
||||
|
||||
$data['images'] = $images;
|
||||
|
||||
$data['price'] = $this->currency->format(
|
||||
$this->tax->calculate(
|
||||
$product_info['price'],
|
||||
$product_info['tax_class_id'],
|
||||
$configTax,
|
||||
),
|
||||
$this->oc->session->data['currency']
|
||||
$productPrice = $this->tax->calculate(
|
||||
$product_info['price'],
|
||||
$product_info['tax_class_id'],
|
||||
$configTax,
|
||||
);
|
||||
$data['price'] = $this->currency->format($productPrice, $currency);
|
||||
$data['currency'] = $currency;
|
||||
$data['final_price_numeric'] = $productPrice;
|
||||
|
||||
if (! is_null($product_info['special']) && (float) $product_info['special'] >= 0) {
|
||||
$data['special'] = $this->currency->format(
|
||||
$this->tax->calculate(
|
||||
$product_info['special'],
|
||||
$product_info['tax_class_id'],
|
||||
$configTax,
|
||||
),
|
||||
$this->oc->session->data['currency']
|
||||
$productSpecialPrice = $this->tax->calculate(
|
||||
$product_info['special'],
|
||||
$product_info['tax_class_id'],
|
||||
$configTax,
|
||||
);
|
||||
|
||||
$data['special'] = $this->currency->format($productSpecialPrice, $currency);
|
||||
$data['final_price_numeric'] = $productSpecialPrice;
|
||||
$tax_price = (float) $product_info['special'];
|
||||
} else {
|
||||
$data['special'] = false;
|
||||
@@ -305,7 +306,7 @@ class ProductsService
|
||||
}
|
||||
|
||||
if ($configTax) {
|
||||
$data['tax'] = $this->currency->format($tax_price, $this->oc->session->data['currency']);
|
||||
$data['tax'] = $this->currency->format($tax_price, $currency);
|
||||
} else {
|
||||
$data['tax'] = false;
|
||||
}
|
||||
@@ -323,7 +324,7 @@ class ProductsService
|
||||
$product_info['tax_class_id'],
|
||||
$configTax,
|
||||
),
|
||||
$this->oc->session->data['currency']
|
||||
$currency
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -341,7 +342,7 @@ class ProductsService
|
||||
$product_info['tax_class_id'],
|
||||
$configTax ? 'P' : false
|
||||
),
|
||||
$this->oc->session->data['currency']
|
||||
$currency
|
||||
);
|
||||
|
||||
$product_option_value_data[] = array(
|
||||
|
||||
14
spa/src/constants/yaMetrikaGoals.js
Normal file
14
spa/src/constants/yaMetrikaGoals.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export const YA_METRIKA_GOAL = {
|
||||
ADD_TO_CART: 'add_to_cart',
|
||||
CREATE_ORDER: 'create_order',
|
||||
ORDER_CREATED_SUCCESS: 'order_created_success',
|
||||
VIEW_PRODUCT: 'view_product',
|
||||
VIEW_CART: 'view_cart',
|
||||
VIEW_CHECKOUT: 'view_checkout',
|
||||
VIEW_HOME: 'view_home',
|
||||
VIEW_FILTERS: 'view_filters',
|
||||
FILTERS_APPLY: 'filters_apply',
|
||||
FILTERS_RESET: 'filters_reset',
|
||||
VIEW_SEARCH: 'view_search',
|
||||
PERFORM_SEARCH: 'perform_search',
|
||||
};
|
||||
@@ -35,3 +35,9 @@ export const router = createRouter({
|
||||
history: createWebHashHistory('/image/catalog/tgshopspa/'),
|
||||
routes,
|
||||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
const ym = useYaMetrikaStore();
|
||||
ym.prevPath = from.path;
|
||||
next();
|
||||
});
|
||||
|
||||
@@ -38,5 +38,24 @@ export const useCategoriesStore = defineStore('categories', {
|
||||
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;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
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: () => ({
|
||||
@@ -31,6 +33,10 @@ export const useSearchStore = defineStore('search', {
|
||||
return this.reset();
|
||||
}
|
||||
|
||||
useYaMetrikaStore().reachGoal(YA_METRIKA_GOAL.PERFORM_SEARCH, {
|
||||
keyword: this.search,
|
||||
});
|
||||
|
||||
try {
|
||||
this.isLoading = true;
|
||||
this.products = await ftch('products', {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
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: {
|
||||
@@ -16,6 +19,8 @@ export const useYaMetrikaStore = defineStore('ya_metrika', {
|
||||
|
||||
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);
|
||||
@@ -33,6 +38,49 @@ export const useYaMetrikaStore = defineStore('ya_metrika', {
|
||||
}
|
||||
},
|
||||
|
||||
reachGoal(target, params = {}) {
|
||||
const settings = useSettingsStore();
|
||||
if (!settings.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 (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;
|
||||
@@ -43,8 +91,10 @@ export const useYaMetrikaStore = defineStore('ya_metrika', {
|
||||
while (this.queue.length > 0) {
|
||||
const item = this.queue.shift();
|
||||
if (item.event === 'hit') {
|
||||
console.debug('[ym] Queue ', item);
|
||||
console.debug('[ym] Queue ', toRaw(item));
|
||||
window.ym(window.YA_METRIKA_ID, item.event, item.payload.url, item.payload.params);
|
||||
} else if (item.event === 'reachGoal') {
|
||||
window.ym(window.YA_METRIKA_ID, item.event, item.payload.target, item.payload.params);
|
||||
} else {
|
||||
console.error('[ym] Unsupported queue event: ', item.event);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export function injectYaMetrika() {
|
||||
window.YA_METRIKA_ID = getMetrikaId();
|
||||
console.debug('[Init] Detected Yandex.Metrika ID:', window.YA_METRIKA_ID);
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
yaMetrika.initUserParams();
|
||||
yaMetrika.processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,9 +139,13 @@ import OptionRadio from "@/components/ProductOptions/Cart/OptionRadio.vue";
|
||||
import OptionCheckbox from "@/components/ProductOptions/Cart/OptionCheckbox.vue";
|
||||
import OptionText from "@/components/ProductOptions/Cart/OptionText.vue";
|
||||
import {computed, onMounted} from "vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
|
||||
const route = useRoute();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const cart = useCartStore();
|
||||
const router = useRouter();
|
||||
const settings = useSettingsStore();
|
||||
@@ -169,11 +173,15 @@ function goToCheckout() {
|
||||
|
||||
onMounted(async () => {
|
||||
window.document.title = 'Корзина покупок';
|
||||
yaMetrika.pushHit(route.path, {
|
||||
title: 'Корзина покупок',
|
||||
});
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_CART);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.btn-checkout {
|
||||
bottom: calc(var(--spacing, 0px) * 22px + var(--tg-safe-area-inset-bottom, 0px))
|
||||
bottom: calc(var(--spacing, 0px) * 22 + var(--tg-safe-area-inset-bottom, 0px))
|
||||
}
|
||||
</style>
|
||||
@@ -58,9 +58,11 @@ import {router} from "@/router.js";
|
||||
import {useCategoriesStore} from "@/stores/CategoriesStore.js";
|
||||
import {useRoute} from "vue-router";
|
||||
import CategoryItem from "@/components/CategoriesList/CategoryItem.vue";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
|
||||
const route = useRoute();
|
||||
const categoriesStore = useCategoriesStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
|
||||
const parentId = computed(() => route.params.id ? Number(route.params.id) : null);
|
||||
|
||||
@@ -106,6 +108,9 @@ function showProductsInParentCategory() {
|
||||
|
||||
onMounted(async () => {
|
||||
window.document.title = 'Каталог';
|
||||
yaMetrika.pushHit(route.path, {
|
||||
title: 'Каталог',
|
||||
});
|
||||
await categoriesStore.fetchCategories();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -69,11 +69,15 @@
|
||||
import {useCheckoutStore} from "@/stores/CheckoutStore.js";
|
||||
import TgInput from "@/components/Form/TgInput.vue";
|
||||
import TgTextarea from "@/components/Form/TgTextarea.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {computed, onMounted, ref} from "vue";
|
||||
import {IMaskComponent} from "vue-imask";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
|
||||
const checkout = useCheckoutStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const error = ref(null);
|
||||
|
||||
@@ -84,7 +88,15 @@ const btnText = computed(() => {
|
||||
async function onCreateBtnClick() {
|
||||
try {
|
||||
error.value = null;
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.CREATE_ORDER, {
|
||||
price: checkout.order?.final_total_numeric,
|
||||
currency: checkout.order?.currency,
|
||||
});
|
||||
await checkout.makeOrder();
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.ORDER_CREATED_SUCCESS, {
|
||||
price: checkout.order?.final_total_numeric,
|
||||
currency: checkout.order?.currency,
|
||||
});
|
||||
router.push({name: 'order_created'});
|
||||
} catch {
|
||||
error.value = 'Невозможно создать заказ.';
|
||||
@@ -93,5 +105,9 @@ async function onCreateBtnClick() {
|
||||
|
||||
onMounted(async () => {
|
||||
window.document.title = 'Оформление заказа';
|
||||
yaMetrika.pushHit(route.path, {
|
||||
title: 'Оформление заказа',
|
||||
});
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_CHECKOUT);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -49,8 +49,10 @@ import {nextTick, onMounted} from "vue";
|
||||
import {useProductFiltersStore} from "@/stores/ProductFiltersStore.js";
|
||||
import ProductPrice from "@/components/ProductFilters/Components/ProductPrice.vue";
|
||||
import ForMainPage from "@/components/ProductFilters/Components/ForMainPage.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import ProductCategory from "@/components/ProductFilters/Components/ProductCategory/ProductCategory.vue";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'Filters'
|
||||
@@ -63,6 +65,8 @@ const componentMap = {
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const route = useRoute();
|
||||
const emit = defineEmits(['close', 'apply']);
|
||||
|
||||
const filtersStore = useProductFiltersStore();
|
||||
@@ -72,6 +76,7 @@ const applyFilters = async () => {
|
||||
filtersStore.applied = JSON.parse(JSON.stringify(filtersStore.draft));
|
||||
console.debug('Filters: apply filters. Hash for router: ', filtersStore.paramsHashForRouter);
|
||||
haptic.impactOccurred('soft');
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.FILTERS_APPLY);
|
||||
await nextTick();
|
||||
router.back();
|
||||
}
|
||||
@@ -80,6 +85,7 @@ const resetFilters = async () => {
|
||||
filtersStore.applied = filtersStore.default;
|
||||
console.debug('Filters: reset filters. Hash for router: ', filtersStore.paramsHashForRouter);
|
||||
haptic.notificationOccurred('success');
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.FILTERS_RESET);
|
||||
await nextTick();
|
||||
window.scrollTo(0, 0);
|
||||
router.back();
|
||||
@@ -89,6 +95,9 @@ onMounted(async () => {
|
||||
console.debug('Filters: OnMounted');
|
||||
window.document.title = 'Фильтры';
|
||||
|
||||
yaMetrika.pushHit(route.path, {title: 'Фильтры'});
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_FILTERS);
|
||||
|
||||
if (filtersStore.applied?.rules) {
|
||||
console.debug('Filters: Found applied filters.');
|
||||
filtersStore.draft = JSON.parse(JSON.stringify(filtersStore.applied));
|
||||
|
||||
@@ -38,6 +38,7 @@ import ftch from "@/utils/ftch.js";
|
||||
import {useProductFiltersStore} from "@/stores/ProductFiltersStore.js";
|
||||
import Banner from "@/components/Banner.vue";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'Home'
|
||||
@@ -99,7 +100,10 @@ async function onLoadMore() {
|
||||
}
|
||||
|
||||
onActivated(() => {
|
||||
yaMetrika.pushHit('/');
|
||||
yaMetrika.pushHit('/', {
|
||||
title: 'Главная страница',
|
||||
});
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_HOME);
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
@@ -39,10 +39,17 @@
|
||||
<script setup>
|
||||
import {useCheckoutStore} from "@/stores/CheckoutStore.js";
|
||||
import {onMounted} from "vue";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {useRoute} from "vue-router";
|
||||
|
||||
const checkout = useCheckoutStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const route = useRoute();
|
||||
|
||||
onMounted(async () => {
|
||||
onMounted(() => {
|
||||
window.document.title = 'Заказ оформлен';
|
||||
yaMetrika.pushHit(route.path, {
|
||||
title: 'Заказ оформлен',
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
class="btn btn-primary btn-lg w-full"
|
||||
:class="isInCart ? 'btn-success' : 'btn-primary'"
|
||||
:disabled="cart.isLoading || canAddToCart === false"
|
||||
@click="actionBtnClick"
|
||||
@click="onCartBtnClick"
|
||||
>
|
||||
<span v-if="cart.isLoading" class="loading loading-spinner loading-sm"></span>
|
||||
{{ btnText }}
|
||||
@@ -156,7 +156,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {computed, nextTick, onMounted, onUnmounted, ref} from "vue";
|
||||
import {computed, onMounted, onUnmounted, ref} from "vue";
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
import ProductOptions from "../components/ProductOptions/ProductOptions.vue";
|
||||
import {useCartStore} from "../stores/CartStore.js";
|
||||
@@ -168,6 +168,7 @@ import LoadingFullScreen from "@/components/LoadingFullScreen.vue";
|
||||
import ProductNotFound from "@/components/ProductNotFound.vue";
|
||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
|
||||
const route = useRoute();
|
||||
const productId = computed(() => route.params.id);
|
||||
@@ -211,7 +212,7 @@ function closeFullScreen() {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
async function actionBtnClick() {
|
||||
async function onCartBtnClick() {
|
||||
try {
|
||||
error.value = '';
|
||||
|
||||
@@ -219,6 +220,10 @@ async function actionBtnClick() {
|
||||
await cart.addProduct(productId.value, product.value.name, product.value.price, quantity.value, product.value.options);
|
||||
isInCart.value = true;
|
||||
window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.ADD_TO_CART, {
|
||||
price: product.value.final_price_numeric,
|
||||
currency: product.value.currency,
|
||||
});
|
||||
} else {
|
||||
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||
await router.push({'name': 'cart'});
|
||||
@@ -275,6 +280,11 @@ onMounted(async () => {
|
||||
'Цена': data.price,
|
||||
},
|
||||
});
|
||||
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_PRODUCT, {
|
||||
price: data.final_price_numeric,
|
||||
currency: data.currency,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
:hasMore="productsStore.products.meta.hasMore"
|
||||
:isLoading="productsStore.isLoading"
|
||||
:isLoadingMore="productsStore.isLoadingMore"
|
||||
:categoryName="category?.name"
|
||||
@loadMore="productsStore.loadMore"
|
||||
/>
|
||||
</div>
|
||||
@@ -12,9 +13,11 @@
|
||||
|
||||
<script setup>
|
||||
import ProductsList from "@/components/ProductsList.vue";
|
||||
import {onMounted} from "vue";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useProductsStore} from "@/stores/ProductsStore.js";
|
||||
import {useCategoriesStore} from "@/stores/CategoriesStore.js";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
|
||||
defineOptions({
|
||||
name: 'Products'
|
||||
@@ -22,12 +25,22 @@ defineOptions({
|
||||
|
||||
const route = useRoute();
|
||||
const productsStore = useProductsStore();
|
||||
const categoriesStore = useCategoriesStore();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
|
||||
const categoryId = route.params.category_id ?? null;
|
||||
const category = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
console.debug("Category Products Mounted");
|
||||
console.debug("Load products for category: ", categoryId);
|
||||
console.debug("[Category] Category Products Mounted");
|
||||
console.debug("[Category] Load products for category: ", categoryId);
|
||||
category.value = await categoriesStore.findCategoryById(categoryId);
|
||||
console.debug("[Category] Category Name: ", category.value?.name);
|
||||
|
||||
window.document.title = `${category.value?.name ?? 'Неизвестная категория'}`;
|
||||
yaMetrika.pushHit(route.path, {
|
||||
title: `${category.value?.name ?? 'Неизвестная категория'}`,
|
||||
});
|
||||
|
||||
if (productsStore.filtersFullUrl === route.fullPath) {
|
||||
await productsStore.loadProducts(productsStore.filters ?? {
|
||||
|
||||
@@ -74,12 +74,21 @@
|
||||
import {useSearchStore} from "@/stores/SearchStore.js";
|
||||
import {useDebounceFn} from "@vueuse/core";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||
import {useRoute} from "vue-router";
|
||||
import {YA_METRIKA_GOAL} from "@/constants/yaMetrikaGoals.js";
|
||||
|
||||
const route = useRoute();
|
||||
const yaMetrika = useYaMetrikaStore();
|
||||
const searchStore = useSearchStore();
|
||||
const searchInput = ref(null);
|
||||
const debouncedSearch = useDebounceFn(() => searchStore.performSearch(), 500);
|
||||
|
||||
onMounted(async () => {
|
||||
window.document.title = 'Поиск';
|
||||
yaMetrika.pushHit(route.path, {
|
||||
title: 'Поиск',
|
||||
});
|
||||
yaMetrika.reachGoal(YA_METRIKA_GOAL.VIEW_SEARCH);
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user