я.метрика

This commit is contained in:
Zakhar 2026-09-03 13:50:12 +03:00
parent e3b9021c68
commit 74f9885677
14 changed files with 122 additions and 16 deletions

60
package-lock.json generated
View File

@ -10,6 +10,7 @@
"react": "^19.2.8", "react": "^19.2.8",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-redux": "^9.3.0", "react-redux": "^9.3.0",
"react-yandex-metrika": "^2.6.0",
"styled-components": "^6.5.3", "styled-components": "^6.5.3",
"zustand": "^5.0.15" "zustand": "^5.0.15"
}, },
@ -2205,6 +2206,13 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT",
"peer": true
},
"node_modules/levn": { "node_modules/levn": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@ -2487,6 +2495,19 @@
"url": "https://opencollective.com/parcel" "url": "https://opencollective.com/parcel"
} }
}, },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -2624,6 +2645,16 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.13.4", "version": "1.13.4",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
@ -2864,6 +2895,18 @@
"node": ">= 0.6.0" "node": ">= 0.6.0"
} }
}, },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/qs": { "node_modules/qs": {
"version": "6.15.2", "version": "6.15.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
@ -2900,6 +2943,13 @@
"react": "^19.2.8" "react": "^19.2.8"
} }
}, },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT",
"peer": true
},
"node_modules/react-redux": { "node_modules/react-redux": {
"version": "9.3.0", "version": "9.3.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz",
@ -2923,6 +2973,16 @@
} }
} }
}, },
"node_modules/react-yandex-metrika": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/react-yandex-metrika/-/react-yandex-metrika-2.6.0.tgz",
"integrity": "sha512-8K4wExsNZtY3DTxh1G8a+zWH9Pg8fw23MJcoJ4I/562qrHRnh7L5nteq3lnNL58dnNQbuuHIRoGgMjIo+r1GjA==",
"license": "MIT",
"peerDependencies": {
"prop-types": "*",
"react": "*"
}
},
"node_modules/redux": { "node_modules/redux": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",

View File

@ -9,6 +9,7 @@
"react": "^19.2.8", "react": "^19.2.8",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-redux": "^9.3.0", "react-redux": "^9.3.0",
"react-yandex-metrika": "^2.6.0",
"styled-components": "^6.5.3", "styled-components": "^6.5.3",
"zustand": "^5.0.15" "zustand": "^5.0.15"
}, },

View File

@ -15,6 +15,7 @@ import CustomSlider from "./components/Fullness/FullnessSlider";
import {useGlobalZustandState} from "./hooks/useGlobalZustandState"; import {useGlobalZustandState} from "./hooks/useGlobalZustandState";
import {setUsers, useAppDispatch, useAppSelector} from "./store"; import {setUsers, useAppDispatch, useAppSelector} from "./store";
import {FinitaLaCommedia} from "./components/Cart/FinitaLaCommedia"; import {FinitaLaCommedia} from "./components/Cart/FinitaLaCommedia";
import ym from "react-yandex-metrika";
export function App() { export function App() {
const [initialData, setInitialData] = useState<InitialData | null>(null); const [initialData, setInitialData] = useState<InitialData | null>(null);
@ -88,6 +89,13 @@ export function App() {
} }
}, [isCartComplete, isCartLoading, precision, setShowEmptyPopup]); }, [isCartComplete, isCartLoading, precision, setShowEmptyPopup]);
useEffect(() => {
ym('reachGoal', 'ac_open_settings_tab_' + openSection);
}, [openSection])
useEffect(() => {
ym('reachGoal', 'ac_fill_percent_' + percent);
}, [percent])
const pageContent = useMemo(() => { const pageContent = useMemo(() => {
if (!initialData) { if (!initialData) {
return <LoadingPage>Загрузка...</LoadingPage>; return <LoadingPage>Загрузка...</LoadingPage>;
@ -100,10 +108,10 @@ export function App() {
<h1>Хватило</h1> <h1>Хватило</h1>
<MobileFilter onClick={() => setMobileShowFilters(true)}> <MobileFilter onClick={() => setMobileShowFilters(true)}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 3V7M19 21V11M12 3V15M12 21V19M5 3V5M5 21V9" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M19 3V7M19 21V11M12 3V15M12 21V19M5 3V5M5 21V9" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
<path d="M17 9C17 10.1046 17.8954 11 19 11C20.1046 11 21 10.1046 21 9C21 7.89543 20.1046 7 19 7C17.8954 7 17 7.89543 17 9Z" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M17 9C17 10.1046 17.8954 11 19 11C20.1046 11 21 10.1046 21 9C21 7.89543 20.1046 7 19 7C17.8954 7 17 7.89543 17 9Z" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
<path d="M10 17C10 18.1046 10.8954 19 12 19C13.1046 19 14 18.1046 14 17C14 15.8954 13.1046 15 12 15C10.8954 15 10 15.8954 10 17Z" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M10 17C10 18.1046 10.8954 19 12 19C13.1046 19 14 18.1046 14 17C14 15.8954 13.1046 15 12 15C10.8954 15 10 15.8954 10 17Z" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
<path d="M3 7C3 8.10457 3.89543 9 5 9C6.10457 9 7 8.10457 7 7C7 5.89543 6.10457 5 5 5C3.89543 5 3 5.89543 3 7Z" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M3 7C3 8.10457 3.89543 9 5 9C6.10457 9 7 8.10457 7 7C7 5.89543 6.10457 5 5 5C3.89543 5 3 5.89543 3 7Z" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
</svg> </svg>
</MobileFilter> </MobileFilter>
<p>Заботимся о балансе нутриентов</p> <p>Заботимся о балансе нутриентов</p>
@ -140,7 +148,7 @@ export function App() {
<h2>Настройте корзину под себя</h2> <h2>Настройте корзину под себя</h2>
<MobileBack onClick={() => setMobileShowFilters(false)}> <MobileBack onClick={() => setMobileShowFilters(false)}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 12L5 12M10.9231 6L5 12L10.9231 18" stroke="#5EA12D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M20 12L5 12M10.9231 6L5 12L10.9231 18" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg> </svg>
</MobileBack> </MobileBack>
<p>Чем больше вы расскажете, тем точнее будет подбор</p> <p>Чем больше вы расскажете, тем точнее будет подбор</p>
@ -199,7 +207,7 @@ export function App() {
id="fullness" id="fullness"
title="Наполненность корзины" title="Наполненность корзины"
icon={<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> icon={<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17 13.23C17 13.23 16.09 12.77 15.182 12.77C13.818 12.77 12 14.615 12 17.385C12 20.154 14.49 22 17 22C19.51 22 22 20.154 22 17.385C22 14.616 20.182 12.769 18.818 12.769C17.909 12.769 17 13.231 17 13.231C17 11.847 17.91 10.001 19.727 10.001M10.655 5C11.551 5 12.278 4.328 12.278 3.5C12.278 2.672 11.55 2 10.655 2H5.245C4.349 2 3.623 2.672 3.623 3.5C3.623 4.328 4.349 5 5.246 5M11.169 4.923C12.125 6.689 12.909 8.283 13.389 10C13.4283 10.14 13.4653 10.281 13.5 10.423M10.428 22H6.328C2.747 22 2 21.31 2 18V13.777C2 10.377 3.098 7.886 4.705 4.915" stroke="#859D96" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M17 13.23C17 13.23 16.09 12.77 15.182 12.77C13.818 12.77 12 14.615 12 17.385C12 20.154 14.49 22 17 22C19.51 22 22 20.154 22 17.385C22 14.616 20.182 12.769 18.818 12.769C17.909 12.769 17 13.231 17 13.231C17 11.847 17.91 10.001 19.727 10.001M10.655 5C11.551 5 12.278 4.328 12.278 3.5C12.278 2.672 11.55 2 10.655 2H5.245C4.349 2 3.623 2.672 3.623 3.5C3.623 4.328 4.349 5 5.246 5M11.169 4.923C12.125 6.689 12.909 8.283 13.389 10C13.4283 10.14 13.4653 10.281 13.5 10.423M10.428 22H6.328C2.747 22 2 21.31 2 18V13.777C2 10.377 3.098 7.886 4.705 4.915" stroke="#859D96" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>} </svg>}
description={openSection === 'fullness' ? 'Чем меньше значение, тем меньше продуктов и калорий в корзине' : percent + '% — ваша цель. Результат может варьироваться'} description={openSection === 'fullness' ? 'Чем меньше значение, тем меньше продуктов и калорий в корзине' : percent + '% — ваша цель. Результат может варьироваться'}
isHighlighted={isFullnessHighlighted} isHighlighted={isFullnessHighlighted}

View File

@ -9,6 +9,7 @@ import { CartItem } from './CartItem';
import { CartFooter } from './CartFooter'; import { CartFooter } from './CartFooter';
import { ProductModal } from './ProductModal'; import { ProductModal } from './ProductModal';
import {useGlobalZustandState} from "../../hooks/useGlobalZustandState"; import {useGlobalZustandState} from "../../hooks/useGlobalZustandState";
import ym from "react-yandex-metrika";
interface CartProps { interface CartProps {
products: Product[]; products: Product[];
@ -56,6 +57,7 @@ export function Cart({
}); });
async function handleReplace(product: Product) { async function handleReplace(product: Product) {
ym('reachGoal', 'ac_product_replace_' + product.name);
setProcessingProductName(product.name); setProcessingProductName(product.name);
try { try {
@ -67,6 +69,7 @@ export function Cart({
} }
async function handleDelete(product: Product) { async function handleDelete(product: Product) {
ym('reachGoal', 'ac_product_delete_' + product.name);
setProcessingProductName(product.name); setProcessingProductName(product.name);
try { try {
@ -130,7 +133,7 @@ export function Cart({
<ShowMore type="button" onClick={() => setVisibleCount(products.length)}> <ShowMore type="button" onClick={() => setVisibleCount(products.length)}>
Показать ещё <span>{remaining}</span> товаров Показать ещё <span>{remaining}</span> товаров
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 9L12 16L5 9" stroke="#5EA12D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M19 9L12 16L5 9" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg> </svg>
</ShowMore> </ShowMore>
)} )}

View File

@ -3,6 +3,7 @@ import {BagIcon} from "../Icons/BagIcon";
import {useState} from "react"; import {useState} from "react";
import {OrderPopup} from "./OrderPopup"; import {OrderPopup} from "./OrderPopup";
import {useAppSelector} from "../../store"; import {useAppSelector} from "../../store";
import ym from "react-yandex-metrika";
interface CartFooterProps { interface CartFooterProps {
@ -29,7 +30,10 @@ export function CartFooter({ isVisible, totalPrice }: CartFooterProps) {
</div> </div>
</TotalWrap> </TotalWrap>
<CheckoutButton type="button" onClick={() => setShowCompletePopup(true)}> <CheckoutButton type="button" onClick={() => {
ym('reachGoal', 'ac_hvatilo')
setShowCompletePopup(true)
}}>
{users.length > 1 ? 'Нам' : 'Мне'} хватило {users.length > 1 ? 'Нам' : 'Мне'} хватило
</CheckoutButton> </CheckoutButton>
{showCompletePopup && <> {showCompletePopup && <>

View File

@ -1,7 +1,8 @@
import {useState} from 'react'; import {useEffect, useState} from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import {getProductAmount} from '../../utils/product'; import {getProductAmount} from '../../utils/product';
import type {Product} from '../../types/cart'; import type {Product} from '../../types/cart';
import ym from "react-yandex-metrika";
interface CartItemProps { interface CartItemProps {
product: Product; product: Product;
@ -19,6 +20,9 @@ export function CartItem({
onDelete, onDelete,
}: CartItemProps) { }: CartItemProps) {
const [isMenuOpen, setIsMenuOpen] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false);
useEffect(() => {
ym('reachGoal', 'ac_product_replacement_menu_' + product.name);
}, [product.name])
return ( return (
<Item $processing={isProcessing}> <Item $processing={isProcessing}>

View File

@ -1,6 +1,7 @@
import styled, {css} from "styled-components"; import styled, {css} from "styled-components";
import {useState} from "react"; import {useState} from "react";
import {FinishPopupContent} from "./FinishPopupContent"; import {FinishPopupContent} from "./FinishPopupContent";
import ym from "react-yandex-metrika";
export const OrderPopup = ({setShowCompletePopup}: any) => { export const OrderPopup = ({setShowCompletePopup}: any) => {
const [showFinal, setShowFinal] = useState(false); const [showFinal, setShowFinal] = useState(false);
@ -16,8 +17,14 @@ export const OrderPopup = ({setShowCompletePopup}: any) => {
<ServiceFee>199 </ServiceFee> <ServiceFee>199 </ServiceFee>
<ServiceFeeDescription>Включена в итоговую стоимость заказа</ServiceFeeDescription> <ServiceFeeDescription>Включена в итоговую стоимость заказа</ServiceFeeDescription>
<ButtonBlock> <ButtonBlock>
<ActiveButton onClick={() => setShowFinal(true)}>Продолжить</ActiveButton> <ActiveButton onClick={() => {
<Button onClick={() => setShowCompletePopup(false)}>Вернуться к корзине</Button> ym('reachGoal', 'ac_order_button')
setShowFinal(true)
}}>Продолжить</ActiveButton>
<Button onClick={() => {
ym('reachGoal', 'ac_no_order_button')
setShowCompletePopup(false)
}}>Вернуться к корзине</Button>
</ButtonBlock> </ButtonBlock>
</ModalContent>} </ModalContent>}
</Window> </Window>

View File

@ -2,6 +2,8 @@ import styled from 'styled-components';
import { formatCurrency } from '../../utils/formatCurrency'; import { formatCurrency } from '../../utils/formatCurrency';
import { getLargeProductImage } from '../../utils/product'; import { getLargeProductImage } from '../../utils/product';
import type { Product } from '../../types/cart'; import type { Product } from '../../types/cart';
import {useEffect} from "react";
import ym from "react-yandex-metrika";
interface ProductModalProps { interface ProductModalProps {
product: Product | null; product: Product | null;
@ -16,6 +18,12 @@ export function ProductModal({
onReplace, onReplace,
onDelete, onDelete,
}: ProductModalProps) { }: ProductModalProps) {
useEffect(() => {
if (product !== null) {
ym('reachGoal', 'ac_open_popup')
}
}, [product]);
if (!product) return null; if (!product) return null;
return ( return (

View File

@ -2,6 +2,7 @@ import { useMemo, useState } from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { setOption } from '../../api/promoApi'; import { setOption } from '../../api/promoApi';
import { useDebounceBatch } from '../../hooks/useDebounceBatch'; import { useDebounceBatch } from '../../hooks/useDebounceBatch';
import ym from "react-yandex-metrika";
interface CategoriesSectionProps { interface CategoriesSectionProps {
categories: string[]; categories: string[];
@ -31,6 +32,7 @@ export function CategoriesSection({
const sendUpdatedCategories = useDebounceBatch<string>(async categoryNames => { const sendUpdatedCategories = useDebounceBatch<string>(async categoryNames => {
let nextCategories = [...selectedCategories]; let nextCategories = [...selectedCategories];
ym('reachGoal', 'ac_set_categories');
categoryNames.forEach(categoryName => { categoryNames.forEach(categoryName => {
if (nextCategories.includes(categoryName)) { if (nextCategories.includes(categoryName)) {
nextCategories = nextCategories.filter(item => item !== categoryName); nextCategories = nextCategories.filter(item => item !== categoryName);

View File

@ -65,7 +65,7 @@ export function FamilySection({
}} }}
> >
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.167 14.1641L5.83366 5.83073M14.167 5.83073L5.83366 14.1641" stroke="#CEDFD0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M14.167 14.1641L5.83366 5.83073M14.167 5.83073L5.83366 14.1641" stroke="#CEDFD0" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg> </svg>
</DeleteButton> </DeleteButton>

View File

@ -2,6 +2,7 @@ import {useEffect, useState} from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import type {Gender, User} from '../../types/user'; import type {Gender, User} from '../../types/user';
import {Tag, TagsInput, TagsWrap} from './TagsInput'; import {Tag, TagsInput, TagsWrap} from './TagsInput';
import ym from "react-yandex-metrika";
interface PersonModalProps { interface PersonModalProps {
isOpen: boolean; isOpen: boolean;
@ -45,6 +46,7 @@ export function PersonModal({
if (!isOpen) return; if (!isOpen) return;
if (user) { if (user) {
ym('reachGoal', 'ac_family_edit');
setForm({ setForm({
name: user.name, name: user.name,
gender: user.gender, gender: user.gender,

View File

@ -1,9 +1,9 @@
export function BagIcon() { export function BagIcon() {
return <svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg"> return <svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="44" height="44" rx="22" fill="#E6F696"/> <rect width="44" height="44" rx="22" fill="#E6F696"/>
<path d="M18 18L18 17C18 14.7909 19.7909 13 22 13C24.2091 13 26 14.7909 26 17L26 18" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M18 18L18 17C18 14.7909 19.7909 13 22 13C24.2091 13 26 14.7909 26 17L26 18" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
<path d="M25 24V22" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M25 24V22" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
<path d="M19 24V22" stroke="#5EA12D" stroke-width="2" stroke-linecap="round"/> <path d="M19 24V22" stroke="#5EA12D" strokeWidth="2" strokeLinecap="round"/>
<path d="M14 22C14 20.1144 14 19.1716 14.5858 18.5858C15.1716 18 16.1144 18 18 18H26C27.8856 18 28.8284 18 29.4142 18.5858C30 19.1716 30 20.1144 30 22V23C30 26.7712 30 28.6569 28.8284 29.8284C27.6569 31 25.7712 31 22 31C18.2288 31 16.3431 31 15.1716 29.8284C14 28.6569 14 26.7712 14 23V22Z" stroke="#5EA12D" stroke-width="2"/> <path d="M14 22C14 20.1144 14 19.1716 14.5858 18.5858C15.1716 18 16.1144 18 18 18H26C27.8856 18 28.8284 18 29.4142 18.5858C30 19.1716 30 20.1144 30 22V23C30 26.7712 30 28.6569 28.8284 29.8284C27.6569 31 25.7712 31 22 31C18.2288 31 16.3431 31 15.1716 29.8284C14 28.6569 14 26.7712 14 23V22Z" stroke="#5EA12D" strokeWidth="2"/>
</svg>; </svg>;
} }

View File

@ -3,6 +3,7 @@ import { getCartUpdates } from '../api/promoApi';
import { normalizeProductImage } from '../utils/product'; import { normalizeProductImage } from '../utils/product';
import type { Product } from '../types/cart'; import type { Product } from '../types/cart';
import {useGlobalZustandState} from "./useGlobalZustandState"; import {useGlobalZustandState} from "./useGlobalZustandState";
import ym from "react-yandex-metrika";
interface UseCartPollingParams { interface UseCartPollingParams {
enabled: boolean; enabled: boolean;
@ -160,6 +161,7 @@ export function useCartPolling({
missing_scenario_element = -1; missing_scenario_element = -1;
if (update.status === 'complete') { if (update.status === 'complete') {
ym('reachGoal', 'ac_cart_complete');
onLoadingChange(false); onLoadingChange(false);
onComplete(); onComplete();
updateFromResponse(true, update.payload?.excess || 0, update.payload?.precision || 0); updateFromResponse(true, update.payload?.excess || 0, update.payload?.precision || 0);

View File

@ -6,6 +6,7 @@ import { GlobalStyle } from './styles/GlobalStyle';
import { theme } from './styles/theme'; import { theme } from './styles/theme';
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import {store} from "./store"; import {store} from "./store";
import { YMInitializer } from 'react-yandex-metrika';
const root = document.getElementById('root'); const root = document.getElementById('root');
@ -20,6 +21,10 @@ createRoot(root).render(
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<GlobalStyle /> <GlobalStyle />
<App /> <App />
<YMInitializer
accounts={[68914120]}
options={{ clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true }}
/>
</ThemeProvider> </ThemeProvider>
</Provider> </Provider>
</React.StrictMode>, </React.StrictMode>,