43 Commits

Author SHA1 Message Date
7d9f611fe5 Merge pull request 'демо исправление карточки' (#14) from 1318 into main
Reviewed-on: #14
2025-07-06 13:20:06 +03:00
8820f4e835 демо исправление карточки 2025-07-06 13:18:53 +03:00
ac7b2de49f Обновлена логика добавления товаров в корзину во всех компонентах. Теперь добавление происходит асинхронно с обработкой успешных и ошибочных результатов. Добавлена информация о наличии товара при добавлении в корзину. Улучшены уведомления о добавлении товара с учетом статуса операции. 2025-07-06 02:21:33 +03:00
a8c8ae60bb Добавлен компонент CartIcon и обновлены уведомления о добавлении товара в корзину во всех соответствующих компонентах. Изменены стили текста и иконки в уведомлениях для улучшения визуального восприятия. 2025-07-05 18:38:12 +03:00
78e17a94ab Исправлены размеры SVG в компонентах CartRecommendedProductCard, Footer и Header. Обновлены атрибуты width и height для корректного отображения и устранения опечаток. В компоненте VinQuick улучшена уникальность ключей при отображении деталей. 2025-07-05 18:00:31 +03:00
36c5990921 Улучшена обработка SSD в компонентах QuickDetailSection, UnitDetailsSection и KnotIn. Добавлены отладочные логи для отслеживания значений SSD и состояния загрузки данных. Обновлены условия пропуска запросов в зависимости от наличия SSD. Исправлена логика передачи SSD в компонент KnotIn с использованием значения узла или родительского SSD. 2025-07-05 13:35:49 +03:00
e989d402a3 Добавлены отладочные логи в компонент WizardSearchForm для отслеживания обновлений и сброса параметров. Обновлена логика автовыбора параметров с учетом состояния загрузки. В компонент VinLeftbar добавлена загрузка единиц для категории при открытии. Улучшена обработка SSD при сбросе параметров. 2025-07-05 12:55:08 +03:00
65710a35be Merge pull request 'newpravki' (#13) from newpravki into main
Reviewed-on: #13
2025-07-04 21:52:14 +03:00
9a604b39b3 переделаны счетчки фильтр рэндж, настроены выборы категорий и подкатегорий 2025-07-04 21:51:28 +03:00
d6d086299f Создание прототипа главной страницы home-new, изменение стилей на остальных страницах. Требуется дальнейшее тестирование. логика выбора авто сделана 2025-07-04 18:51:57 +03:00
5b8ff6c02e Добавлены отладочные логи для отслеживания значений SSD в компонентах QuickDetailSection и UnitDetailsSection. Обновлены GraphQL запросы для включения поля ssd. Отключено кэширование для получения актуальных данных SSD в UnitDetailsSection. 2025-07-03 15:35:37 +03:00
513163b174 Добавлены новые компоненты Header и MobileMenuBottomSection, улучшено отображение информации о производителях. Упрощены классы и улучшена читаемость кода. Обновлены заголовки и сообщения об ошибках для лучшего пользовательского опыта. 2025-07-03 14:24:02 +03:00
8aa5ab007d Удалены модальные окна выбора бренда из компонентов PartDetailCard, KnotParts, VinPartCard и VinQuick. Вместо этого добавлена логика для перехода на страницу выбора бренда при клике на деталь. Обновлены компоненты для передачи параметров catalogCode и vehicleId. Исправлены типы и улучшена читаемость кода. 2025-07-02 18:03:37 +03:00
a9e4b74179 Обновлены компоненты VehicleSearchResults и InfoVin для поддержки отображения дополнительных атрибутов автомобиля. В VehicleSearchResults добавлена логика для отображения атрибутов из API, а в InfoVin реализован вывод основных параметров и tooltip с полной информацией об автомобиле. Обновлены GraphQL запросы для получения атрибутов. Исправлены типы для LaximoVehicleSearchResult. 2025-07-02 17:52:55 +03:00
35d807f234 Исправлено определение типов для inputRefs в компоненте WizardSearchForm: добавлено поддержка null для HTMLInputElement. 2025-07-02 17:02:31 +03:00
f71672dfa8 Исправление GraphQL ошибок: удаление несуществующих полей из запросов Laximo
- Удалены несуществующие поля doors, frame, frames, framefrom, frameto, engine1, engine2, attributes
- Обновлены GraphQL запросы для соответствия схеме
- Обновлены TypeScript типы LaximoVehicleSearchResult
- Сохранены улучшения UI из удаленного репозитория
- Исправлены ApolloError при поиске автомобилей
2025-07-02 16:36:27 +03:00
cfddecd686 Merge pull request '0207' (#11) from jule into main
Reviewed-on: #11
2025-07-02 16:31:18 +03:00
985ba8aeb1 0207 2025-07-02 16:28:37 +03:00
58991e4226 Обновлены компоненты для улучшения обработки групп быстрого поиска и деталей узлов. Внесены изменения в логику отображения подкатегорий в VinCategory и VinLeftbar, добавлены комментарии для ясности. Исправлены условия пропуска запросов и обновлены типы для поддержки SSD узлов. 2025-07-01 22:24:59 +03:00
1613732775 Изменен порт фронтенда в файле docker-compose.yml с использования переменной окружения на фиксированное значение 3001. Обновлены комментарии для ясности конфигурации. 2025-06-30 19:01:11 +03:00
66d443c58a Добавлены переменные окружения для порта фронтенда и режима работы, обновлены комментарии в файле docker-compose.yml для улучшения читаемости конфигурации. 2025-06-30 18:31:49 +03:00
8e7c398b95 Обновлены компоненты для обработки необязательных свойств и добавлены заглушки для случаев отсутствия данных о транспортном средстве и деталях. Изменены условия пропуска запросов в компонентах InfoVin, KnotIn, KnotParts, VinCategory и VinLeftbar. 2025-06-30 17:42:36 +03:00
6af1ed325c Merge pull request 'ура епте' (#10) from end into main
Reviewed-on: #10
2025-06-30 17:29:00 +03:00
1f1ea8baaf ура епте 2025-06-30 17:28:15 +03:00
8a953d32ae Merge pull request '1452' (#9) from vinleftbaandsearch into main
Reviewed-on: #9
2025-06-30 14:57:52 +03:00
69ccc786ea 1452 2025-06-30 14:52:30 +03:00
8cae029d7f Обновлены запросы GraphQL для поиска: заменен SEARCH_LAXIMO_FULLTEXT на GET_LAXIMO_FULLTEXT_SEARCH в компонентах FulltextSearchSection и VinLeftbar. Удален устаревший запрос SEARCH_LAXIMO_FULLTEXT из файла graphql.ts. 2025-06-30 00:48:55 +03:00
cbf50691c4 Merge pull request 'all cart' (#8) from frontcart into main
Reviewed-on: #8
2025-06-30 00:40:36 +03:00
4a3da4d5c5 Обновлены условия пропуска запросов в компонентах, чтобы учитывать случаи, когда vehicleId может быть undefined или null. Исправлены проверки в следующих компонентах: CatalogGroupsSection, CategoriesSection, GroupDetailsSection, QuickGroupsSection, UnitDetailsSection, UnitsSection, KnotIn, VinCategory, VinLeftbar, VehicleDetailsPage и PartDetailPage. 2025-06-30 00:39:55 +03:00
215853e8c7 all cart 2025-06-30 00:38:29 +03:00
f894b7e023 Merge pull request 'all fixes' (#7) from front into main
Reviewed-on: #7
2025-06-29 21:46:12 +03:00
a879e5e5e7 all fixes 2025-06-29 21:45:30 +03:00
85f7634158 Merge pull request 'checkbox' (#6) from numbers into main
Reviewed-on: #6
2025-06-29 15:45:16 +03:00
d62db55160 checkbox 2025-06-29 15:44:36 +03:00
5e454a7367 Merge pull request 'pravkiend cart' (#5) from cartandfavorite into main
Reviewed-on: #5
2025-06-29 12:37:29 +03:00
e8f1fecb47 pravkiend cart 2025-06-29 12:36:49 +03:00
7f91da525f Удален файл интеграции с Parts Index API и обновлены компоненты для работы с корзиной и избранным. Добавлены функции для обработки добавления товаров в корзину с уведомлениями, улучшена логика работы с избранным, а также добавлены фильтры для истории поиска по производителю. 2025-06-29 03:36:21 +03:00
d268bb3359 Merge pull request 'pravkiend 29.06' (#4) from pravki29 into main
Reviewed-on: #4
2025-06-29 03:24:19 +03:00
d4ba549a81 pravkiend 29.06 2025-06-29 03:20:45 +03:00
936a08aa11 Merge pull request 'pravki 29.06' (#3) from pravki2906 into main
Reviewed-on: #3
2025-06-29 00:42:23 +03:00
f6cc95e714 pravki 29.06 2025-06-29 00:39:17 +03:00
1b0bbb2992 Merge pull request 'pravki 27.06' (#2) from pravki into main
Reviewed-on: #2
2025-06-27 18:24:38 +03:00
dcd47e9139 Merge pull request 'feat: перенос vin в компоненты, добавление логики и исправления' (#1) from vin-new into main
Reviewed-on: #1
2025-06-27 17:33:09 +03:00
118 changed files with 6605 additions and 2626 deletions

View File

@ -1,117 +0,0 @@
# Интеграция Parts Index API
## Описание
В проект добавлена интеграция с Parts Index API для отображения детальной информации о деталях, включая:
- Главную фотографию детали
- Штрих-коды
- Технические характеристики
- Категории
- Дополнительные изображения
- Логотип "powered by Parts Index"
## Реализованные компоненты
### 1. Типы (`src/types/partsindex.ts`)
- `PartsIndexEntityInfo` - информация о детали
- `PartsIndexEntityInfoResponse` - ответ API
- `PartsIndexEntityInfoVariables` - параметры запроса
### 2. Сервис (`src/lib/partsindex-service.ts`)
- `getEntityInfo(code, brand?, lang?)` - получение информации о детали
### 3. Хук (`src/hooks/usePartsIndex.ts`)
- `usePartsIndexEntityInfo(code, brand)` - хук для получения данных
### 4. Компонент (`src/components/PartsIndexCard.tsx`)
- Отображение карточки с информацией о детали
- Поддержка состояния загрузки
- Адаптивный дизайн
## Интеграция в страницу поиска
В файле `src/pages/search-result.tsx` добавлено:
```tsx
import PartsIndexCard from "@/components/PartsIndexCard";
import { usePartsIndexEntityInfo } from "@/hooks/usePartsIndex";
// В компоненте:
const { entityInfo, loading: partsIndexLoading } = usePartsIndexEntityInfo(
searchQuery || null,
brandQuery || null
);
// В JSX:
{partsIndexLoading && (
<PartsIndexCard
entityInfo={null as any}
loading={true}
/>
)}
{entityInfo && !partsIndexLoading && (
<PartsIndexCard
entityInfo={entityInfo}
loading={false}
/>
)}
```
## API Parts Index
### Endpoint
```
GET https://api.parts-index.com/v1/entities
```
### Параметры
- `code` (обязательный) - артикул детали
- `brand` (опциональный) - бренд
- `lang` (опциональный) - язык (по умолчанию 'ru')
### Заголовки
```
Authorization: PI-E1C0ADB7-E4A8-4960-94A0-4D9C0A074DAE
Accept: application/json
```
### Пример запроса
```bash
curl -H "Authorization: PI-E1C0ADB7-E4A8-4960-94A0-4D9C0A074DAE" \
"https://api.parts-index.com/v1/entities?code=059198405B&brand=VAG&lang=ru"
```
## Тестирование
### URL для тестирования
```
http://localhost:3002/search-result?article=059198405B&brand=VAG
```
### Тестовая HTML страница
Создана страница `test-parts-index.html` для демонстрации работы API без React.
## Функциональность
1. **Автоматическая загрузка** - при переходе на страницу результатов поиска
2. **Главная фотография** - отображается первое изображение из массива
3. **Логотип Parts Index** - в правом верхнем углу карточки
4. **Характеристики** - первые 6 параметров из API
5. **Штрих-коды** - все доступные штрих-коды
6. **Дополнительные изображения** - до 4 дополнительных фото
7. **Обработка ошибок** - скрытие изображений при ошибке загрузки
## Стили
Компонент использует Tailwind CSS классы для стилизации:
- Адаптивная сетка для характеристик
- Скроллинг для дополнительных изображений
- Состояние загрузки с анимацией
- Обработка ошибок изображений
## Производительность
- Загрузка данных только при наличии артикула
- Кэширование на уровне React Query (через Apollo Client)
- Ленивая загрузка изображений
- Обработка ошибок сети

View File

@ -10,15 +10,26 @@ services:
NEXT_PUBLIC_UPLOAD_URL: ${NEXT_PUBLIC_UPLOAD_URL:-http://localhost:4000/upload}
NEXT_PUBLIC_MAINTENANCE_MODE: ${NEXT_PUBLIC_MAINTENANCE_MODE:-false}
NEXT_PUBLIC_YANDEX_MAPS_API_KEY: ${NEXT_PUBLIC_YANDEX_MAPS_API_KEY}
FRONTEND_PORT: ${FRONTEND_PORT:-3000}
NODE_ENV: ${NODE_ENV:-production}
container_name: protekauto-frontend
ports:
- "3001:3000"
environment:
- NODE_ENV=production
# Порт приложения
- FRONTEND_PORT=${FRONTEND_PORT:-3000}
# Окружение
- NODE_ENV=${NODE_ENV:-production}
# API конфигурация
- NEXT_PUBLIC_CMS_GRAPHQL_URL=${NEXT_PUBLIC_CMS_GRAPHQL_URL:-http://localhost:4000/graphql}
- NEXT_PUBLIC_UPLOAD_URL=${NEXT_PUBLIC_UPLOAD_URL:-http://localhost:4000/upload}
- NEXT_PUBLIC_MAINTENANCE_MODE=${NEXT_PUBLIC_MAINTENANCE_MODE:-false}
# Yandex Maps API
- NEXT_PUBLIC_YANDEX_MAPS_API_KEY=${NEXT_PUBLIC_YANDEX_MAPS_API_KEY}
restart: unless-stopped
networks:
- protekauto-network

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6836c4d0a840357cccfad382" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6836c4d0a840357cccfad382" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>About</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6849d22099f3f43006edf7a6" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6849d22099f3f43006edf7a6" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>brand</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6834155694a300ddf57ddb5f" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6834155694a300ddf57ddb5f" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Search result</title>
@ -228,7 +228,7 @@
<h1 class="heading-bi">Аккумуляторная батарея SPEEDMATE AGM 60А</h1>
<div class="div-block-127">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
</div>
@ -439,7 +439,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -468,7 +468,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -497,7 +497,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -526,7 +526,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -555,7 +555,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -584,7 +584,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6835795623b8021d75a042a1" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6835795623b8021d75a042a1" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Cart Step 2</title>
@ -214,7 +214,7 @@
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Избранное</div>
@ -829,7 +829,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -858,7 +858,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -887,7 +887,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -916,7 +916,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -945,7 +945,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -974,7 +974,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68341f3cfbb7c099cf08ee05" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68341f3cfbb7c099cf08ee05" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Cart</title>
@ -214,7 +214,7 @@
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Избранное</div>
@ -1123,7 +1123,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1152,7 +1152,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1181,7 +1181,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1210,7 +1210,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1239,7 +1239,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1268,7 +1268,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68258c4d57e731a25c8493c1" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68258c4d57e731a25c8493c1" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Catalog</title>
@ -214,7 +214,7 @@
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Избранное</div>
@ -478,7 +478,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -507,7 +507,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -536,7 +536,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -565,7 +565,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -594,7 +594,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -623,7 +623,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -652,7 +652,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -681,7 +681,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -710,7 +710,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -739,7 +739,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -768,7 +768,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -797,7 +797,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -826,7 +826,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -855,7 +855,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -884,7 +884,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -913,7 +913,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -942,7 +942,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -971,7 +971,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1000,7 +1000,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -1029,7 +1029,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5b41" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5b41" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Protek</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68455d9b5af7aa0e7725a609" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68455d9b5af7aa0e7725a609" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>contacts</title>

View File

@ -4601,7 +4601,6 @@ body {
justify-content: flex-start;
align-self: auto;
align-items: flex-start;
margin-bottom: 80px;
display: flex;
}
@ -6533,6 +6532,14 @@ body {
margin-left: 30px;
}
.flex-block-108-copy {
grid-column-gap: 18px;
grid-row-gap: 18px;
justify-content: space-between;
align-items: flex-start;
overflow: scroll;
}
@media screen and (min-width: 1440px) {
.body {
--_fonts---font-family: Onest, sans-serif;
@ -6838,6 +6845,10 @@ body {
margin-top: 0;
}
.ci1:hover {
background-color: var(--light-blue);
}
.vinleftbar {
width: 320px;
}
@ -6855,18 +6866,32 @@ body {
max-width: none;
}
.flex-block-118 {
grid-column-gap: 0px;
grid-row-gap: 0px;
}
.heading-20 {
font-size: 48px;
}
.flex-block-119 {
width: 520px;
width: 480px;
}
.bestpriceitem.end {
display: flex;
}
.flex-block-121 {
grid-column-gap: 15px;
grid-row-gap: 15px;
}
.ci2:hover, .ci3:hover, .ci4:hover, .ci5:hover, .ci6:hover, .ci7:hover, .ci8:hover, .ci9:hover {
background-color: var(--light-blue);
}
.flex-block-124 {
width: 540px;
}
@ -7251,6 +7276,7 @@ body {
}
.slider {
align-self: stretch;
height: auto;
display: flex;
}
@ -7348,6 +7374,8 @@ body {
flex-flow: column;
justify-content: space-between;
align-items: flex-start;
padding-top: 40px;
padding-bottom: 40px;
}
.div-block-12, .div-block-12.small {
@ -8032,8 +8060,12 @@ body {
margin-top: 0;
}
.code-embed-15 {
width: 160px;
}
.topnav {
margin-left: 0;
margin-left: 190px;
}
.topmenub {
@ -8061,6 +8093,10 @@ body {
padding-bottom: 40px;
}
.div-block-128 {
background-position: 0%;
}
.catnav {
padding-left: 30px;
padding-right: 30px;
@ -8089,10 +8125,19 @@ body {
flex-flow: row;
}
.supportheading {
font-size: 30px;
}
.image-5-copy {
object-fit: contain;
}
.image-27 {
margin-bottom: -280px;
margin-left: 530px;
}
.container-copy, .container-copy.nav, .container-copy.info {
padding-left: 0;
padding-right: 0;
@ -8324,6 +8369,10 @@ body {
align-items: center;
}
.flex-block-26 {
min-width: 120px;
}
.container2 {
padding: 20px 30px;
}
@ -8976,6 +9025,18 @@ body {
padding-bottom: 90px;
}
.div-block-129 {
justify-content: flex-start;
align-self: stretch;
align-items: center;
}
.flex-block-108 {
flex-flow: column;
justify-content: space-between;
align-items: center;
}
.container-vin {
padding-top: 20px;
}
@ -8989,7 +9050,24 @@ body {
padding-bottom: 90px;
}
.inbt, .news-index-block-copy {
.inbt {
grid-column-gap: 20px;
grid-row-gap: 20px;
}
.flex-block-123 {
flex-flow: column;
}
.flex-block-124 {
flex: 1;
}
.image-27 {
margin-left: 330px;
}
.news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
}
@ -9349,7 +9427,7 @@ body {
}
.heading_news {
line-height: 28px;
line-height: 20px;
}
.text-block-20 {
@ -9881,6 +9959,10 @@ body {
padding-bottom: 5px;
}
.icon-setting {
border: 0 #000;
}
.section-3 {
padding-left: 15px;
padding-right: 15px;
@ -10246,11 +10328,16 @@ body {
}
.favcardcat {
border-style: none;
width: 30px;
height: 30px;
margin-top: 0;
}
.code-embed-15 {
display: none;
}
.topnav {
margin-left: 0;
top: 58px;
@ -10319,6 +10406,17 @@ body {
padding: 40px 0 90px;
}
.div-block-129 {
justify-content: flex-start;
align-items: flex-start;
width: 100%;
height: auto;
}
.flex-block-109 {
margin-bottom: 10px;
}
.saletag {
padding-top: 3px;
padding-bottom: 3px;
@ -10326,6 +10424,15 @@ body {
top: -15px;
}
.flex-block-110 {
grid-column-gap: 10px;
grid-row-gap: 10px;
flex-flow: column-reverse;
justify-content: flex-start;
align-items: flex-start;
margin-bottom: 20px;
}
.catnav {
padding-left: 15px;
padding-right: 15px;
@ -10452,16 +10559,17 @@ body {
}
.submit-button-copy {
align-self: stretch;
padding: 15px 30px;
align-self: auto;
padding: 15px 25px;
}
.supportheading {
font-size: var(--_fonts---font-size--heading-2);
width: 220px;
}
.image-5-copy {
width: 100%;
width: 60%;
height: 100%;
min-height: auto;
}
@ -10470,6 +10578,10 @@ body {
margin-bottom: 10px;
}
.image-27 {
display: none;
}
.container-copy {
max-width: 100%;
margin-left: 0;

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5aec" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5aec" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Protek</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5b04" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5b04" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Protek</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5af0" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b281fe71c1c06a5af0" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Protek</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="683564cb54d9f20bcc1ef4b9" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="683564cb54d9f20bcc1ef4b9" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Favorite</title>
@ -605,7 +605,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -634,7 +634,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -663,7 +663,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -692,7 +692,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -721,7 +721,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685be6dfd87db2e01cbdb7a2" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685be6dfd87db2e01cbdb7a2" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Home New</title>
@ -20,7 +20,7 @@
<section class="topmenuh">
<div class="w-layout-blockcontainer container nav w-container">
<div class="w-layout-hflex flex-block-93">
<div class="code-embed-15 w-embed"><svg width="190" height="72" viewbox="0 0 190 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<div class="code-embed-15 w-embed"><svg width="currentwidht" height="currentheight" viewbox="0 0 190 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M138.377 29.5883V23.1172H112.878V29.5883H138.377Z" fill="white"></path>
<path d="M107.423 18.1195C109.21 18.1195 110.658 16.6709 110.658 14.884C110.658 13.097 109.21 11.6484 107.423 11.6484L88.395 11.6484C86.6082 11.6484 85.1596 13.097 85.1596 14.884C85.1596 16.6709 86.6082 18.1195 88.395 18.1195H107.423Z" fill="white"></path>
<path d="M130.288 34.2491C128.773 35.3865 126.89 36.0628 124.852 36.0628C119.849 36.0628 115.791 32.0052 115.791 27.0013C115.791 21.9974 119.849 17.9399 124.852 17.9399C129.856 17.9399 133.913 21.9974 133.913 27.0013C133.913 27.9022 133.779 28.7696 133.536 29.5893H140.169C140.31 28.7481 140.384 27.8831 140.384 27.0013C140.384 18.4226 133.431 11.4688 124.852 11.4688C116.274 11.4688 109.32 18.4226 109.32 27.0013C109.32 35.5801 116.274 42.5339 124.852 42.5339C129.249 42.5339 133.218 40.7058 136.045 37.769L130.288 34.2491Z" fill="white"></path>
@ -284,7 +284,7 @@
</section>
<section class="catnav">
<div class="w-layout-blockcontainer batd w-container">
<div class="w-layout-hflex flex-block-108">
<div class="w-layout-hflex flex-block-108-copy">
<div class="ci1">
<div class="text-block-54-copy">Детали для ТО</div>
</div>
@ -456,7 +456,7 @@
<div class="w-layout-vflex bestpriceitem">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="imgitembp"><img width="Auto" height="Auto" alt="" src="images/162615.webp" loading="lazy" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -482,7 +482,7 @@
<div class="w-layout-vflex bestpriceitem">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="imgitembp"><img width="Auto" height="Auto" alt="" src="images/162615.webp" loading="lazy" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -508,7 +508,7 @@
<div class="w-layout-vflex bestpriceitem">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="imgitembp"><img width="Auto" height="Auto" alt="" src="images/162615.webp" loading="lazy" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -534,7 +534,7 @@
<div class="w-layout-vflex bestpriceitem">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="imgitembp"><img width="Auto" height="Auto" alt="" src="images/162615.webp" loading="lazy" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -560,7 +560,7 @@
<div class="w-layout-vflex bestpriceitem">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="imgitembp"><img width="Auto" height="Auto" alt="" src="images/162615.webp" loading="lazy" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -597,7 +597,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -626,7 +626,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -655,7 +655,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -684,7 +684,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -713,7 +713,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -742,7 +742,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -791,7 +791,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -820,7 +820,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -849,7 +849,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -878,7 +878,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -907,7 +907,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -936,7 +936,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -970,7 +970,7 @@
<div class="w-layout-blockcontainer container-copy w-container"><img src="images/support_img.png" loading="lazy" alt="" class="image-27">
<div class="div-block-11">
<div class="w-layout-vflex flex-block-30">
<h3 class="supportheading">МЫ ВСЕГДА РАДЫ ПОМОЧЬ</h3>
<h3 class="supportheading">МЫ ВСЕГДА РАДЫ ПОМОЧЬ</h3>
<div class="text-block-19">Если вам нужна помощь с подбором автозапчастей, то воспользуйтесь формой VIN-запроса. Введите идентификационный номер (VIN) вашего автомобиля — и мы найдём нужную деталь.</div>
</div>
<a href="#" class="submit-button-copy w-button">Отправить VIN-запрос</a>
@ -1173,6 +1173,51 @@
</div>
</div>
</footer>
<nav class="mobile-menu-buttom-section">
<div class="w-layout-blockcontainer mobile-menu-bottom w-container">
<div class="w-layout-hflex flex-block-87">
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="30" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27 10.8V24H24.6V13.2H5.4V24H3V10.8L15 6L27 10.8ZM23.4 14.4H6.6V16.8H23.4V14.4ZM23.4 18H6.6V20.4H23.4V18Z" fill="currentColor"></path>
<path d="M6.6 21.6H23.4V24H6.6V21.6Z" fill="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Гараж</div>
</a>
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Избранное</div>
</a>
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currentWidht" height="currentHeight" viewbox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z" fill="currentColor"></path>
</svg></div>
<div class="pcs-info">
<div class="text-block-39">12</div>
</div>
</div>
<div class="name-mobile-menu-item">Корзина</div>
</a>
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currentwidht" height="currentheight" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 3C8.376 3 3 8.376 3 15C3 21.624 8.376 27 15 27C21.624 27 27 21.624 27 15C27 8.376 21.624 3 15 3ZM15 7.8C17.316 7.8 19.2 9.684 19.2 12C19.2 14.316 17.316 16.2 15 16.2C12.684 16.2 10.8 14.316 10.8 12C10.8 9.684 12.684 7.8 15 7.8ZM15 24.6C12.564 24.6 9.684 23.616 7.632 21.144C9.73419 19.4955 12.3285 18.5995 15 18.5995C17.6715 18.5995 20.2658 19.4955 22.368 21.144C20.316 23.616 17.436 24.6 15 24.6Z" fill="currentColor"></path>
</svg></div>
<div class="info-satus">
<div class="text-block-39">!</div>
</div>
</div>
<div class="name-mobile-menu-item">Кабинет</div>
</a>
</div>
</div>
</nav>
<script src="https://d3e54v103j8qbb.cloudfront.net/js/jquery-3.5.1.min.dc5e7f18c8.js?site=6800f7e35fcfd4ca3b323269" type="text/javascript" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="js/webflow.js" type="text/javascript"></script>
</body>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f7e35fcfd4ca3b3232bc" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f7e35fcfd4ca3b3232bc" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Protek</title>
@ -491,7 +491,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -520,7 +520,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -549,7 +549,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -578,7 +578,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -607,7 +607,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -636,7 +636,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -690,7 +690,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -719,7 +719,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -748,7 +748,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -777,7 +777,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -806,7 +806,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -835,7 +835,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -273,7 +273,7 @@ spurious results.`)}}return!1};class z{constructor(e,t="GraphQL request",n={line
count
product {
id
f_name_: name
f_name_
}
sku {
id
@ -285,7 +285,7 @@ spurious results.`)}}return!1};class z{constructor(e,t="GraphQL request",n={line
}
}
}
`,w=(e,t)=>e.query({query:N,variables:{finalizedOrder:t}}).then(e=>e?.data?.database?.commerceOrder),R=(e,t)=>{if("undefined"==typeof fbq&&"undefined"==typeof gtag)return;let n={};try{let e=window.localStorage.getItem("wf-seen-orders");e&&(n=JSON.parse(e))}catch(e){return}n[t.orderId]||w(e,t).then(e=>{if(!e)return;let{decimalValue:r,unit:i}=e.total;"undefined"!=typeof fbq&&"function"==typeof fbq&&fbq("track","Purchase",{value:r,currency:i,content_ids:(e.userItems||[]).map(e=>e.sku.id),content_type:"product",contents:(e.userItems||[]).map(e=>({id:e.sku.id,quantity:e.count,item_price:e.price.decimalValue}))}),"undefined"!=typeof gtag&&"function"==typeof gtag&&gtag("event","purchase",{transaction_id:e.id,value:r,currency:i,items:(e.userItems||[]).map(e=>({id:e.sku.id,name:e.product.f_name_,quantity:e.count,price:e.price.decimalValue}))}),n[t.orderId]=!0;try{window.localStorage.setItem("wf-seen-orders",JSON.stringify(n))}catch(e){return}})}},14155:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"PillGroups",{enumerable:!0,get:function(){return a}});let r=n(10873),i=Object.freeze({RETURN:13,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40});class a{form;pillGroups;onSelect;static hasPillGroups(e){return e.querySelectorAll(`[${r.DATA_ATTR_NODE_TYPE}="${r.NODE_TYPE_COMMERCE_ADD_TO_CART_PILL_GROUP}"]`).length>0}constructor(e,t){this.form=e,this.pillGroups={},this.onSelect=t}init(){for(let e of this.form.querySelectorAll(`[${r.DATA_ATTR_NODE_TYPE}="${r.NODE_TYPE_COMMERCE_ADD_TO_CART_PILL_GROUP}"]`)){let t=new o(e,this.onSelect,this);t.init(),this.pillGroups[t.optionSetId]=t}}setSelectedPillsForSkuValues(e){for(let t of Object.keys(e)){let n=e[t],r=this.pillGroups[t];if(r){let e=r.findPillById(String(n));r.updatePillsWithNewSelected(e)}}}}class o{node;optionSetId;onSelect;pills;groups;constructor(e,t,n){this.node=e,this.optionSetId=String(e.getAttribute(r.DATA_ATTR_COMMERCE_OPTION_SET_ID)),this.onSelect=t,this.pills=[],this.groups=n}get firstEnabledPill(){return this.pills.find(e=>!1===e.disabled)}get value(){let e=this.pills.find(e=>!0===e.checked);return e?e.value:""}get options(){return this.pills}set selectedIndex(e){let t=this.pills[e]||null;this.emitSelected(t)}getAttribute(e){if(e===r.DATA_ATTR_COMMERCE_OPTION_SET_ID)return this.optionSetId;throw Error(`PillGroup: Attempted to fetch unsupported attribute ${e}`)}init(){let e=this.node.querySelectorAll(`[${r.DATA_ATTR_NODE_TYPE}="${r.NODE_TYPE_COMMERCE_ADD_TO_CART_PILL}"]`);this.pills=Array.from(e).map(e=>{let t=new s(e,this);return t.init(),t}),this.firstEnabledPill&&(this.firstEnabledPill.tabIndex=0),this.node._wfPillGroup=this}findPillById(e){return this.pills.find(t=>t.optionId===e)}updatePillsWithNewSelected(e){for(let e of this.pills)e.tabIndex=-1,e.checked=!1;e instanceof s?(e.tabIndex=0,e.checked=!0):this.firstEnabledPill&&(this.firstEnabledPill.tabIndex=0)}emitSelected(e){this.onSelect({optionId:e.optionId,optionSetId:this.optionSetId,groups:Object.values(this.groups.pillGroups)})}traverseAndEmitSelected(e,t){let n,r=this.pills.indexOf(e),i=!1,a=r;for(;!i;){if("previous"===t)(n=a-1)<0&&(n=this.pills.length-1);else if("next"===t)(n=a+1)===this.pills.length&&(n=0);else throw Error(`Unknown pill traversal direction "${t}", use "previous" or "next"`);if(n===r)break;let e=this.pills[n];e.disabled?a=n:(this.emitSelected(e),e.focus(),i=!0)}}}class s{node;optionId;group;constructor(e,t){this.node=e,this.optionId=String(this.node.getAttribute("data-option-id")),this.group=t}init(){this.tabIndex=-1,this.checked=!1,this.node.addEventListener("keydown",this.handleKeyDown),this.node.addEventListener("click",this.handleClick)}get tabIndex(){return this.node.tabIndex}set tabIndex(e){this.node.tabIndex=e}get value(){return this.optionId}get checked(){return"true"===this.node.getAttribute("aria-checked")}set checked(e){this.node.setAttribute("aria-checked",String(e)),e?this.node.classList.add("w--ecommerce-pill-selected"):this.node.classList.remove("w--ecommerce-pill-selected")}get disabled(){return"true"===this.node.getAttribute("aria-disabled")}set disabled(e){this.node.setAttribute("aria-disabled",String(e)),e?(this.node.classList.add("w--ecommerce-pill-disabled"),this.checked=!1,this.tabIndex=-1):this.node.classList.remove("w--ecommerce-pill-disabled")}get enabled(){return!this.disabled}set enabled(e){this.disabled=!e}focus(){this.node.focus()}handleKeyDown=e=>{let t=!1;if(!e.altKey&&!e.metaKey){switch(e.keyCode){case i.RETURN:case i.SPACE:this.handleClick(),t=!0;break;case i.UP:case i.LEFT:this.group.traverseAndEmitSelected(this,"previous"),t=!0;break;case i.DOWN:case i.RIGHT:this.group.traverseAndEmitSelected(this,"next"),t=!0}t&&(e.stopPropagation(),e.preventDefault())}};handleClick=()=>{this.disabled||this.checked||(this.focus(),this.group.emitSelected(this))}}},85986:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return n}});let n={log:(...e)=>{},error:(...e)=>{}}},48873:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i}});let n=(e,t=[])=>null==e?t:t.concat(n(Object.getPrototypeOf(e))).concat(Object.keys(e)),r=(e,t)=>{let r=n(e).filter(e=>"currentTarget"!==e).reduce((t,n)=>(t[n]="function"==typeof e[n]?{value:(...t)=>e[n](...t)}:{get:()=>e[n]},t),{});return Object.create(e,{currentTarget:{value:t},...r})};class i{apolloClient;stripeStore;eventHandlers;constructor(e,t){this.eventHandlers={},this.apolloClient=e,this.stripeStore=t}on=(e,t,n)=>{let r=this.eventHandlers[e]instanceof Array?this.eventHandlers[e]:[];return this.eventHandlers[e]=[...r,this.createHandlerProxy(e,t,n)],this};createHandlerProxy=(e,t,n)=>e=>{let i=t(e),a=i instanceof Element?r(e,i):e;i&&n(a,this.apolloClient,this.stripeStore)};attachHandlers=e=>(Object.keys(this.eventHandlers).forEach(t=>{this.eventHandlers[t].forEach(n=>e.addEventListener(t,n,!0))}),this);removeHandlers=e=>(Object.keys(this.eventHandlers).forEach(t=>{this.eventHandlers[t].forEach(n=>e.removeEventListener(t,n,!0))}),this)}},2330:function(e,t,n){"use strict";let r,i,a;Object.defineProperty(t,"__esModule",{value:!0});var o={design:function(){return L},destroy:function(){return O},init:function(){return E},preview:function(){return v}};for(var s in o)Object.defineProperty(t,s,{enumerable:!0,get:o[s]});n(84037),n(68259),n(60033),n(9246),n(67321),n(52897),n(233),n(49754),n(30971),n(62374),n(55152),n(35273),n(30172),n(65723),n(48258),n(89433);let c=n(25195),u=b(n(48873)),l=b(n(84303)),d=b(n(82150)),f=b(n(82333)),p=b(n(45870)),m=b(n(94492)),_=n(5841),h=n(54556);n(67304),n(14362);let M=n(17696),y=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=A(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var o=i?Object.getOwnPropertyDescriptor(e,a):null;o&&(o.get||o.set)?Object.defineProperty(r,a,o):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(86365));function b(e){return e&&e.__esModule?e:{default:e}}function A(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(A=function(e){return e?n:t})(e)}function g(){r&&r.attachHandlers(window)}function T(){r&&r.removeHandlers(window)}function E({siteId:e}){i=(0,c.createApolloClient)({path:window.Webflow.env("design")||window.Webflow.env("preview")?`/api/v2/sites/${e}/apollo`:"/.wf_graphql/apollo",retryConfig:{maxAttempts:5},useCsrf:!0}),a=new _.StripeStore(document),r=new u.default(i,a),l.default.register(r),d.default.register(r),f.default.register(r),p.default.register(r),m.default.register(r),y.default.register(r),(0,M.initializeStripeElements)(a),T(),g(),(0,h.triggerRender)(null,!0),window.Webflow.env()||window.Webflow.load((0,y.renderPaypalButtons)(i))}function v(){T(),g(),(0,h.triggerRender)(null,!0)}function L(){T(),i&&i.store&&i.resetStore()}function O(){T()}},45870:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r={default:function(){return m},register:function(){return p}};for(var i in r)Object.defineProperty(t,i,{enumerable:!0,get:r[i]});let a=l(n(28160)),o=l(n(26882)),s=n(54556),c=n(91898),u=n(10873);function l(e){return e&&e.__esModule?e:{default:e}}let d=(e,t)=>{(0,c.renderTree)(e,t)},f=(e,t)=>{if(window.Webflow.env("design")||window.Webflow.env("preview")||!(e instanceof CustomEvent&&e.type===u.RENDER_TREE_EVENT))return;let n=[],{detail:r}=e;null!=r&&r.error&&n.push(r.error);let i=(0,s.findElementByNodeType)(u.NODE_TYPE_COMMERCE_ORDER_CONFIRMATION_WRAPPER);if(!i)return;let{orderId:c,token:l}=o.default.parse(window.location.search.substring(1));if(!c||!l)return;let f={orderId:c,token:l};(0,s.trackOrder)(t,f);let p=(0,s.findAllElementsByNodeType)(u.NODE_TYPE_COMMERCE_ORDER_CONFIRMATION_WRAPPER);t.query({query:(0,a.default)`
`,w=(e,t)=>e.query({query:N,variables:{finalizedOrder:t}}).then(e=>e?.data?.database?.commerceOrder),R=(e,t)=>{if("undefined"==typeof fbq&&"undefined"==typeof gtag)return;let n={};try{let e=window.localStorage.getItem("wf-seen-orders");e&&(n=JSON.parse(e))}catch(e){return}n[t.orderId]||w(e,t).then(e=>{if(!e)return;let{decimalValue:r,unit:i}=e.total;"undefined"!=typeof fbq&&"function"==typeof fbq&&fbq("track","Purchase",{value:r,currency:i,content_ids:(e.userItems||[]).map(e=>e.sku.id),content_type:"product",contents:(e.userItems||[]).map(e=>({id:e.sku.id,quantity:e.count,item_price:e.price.decimalValue}))}),"undefined"!=typeof gtag&&"function"==typeof gtag&&gtag("event","purchase",{transaction_id:e.id,value:r,currency:i,items:(e.userItems||[]).map(e=>({id:e.sku.id,name:e.product.f_name_,quantity:e.count,price:e.price.decimalValue}))}),n[t.orderId]=!0;try{window.localStorage.setItem("wf-seen-orders",JSON.stringify(n))}catch(e){return}})}},14155:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"PillGroups",{enumerable:!0,get:function(){return a}});let r=n(10873),i=Object.freeze({RETURN:13,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40});class a{form;pillGroups;onSelect;static hasPillGroups(e){return e.querySelectorAll(`[${r.DATA_ATTR_NODE_TYPE}="${r.NODE_TYPE_COMMERCE_ADD_TO_CART_PILL_GROUP}"]`).length>0}constructor(e,t){this.form=e,this.pillGroups={},this.onSelect=t}init(){for(let e of this.form.querySelectorAll(`[${r.DATA_ATTR_NODE_TYPE}="${r.NODE_TYPE_COMMERCE_ADD_TO_CART_PILL_GROUP}"]`)){let t=new o(e,this.onSelect,this);t.init(),this.pillGroups[t.optionSetId]=t}}setSelectedPillsForSkuValues(e){for(let t of Object.keys(e)){let n=e[t],r=this.pillGroups[t];if(r){let e=r.findPillById(String(n));r.updatePillsWithNewSelected(e)}}}}class o{node;optionSetId;onSelect;pills;groups;constructor(e,t,n){this.node=e,this.optionSetId=String(e.getAttribute(r.DATA_ATTR_COMMERCE_OPTION_SET_ID)),this.onSelect=t,this.pills=[],this.groups=n}get firstEnabledPill(){return this.pills.find(e=>!1===e.disabled)}get value(){let e=this.pills.find(e=>!0===e.checked);return e?e.value:""}get options(){return this.pills}set selectedIndex(e){let t=this.pills[e]||null;this.emitSelected(t)}getAttribute(e){if(e===r.DATA_ATTR_COMMERCE_OPTION_SET_ID)return this.optionSetId;throw Error(`PillGroup: Attempted to fetch unsupported attribute ${e}`)}init(){let e=this.node.querySelectorAll(`[${r.DATA_ATTR_NODE_TYPE}="${r.NODE_TYPE_COMMERCE_ADD_TO_CART_PILL}"]`);this.pills=Array.from(e).map(e=>{let t=new s(e,this);return t.init(),t}),this.firstEnabledPill&&(this.firstEnabledPill.tabIndex=0),this.node._wfPillGroup=this}findPillById(e){return this.pills.find(t=>t.optionId===e)}updatePillsWithNewSelected(e){for(let e of this.pills)e.tabIndex=-1,e.checked=!1;e instanceof s?(e.tabIndex=0,e.checked=!0):this.firstEnabledPill&&(this.firstEnabledPill.tabIndex=0)}emitSelected(e){this.onSelect({optionId:e.optionId,optionSetId:this.optionSetId,groups:Object.values(this.groups.pillGroups)})}traverseAndEmitSelected(e,t){let n,r=this.pills.indexOf(e),i=!1,a=r;for(;!i;){if("previous"===t)(n=a-1)<0&&(n=this.pills.length-1);else if("next"===t)(n=a+1)===this.pills.length&&(n=0);else throw Error(`Unknown pill traversal direction "${t}", use "previous" or "next"`);if(n===r)break;let e=this.pills[n];e.disabled?a=n:(this.emitSelected(e),e.focus(),i=!0)}}}class s{node;optionId;group;constructor(e,t){this.node=e,this.optionId=String(this.node.getAttribute("data-option-id")),this.group=t}init(){this.tabIndex=-1,this.checked=!1,this.node.addEventListener("keydown",this.handleKeyDown),this.node.addEventListener("click",this.handleClick)}get tabIndex(){return this.node.tabIndex}set tabIndex(e){this.node.tabIndex=e}get value(){return this.optionId}get checked(){return"true"===this.node.getAttribute("aria-checked")}set checked(e){this.node.setAttribute("aria-checked",String(e)),e?this.node.classList.add("w--ecommerce-pill-selected"):this.node.classList.remove("w--ecommerce-pill-selected")}get disabled(){return"true"===this.node.getAttribute("aria-disabled")}set disabled(e){this.node.setAttribute("aria-disabled",String(e)),e?(this.node.classList.add("w--ecommerce-pill-disabled"),this.checked=!1,this.tabIndex=-1):this.node.classList.remove("w--ecommerce-pill-disabled")}get enabled(){return!this.disabled}set enabled(e){this.disabled=!e}focus(){this.node.focus()}handleKeyDown=e=>{let t=!1;if(!e.altKey&&!e.metaKey){switch(e.keyCode){case i.RETURN:case i.SPACE:this.handleClick(),t=!0;break;case i.UP:case i.LEFT:this.group.traverseAndEmitSelected(this,"previous"),t=!0;break;case i.DOWN:case i.RIGHT:this.group.traverseAndEmitSelected(this,"next"),t=!0}t&&(e.stopPropagation(),e.preventDefault())}};handleClick=()=>{this.disabled||this.checked||(this.focus(),this.group.emitSelected(this))}}},85986:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return n}});let n={log:(...e)=>{},error:(...e)=>{}}},48873:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return i}});let n=(e,t=[])=>null==e?t:t.concat(n(Object.getPrototypeOf(e))).concat(Object.keys(e)),r=(e,t)=>{let r=n(e).filter(e=>"currentTarget"!==e).reduce((t,n)=>(t[n]="function"==typeof e[n]?{value:(...t)=>e[n](...t)}:{get:()=>e[n]},t),{});return Object.create(e,{currentTarget:{value:t},...r})};class i{apolloClient;stripeStore;eventHandlers;constructor(e,t){this.eventHandlers={},this.apolloClient=e,this.stripeStore=t}on=(e,t,n)=>{let r=this.eventHandlers[e]instanceof Array?this.eventHandlers[e]:[];return this.eventHandlers[e]=[...r,this.createHandlerProxy(e,t,n)],this};createHandlerProxy=(e,t,n)=>e=>{let i=t(e),a=i instanceof Element?r(e,i):e;i&&n(a,this.apolloClient,this.stripeStore)};attachHandlers=e=>(Object.keys(this.eventHandlers).forEach(t=>{this.eventHandlers[t].forEach(n=>e.addEventListener(t,n,!0))}),this);removeHandlers=e=>(Object.keys(this.eventHandlers).forEach(t=>{this.eventHandlers[t].forEach(n=>e.removeEventListener(t,n,!0))}),this)}},2330:function(e,t,n){"use strict";let r,i,a;Object.defineProperty(t,"__esModule",{value:!0});var o={design:function(){return L},destroy:function(){return O},init:function(){return E},preview:function(){return v}};for(var s in o)Object.defineProperty(t,s,{enumerable:!0,get:o[s]});n(84037),n(68259),n(60033),n(9246),n(67321),n(52897),n(233),n(49754),n(30971),n(62374),n(55152),n(35273),n(30172),n(65723),n(48258),n(89433);let c=n(25195),u=b(n(48873)),l=b(n(84303)),d=b(n(82150)),f=b(n(82333)),p=b(n(45870)),m=b(n(94492)),_=n(5841),h=n(54556);n(67304),n(14362);let M=n(17696),y=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=A(t);if(n&&n.has(e))return n.get(e);var r={__proto__:null},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var o=i?Object.getOwnPropertyDescriptor(e,a):null;o&&(o.get||o.set)?Object.defineProperty(r,a,o):r[a]=e[a]}return r.default=e,n&&n.set(e,r),r}(n(86365));function b(e){return e&&e.__esModule?e:{default:e}}function A(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(A=function(e){return e?n:t})(e)}function g(){r&&r.attachHandlers(window)}function T(){r&&r.removeHandlers(window)}function E({siteId:e}){let t=window.Webflow.env("design")||window.Webflow.env("preview");i=(0,c.createApolloClient)({path:t?`/api/v2/sites/${e}/apollo`:"/.wf_graphql/apollo",retryConfig:{maxAttempts:5},useCsrf:!0,disableBatching:!t}),a=new _.StripeStore(document),r=new u.default(i,a),l.default.register(r),d.default.register(r),f.default.register(r),p.default.register(r),m.default.register(r),y.default.register(r),(0,M.initializeStripeElements)(a),T(),g(),(0,h.triggerRender)(null,!0),window.Webflow.env()||window.Webflow.load((0,y.renderPaypalButtons)(i))}function v(){T(),g(),(0,h.triggerRender)(null,!0)}function L(){T(),i&&i.store&&i.resetStore()}function O(){T()}},45870:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r={default:function(){return m},register:function(){return p}};for(var i in r)Object.defineProperty(t,i,{enumerable:!0,get:r[i]});let a=l(n(28160)),o=l(n(26882)),s=n(54556),c=n(91898),u=n(10873);function l(e){return e&&e.__esModule?e:{default:e}}let d=(e,t)=>{(0,c.renderTree)(e,t)},f=(e,t)=>{if(window.Webflow.env("design")||window.Webflow.env("preview")||!(e instanceof CustomEvent&&e.type===u.RENDER_TREE_EVENT))return;let n=[],{detail:r}=e;null!=r&&r.error&&n.push(r.error);let i=(0,s.findElementByNodeType)(u.NODE_TYPE_COMMERCE_ORDER_CONFIRMATION_WRAPPER);if(!i)return;let{orderId:c,token:l}=o.default.parse(window.location.search.substring(1));if(!c||!l)return;let f={orderId:c,token:l};(0,s.trackOrder)(t,f);let p=(0,s.findAllElementsByNodeType)(u.NODE_TYPE_COMMERCE_ORDER_CONFIRMATION_WRAPPER);t.query({query:(0,a.default)`
${i.getAttribute(u.ORDER_QUERY)}
`,variables:{finalizedOrder:f},fetchPolicy:"network-only",errorPolicy:"all"}).then(e=>{p.forEach(t=>{d(t,{...e,errors:n.concat(e.errors).filter(Boolean)})})}).catch(e=>{n.push(e),p.forEach(e=>{d(e,{errors:n})})})},p=e=>{e.on(u.RENDER_TREE_EVENT,Boolean,f)},m={register:p}},86365:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,i={default:function(){return T},renderPaypalButtons:function(){return g}};for(var a in i)Object.defineProperty(t,a,{enumerable:!0,get:i[a]});let o=n(54556),s=n(17696),c=n(69773),u=(r=n(85986))&&r.__esModule?r:{default:r},l=n(94797),d=n(10873),f=({target:e})=>!!((0,o.findClosestElementByNodeType)(d.NODE_TYPE_COMMERCE_CHECKOUT_PLACE_ORDER_BUTTON,e)&&e instanceof Element)&&e,p=!1,m=(e,t)=>{if(window.Webflow.env("design")||window.Webflow.env("preview")||!(e instanceof CustomEvent&&e.type===d.RENDER_TREE_EVENT))return;let n=(0,o.findAllElementsByNodeType)(d.NODE_TYPE_COMMERCE_PAYPAL_CHECKOUT_FORM_CONTAINER);if(!n||0===n.length)return;let r=[],{detail:i}=e;null!=i&&i.error&&r.push(i.error);let a=window.document.activeElement,c=(0,o.findClosestElementByNodeType)(d.NODE_TYPE_COMMERCE_PAYPAL_CHECKOUT_FORM_CONTAINER,a),u=null;a instanceof HTMLInputElement&&c&&((u=a.id)||(u=a.getAttribute("data-wf-bindings")),u=u?null:u),(p?Promise.resolve():t.mutate({mutation:l.syncPayPalOrderInfo})).then(()=>{p=!0,(0,s.renderCheckoutFormContainers)(n,r,t,void 0,u)})},_=!1,h=e=>{_=!0,window.addEventListener("beforeunload",s.beforeUnloadHandler);let t=e.innerHTML,n=e.getAttribute(d.DATA_ATTR_LOADING_TEXT);return e.innerHTML=n||d.CHECKOUT_PLACE_ORDER_LOADING_TEXT_DEFAULT,(n=!1)=>{n||(_=!1),window.removeEventListener("beforeunload",s.beforeUnloadHandler),e.innerHTML=t||d.CHECKOUT_PLACE_ORDER_BUTTON_TEXT_DEFAULT}},M=({shippingInfo:e,additionalInfo:t,requiresShipping:n})=>!HTMLFormElement.prototype.reportValidity||!(n&&!e.reportValidity()||t&&t instanceof HTMLFormElement&&!t.reportValidity()),y=(e,t)=>{if(window.Webflow.env("design")||window.Webflow.env("preview")||_)return;let{currentTarget:n}=e;if(!(n instanceof Element))return;let r=(0,o.findClosestElementByNodeType)(d.NODE_TYPE_COMMERCE_PAYPAL_CHECKOUT_FORM_CONTAINER,n);if(!(r instanceof Element))return;let i=(0,o.findElementByNodeType)(d.NODE_TYPE_COMMERCE_PAYPAL_CHECKOUT_ERROR_STATE,r),a=(0,o.findElementByNodeType)(d.NODE_TYPE_COMMERCE_CHECKOUT_SHIPPING_METHODS_WRAPPER,r),c=(0,o.findElementByNodeType)(d.NODE_TYPE_COMMERCE_CHECKOUT_PLACE_ORDER_BUTTON,r),l=(0,o.findElementByNodeType)(d.NODE_TYPE_COMMERCE_CHECKOUT_ADDITIONAL_INFO,r);if(!(i instanceof HTMLElement)||!(a instanceof HTMLFormElement)||!(c instanceof Element))return;let f=i.querySelector(d.CART_CHECKOUT_ERROR_MESSAGE_SELECTOR);if(f&&f.hasAttribute(d.NEEDS_REFRESH))return;let p=l&&l instanceof HTMLElement,m=h(c);i.style.setProperty("display","none"),(0,o.fetchOrderStatusFlags)(t).then(({requiresShipping:e})=>{if(!M({shippingInfo:a,additionalInfo:l,requiresShipping:e}))return void m();let n="";if(e&&a.elements["shipping-method-choice"]){let e=a.querySelector('input[name="shipping-method-choice"]:checked');e&&(n=e.value)}let r=p?(0,o.customDataFormToArray)(l):[];Promise.all([e?(0,s.createOrderShippingMethodMutation)(t,n):Promise.resolve(),p?(0,s.createCustomDataMutation)(t,r):Promise.resolve()]).then(()=>(0,s.createAttemptSubmitOrderRequest)(t,{checkoutType:"paypal"})).then(e=>{u.default.log(e);let t=(0,s.getOrderDataFromGraphQLResponse)(e);t.ok&&(m(!0),(0,s.redirectToOrderConfirmation)(t,!0))}).catch(e=>{if(m(),u.default.error(e),i.style.removeProperty("display"),(0,s.updateErrorMessage)(i,e),e.graphQLErrors&&e.graphQLErrors[0]&&e.graphQLErrors[0].message){let t=(0,o.safeParseJson)(e.graphQLErrors[0].message);t&&t.details&&t.details[0]&&"INSTRUMENT_DECLINED"===t.details[0].issue&&window.parent.postMessage(JSON.stringify({isWebflow:!0,type:"error",detail:t}),window.location.origin)}})})},b=`
display: block;

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="684561bc22684ab14f0094e7" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="684561bc22684ab14f0094e7" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>news open</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6836bfe4b6ece7af45e3e6f2" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6836bfe4b6ece7af45e3e6f2" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>News</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b381fe71c1c06a5b70" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b381fe71c1c06a5b70" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Protek</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6836cad8b1a5806f12459deb" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6836cad8b1a5806f12459deb" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Payments method</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b381fe71c1c06a5b52" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6800f8b381fe71c1c06a5b52" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<base target="_parent">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68274b3afd7280478878db26" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="68274b3afd7280478878db26" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Search result</title>
@ -214,7 +214,7 @@
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Избранное</div>
@ -251,7 +251,7 @@
<div class="text-block-53">INA 530059210</div>
<div class="fsfav">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
</div>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="682311e1c6efc75810555f64" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="682311e1c6efc75810555f64" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Search Results</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6847e8e8e1b22b8406a39690" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6847e8e8e1b22b8406a39690" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
@ -214,7 +214,7 @@
<a href="#" class="button-for-mobile-menu-block w-inline-block">
<div class="block-for-moble-menu-icon">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="name-mobile-menu-item">Избранное</div>
@ -478,7 +478,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -507,7 +507,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -536,7 +536,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -565,7 +565,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -594,7 +594,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -623,7 +623,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -652,7 +652,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -681,7 +681,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -710,7 +710,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -739,7 +739,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -768,7 +768,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -797,7 +797,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -826,7 +826,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -855,7 +855,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -884,7 +884,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -913,7 +913,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -942,7 +942,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">
@ -971,7 +971,7 @@
<div class="w-layout-vflex flex-block-15-copy">
<div class="favcardcat">
<div class="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewbox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="black"></path>
<path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path>
</svg></div>
</div>
<div class="div-block-4"><img src="images/162615.webp" loading="lazy" width="Auto" height="Auto" alt="" srcset="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" class="image-5">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="684e73c998b3d031bf41baf3" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="684e73c998b3d031bf41baf3" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>thankyoupage</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685e5d95b4304bd8428c1631" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685e5d95b4304bd8428c1631" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>VIN knot</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685d5d68623a85f76b103bfa" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685d5d68623a85f76b103bfa" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>VIN knot</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685d5478c4ebd5c8793f8c54" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="685d5478c4ebd5c8793f8c54" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>VIN</title>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Fri Jun 27 2025 11:05:44 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6845507cd7ed248b659ca3b9" data-wf-site="6800f7e35fcfd4ca3b323269">
<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Wed Jul 02 2025 10:20:31 GMT+0000 (Coordinated Universal Time) -->
<html data-wf-page="6845507cd7ed248b659ca3b9" data-wf-site="6800f7e35fcfd4ca3b323269" lang="en">
<head>
<meta charset="utf-8">
<title>wholesale</title>

View File

@ -1,4 +1,7 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { useCart } from "@/contexts/CartContext";
import toast from "react-hot-toast";
import CartIcon from "./CartIcon";
interface BestPriceCardProps {
bestOfferType: string;
@ -7,13 +10,29 @@ interface BestPriceCardProps {
price: string;
delivery: string;
stock: string;
offer?: any; // Добавляем полный объект предложения для корзины
}
const BestPriceCard: React.FC<BestPriceCardProps> = ({ bestOfferType, title, description, price, delivery, stock }) => {
const BestPriceCard: React.FC<BestPriceCardProps> = ({
bestOfferType,
title,
description,
price,
delivery,
stock,
offer
}) => {
const { addItem } = useCart();
// Парсим stock в число, если возможно
const parsedStock = parseInt(stock.replace(/[^\d]/g, ""), 10);
const maxCount = isNaN(parsedStock) ? undefined : parsedStock;
const [count, setCount] = useState(1);
const [inputValue, setInputValue] = useState("1");
useEffect(() => {
setInputValue(count.toString());
}, [count]);
const handleMinus = () => setCount(prev => Math.max(1, prev - 1));
const handlePlus = () => {
@ -25,15 +44,91 @@ const BestPriceCard: React.FC<BestPriceCardProps> = ({ bestOfferType, title, des
};
const handleInput = (e: React.ChangeEvent<HTMLInputElement>) => {
let value = parseInt(e.target.value, 10);
const val = e.target.value;
setInputValue(val);
if (val === "") {
// Не обновляем count, пока не будет blur
return;
}
let value = parseInt(val, 10);
if (isNaN(value) || value < 1) value = 1;
if (maxCount !== undefined && value > maxCount) {
window.alert(`Максимум ${maxCount} шт.`);
toast.error(`Максимум ${maxCount} шт.`);
return;
}
setCount(value);
};
const handleInputBlur = () => {
if (inputValue === "") {
setInputValue("1");
setCount(1);
}
};
// Функция для парсинга цены из строки
const parsePrice = (priceStr: string): number => {
const cleanPrice = priceStr.replace(/[^\d.,]/g, '').replace(',', '.');
return parseFloat(cleanPrice) || 0;
};
// Обработчик добавления в корзину
const handleAddToCart = async (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (!offer) {
toast.error('Информация о товаре недоступна');
return;
}
const numericPrice = parsePrice(price);
if (numericPrice <= 0) {
toast.error('Цена товара не найдена');
return;
}
try {
const result = await addItem({
productId: offer.productId,
offerKey: offer.offerKey,
name: description,
description: `${offer.brand} ${offer.articleNumber} - ${description}`,
brand: offer.brand,
article: offer.articleNumber,
price: numericPrice,
currency: offer.currency || 'RUB',
quantity: count,
stock: maxCount, // передаем информацию о наличии
deliveryTime: delivery,
warehouse: offer.warehouse || 'Склад',
supplier: offer.supplier || (offer.isExternal ? 'AutoEuro' : 'Protek'),
isExternal: offer.isExternal || false,
image: offer.image,
});
if (result.success) {
// Показываем тоастер об успешном добавлении
toast.success(
<div>
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{`${offer.brand} ${offer.articleNumber} (${count} шт.)`}</div>
</div>,
{
duration: 3000,
icon: <CartIcon size={20} color="#fff" />,
}
);
} else {
// Показываем ошибку
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
}
} catch (error) {
console.error('Ошибка добавления в корзину:', error);
toast.error('Ошибка добавления товара в корзину');
}
};
return (
<div className="w-layout-vflex flex-block-44">
<h3 className="heading-8-copy line-clamp-2 md:line-clamp-1 min-h-[2.5em] md:min-h-0">{bestOfferType}</h3>
@ -68,8 +163,9 @@ const BestPriceCard: React.FC<BestPriceCardProps> = ({ bestOfferType, title, des
type="number"
min={1}
max={maxCount}
value={count}
value={inputValue}
onChange={handleInput}
onBlur={handleInputBlur}
className="text-block-26 w-full text-center outline-none"
aria-label="Количество"
/>
@ -80,11 +176,17 @@ const BestPriceCard: React.FC<BestPriceCardProps> = ({ bestOfferType, title, des
</div>
</div>
<div className="w-layout-hflex flex-block-42">
<a href="#" className="button-icon w-inline-block">
<button
type="button"
onClick={handleAddToCart}
className="button-icon w-inline-block"
style={{ cursor: 'pointer', textDecoration: 'none' }}
aria-label="Добавить в корзину"
>
<div className="div-block-26">
<div className="icon-setting w-embed"><svg width="currentWidht" height="currentHeight" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z" fill="currentColor"/></svg></div>
</div>
</a>
</button>
</div>
</div>
</div>

View File

@ -52,7 +52,7 @@ const BrandSelectionModal: React.FC<BrandSelectionModalProps> = ({
return (
<div
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
className="fixed inset-0 bg-black/10 bg-opacity-50 flex items-center justify-center z-50 p-4"
onClick={handleBackdropClick}
>
<div className="bg-white rounded-lg shadow-xl max-w-md w-full max-h-[80vh] overflow-hidden">

View File

@ -14,6 +14,8 @@ const BrandWizardSearchSection: React.FC = () => {
const [vehicles, setVehicles] = useState<LaximoVehicleSearchResult[] | null>(null);
const [brandQuery, setBrandQuery] = useState('');
const buttonRef = useRef<HTMLButtonElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const [isOpen, setIsOpen] = useState(false);
// Получение информации о каталоге через useQuery
const {
@ -68,7 +70,7 @@ const BrandWizardSearchSection: React.FC = () => {
const catalogInfo = catalogData?.laximoCatalogInfo;
return (
<section className="max-w-[1100px] min-h-[450px] mx-auto bg-white rounded-2xl shadow p-6 md:p-10 my-8">
<section className="max-w-[1580px] min-h-[450px] mx-auto bg-white rounded-2xl shadow p-6 md:p-10 my-8">
{/* <div className="text-2xl font-bold text-gray-900 mb-6 mt-6 text-center" style={{ fontSize: '28px' }}>Подбор автомобиля по параметрам</div> */}
{/* Combobox бренда */}
<div className="mb-8 w-full">
@ -82,45 +84,64 @@ const BrandWizardSearchSection: React.FC = () => {
</div>
<Combobox value={selectedBrand} onChange={handleBrandChange} nullable>
<div className="relative">
{/* Невидимая кнопка поверх инпута */}
<button
type="button"
className="absolute top-0 left-0 w-full h-full opacity-0 z-10 cursor-pointer"
tabIndex={0}
aria-label="Открыть список брендов"
onClick={() => {
inputRef.current?.focus();
if (inputRef.current) {
inputRef.current.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
}
}}
/>
<Combobox.Input
ref={inputRef}
id="brand-combobox"
className="w-full px-6 py-4 bg-white rounded border border-stone-300 text-sm text-gray-950 placeholder:text-neutral-500 outline-none focus:shadow-none focus:border-stone-300 transition-colors"
displayValue={(brand: LaximoBrand | null) => brand?.name || ''}
onChange={e => setBrandQuery(e.target.value)}
placeholder="Начните вводить бренд..."
autoComplete="off"
onFocus={() => setIsOpen(true)}
onClick={() => setIsOpen(true)}
onBlur={() => setIsOpen(false)}
/>
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center px-3 focus:outline-none w-12">
<Combobox.Button ref={buttonRef} className="absolute inset-y-0 right-0 flex items-center px-3 focus:outline-none w-12">
<svg className="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 9l6 6 6-6" />
</svg>
</Combobox.Button>
<Combobox.Options
className="absolute left-0 top-full z-10 bg-white border-x border-b border-stone-300 rounded-b-lg shadow-lg w-full max-h-60 overflow-auto scrollbar-none"
style={{ scrollbarWidth: 'none' }}
data-hide-scrollbar
>
{brandsLoading && (
<div className="px-6 py-4 text-gray-500">Загрузка брендов...</div>
)}
{brandsError && (
<div className="px-6 py-4 text-red-500">Ошибка загрузки брендов</div>
)}
{filteredBrands.length === 0 && !brandsLoading && !brandsError && (
<div className="px-6 py-4 text-gray-500">Бренды не найдены</div>
)}
{filteredBrands.map(brand => (
<Combobox.Option
key={brand.code}
value={brand}
className={({ active, selected }) =>
`px-6 py-4 cursor-pointer hover:!bg-[rgb(236,28,36)] hover:!text-white text-sm transition-colors ${selected ? 'bg-red-50 font-semibold text-gray-950' : 'text-neutral-500'}`
}
>
{brand.name}
</Combobox.Option>
))}
</Combobox.Options>
{isOpen && (
<Combobox.Options
className="absolute left-0 top-full z-10 bg-white border-x border-b border-stone-300 rounded-b-lg shadow-lg w-full max-h-60 overflow-auto scrollbar-none"
style={{ scrollbarWidth: 'none' }}
data-hide-scrollbar
>
{brandsLoading && (
<div className="px-6 py-4 text-gray-500">Загрузка брендов...</div>
)}
{brandsError && (
<div className="px-6 py-4 text-red-500">Ошибка загрузки брендов</div>
)}
{filteredBrands.length === 0 && !brandsLoading && !brandsError && (
<div className="px-6 py-4 text-gray-500">Бренды не найдены</div>
)}
{filteredBrands.map(brand => (
<Combobox.Option
key={brand.code}
value={brand}
className={({ active, selected }) =>
`px-6 py-4 cursor-pointer hover:!bg-[rgb(236,28,36)] hover:!text-white text-sm transition-colors ${selected ? 'bg-red-50 font-semibold text-gray-950' : 'text-neutral-500'}`
}
>
{brand.name}
</Combobox.Option>
))}
</Combobox.Options>
)}
</div>
</Combobox>
</div>
@ -152,7 +173,7 @@ const BrandWizardSearchSection: React.FC = () => {
</>
)}
{catalogInfo && !catalogInfo.supportparameteridentification2 && (
<div className="text-yellow-700 bg-yellow-50 border border-yellow-200 rounded-lg p-4 mt-6 text-center">
<div className="text-blue-700 bg-blue-50 border border-blue-200 rounded-lg p-4 mt-6 text-center">
Для выбранного бренда подбор по параметрам недоступен.
</div>
)}

View File

@ -0,0 +1,25 @@
import React from 'react';
interface CartIconProps {
size?: number;
color?: string;
}
const CartIcon: React.FC<CartIconProps> = ({ size = 24, color = '#fff' }) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z"
fill={color}
/>
</svg>
);
};
export default CartIcon;

View File

@ -11,6 +11,7 @@ const CartInfo: React.FC = () => {
};
return (
<section className="section-info">
<div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9">
<div className="w-layout-hflex flex-block-7">
@ -44,6 +45,7 @@ const CartInfo: React.FC = () => {
</div>
</div>
</div>
</section>
);
};

View File

@ -16,6 +16,8 @@ interface CartItemProps {
onComment: (comment: string) => void;
onCountChange?: (count: number) => void;
onRemove?: () => void;
isSummaryStep?: boolean;
itemNumber?: number;
}
const CartItem: React.FC<CartItemProps> = ({
@ -34,76 +36,182 @@ const CartItem: React.FC<CartItemProps> = ({
onComment,
onCountChange,
onRemove,
}) => (
<div className="w-layout-hflex cart-item">
<div className="w-layout-hflex info-block-search-copy">
<div
className={"div-block-7" + (selected ? " active" : "")}
onClick={onSelect}
style={{ marginRight: 12, cursor: 'pointer' }}
>
{selected && (
<svg width="14" height="10" viewBox="0 0 14 10" fill="none">
<path d="M2 5.5L6 9L12 2" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
isSummaryStep = false,
itemNumber,
}) => {
// --- Фикс для input: можно стереть, при blur пустое = 1 ---
const [inputValue, setInputValue] = React.useState(count.toString());
React.useEffect(() => {
setInputValue(count.toString());
}, [count]);
return (
<div className="w-layout-hflex cart-item">
<div className="w-layout-hflex info-block-search-copy">
{isSummaryStep ? (
<div style={{ marginRight: 12, minWidth: 24, textAlign: 'center', fontWeight: 600, fontSize: 14 }}>{itemNumber}</div>
) : (
<div
className={"div-block-7" + (selected ? " active" : "")}
onClick={onSelect}
style={{ marginRight: 12, cursor: 'pointer' }}
>
{selected && (
<svg width="14" height="10" viewBox="0 0 14 10" fill="none">
<path d="M2 5.5L6 9L12 2" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
)}
</div>
)}
<div className="w-layout-hflex block-name">
<h4 className="heading-9-copy">{name}</h4>
<div
className={
"text-block-21-copy" +
(isSummaryStep && itemNumber === 1 ? " border-t-0" : "")
}
style={
isSummaryStep && itemNumber === 1
? { borderTop: 'none' }
: undefined
}
>
{description}
</div>
</div>
<div className="form-block-copy w-form">
<form className="form-copy" onSubmit={e => e.preventDefault()}>
<input
className="text-field-copy w-input"
maxLength={256}
name="Search-5"
data-name="Search 5"
placeholder="Комментарий"
type="text"
id="Search-5"
value={comment}
onChange={e => onComment(e.target.value)}
disabled={isSummaryStep}
/>
</form>
<div className="success-message w-form-done">
<div>Thank you! Your submission has been received!</div>
</div>
<div className="error-message w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
</div>
</div>
</div>
<div className="w-layout-hflex add-to-cart-block">
<div className="w-layout-hflex flex-block-39-copy">
<h4 className="delivery-cart-s1">{delivery}</h4>
<div className="text-block-21-copy-copy">{deliveryDate}</div>
</div>
<div className="w-layout-hflex pcs-cart-s1">
{isSummaryStep ? (
<div className="text-block-26" style={{ fontWeight: 600, fontSize: 14 }}>{count} шт.</div>
) : (
<>
<div
className="minus-plus"
onClick={() => onCountChange && onCountChange(count - 1)}
style={{ cursor: 'pointer' }}
aria-label="Уменьшить количество"
tabIndex={0}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onCountChange && onCountChange(count - 1)}
role="button"
>
<div className="pluspcs w-embed">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 10.5V9.5H14V10.5H6Z" fill="currentColor"/>
</svg>
</div>
</div>
<div className="input-pcs">
<input
type="number"
min={1}
value={inputValue}
onChange={e => {
const val = e.target.value;
setInputValue(val);
if (val === "") {
// Не обновляем count, пока не будет blur
return;
}
const valueNum = Math.max(1, parseInt(val, 10) || 1);
onCountChange && onCountChange(valueNum);
}}
onBlur={() => {
if (inputValue === "") {
setInputValue("1");
onCountChange && onCountChange(1);
}
}}
className="text-block-26 w-full text-center outline-none"
aria-label="Количество"
style={{ width: 40 }}
/>
</div>
<div
className="minus-plus"
onClick={() => onCountChange && onCountChange(count + 1)}
style={{ cursor: 'pointer' }}
aria-label="Увеличить количество"
tabIndex={0}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onCountChange && onCountChange(count + 1)}
role="button"
>
<div className="pluspcs w-embed">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 10.5V9.5H14V10.5H6ZM9.5 6H10.5V14H9.5V6Z" fill="currentColor"/>
</svg>
</div>
</div>
</>
)}
</div>
<div className="w-layout-hflex flex-block-39-copy-copy">
<h4 className="price-in-cart-s1">{price}</h4>
<div className="price-1-pcs-cart-s1">{pricePerItem}</div>
</div>
{!isSummaryStep && (
<div className="w-layout-hflex control-element">
<div className="favorite-icon w-embed" onClick={onFavorite} style={{ cursor: 'pointer', color: favorite ? '#e53935' : undefined }}>
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 16.5L7.84 15.4929C3.72 11.93 1 9.57248 1 6.69619C1 4.33869 2.936 2.5 5.4 2.5C6.792 2.5 8.128 3.11798 9 4.08692C9.872 3.11798 11.208 2.5 12.6 2.5C15.064 2.5 17 4.33869 17 6.69619C17 9.57248 14.28 11.93 10.16 15.4929L9 16.5Z" fill={favorite ? "#e53935" : "currentColor"} />
</svg>
</div>
<div
className="bdel"
role="button"
tabIndex={0}
aria-label="Удалить из корзины"
onClick={onRemove}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onRemove && onRemove()}
style={{ display: 'inline-flex', cursor: 'pointer', transition: 'color 0.2s' }}
onMouseEnter={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
</div>
</div>
)}
</div>
<div className="w-layout-hflex block-name">
<h4 className="heading-9-copy">{name}</h4>
<div className="text-block-21-copy">{description}</div>
</div>
<div className="form-block-copy w-form">
<form className="form-copy" onSubmit={e => e.preventDefault()}>
<input
className="text-field-copy w-input"
maxLength={256}
name="Search-5"
data-name="Search 5"
placeholder="Комментарий"
type="text"
id="Search-5"
value={comment}
onChange={e => onComment(e.target.value)}
/>
</form>
<div className="success-message w-form-done">
<div>Thank you! Your submission has been received!</div>
</div>
<div className="error-message w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
</div>
</div>
</div>
<div className="w-layout-hflex add-to-cart-block">
<div className="w-layout-hflex flex-block-39-copy">
<h4 className="delivery-cart-s1">{delivery}</h4>
<div className="text-block-21-copy-copy">{deliveryDate}</div>
</div>
<div className="w-layout-hflex pcs-cart-s1">
<div className="minus-plus" onClick={() => onCountChange && onCountChange(count - 1)} style={{ cursor: 'pointer' }}>
<img loading="lazy" src="/images/minus_icon.svg" alt="-" />
</div>
<div className="input-pcs">
<div className="text-block-26">{count}</div>
</div>
<div className="minus-plus" onClick={() => onCountChange && onCountChange(count + 1)} style={{ cursor: 'pointer' }}>
<img loading="lazy" src="/images/plus_icon.svg" alt="+" />
</div>
</div>
<div className="w-layout-hflex flex-block-39-copy-copy">
<h4 className="price-in-cart-s1">{price}</h4>
<div className="price-1-pcs-cart-s1">{pricePerItem}</div>
</div>
<div className="w-layout-hflex control-element">
<div className="favorite-icon w-embed" onClick={onFavorite} style={{ cursor: 'pointer', color: favorite ? '#e53935' : undefined }}>
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 16.5L7.84 15.4929C3.72 11.93 1 9.57248 1 6.69619C1 4.33869 2.936 2.5 5.4 2.5C6.792 2.5 8.128 3.11798 9 4.08692C9.872 3.11798 11.208 2.5 12.6 2.5C15.064 2.5 17 4.33869 17 6.69619C17 9.57248 14.28 11.93 10.16 15.4929L9 16.5Z" fill={favorite ? "#e53935" : "currentColor"} />
</svg>
</div>
<img src="/images/delete.svg" loading="lazy" alt="" className="image-13" style={{ cursor: 'pointer' }} onClick={onRemove} />
</div>
</div>
</div>
);
);
};
export default CartItem;

View File

@ -1,11 +1,15 @@
import React from "react";
import React, { useEffect } from "react";
import CartItem from "./CartItem";
import { useCart } from "@/contexts/CartContext";
import { useFavorites } from "@/contexts/FavoritesContext";
const CartList: React.FC = () => {
const { state, toggleSelect, updateComment, removeItem, selectAll, removeSelected, updateQuantity } = useCart();
const { addToFavorites, removeFromFavorites, isFavorite } = useFavorites();
interface CartListProps {
isSummaryStep?: boolean;
}
const CartList: React.FC<CartListProps> = ({ isSummaryStep = false }) => {
const { state, toggleSelect, updateComment, removeItem, selectAll, removeSelected, updateQuantity, clearError } = useCart();
const { addToFavorites, removeFromFavorites, isFavorite, favorites } = useFavorites();
const { items } = state;
const allSelected = items.length > 0 && items.every((item) => item.selected);
@ -25,15 +29,18 @@ const CartList: React.FC = () => {
const handleFavorite = (id: string) => {
const item = items.find(item => item.id === id);
if (!item) return;
const isInFavorites = isFavorite(item.productId, item.offerKey, item.article, item.brand);
if (isInFavorites) {
// Удаляем из избранного
const favoriteId = `${item.productId || item.offerKey || ''}:${item.article}:${item.brand}`;
removeFromFavorites(favoriteId);
const favoriteItem = favorites.find((fav: any) => {
if (item.productId && fav.productId === item.productId) return true;
if (item.offerKey && fav.offerKey === item.offerKey) return true;
if (fav.article === item.article && fav.brand === item.brand) return true;
return false;
});
if (favoriteItem) {
removeFromFavorites(favoriteItem.id);
}
} else {
// Добавляем в избранное
addToFavorites({
productId: item.productId,
offerKey: item.offerKey,
@ -59,44 +66,105 @@ const CartList: React.FC = () => {
updateQuantity(id, count);
};
// Функция для форматирования цены
const formatPrice = (price: number, currency: string = 'RUB') => {
return `${price.toLocaleString('ru-RU')} ${currency === 'RUB' ? '₽' : currency}`;
};
// На втором шаге показываем только выбранные товары
const displayItems = isSummaryStep ? items.filter(item => item.selected) : items;
// Автоматически очищаем ошибки через 5 секунд
useEffect(() => {
if (state.error) {
const timer = setTimeout(() => {
clearError();
}, 5000);
return () => clearTimeout(timer);
}
}, [state.error, clearError]);
return (
<div className="w-layout-vflex flex-block-48">
<div className="w-layout-vflex product-list-cart">
<div className="w-layout-hflex multi-control">
<div className="w-layout-hflex select-all-block" onClick={handleSelectAll} style={{ cursor: 'pointer' }}>
<div
className={"div-block-7" + (allSelected ? " active" : "")}
style={{ marginRight: 8, cursor: 'pointer' }}
>
{allSelected && (
<svg width="14" height="10" viewBox="0 0 14 10" fill="none">
<path d="M2 5.5L6 9L12 2" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
)}
{/* Отображение ошибок корзины */}
{state.error && (
<div className="alert alert-error mb-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
<div className="flex items-center justify-between">
<div className="flex items-center">
<svg className="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
<span>{state.error}</span>
</div>
<div className="text-block-30">Выделить всё</div>
</div>
<div className="w-layout-hflex select-all-block" onClick={handleRemoveSelected} style={{ cursor: 'pointer' }}>
<div className="text-block-30">Удалить выбранные</div>
<img src="/images/delete.svg" loading="lazy" alt="" className="image-13" />
<button
onClick={clearError}
className="ml-2 text-red-500 hover:text-red-700"
aria-label="Закрыть уведомление"
>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{items.length === 0 ? (
)}
<div className="w-layout-vflex product-list-cart">
{!isSummaryStep && (
<div className="w-layout-hflex multi-control">
<div className="w-layout-hflex select-all-block" onClick={handleSelectAll} style={{ cursor: 'pointer' }}>
<div
className={"div-block-7" + (allSelected ? " active" : "")}
style={{ marginRight: 8, cursor: 'pointer' }}
>
{allSelected && (
<svg width="14" height="10" viewBox="0 0 14 10" fill="none">
<path d="M2 5.5L6 9L12 2" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
)}
</div>
<div className="text-block-30">Выделить всё</div>
</div>
<div className="w-layout-hflex select-all-block" onClick={handleRemoveSelected} style={{ cursor: 'pointer' }}
onMouseEnter={e => {
const path = (e.currentTarget.querySelector('path'));
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = (e.currentTarget.querySelector('path'));
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<div className="text-block-30">Удалить выбранные</div>
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg" className="image-13">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
</div>
</div>
)}
{displayItems.length === 0 ? (
<div className="empty-cart-message" style={{ textAlign: 'center', padding: '2rem', color: '#666' }}>
<p>Ваша корзина пуста</p>
<p>Добавьте товары из каталога</p>
</div>
) : (
items.map((item) => {
displayItems.map((item, idx) => {
const isInFavorites = isFavorite(item.productId, item.offerKey, item.article, item.brand);
return (
<div className="div-block-21" key={item.id}>
<div
className={
"div-block-21" +
(isSummaryStep && idx === 0 ? " border-t-0" : "")
}
style={
isSummaryStep && idx === 0
? { borderTop: 'none' }
: undefined
}
key={item.id}
>
<CartItem
name={item.name}
description={item.description}
@ -113,6 +181,8 @@ const CartList: React.FC = () => {
onComment={(comment) => handleComment(item.id, comment)}
onCountChange={(count) => handleCountChange(item.id, count)}
onRemove={() => handleRemove(item.id)}
isSummaryStep={isSummaryStep}
itemNumber={idx + 1}
/>
</div>
);

View File

@ -1,88 +1,88 @@
import React, { useState } from "react";
const initialItems = [
{
id: 1,
name: "Ganz GIE37312",
description: "Ролик ремня ГРМ VW AD GANZ GIE37312",
delivery: "Послезавтра, курьером",
deliveryDate: "пт, 7 февраля",
price: "18 763 ₽",
pricePerItem: "18 763 ₽/шт",
count: 1,
comment: "",
},
{
id: 2,
name: "Ganz GIE37312",
description: "Ролик ремня ГРМ VW AD GANZ GIE37312",
delivery: "Послезавтра, курьером",
deliveryDate: "пт, 7 февраля",
price: "18 763 ₽",
pricePerItem: "18 763 ₽/шт",
count: 1,
comment: "",
},
// ...ещё товары
];
import React from "react";
import { useCart } from "@/contexts/CartContext";
const CartList2: React.FC = () => {
const [items, setItems] = useState(initialItems);
const { state, updateComment } = useCart();
const { items } = state;
const handleComment = (id: number, comment: string) => {
setItems((prev) => prev.map((item) => item.id === id ? { ...item, comment } : item));
const handleComment = (id: string, comment: string) => {
updateComment(id, comment);
};
// Функция для форматирования цены
const formatPrice = (price: number, currency: string = 'RUB') => {
return `${price.toLocaleString('ru-RU')} ${currency === 'RUB' ? '₽' : currency}`;
};
// Показываем только выбранные товары на втором этапе
const selectedItems = items.filter(item => item.selected);
return (
<div className="w-layout-vflex flex-block-48">
<div className="w-layout-vflex product-list-cart-check">
{items.map((item) => (
<div className="div-block-21-copy" key={item.id}>
<div className="w-layout-hflex cart-item-check">
<div className="w-layout-hflex info-block-search">
<div className="text-block-35">{item.count}</div>
<div className="w-layout-hflex block-name">
<h4 className="heading-9-copy">{item.name}</h4>
<div className="text-block-21-copy">{item.description}</div>
</div>
<div className="form-block-copy w-form">
<form className="form-copy" onSubmit={e => e.preventDefault()}>
<input
className="text-field-copy w-input"
maxLength={256}
name="Search-5"
data-name="Search 5"
placeholder="Комментарий"
type="text"
id="Search-5"
value={item.comment}
onChange={e => handleComment(item.id, e.target.value)}
/>
</form>
<div className="success-message w-form-done">
<div>Thank you! Your submission has been received!</div>
{selectedItems.length === 0 ? (
<div className="empty-cart-message" style={{ textAlign: 'center', padding: '2rem', color: '#666' }}>
<p>Не выбрано товаров для заказа</p>
<p>Вернитесь на предыдущий шаг и выберите товары</p>
</div>
) : (
selectedItems.map((item, index) => (
<div
className={
"div-block-21-copy" +
(index === 0 ? " border-t-0" : "")
}
style={
index === 0 ? { borderTop: 'none' } : undefined
}
key={item.id}
>
<div className="w-layout-hflex cart-item-check">
<div className="w-layout-hflex info-block-search">
<div className="text-block-35">{item.quantity}</div>
<div className="w-layout-hflex block-name">
<h4 className="heading-9-copy">{item.name}</h4>
<div className="text-block-21-copy">{item.description}</div>
</div>
<div className="error-message w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
<div className="form-block-copy w-form">
<form className="form-copy" onSubmit={e => e.preventDefault()}>
<input
className="text-field-copy w-input"
maxLength={256}
name="Search-5"
data-name="Search 5"
placeholder="Комментарий"
type="text"
id={`Search-${item.id}`}
value={item.comment || ''}
onChange={e => handleComment(item.id, e.target.value)}
/>
</form>
<div className="success-message w-form-done">
<div>Thank you! Your submission has been received!</div>
</div>
<div className="error-message w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
</div>
</div>
</div>
</div>
<div className="w-layout-hflex add-to-cart-block">
<div className="w-layout-hflex flex-block-39-copy">
<h4 className="heading-9-copy">{item.delivery}</h4>
<div className="text-block-21-copy">{item.deliveryDate}</div>
</div>
<div className="w-layout-hflex pcs">
<div className="pcs-text">{item.count} шт.</div>
</div>
<div className="w-layout-hflex flex-block-39-copy-copy">
<h4 className="heading-9-copy-copy">{item.price}</h4>
<div className="text-block-21-copy-copy">{item.pricePerItem}</div>
<div className="w-layout-hflex add-to-cart-block">
<div className="w-layout-hflex flex-block-39-copy">
<h4 className="heading-9-copy">{item.deliveryTime || 'Уточняется'}</h4>
<div className="text-block-21-copy">{item.deliveryDate || ''}</div>
</div>
<div className="w-layout-hflex pcs">
<div className="pcs-text">{item.quantity} шт.</div>
</div>
<div className="w-layout-hflex flex-block-39-copy-copy">
<h4 className="heading-9-copy-copy">{formatPrice(item.price * item.quantity, item.currency)}</h4>
<div className="text-block-21-copy-copy">{formatPrice(item.price, item.currency)}/шт</div>
</div>
</div>
</div>
</div>
</div>
))}
))
)}
</div>
</div>
);

View File

@ -3,6 +3,7 @@ import CatalogProductCard from "./CatalogProductCard";
import { useArticleImage } from "@/hooks/useArticleImage";
import { useCart } from "@/contexts/CartContext";
import { toast } from "react-hot-toast";
import CartIcon from "./CartIcon";
interface CartRecommendedProps {
recommendedProducts?: any[];
@ -36,13 +37,14 @@ const RecommendedProductCard: React.FC<{
}
// Добавляем товар в корзину
addItem({
const result = await addItem({
productId: String(item.artId) || undefined,
name: item.name || `${item.brand} ${item.articleNumber}`,
description: item.name || `${item.brand} ${item.articleNumber}`,
price: numericPrice,
currency: 'RUB',
quantity: 1,
stock: undefined, // информация о наличии не доступна для рекомендуемых товаров
image: displayImage,
brand: item.brand,
article: item.articleNumber,
@ -51,17 +53,22 @@ const RecommendedProductCard: React.FC<{
isExternal: true
});
// Показываем успешный тоастер
toast.success(
<div>
<div className="font-semibold">Товар добавлен в корзину!</div>
<div className="text-sm text-gray-600">{item.name || `${item.brand} ${item.articleNumber}`}</div>
</div>,
{
duration: 3000,
icon: '🛒',
}
);
if (result.success) {
// Показываем успешный тоастер
toast.success(
<div>
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{item.name || `${item.brand} ${item.articleNumber}`}</div>
</div>,
{
duration: 3000,
icon: <CartIcon size={20} color="#fff" />,
}
);
} else {
// Показываем ошибку
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
}
} catch (error) {
console.error('Ошибка добавления в корзину:', error);
toast.error('Ошибка при добавлении товара в корзину');

View File

@ -42,7 +42,7 @@ const CartRecommendedProductCard: React.FC<CartRecommendedProductCardProps> = ({
<Link href="/cart" className="link-block-4-copy w-inline-block">
<div className="div-block-25">
<span className="icon-setting w-embed">
<svg width="currentWidht" height="currentHight" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z" fill="currentColor" />
</svg>
</span>

View File

@ -2,9 +2,15 @@ import React, { useState, useEffect, useRef } from "react";
import Link from "next/link";
import { useCart } from "@/contexts/CartContext";
import { useMutation, useQuery } from "@apollo/client";
import { CREATE_ORDER, CREATE_PAYMENT, GET_CLIENT_ME, GET_CLIENT_DELIVERY_ADDRESSES, GET_DELIVERY_OFFERS } from "@/lib/graphql";
import { CREATE_ORDER, CREATE_PAYMENT, GET_CLIENT_ME, GET_CLIENT_DELIVERY_ADDRESSES } from "@/lib/graphql";
import toast from "react-hot-toast";
const CartSummary: React.FC = () => {
interface CartSummaryProps {
step: number;
setStep: (step: number) => void;
}
const CartSummary: React.FC<CartSummaryProps> = ({ step, setStep }) => {
const { state, updateDelivery, updateOrderComment, clearCart } = useCart();
const { summary, delivery, items, orderComment } = state;
const legalEntityDropdownRef = useRef<HTMLDivElement>(null);
@ -15,7 +21,6 @@ const CartSummary: React.FC = () => {
const [error, setError] = useState("");
const [isProcessing, setIsProcessing] = useState(false);
const [showAuthWarning, setShowAuthWarning] = useState(false);
const [currentStep, setCurrentStep] = useState(1); // 1 - первый шаг, 2 - второй шаг
// Новые состояния для первого шага
const [selectedLegalEntity, setSelectedLegalEntity] = useState<string>("");
@ -32,22 +37,17 @@ const CartSummary: React.FC = () => {
const [paymentMethod, setPaymentMethod] = useState<string>("yookassa");
const [showPaymentDropdown, setShowPaymentDropdown] = useState(false);
// Состояния для офферов доставки
const [deliveryOffers, setDeliveryOffers] = useState<any[]>([]);
const [selectedDeliveryOffer, setSelectedDeliveryOffer] = useState<any>(null);
const [loadingOffers, setLoadingOffers] = useState(false);
const [offersError, setOffersError] = useState<string>("");
// Упрощенный тип доставки - только курьер или самовывоз
// const [deliveryType, setDeliveryType] = useState<'courier' | 'pickup'>('courier');
const [createOrder] = useMutation(CREATE_ORDER);
const [createPayment] = useMutation(CREATE_PAYMENT);
const [getDeliveryOffers] = useMutation(GET_DELIVERY_OFFERS);
// Убираем useMutation для GET_DELIVERY_OFFERS
// Получаем данные клиента
const { data: clientData, loading: clientLoading } = useQuery(GET_CLIENT_ME);
const { data: addressesData, loading: addressesLoading } = useQuery(GET_CLIENT_DELIVERY_ADDRESSES);
// Получаем пользователя из localStorage для проверки авторизации
const [userData, setUserData] = useState<any>(null);
@ -67,7 +67,7 @@ const CartSummary: React.FC = () => {
if (savedCartSummaryState) {
try {
const state = JSON.parse(savedCartSummaryState);
setCurrentStep(state.currentStep || 1);
setStep(state.step || 1);
setSelectedLegalEntity(state.selectedLegalEntity || '');
setSelectedLegalEntityId(state.selectedLegalEntityId || '');
setIsIndividual(state.isIndividual ?? true);
@ -87,7 +87,7 @@ const CartSummary: React.FC = () => {
useEffect(() => {
if (typeof window !== 'undefined') {
const stateToSave = {
currentStep,
step,
selectedLegalEntity,
selectedLegalEntityId,
isIndividual,
@ -99,7 +99,7 @@ const CartSummary: React.FC = () => {
};
localStorage.setItem('cartSummaryState', JSON.stringify(stateToSave));
}
}, [currentStep, selectedLegalEntity, selectedLegalEntityId, isIndividual, selectedDeliveryAddress, recipientName, recipientPhone, paymentMethod, consent]);
}, [step, selectedLegalEntity, selectedLegalEntityId, isIndividual, selectedDeliveryAddress, recipientName, recipientPhone, paymentMethod, consent]);
// Инициализация данных получателя
useEffect(() => {
@ -134,176 +134,30 @@ const CartSummary: React.FC = () => {
};
}, []);
// Функция для загрузки офферов доставки
const loadDeliveryOffers = async () => {
if (!selectedDeliveryAddress || !recipientName || !recipientPhone || items.length === 0) {
return;
}
setLoadingOffers(true);
setOffersError("");
try {
// Подготавливаем данные для API
const deliveryOffersInput = {
items: items.map(item => {
// Извлекаем срок поставки из deliveryTime товара
let deliveryDays = 0;
if (item.deliveryTime) {
const match = item.deliveryTime.match(/(\d+)/);
if (match) {
deliveryDays = parseInt(match[0]);
}
}
return {
name: item.name,
article: item.article || '',
brand: item.brand || '',
price: item.price,
quantity: item.quantity,
weight: item.weight || 500, // Примерный вес в граммах
dimensions: "10x10x5", // Примерные размеры
deliveryTime: deliveryDays, // Срок поставки товара в днях
offerKey: item.offerKey,
isExternal: item.isExternal
};
}),
deliveryAddress: selectedDeliveryAddress,
recipientName,
recipientPhone
};
const { data } = await getDeliveryOffers({
variables: { input: deliveryOffersInput }
});
if (data?.getDeliveryOffers?.success && data.getDeliveryOffers.offers && Array.isArray(data.getDeliveryOffers.offers) && data.getDeliveryOffers.offers.length > 0) {
setDeliveryOffers(data.getDeliveryOffers.offers);
setOffersError('');
// Автоматически выбираем первый оффер
const firstOffer = data.getDeliveryOffers.offers[0];
setSelectedDeliveryOffer(firstOffer);
// Обновляем стоимость доставки в корзине
updateDelivery({
address: selectedDeliveryAddress,
cost: firstOffer.cost,
date: firstOffer.deliveryDate,
time: firstOffer.deliveryTime
});
} else {
const errorMessage = data?.getDeliveryOffers?.error || 'Не удалось получить варианты доставки';
setOffersError(errorMessage);
// Добавляем стандартные варианты доставки как fallback
const standardOffers = data?.getDeliveryOffers?.offers || [
{
id: 'standard',
name: 'Стандартная доставка',
description: 'Доставка в течение 3-5 рабочих дней',
deliveryDate: 'в течение 3-5 рабочих дней',
deliveryTime: '',
cost: 500
},
{
id: 'express',
name: 'Экспресс доставка',
description: 'Доставка на следующий день',
deliveryDate: 'завтра',
deliveryTime: '10:00-18:00',
cost: 1000
}
];
setDeliveryOffers(standardOffers);
setSelectedDeliveryOffer(standardOffers[0]);
updateDelivery({
address: selectedDeliveryAddress,
cost: standardOffers[0].cost,
date: standardOffers[0].deliveryDate,
time: standardOffers[0].deliveryTime
});
}
} catch (error) {
setOffersError('Ошибка загрузки вариантов доставки');
// Добавляем стандартные варианты доставки как fallback при ошибке
const standardOffers = [
{
id: 'standard',
name: 'Стандартная доставка',
description: 'Доставка в течение 3-5 рабочих дней',
deliveryDate: 'в течение 3-5 рабочих дней',
deliveryTime: '',
cost: 500
}
];
setDeliveryOffers(standardOffers);
setSelectedDeliveryOffer(standardOffers[0]);
updateDelivery({
address: selectedDeliveryAddress,
cost: standardOffers[0].cost,
date: standardOffers[0].deliveryDate,
time: standardOffers[0].deliveryTime
});
} finally {
setLoadingOffers(false);
}
};
// Автоматическая загрузка офферов при изменении ключевых данных
useEffect(() => {
if (selectedDeliveryAddress && recipientName && recipientPhone && items.length > 0) {
// Загружаем офферы с небольшой задержкой для избежания множественных запросов
const timeoutId = setTimeout(() => {
loadDeliveryOffers();
}, 500);
return () => clearTimeout(timeoutId);
}
}, [selectedDeliveryAddress, recipientName, recipientPhone, items.length]);
const handleProceedToStep2 = () => {
if (!selectedDeliveryAddress) {
setError("Пожалуйста, выберите адрес доставки.");
if (!recipientName.trim()) {
toast.error('Пожалуйста, введите имя получателя');
return;
}
if (summary.totalItems === 0) {
setError("Корзина пуста. Добавьте товары для оформления заказа.");
if (!recipientPhone.trim()) {
toast.error('Пожалуйста, введите телефон получателя');
return;
}
if (!selectedDeliveryOffer) {
setError("Пожалуйста, выберите способ доставки.");
if (!selectedDeliveryAddress.trim()) {
toast.error('Пожалуйста, выберите адрес доставки');
return;
}
// Проверяем достаточность средств для оплаты с баланса
if (paymentMethod === 'balance' && !isIndividual) {
const defaultContract = clientData?.clientMe?.contracts?.find((contract: any) => contract.isDefault && contract.isActive);
const finalAmount = summary.totalPrice - summary.totalDiscount + (selectedDeliveryOffer?.cost || summary.deliveryPrice);
const availableBalance = (defaultContract?.balance || 0) + (defaultContract?.creditLimit || 0);
if (availableBalance < finalAmount) {
setError("Недостаточно средств на балансе для оплаты заказа. Выберите другой способ оплаты.");
return;
}
}
setError("");
setCurrentStep(2);
updateDelivery({
address: selectedDeliveryAddress,
cost: 0,
date: 'Включена в стоимость товаров',
time: 'Способ доставки указан в адресе'
});
setStep(2);
};
const handleBackToStep1 = () => {
setCurrentStep(1);
setStep(1);
};
const handleSubmit = async () => {
@ -339,7 +193,7 @@ const CartSummary: React.FC = () => {
deliveryAddress: selectedDeliveryAddress || delivery.address,
legalEntityId: !isIndividual ? selectedLegalEntityId : null,
paymentMethod: paymentMethod,
comment: orderComment || `Адрес доставки: ${selectedDeliveryAddress}. ${!isIndividual && selectedLegalEntity ? `Юридическое лицо: ${selectedLegalEntity}.` : 'Физическое лицо.'} Способ оплаты: ${getPaymentMethodName(paymentMethod)}. Доставка: ${selectedDeliveryOffer?.name || 'Стандартная доставка'} (${selectedDeliveryOffer?.deliveryDate || ''} ${selectedDeliveryOffer?.deliveryTime || ''}).`,
comment: orderComment || `Адрес доставки: ${selectedDeliveryAddress}. ${!isIndividual && selectedLegalEntity ? `Юридическое лицо: ${selectedLegalEntity}.` : 'Физическое лицо.'} Способ оплаты: ${getPaymentMethodName(paymentMethod)}. Доставка: ${selectedDeliveryAddress}.`,
items: selectedItems.map(item => ({
productId: item.productId,
externalId: item.offerKey,
@ -367,14 +221,6 @@ const CartSummary: React.FC = () => {
localStorage.removeItem('cartSummaryState');
}
window.location.href = `/payment/success?orderId=${order.id}&orderNumber=${order.orderNumber}&paymentMethod=balance`;
} else if (paymentMethod === 'invoice') {
// Для оплаты по реквизитам - переходим на страницу с реквизитами
clearCart();
// Очищаем сохраненное состояние оформления заказа
if (typeof window !== 'undefined') {
localStorage.removeItem('cartSummaryState');
}
window.location.href = `/payment/invoice?orderId=${order.id}&orderNumber=${order.orderNumber}`;
} else {
// Для ЮКассы - создаем платеж и переходим на оплату
const paymentResult = await createPayment({
@ -421,14 +267,12 @@ const CartSummary: React.FC = () => {
return 'ЮКасса (банковские карты)';
case 'balance':
return 'Оплата с баланса';
case 'invoice':
return 'Оплата по реквизитам';
default:
return 'Выберите способ оплаты';
return 'ЮКасса (банковские карты)';
}
};
if (currentStep === 1) {
if (step === 1) {
// Первый шаг - настройка доставки
return (
<div className="w-layout-vflex cart-ditail">
@ -650,107 +494,6 @@ const CartSummary: React.FC = () => {
)}
</div>
{/* Варианты доставки */}
<div className="w-layout-vflex flex-block-66">
<div className="text-block-31" style={{ marginBottom: '12px' }}>Варианты доставки</div>
{loadingOffers && (
<div style={{
padding: '16px',
textAlign: 'center',
fontSize: '14px',
color: '#666'
}}>
Загружаем варианты доставки...
</div>
)}
{offersError && (
<div style={{
padding: '12px',
backgroundColor: '#FEF3C7',
border: '1px solid #F59E0B',
borderRadius: '4px',
fontSize: '12px',
color: '#92400E',
marginBottom: '12px'
}}>
{offersError}
</div>
)}
{deliveryOffers.length > 0 && !loadingOffers && (
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
{deliveryOffers.map((offer, index) => (
<div
key={offer.id}
onClick={() => {
setSelectedDeliveryOffer(offer);
updateDelivery({
address: selectedDeliveryAddress,
cost: offer.cost,
date: offer.deliveryDate,
time: offer.deliveryTime
});
}}
style={{
padding: '12px',
border: selectedDeliveryOffer?.id === offer.id ? '2px solid #007bff' : '1px solid #dee2e6',
borderRadius: '8px',
cursor: 'pointer',
backgroundColor: selectedDeliveryOffer?.id === offer.id ? '#f8f9fa' : 'white',
transition: 'all 0.2s'
}}
onMouseEnter={(e) => {
if (selectedDeliveryOffer?.id !== offer.id) {
e.currentTarget.style.backgroundColor = '#f8f9fa';
}
}}
onMouseLeave={(e) => {
if (selectedDeliveryOffer?.id !== offer.id) {
e.currentTarget.style.backgroundColor = 'white';
}
}}
>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<div style={{ flex: 1 }}>
<div style={{ fontWeight: 500, fontSize: '14px', marginBottom: '4px' }}>
{offer.name}
</div>
<div style={{ fontSize: '12px', color: '#666', marginBottom: '4px' }}>
{offer.description}
</div>
<div style={{ fontSize: '12px', color: '#007bff' }}>
{offer.deliveryDate} {offer.deliveryTime}
</div>
</div>
<div style={{
fontWeight: 500,
fontSize: '14px',
color: offer.cost === 0 ? '#28a745' : '#333'
}}>
{offer.cost === 0 ? 'Бесплатно' : `${offer.cost}`}
</div>
</div>
</div>
))}
</div>
)}
{deliveryOffers.length === 0 && !loadingOffers && selectedDeliveryAddress && (
<div style={{
padding: '16px',
textAlign: 'center',
fontSize: '14px',
color: '#666',
border: '1px dashed #dee2e6',
borderRadius: '8px'
}}>
Выберите адрес доставки для просмотра вариантов
</div>
)}
</div>
{/* Способ оплаты */}
<div className="w-layout-vflex flex-block-58" style={{ position: 'relative' }} ref={paymentDropdownRef}>
<div className="text-block-31">Способ оплаты</div>
@ -856,24 +599,19 @@ const CartSummary: React.FC = () => {
);
}
const contracts = clientData?.clientMe?.contracts || [];
const defaultContract = contracts.find((contract: any) => contract.isDefault && contract.isActive);
const activeContracts = clientData?.clientMe?.contracts?.filter((contract: any) => contract.isActive) || [];
const defaultContract = activeContracts.find((contract: any) => contract.isDefault) || activeContracts[0];
if (!defaultContract) {
const anyActiveContract = contracts.find((contract: any) => contract.isActive);
if (!anyActiveContract) {
return (
<span style={{ fontWeight: 500, color: '#e74c3c' }}>
Нет активных контрактов
</span>
);
}
return (
<span style={{ color: '#EF4444', fontWeight: 500 }}>
Активный договор не найден
</span>
);
}
const contract = defaultContract || contracts.find((contract: any) => contract.isActive);
const balance = contract?.balance || 0;
const creditLimit = contract?.creditLimit || 0;
const balance = defaultContract.balance || 0;
const creditLimit = defaultContract.creditLimit || 0;
const totalAvailable = balance + creditLimit;
return (
@ -884,59 +622,10 @@ const CartSummary: React.FC = () => {
})()}
</div>
</div>
<div
onClick={() => {
setPaymentMethod('invoice');
setShowPaymentDropdown(false);
}}
style={{
padding: '12px 16px',
cursor: 'pointer',
backgroundColor: paymentMethod === 'invoice' ? '#f8f9fa' : 'white',
fontSize: '14px'
}}
onMouseEnter={(e) => {
if (paymentMethod !== 'invoice') {
e.currentTarget.style.backgroundColor = '#f8f9fa';
}
}}
onMouseLeave={(e) => {
if (paymentMethod !== 'invoice') {
e.currentTarget.style.backgroundColor = 'white';
}
}}
>
Оплата по реквизитам
</div>
</>
)}
</div>
)}
{/* Показываем предупреждение для оплаты с баланса если недостаточно средств */}
{paymentMethod === 'balance' && !isIndividual && (
(() => {
const defaultContract = clientData?.clientMe?.contracts?.find((contract: any) => contract.isDefault && contract.isActive);
const availableBalance = (defaultContract?.balance || 0) + (defaultContract?.creditLimit || 0);
const finalAmount = summary.totalPrice - summary.totalDiscount + (selectedDeliveryOffer?.cost || summary.deliveryPrice);
const isInsufficientFunds = availableBalance < finalAmount;
return isInsufficientFunds ? (
<div style={{
marginTop: '8px',
padding: '8px 12px',
backgroundColor: '#FEF3C7',
border: '1px solid #F59E0B',
borderRadius: '4px',
fontSize: '12px',
color: '#92400E'
}}>
Недостаточно средств на балансе для оплаты заказа
</div>
) : null;
})()
)}
</div>
<div className="px-line"></div>
@ -958,10 +647,7 @@ const CartSummary: React.FC = () => {
<div className="w-layout-hflex flex-block-59">
<div className="text-block-21-copy-copy">Доставка</div>
<div className="text-block-33">
{selectedDeliveryOffer?.cost === 0
? 'Бесплатно'
: formatPrice(selectedDeliveryOffer?.cost || summary.deliveryPrice)
}
Включена в стоимость товаров
</div>
</div>
</div>
@ -972,7 +658,7 @@ const CartSummary: React.FC = () => {
<div className="text-block-32">Итого</div>
<h4 className="heading-9-copy-copy">
{formatPrice(
summary.totalPrice - summary.totalDiscount + (selectedDeliveryOffer?.cost || summary.deliveryPrice)
summary.totalPrice - summary.totalDiscount + (selectedDeliveryAddress ? 0 : summary.deliveryPrice)
)}
</h4>
</div>
@ -980,10 +666,10 @@ const CartSummary: React.FC = () => {
<button
className="submit-button fill w-button"
onClick={handleProceedToStep2}
disabled={summary.totalItems === 0}
disabled={summary.totalItems === 0 || !consent}
style={{
opacity: summary.totalItems === 0 ? 0.5 : 1,
cursor: summary.totalItems === 0 ? 'not-allowed' : 'pointer'
opacity: summary.totalItems === 0 || !consent ? 0.5 : 1,
cursor: summary.totalItems === 0 || !consent ? 'not-allowed' : 'pointer'
}}
>
Оформить заказ
@ -1035,10 +721,9 @@ const CartSummary: React.FC = () => {
style={{
width: '100%',
padding: '8px 12px',
border: '1px solid #D0D0D0',
borderRadius: '4px',
fontSize: '14px',
fontFamily: 'inherit'
border: 'none',
outline: 'none',
boxShadow: 'none',
}}
/>
</div>
@ -1051,10 +736,9 @@ const CartSummary: React.FC = () => {
style={{
width: '100%',
padding: '8px 12px',
border: '1px solid #D0D0D0',
borderRadius: '4px',
fontSize: '14px',
fontFamily: 'inherit'
border: 'none',
outline: 'none',
boxShadow: 'none',
}}
/>
</div>
@ -1075,9 +759,19 @@ const CartSummary: React.FC = () => {
{paymentMethod === 'balance' && !isIndividual && (
<div style={{ fontSize: '12px', color: '#666', marginTop: '4px' }}>
{(() => {
const defaultContract = clientData?.clientMe?.contracts?.find((contract: any) => contract.isDefault && contract.isActive);
const balance = defaultContract?.balance || 0;
const creditLimit = defaultContract?.creditLimit || 0;
const activeContracts = clientData?.clientMe?.contracts?.filter((contract: any) => contract.isActive) || [];
const defaultContract = activeContracts.find((contract: any) => contract.isDefault) || activeContracts[0];
if (!defaultContract) {
return (
<span style={{ color: '#EF4444', fontWeight: 500 }}>
Активный договор не найден
</span>
);
}
const balance = defaultContract.balance || 0;
const creditLimit = defaultContract.creditLimit || 0;
const totalAvailable = balance + creditLimit;
return (
@ -1131,10 +825,7 @@ const CartSummary: React.FC = () => {
<div className="w-layout-hflex flex-block-59">
<div className="text-block-21-copy-copy">Доставка</div>
<div className="text-block-33">
{selectedDeliveryOffer?.cost === 0
? 'Бесплатно'
: formatPrice(selectedDeliveryOffer?.cost || summary.deliveryPrice)
}
Включена в стоимость товаров
</div>
</div>
</div>
@ -1145,7 +836,7 @@ const CartSummary: React.FC = () => {
<div className="text-block-32">Итого</div>
<h4 className="heading-9-copy-copy">
{formatPrice(
summary.totalPrice - summary.totalDiscount + (selectedDeliveryOffer?.cost || summary.deliveryPrice)
summary.totalPrice - summary.totalDiscount + (selectedDeliveryAddress ? 0 : summary.deliveryPrice)
)}
</h4>
</div>
@ -1188,15 +879,14 @@ const CartSummary: React.FC = () => {
<button
className="submit-button fill w-button"
onClick={handleSubmit}
disabled={summary.totalItems === 0 || isProcessing || !recipientName.trim() || !recipientPhone.trim()}
disabled={summary.totalItems === 0 || isProcessing || !recipientName.trim() || !recipientPhone.trim() || !consent}
style={{
opacity: (summary.totalItems === 0 || isProcessing || !recipientName.trim() || !recipientPhone.trim()) ? 0.5 : 1,
cursor: (summary.totalItems === 0 || isProcessing || !recipientName.trim() || !recipientPhone.trim()) ? 'not-allowed' : 'pointer'
opacity: (summary.totalItems === 0 || isProcessing || !recipientName.trim() || !recipientPhone.trim() || !consent) ? 0.5 : 1,
cursor: (summary.totalItems === 0 || isProcessing || !recipientName.trim() || !recipientPhone.trim() || !consent) ? 'not-allowed' : 'pointer'
}}
>
{isProcessing ? 'Оформляем заказ...' :
paymentMethod === 'balance' ? 'Оплатить с баланса' :
paymentMethod === 'invoice' ? 'Выставить счёт' :
'Оплатить'}
</button>

View File

@ -208,7 +208,7 @@ const CatalogGroupsSection: React.FC<CatalogGroupsSectionProps> = ({
vehicleId,
...(ssd && ssd.trim() !== '' && { ssd })
},
skip: !catalogCode || !vehicleId || catalogType !== 'quickGroups',
skip: !catalogCode || vehicleId === undefined || vehicleId === null || catalogType !== 'quickGroups',
errorPolicy: 'all'
}
);

View File

@ -35,7 +35,7 @@ const CatalogProductCard: React.FC<CatalogProductCardProps> = ({
priceElement,
onAddToCart,
}) => {
const { addToFavorites, removeFromFavorites, isFavorite } = useFavorites();
const { addToFavorites, removeFromFavorites, isFavorite, favorites } = useFavorites();
// Обрабатываем пустое изображение - используем SVG-заглушку вместо мокап-фотки
const displayImage = image || 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEwIiBoZWlnaHQ9IjE5MCIgdmlld0JveD0iMCAwIDIxMCAxOTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMTAiIGhlaWdodD0iMTkwIiBmaWxsPSIjRjNGNEY2Ii8+CjxwYXRoIGQ9Ik04NSA5NUw5NSA4NUwxMjUgMTE1TDE0MCA5NUwxNjUgMTIwSDE2NVY5MEg0NVY5MEw4NSA5NVoiIGZpbGw9IiNEMUQ1REIiLz4KPGNpcmNsZSBjeD0iNzUiIGN5PSI3NSIgcj0iMTAiIGZpbGw9IiNEMUQ1REIiLz4KPHRleHQgeD0iMTA1IiB5PSIxNTAiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzlDQTNBRiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+Tm8gaW1hZ2U8L3RleHQ+Cjwvc3ZnPgo=';
@ -57,9 +57,18 @@ const CatalogProductCard: React.FC<CatalogProductCardProps> = ({
const numericPrice = parseFloat(price.replace(/[^\d.,]/g, '').replace(',', '.')) || 0;
if (isItemFavorite) {
// Создаем ID для удаления
const id = `${productId || offerKey || ''}:${articleNumber}:${brandName || brand}`;
removeFromFavorites(id);
// Находим товар в избранном по правильному ID
const favoriteItem = favorites.find((fav: any) => {
// Проверяем по разным комбинациям идентификаторов
if (productId && fav.productId === productId) return true;
if (offerKey && fav.offerKey === offerKey) return true;
if (fav.article === articleNumber && fav.brand === (brandName || brand)) return true;
return false;
});
if (favoriteItem) {
removeFromFavorites(favoriteItem.id);
}
} else {
// Добавляем в избранное
addToFavorites({

View File

@ -33,7 +33,7 @@ const CategoriesSection: React.FC<CategoriesSectionProps> = ({
vehicleId,
...(ssd && ssd.trim() !== '' && { ssd })
},
skip: !catalogCode || !vehicleId,
skip: !catalogCode || vehicleId === undefined || vehicleId === null,
errorPolicy: 'all'
}
);

View File

@ -1,6 +1,8 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { useCart } from "@/contexts/CartContext";
import { useFavorites } from "@/contexts/FavoritesContext";
import toast from "react-hot-toast";
import CartIcon from "./CartIcon";
const INITIAL_OFFERS_LIMIT = 5;
@ -46,13 +48,21 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
partsIndexPowered = false
}) => {
const { addItem } = useCart();
const { addToFavorites, removeFromFavorites, isFavorite } = useFavorites();
const { addToFavorites, removeFromFavorites, isFavorite, favorites } = useFavorites();
const [visibleOffersCount, setVisibleOffersCount] = useState(INITIAL_OFFERS_LIMIT);
const [quantities, setQuantities] = useState<{ [key: number]: number }>(
offers.reduce((acc, _, index) => ({ ...acc, [index]: 1 }), {})
);
const [inputValues, setInputValues] = useState<{ [key: number]: string }>(
offers.reduce((acc, _, index) => ({ ...acc, [index]: "1" }), {})
);
const [quantityErrors, setQuantityErrors] = useState<{ [key: number]: string }>({});
useEffect(() => {
setInputValues(offers.reduce((acc, _, index) => ({ ...acc, [index]: "1" }), {}));
setQuantities(offers.reduce((acc, _, index) => ({ ...acc, [index]: 1 }), {}));
}, [offers.length]);
const displayedOffers = offers.slice(0, visibleOffersCount);
const hasMoreOffers = visibleOffersCount < offers.length;
@ -82,31 +92,44 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
return match ? parseInt(match[0]) : 0;
};
const handleQuantityInput = (index: number, value: string) => {
const offer = offers[index];
const availableStock = parseStock(offer.pcs);
let num = parseInt(value, 10);
if (isNaN(num) || num < 1) num = 1;
if (num > availableStock) {
window.alert(`Максимум ${availableStock} шт.`);
return;
}
setQuantities(prev => ({ ...prev, [index]: num }));
const handleInputChange = (idx: number, val: string) => {
setInputValues(prev => ({ ...prev, [idx]: val }));
if (val === "") return;
const valueNum = Math.max(1, parseInt(val, 10) || 1);
setQuantities(prev => ({ ...prev, [idx]: valueNum }));
};
const handleAddToCart = (offer: CoreProductCardOffer, index: number) => {
const handleInputBlur = (idx: number) => {
if (inputValues[idx] === "") {
setInputValues(prev => ({ ...prev, [idx]: "1" }));
setQuantities(prev => ({ ...prev, [idx]: 1 }));
}
};
const handleMinus = (idx: number) => {
setQuantities(prev => {
const newVal = Math.max(1, (prev[idx] || 1) - 1);
setInputValues(vals => ({ ...vals, [idx]: newVal.toString() }));
return { ...prev, [idx]: newVal };
});
};
const handlePlus = (idx: number, maxCount?: number) => {
setQuantities(prev => {
let newVal = (prev[idx] || 1) + 1;
if (maxCount !== undefined) newVal = Math.min(newVal, maxCount);
setInputValues(vals => ({ ...vals, [idx]: newVal.toString() }));
return { ...prev, [idx]: newVal };
});
};
const handleAddToCart = async (offer: CoreProductCardOffer, index: number) => {
const quantity = quantities[index] || 1;
const availableStock = parseStock(offer.pcs);
// Проверяем наличие
if (quantity > availableStock) {
alert(`Недостаточно товара в наличии. Доступно: ${availableStock} шт.`);
return;
}
const numericPrice = parsePrice(offer.price);
addItem({
const result = await addItem({
productId: offer.productId,
offerKey: offer.offerKey,
name: name,
@ -116,6 +139,7 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
price: numericPrice,
currency: offer.currency || 'RUB',
quantity: quantity,
stock: availableStock, // передаем информацию о наличии
deliveryTime: parseDeliveryTime(offer.days),
warehouse: offer.warehouse || 'Склад',
supplier: offer.supplier || (offer.isExternal ? 'AutoEuro' : 'Protek'),
@ -123,8 +147,22 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
image: image,
});
// Показываем уведомление о добавлении
alert(`Товар "${brand} ${article}" добавлен в корзину (${quantity} шт.)`);
if (result.success) {
// Показываем тоастер вместо alert
toast.success(
<div>
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{`${brand} ${article} (${quantity} шт.)`}</div>
</div>,
{
duration: 3000,
icon: <CartIcon size={20} color="#fff" />,
}
);
} else {
// Показываем ошибку
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
}
};
// Обработчик клика по сердечку
@ -133,9 +171,18 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
e.stopPropagation();
if (isItemFavorite) {
// Создаем ID для удаления
const id = `${offers[0]?.productId || offers[0]?.offerKey || ''}:${article}:${brand}`;
removeFromFavorites(id);
// Находим товар в избранном и удаляем по правильному ID
const favoriteItem = favorites.find((item: any) => {
// Проверяем по разным комбинациям идентификаторов
if (offers[0]?.productId && item.productId === offers[0].productId) return true;
if (offers[0]?.offerKey && item.offerKey === offers[0].offerKey) return true;
if (item.article === article && item.brand === brand) return true;
return false;
});
if (favoriteItem) {
removeFromFavorites(favoriteItem.id);
}
} else {
// Добавляем в избранное
const bestOffer = offers[0]; // Берем первое предложение как лучшее
@ -272,6 +319,7 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
<div className="w-layout-vflex product-list-search-s1">
{displayedOffers.map((offer, idx) => {
const isLast = idx === displayedOffers.length - 1;
const maxCount = parseStock(offer.pcs);
return (
<div
className="w-layout-hflex product-item-search-s1"
@ -298,43 +346,48 @@ const CoreProductCard: React.FC<CoreProductCardProps> = ({
<div className="w-layout-hflex add-to-cart-block-s1">
<div className="w-layout-hflex flex-block-82">
<div className="w-layout-hflex pcs-cart-s1">
<button
type="button"
<div
className="minus-plus"
onClick={() => handleQuantityInput(idx, ((quantities[idx] || 1) - 1).toString())}
onClick={() => handleMinus(idx)}
style={{ cursor: 'pointer' }}
aria-label="Уменьшить количество"
tabIndex={0}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && handleMinus(idx)}
role="button"
>
<div className="pluspcs w-embed">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 10.5V9.5H14V10.5H6Z" fill="currentColor" />
</svg>
</div>
</button>
</div>
<div className="input-pcs">
<input
type="number"
min={1}
max={parseStock(offer.pcs)}
value={quantities[idx] || 1}
onChange={e => handleQuantityInput(idx, e.target.value)}
max={maxCount}
value={inputValues[idx]}
onChange={e => handleInputChange(idx, e.target.value)}
onBlur={() => handleInputBlur(idx)}
className="text-block-26 w-full text-center outline-none"
aria-label="Количество"
/>
</div>
<button
type="button"
<div
className="minus-plus"
onClick={() => handleQuantityInput(idx, ((quantities[idx] || 1) + 1).toString())}
onClick={() => handlePlus(idx, maxCount)}
style={{ cursor: 'pointer' }}
aria-label="Увеличить количество"
tabIndex={0}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && handlePlus(idx, maxCount)}
role="button"
>
<div className="pluspcs w-embed">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 10.5V9.5H14V10.5H6ZM9.5 6H10.5V14H9.5V6Z" fill="currentColor" />
</svg>
</div>
</button>
</div>
</div>
<button
type="button"

View File

@ -0,0 +1,25 @@
import React from 'react';
interface DeleteCartIconProps {
size?: number;
color?: string;
}
const DeleteCartIcon: React.FC<DeleteCartIconProps> = ({ size = 24, color = '#ec1c24' }) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 30 30"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z"
fill={color}
/>
</svg>
);
};
export default DeleteCartIcon;

View File

@ -1,4 +1,5 @@
import React, { useState } from "react";
import { useRouter } from "next/router";
import Filters, { FilterConfig } from "./Filters";
import { useFavorites } from "@/contexts/FavoritesContext";
@ -8,9 +9,9 @@ interface FavoriteListProps {
onFilterChange?: (type: string, value: any) => void;
searchQuery?: string;
onSearchChange?: (value: string) => void;
sortBy?: 'name' | 'brand' | 'price' | 'date';
sortBy?: 'name' | 'brand' | 'date';
sortOrder?: 'asc' | 'desc';
onSortChange?: (sortBy: 'name' | 'brand' | 'price' | 'date') => void;
onSortChange?: (sortBy: 'name' | 'brand' | 'date') => void;
onSortOrderChange?: (sortOrder: 'asc' | 'desc') => void;
}
@ -25,6 +26,7 @@ const FavoriteList: React.FC<FavoriteListProps> = ({
onSortChange,
onSortOrderChange
}) => {
const router = useRouter();
const { favorites, removeFromFavorites, clearFavorites } = useFavorites();
const handleRemove = (id: string) => {
@ -35,6 +37,14 @@ const FavoriteList: React.FC<FavoriteListProps> = ({
clearFavorites();
};
// Функция для поиска товара
const handleSearchItem = (item: any) => {
// Формируем поисковый запрос из бренда и артикула
const searchQuery = `${item.brand} ${item.article}`;
// Переходим на страницу поиска с результатами
router.push(`/search-result?article=${encodeURIComponent(item.article)}&brand=${encodeURIComponent(item.brand)}`);
};
// Состояние для hover на иконке удаления всех
const [removeAllHover, setRemoveAllHover] = useState(false);
// Состояние для hover на корзине отдельного товара
@ -82,11 +92,6 @@ const FavoriteList: React.FC<FavoriteListProps> = ({
case 'brand':
comparison = a.brand.localeCompare(b.brand);
break;
case 'price':
const priceA = a.price || 0;
const priceB = b.price || 0;
comparison = priceA - priceB;
break;
case 'date':
comparison = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
break;
@ -97,29 +102,19 @@ const FavoriteList: React.FC<FavoriteListProps> = ({
return sortOrder === 'asc' ? comparison : -comparison;
});
const formatPrice = (price?: number, currency?: string) => {
if (!price) {
return 'Цена не указана';
}
if (currency === 'RUB') {
return `от ${price.toLocaleString('ru-RU')}`;
}
return `от ${price} ${currency || ''}`;
};
const handleSortClick = (newSortBy: 'name' | 'brand' | 'price' | 'date') => {
const handleSortClick = (newSortBy: 'name' | 'brand' | 'date') => {
if (sortBy === newSortBy) {
// Если тот же столбец, меняем порядок
onSortOrderChange?.(sortOrder === 'asc' ? 'desc' : 'asc');
} else {
// Если новый столбец, устанавливаем его и порядок по умолчанию
onSortChange?.(newSortBy);
onSortOrderChange?.(newSortBy === 'price' ? 'asc' : 'desc');
onSortOrderChange?.(newSortBy === 'date' ? 'desc' : 'asc');
}
};
// SVG-галочки для сортировки — всегда видны у всех колонок
const getSortIcon = (columnSort: 'name' | 'brand' | 'price' | 'date') => {
const getSortIcon = (columnSort: 'name' | 'brand' | 'date') => {
const isActive = sortBy === columnSort;
const isAsc = sortOrder === 'asc';
const color = isActive ? 'var(--_button---primary)' : '#94a3b8';
@ -176,6 +171,9 @@ const FavoriteList: React.FC<FavoriteListProps> = ({
</div>
<div className="sort-item-comments">Комментарий</div>
</div>
{/* <div className="w-layout-hflex add-to-cart-block-copy">
<div className="text-sm font-medium text-gray-600">Действия</div>
</div> */}
{favorites.length > 0 && (
<div
className="w-layout-hflex select-all-block"
@ -233,12 +231,24 @@ const FavoriteList: React.FC<FavoriteListProps> = ({
</div>
</div>
<div className="w-layout-hflex add-to-cart-block-copy">
<h4
className="heading-9-copy-copy cursor-pointer hover:text-blue-600 flex items-center gap-1"
onClick={() => handleSortClick('price')}
>
{formatPrice(item.price, item.currency)} {getSortIcon('price')}
</h4>
<button
onClick={() => handleSearchItem(item)}
className="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors duration-200 flex items-center gap-2 text-sm font-medium"
style={{color: '#fff'}}
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="11" cy="11" r="8" stroke="currentColor" strokeWidth="2"/>
<path d="m21 21-4.35-4.35" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
Поиск
</button>
<div className="w-layout-hflex control-element-copy">
{/* Корзина с hover-эффектом для удаления товара */}
<span

View File

@ -24,7 +24,7 @@ const Footer = () => (
<div data-hover="false" data-delay="0" className="dropdown-3 w-dropdown">
<div className="dropdown-toggle-2 w-dropdown-toggle">
<div className="text-block-17">Покупателям</div>
<div className="code-embed-10 w-embed"><svg width="currentwight" height="currentheight" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentcolor"></path></svg></div>
<div className="code-embed-10 w-embed"><svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentColor"></path></svg></div>
</div>
<nav className="dropdown-list-3 w-dropdown-list">
<a href="#" className="dropdown-link-2 w-dropdown-link">Оплата</a>
@ -43,7 +43,7 @@ const Footer = () => (
<div data-hover="false" data-delay="0" className="dropdown-3 w-dropdown">
<div className="dropdown-toggle-2 w-dropdown-toggle">
<div className="text-block-17">Сотрудничество</div>
<div className="code-embed-10 w-embed"><svg width="currentwight" height="currentheight" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentcolor"></path></svg></div>
<div className="code-embed-10 w-embed"><svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentColor"></path></svg></div>
</div>
<nav className="dropdown-list-3 w-dropdown-list">
<a href="#" className="dropdown-link-2 w-dropdown-link">Поставщикам</a>
@ -62,7 +62,7 @@ const Footer = () => (
<div data-hover="false" data-delay="0" className="dropdown-3 w-dropdown">
<div className="dropdown-toggle-2 w-dropdown-toggle">
<div className="text-block-17">PROTEK</div>
<div className="code-embed-10 w-embed"><svg width="currentwight" height="currentheight" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentcolor"></path></svg></div>
<div className="code-embed-10 w-embed"><svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentColor"></path></svg></div>
</div>
<nav className="dropdown-list-3 w-dropdown-list">
<a href="#" className="dropdown-link-2 w-dropdown-link">Вакансии</a>
@ -81,7 +81,7 @@ const Footer = () => (
<div data-hover="false" data-delay="0" className="dropdown-3 w-dropdown">
<div className="dropdown-toggle-2 w-dropdown-toggle">
<div className="text-block-17">Оферта</div>
<div className="code-embed-10 w-embed"><svg width="currentwight" height="currentheight" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentcolor"></path></svg></div>
<div className="code-embed-10 w-embed"><svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" clipRule="evenodd" d="M2 6.74036L3.28446 5.5L9 11.0193L14.7155 5.5L16 6.74036L9 13.5L2 6.74036Z" fill="currentColor"></path></svg></div>
</div>
<nav className="dropdown-list-3 w-dropdown-list">
<a href="#" className="dropdown-link-2 w-dropdown-link">Поставщикам</a>

View File

@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { useLazyQuery } from '@apollo/client';
import { LaximoFulltextSearchResult, LaximoFulltextDetail, LaximoOEMResult } from '@/types/laximo';
import { SEARCH_LAXIMO_FULLTEXT, SEARCH_LAXIMO_OEM } from '@/lib/graphql';
import { GET_LAXIMO_FULLTEXT_SEARCH, SEARCH_LAXIMO_OEM } from '@/lib/graphql/laximo';
import PartDetailCard from './PartDetailCard';
interface FulltextSearchSectionProps {
@ -17,7 +17,7 @@ const FulltextSearchSection: React.FC<FulltextSearchSectionProps> = ({
}) => {
const [searchQuery, setSearchQuery] = useState('');
const [executeSearch, { data, loading, error }] = useLazyQuery(SEARCH_LAXIMO_FULLTEXT, {
const [executeSearch, { data, loading, error }] = useLazyQuery(GET_LAXIMO_FULLTEXT_SEARCH, {
errorPolicy: 'all'
});
@ -31,6 +31,8 @@ const FulltextSearchSection: React.FC<FulltextSearchSectionProps> = ({
return;
}
console.log('SEARCH PARAMS', { catalogCode, vehicleId, searchQuery: searchQuery.trim(), ssd });
executeSearch({
variables: {
catalogCode,
@ -199,6 +201,4 @@ const FulltextSearchSection: React.FC<FulltextSearchSectionProps> = ({
);
};
export default FulltextSearchSection;

View File

@ -187,13 +187,13 @@ const GroupDetailsSection: React.FC<GroupDetailsSectionProps> = ({
const { data, loading, error } = useQuery<{ laximoQuickDetail: LaximoQuickDetail }>(
GET_LAXIMO_QUICK_DETAIL,
{
variables: {
variables: quickGroupId ? {
catalogCode,
vehicleId,
quickGroupId,
ssd
},
skip: !catalogCode || !vehicleId || !quickGroupId || !ssd,
} : undefined,
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !quickGroupId || !ssd || ssd.trim() === '',
errorPolicy: 'all'
}
);

View File

@ -37,10 +37,8 @@ const Header: React.FC<HeaderProps> = ({ onOpenAuthModal = () => console.log('Au
// Если мы находимся на странице search-result, восстанавливаем поисковый запрос
if (router.pathname === '/search-result') {
const { article, brand } = router.query;
if (article && brand && typeof article === 'string' && typeof brand === 'string') {
// Формируем поисковый запрос из артикула и бренда
setSearchQuery(`${brand} ${article}`);
} else if (article && typeof article === 'string') {
if (article && typeof article === 'string') {
// Отображаем только артикул, без бренда
setSearchQuery(article);
}
}
@ -58,6 +56,15 @@ const Header: React.FC<HeaderProps> = ({ onOpenAuthModal = () => console.log('Au
setSearchQuery(q);
}
}
// Если мы находимся на странице деталей автомобиля, восстанавливаем VIN из URL
else if (router.pathname === '/vehicle-search/[brand]/[vehicleId]') {
const { vin } = router.query;
if (vin && typeof vin === 'string') {
setSearchQuery(vin);
} else {
setSearchQuery('');
}
}
// Для других страниц очищаем поисковый запрос
else {
setSearchQuery('');
@ -321,11 +328,31 @@ const Header: React.FC<HeaderProps> = ({ onOpenAuthModal = () => console.log('Au
const catalogCode = (vehicle as any).catalog || vehicle.brand.toLowerCase();
console.log('🚗 Переход на страницу автомобиля:', { catalogCode, vehicleId: vehicle.vehicleid, ssd: vehicle.ssd });
// Создаем параметры URL
const urlParams = new URLSearchParams();
// Добавляем SSD если есть
if (vehicle.ssd) {
urlParams.set('ssd', vehicle.ssd);
}
// Добавляем VIN-номер в URL, если поиск был по VIN
if (searchType === 'vin' && searchQuery) {
urlParams.set('vin', searchQuery);
}
// Если переход происходит из поиска автомобилей по артикулу, передаем артикул для автоматического поиска
const currentOEMNumber = oemSearchMode === 'vehicles' ? searchQuery.trim().toUpperCase() : '';
const url = `/vehicle-search/${catalogCode}/${vehicle.vehicleid}?ssd=${vehicle.ssd || ''}${currentOEMNumber ? `&oemNumber=${encodeURIComponent(currentOEMNumber)}` : ''}`;
if (currentOEMNumber) {
urlParams.set('oemNumber', currentOEMNumber);
}
setSearchQuery('');
// Формируем URL
const baseUrl = `/vehicle-search/${catalogCode}/${vehicle.vehicleid}`;
const url = urlParams.toString() ? `${baseUrl}?${urlParams.toString()}` : baseUrl;
// НЕ очищаем поисковый запрос, чтобы он остался в строке поиска
// setSearchQuery('');
router.push(url);
};
@ -346,7 +373,7 @@ const Header: React.FC<HeaderProps> = ({ onOpenAuthModal = () => console.log('Au
<div className="w-layout-hflex flex-block-2">
<div className="w-layout-hflex flex-block-3">
<div className="w-layout-hflex flex-block-77-copy">
<div className="code-embed-4 w-embed"><svg width="currentwidth" height="currenthight" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.51667 8.99167C6.71667 11.35 8.65 13.275 11.0083 14.4833L12.8417 12.65C13.0667 12.425 13.4 12.35 13.6917 12.45C14.625 12.7583 15.6333 12.925 16.6667 12.925C17.125 12.925 17.5 13.3 17.5 13.7583V16.6667C17.5 17.125 17.125 17.5 16.6667 17.5C8.84167 17.5 2.5 11.1583 2.5 3.33333C2.5 2.875 2.875 2.5 3.33333 2.5H6.25C6.70833 2.5 7.08333 2.875 7.08333 3.33333C7.08333 4.375 7.25 5.375 7.55833 6.30833C7.65 6.6 7.58333 6.925 7.35 7.15833L5.51667 8.99167Z" fill="currentColor" /></svg></div>
<div className="code-embed-4 w-embed"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.51667 8.99167C6.71667 11.35 8.65 13.275 11.0083 14.4833L12.8417 12.65C13.0667 12.425 13.4 12.35 13.6917 12.45C14.625 12.7583 15.6333 12.925 16.6667 12.925C17.125 12.925 17.5 13.3 17.5 13.7583V16.6667C17.5 17.125 17.125 17.5 16.6667 17.5C8.84167 17.5 2.5 11.1583 2.5 3.33333C2.5 2.875 2.875 2.5 3.33333 2.5H6.25C6.70833 2.5 7.08333 2.875 7.08333 3.33333C7.08333 4.375 7.25 5.375 7.55833 6.30833C7.65 6.6 7.58333 6.925 7.35 7.15833L5.51667 8.99167Z" fill="currentColor" /></svg></div>
<div className="phone-copy">+7 (495) 260-20-60</div>
</div>
</div>
@ -364,7 +391,7 @@ const Header: React.FC<HeaderProps> = ({ onOpenAuthModal = () => console.log('Au
onClick={() => setMenuOpen((open) => !open)}
style={{ cursor: "pointer" }}
>
<div className="code-embed-5 w-embed"><svg width="currentwidth" height="currenthight" viewBox="0 0 30 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<div className="code-embed-5 w-embed"><svg width="30" height="18" viewBox="0 0 30 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0H30V3H0V0Z" fill="currentColor"></path>
<path d="M0 7.5H30V10.5H0V7.5Z" fill="currentColor"></path>
<path d="M0 15H30V18H0V15Z" fill="currentColor"></path>

View File

@ -1,7 +1,9 @@
import * as React from "react";
import Link from 'next/link';
import { useRouter } from 'next/router';
import { useQuery } from '@apollo/client';
import { useIsClient } from '@/lib/useIsomorphicLayoutEffect';
import { GET_CLIENT_ME } from '@/lib/graphql';
const menuItems = [
{ label: 'Заказы', href: '/profile-orders', icon: 'https://cdn.builder.io/api/v1/image/assets/TEMP/22ecd7e6251abe04521d03f0ac09f73018a8c2c8?placeholderIfAbsent=true&apiKey=f5bc5a2dc9b841d0aba1cc6c74a35920' },
@ -28,6 +30,15 @@ const LKMenu = React.forwardRef<HTMLDivElement>((props, ref) => {
const router = useRouter();
const isClient = useIsClient();
// Получаем данные клиента для проверки наличия юридических лиц
const { data: clientData } = useQuery(GET_CLIENT_ME, {
skip: !isClient,
errorPolicy: 'ignore' // Игнорируем ошибки, чтобы не ломать интерфейс
});
// Проверяем есть ли у клиента юридические лица
const hasLegalEntities = clientData?.clientMe?.legalEntities && clientData.clientMe.legalEntities.length > 0;
const handleLogout = () => {
if (isClient) {
localStorage.removeItem('authToken');
@ -66,31 +77,37 @@ const LKMenu = React.forwardRef<HTMLDivElement>((props, ref) => {
);
})}
</div>
<div className="gap-2.5 self-start px-2.5 pt-2.5 mt-3 whitespace-nowrap text-gray-950">
Финансы
</div>
<div className="flex flex-col mt-3 w-full text-base leading-snug text-gray-600">
{financeItems.map((item) => {
const isActive = normalizePath(router.asPath) === normalizePath(item.href);
return (
<Link href={item.href} key={item.href}>
<div
className={`flex gap-2.5 items-center px-2.5 py-2 w-full whitespace-nowrap rounded-lg ${
isActive ? 'bg-slate-200' : 'bg-white'
}`}
>
<img
loading="lazy"
src={item.icon}
className="object-contain shrink-0 self-stretch my-auto w-5 aspect-square"
alt={item.label}
/>
<div className="self-stretch my-auto text-gray-600">{item.label}</div>
</div>
</Link>
);
})}
</div>
{/* Раздел "Финансы" показываем только если есть юридические лица */}
{hasLegalEntities && (
<>
<div className="gap-2.5 self-start px-2.5 pt-2.5 mt-3 whitespace-nowrap text-gray-950">
Финансы
</div>
<div className="flex flex-col mt-3 w-full text-base leading-snug text-gray-600">
{financeItems.map((item) => {
const isActive = normalizePath(router.asPath) === normalizePath(item.href);
return (
<Link href={item.href} key={item.href}>
<div
className={`flex gap-2.5 items-center px-2.5 py-2 w-full whitespace-nowrap rounded-lg ${
isActive ? 'bg-slate-200' : 'bg-white'
}`}
>
<img
loading="lazy"
src={item.icon}
className="object-contain shrink-0 self-stretch my-auto w-5 aspect-square"
alt={item.label}
/>
<div className="self-stretch my-auto text-gray-600">{item.label}</div>
</div>
</Link>
);
})}
</div>
</>
)}
{/* Кнопка выхода */}
<div className="mt-3">

View File

@ -30,7 +30,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
onSuccess={handleAuthSuccess}
/>
</header>
<main className="pt-[132px]">{children}</main>
<main className="pt-[108px] md:pt-[131px]">{children}</main>
<MobileMenuBottomSection onOpenAuthModal={() => setAuthModalOpen(true)} />
</>
);

View File

@ -3,7 +3,6 @@ import { useRouter } from 'next/router';
import { useLazyQuery } from '@apollo/client';
import { LaximoOEMResult } from '@/types/laximo';
import { SEARCH_LAXIMO_OEM } from '@/lib/graphql';
import BrandSelectionModal from './BrandSelectionModal';
interface PartDetailCardProps {
oem: string;
@ -30,7 +29,6 @@ const PartDetailCard: React.FC<PartDetailCardProps> = ({
}) => {
const router = useRouter();
const [localExpanded, setLocalExpanded] = useState(false);
const [isBrandModalOpen, setIsBrandModalOpen] = useState(false);
// Используем локальное состояние если нет внешнего контроля
const expanded = onToggleExpand ? isExpanded : localExpanded;
@ -53,13 +51,12 @@ const PartDetailCard: React.FC<PartDetailCardProps> = ({
const handleFindOffers = () => {
console.log('🔍 Выбрана деталь для поиска предложений:', name, 'OEM:', oem);
// Показываем модал выбора бренда
setIsBrandModalOpen(true);
// Переходим на страницу выбора бренда
const url = `/vehicle-search/${catalogCode}/${vehicleId}/part/${oem}/brands?detailName=${encodeURIComponent(name || '')}`;
router.push(url);
};
const handleCloseBrandModal = () => {
setIsBrandModalOpen(false);
};
const handleOpenFullInfo = () => {
// Переход на отдельную страницу с детальной информацией о детали
@ -250,13 +247,6 @@ const PartDetailCard: React.FC<PartDetailCardProps> = ({
</div>
)}
{/* Модал выбора бренда */}
<BrandSelectionModal
isOpen={isBrandModalOpen}
onClose={handleCloseBrandModal}
articleNumber={oem}
detailName={name}
/>
</div>
);
};

View File

@ -59,19 +59,13 @@ const ProductListCard: React.FC<ProductListCardProps> = ({
return match ? parseInt(match[0]) : 0;
};
const handleAddToCart = () => {
const handleAddToCart = async () => {
const availableStock = parseStock(stock);
// Проверяем наличие
if (count > availableStock) {
alert(`Недостаточно товара в наличии. Доступно: ${availableStock} шт.`);
return;
}
const numericPrice = parsePrice(price);
const numericOldPrice = oldPrice ? parsePrice(oldPrice) : undefined;
addItem({
const result = await addItem({
productId: productId,
offerKey: offerKey,
name: title,
@ -81,6 +75,7 @@ const ProductListCard: React.FC<ProductListCardProps> = ({
originalPrice: numericOldPrice,
currency: currency,
quantity: count,
stock: availableStock, // передаем информацию о наличии
deliveryTime: deliveryTime || delivery,
warehouse: warehouse || address,
supplier: supplier,
@ -88,8 +83,13 @@ const ProductListCard: React.FC<ProductListCardProps> = ({
image: image,
});
// Показываем уведомление о добавлении
alert(`Товар "${title}" добавлен в корзину (${count} шт.)`);
if (result.success) {
// Показываем уведомление о добавлении
alert(`Товар "${title}" добавлен в корзину (${count} шт.)`);
} else {
// Показываем ошибку
alert(result.error || 'Ошибка при добавлении товара в корзину');
}
};
return (

View File

@ -1,5 +1,7 @@
import React from 'react';
import { useQuery } from '@apollo/client';
import { useIsClient } from '@/lib/useIsomorphicLayoutEffect';
import { GET_CLIENT_ME } from '@/lib/graphql';
interface ProfileSidebarProps {
activeItem: string;
@ -8,6 +10,15 @@ interface ProfileSidebarProps {
const ProfileSidebar: React.FC<ProfileSidebarProps> = ({ activeItem }) => {
const isClient = useIsClient();
// Получаем данные клиента для проверки наличия юридических лиц
const { data: clientData } = useQuery(GET_CLIENT_ME, {
skip: !isClient,
errorPolicy: 'ignore' // Игнорируем ошибки, чтобы не ломать интерфейс
});
// Проверяем есть ли у клиента юридические лица
const hasLegalEntities = clientData?.clientMe?.legalEntities && clientData.clientMe.legalEntities.length > 0;
const menuItems = [
{ id: 'orders', icon: 'order', label: 'Заказы', href: '/profile-orders' },
{ id: 'history', icon: 'history', label: 'История поиска', href: '/profile-history' },
@ -133,25 +144,28 @@ const ProfileSidebar: React.FC<ProfileSidebarProps> = ({ activeItem }) => {
</div>
</div>
<div className="sidebar-section">
<div className="sidebar-header">
<h3 className="sidebar-title">Финансы</h3>
{/* Раздел "Финансы" показываем только если есть юридические лица */}
{hasLegalEntities && (
<div className="sidebar-section">
<div className="sidebar-header">
<h3 className="sidebar-title">Финансы</h3>
</div>
<div className="sidebar-menu">
{financeItems.map((item) => (
<a
key={item.id}
href={item.href}
className={`sidebar-item ${activeItem === item.id ? 'active' : ''}`}
>
<div className="sidebar-icon">
{renderIcon(item.icon, activeItem === item.id)}
</div>
<span className="sidebar-label">{item.label}</span>
</a>
))}
</div>
</div>
<div className="sidebar-menu">
{financeItems.map((item) => (
<a
key={item.id}
href={item.href}
className={`sidebar-item ${activeItem === item.id ? 'active' : ''}`}
>
<div className="sidebar-icon">
{renderIcon(item.icon, activeItem === item.id)}
</div>
<span className="sidebar-label">{item.label}</span>
</a>
))}
</div>
</div>
)}
{/* Кнопка выхода */}
<div className="logout-section">

View File

@ -25,9 +25,17 @@ const QuickGroupItem: React.FC<QuickGroupItemProps> = ({ group, level, onGroupCl
const handleGroupClick = () => {
if (canShowDetails) {
// Если это конечная группа с поиском деталей - переходим к просмотру деталей
onGroupClick(group);
} else if (hasChildren) {
// Если это родительская группа с подгруппами
if (group.children?.some(child => child.link)) {
// Есть подгруппы с активным поиском - показываем пользователю выбор
setIsExpanded(!isExpanded);
} else {
// Все подгруппы неактивны - просто разворачиваем
setIsExpanded(!isExpanded);
}
}
};
@ -69,6 +77,11 @@ const QuickGroupItem: React.FC<QuickGroupItemProps> = ({ group, level, onGroupCl
Доступен поиск
</span>
)}
{hasChildren && !canShowDetails && (
<span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800">
{group.children?.filter(child => child.link).length || 0} подгрупп
</span>
)}
</p>
</div>
</div>
@ -143,8 +156,15 @@ const QuickDetailSection: React.FC<QuickDetailSectionProps> = ({
};
const handleUnitClick = (unit: LaximoUnit) => {
console.log('🔍 Выбран узел для детального просмотра:', unit.name, 'ID:', unit.unitid);
setSelectedUnit(unit);
// ИСПРАВЛЕНИЕ: Сохраняем SSD узла из API ответа
console.log('🔍 handleUnitClick - сохраняем узел с SSD:', {
unitId: unit.unitid,
unitName: unit.name,
unitSsd: unit.ssd ? `${unit.ssd.substring(0, 50)}...` : 'отсутствует',
unitSsdLength: unit.ssd?.length
});
setSelectedUnit(unit); // Сохраняем полный объект узла с его SSD
};
const handleBackFromUnit = () => {
@ -154,13 +174,13 @@ const QuickDetailSection: React.FC<QuickDetailSectionProps> = ({
const { data: quickDetailData, loading: quickDetailLoading, error: quickDetailError } = useQuery<{ laximoQuickDetail: LaximoQuickDetail }>(
GET_LAXIMO_QUICK_DETAIL,
{
variables: {
variables: selectedGroup?.quickgroupid ? {
catalogCode,
vehicleId,
quickGroupId: selectedGroup.quickgroupid,
ssd
},
skip: !catalogCode || !vehicleId || !selectedGroup.quickgroupid || !ssd,
} : undefined,
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !selectedGroup?.quickgroupid || !ssd || ssd.trim() === '',
errorPolicy: 'all',
fetchPolicy: 'cache-and-network' // Принудительно запрашиваем данные
}
@ -169,19 +189,48 @@ const QuickDetailSection: React.FC<QuickDetailSectionProps> = ({
const quickDetail = quickDetailData?.laximoQuickDetail;
// Добавляем отладочную информацию
console.log('🔍 QuickDetailSection Debug:');
console.log('📊 quickDetailData:', quickDetailData);
console.log('📋 quickDetail:', quickDetail);
console.log('🏗️ quickDetail.units:', quickDetail?.units);
console.log('⚙️ Variables:', { catalogCode, vehicleId, quickGroupId: selectedGroup.quickgroupid, ssd });
console.log('🔍 QuickDetailSection Debug:', {
catalogCode,
vehicleId,
vehicleIdType: typeof vehicleId,
quickGroupId: selectedGroup?.quickgroupid,
quickGroupIdType: typeof selectedGroup?.quickgroupid,
ssd: ssd ? `${ssd.substring(0, 30)}...` : 'отсутствует',
ssdType: typeof ssd,
ssdLength: ssd?.length,
hasData: !!quickDetailData,
hasQuickDetail: !!quickDetail,
unitsCount: quickDetail?.units?.length || 0,
loading: quickDetailLoading,
error: quickDetailError?.message,
skipCondition: !catalogCode || vehicleId === undefined || vehicleId === null || !selectedGroup?.quickgroupid || !ssd,
skipDetails: {
noCatalogCode: !catalogCode,
noVehicleId: vehicleId === undefined || vehicleId === null,
noQuickGroupId: !selectedGroup?.quickgroupid,
noSsd: !ssd
}
});
// Если выбран узел для детального просмотра, показываем UnitDetailsSection
if (selectedUnit) {
// ИСПРАВЛЕНИЕ: Используем SSD узла из API ответа, а не родительский SSD
// API Laximo возвращает для каждого узла свой собственный SSD
console.log('🔍 QuickDetailSection передает в UnitDetailsSection:', {
parentSsd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
parentSsdLength: ssd?.length,
selectedUnitSsd: selectedUnit.ssd ? `${selectedUnit.ssd.substring(0, 50)}...` : 'отсутствует',
selectedUnitSsdLength: selectedUnit.ssd?.length,
unitId: selectedUnit.unitid,
unitName: selectedUnit.name,
note: 'Используем SSD УЗЛА из API ответа'
});
return (
<UnitDetailsSection
catalogCode={catalogCode}
vehicleId={vehicleId}
ssd={ssd}
ssd={selectedUnit.ssd || ssd} // Используем SSD узла, fallback на родительский SSD
unitId={selectedUnit.unitid}
unitName={selectedUnit.name}
onBack={handleBackFromUnit}
@ -213,6 +262,20 @@ const QuickDetailSection: React.FC<QuickDetailSectionProps> = ({
}
if (quickDetailError) {
console.error('🚨 QuickDetailSection Error Details:', {
message: quickDetailError.message,
graphQLErrors: quickDetailError.graphQLErrors,
networkError: quickDetailError.networkError,
extraInfo: quickDetailError.extraInfo,
selectedGroup: selectedGroup,
variables: selectedGroup?.quickgroupid ? {
catalogCode,
vehicleId,
quickGroupId: selectedGroup.quickgroupid,
ssd
} : 'undefined (no variables sent)'
});
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
@ -231,6 +294,33 @@ const QuickDetailSection: React.FC<QuickDetailSectionProps> = ({
<h3 className="text-lg font-medium text-red-600 mb-2">Ошибка загрузки деталей</h3>
<p className="text-red-700">Не удалось загрузить детали для группы "{selectedGroup.name}"</p>
<p className="text-sm text-red-600 mt-2">Ошибка: {quickDetailError.message}</p>
{/* Отладочная информация */}
<details className="mt-4">
<summary className="text-sm text-red-700 cursor-pointer hover:text-red-800">
🔧 Показать отладочную информацию
</summary>
<div className="mt-2 p-3 bg-red-100 rounded text-xs">
<div><strong>Catalog Code:</strong> {catalogCode}</div>
<div><strong>Vehicle ID:</strong> {vehicleId} (type: {typeof vehicleId})</div>
<div><strong>Quick Group ID:</strong> {selectedGroup?.quickgroupid} (type: {typeof selectedGroup?.quickgroupid})</div>
<div><strong>SSD:</strong> {ssd ? `${ssd.substring(0, 100)}...` : 'отсутствует'} (length: {ssd?.length})</div>
<div className="mt-2">
<strong>GraphQL Errors:</strong>
<pre className="mt-1 text-xs overflow-auto">
{JSON.stringify(quickDetailError.graphQLErrors, null, 2)}
</pre>
</div>
{quickDetailError.networkError && (
<div className="mt-2">
<strong>Network Error:</strong>
<pre className="mt-1 text-xs overflow-auto">
{JSON.stringify(quickDetailError.networkError, null, 2)}
</pre>
</div>
)}
</div>
</details>
</div>
</div>
);
@ -464,7 +554,7 @@ const QuickGroupsSection: React.FC<QuickGroupsSectionProps> = ({
vehicleId,
...(ssd && ssd.trim() !== '' && { ssd })
},
skip: !catalogCode || !vehicleId,
skip: !catalogCode || vehicleId === undefined || vehicleId === null,
errorPolicy: 'all'
}
);

View File

@ -29,7 +29,23 @@ const UnitDetailsSection: React.FC<UnitDetailsSectionProps> = ({
const [isBrandModalOpen, setIsBrandModalOpen] = useState(false);
const [selectedDetail, setSelectedDetail] = useState<LaximoUnitDetail | null>(null);
// Отладочная информация для SSD
console.log('🔍 UnitDetailsSection получил SSD:', {
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length,
unitId,
unitName
});
// Получаем информацию об узле
console.log('🔍 UnitDetailsSection - GET_LAXIMO_UNIT_INFO SSD:', {
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length,
unitId,
unitName,
note: 'Используем SSD узла для API запросов'
});
const { data: unitInfoData, loading: unitInfoLoading, error: unitInfoError } = useQuery<{ laximoUnitInfo: LaximoUnitInfo }>(
GET_LAXIMO_UNIT_INFO,
{
@ -37,14 +53,23 @@ const UnitDetailsSection: React.FC<UnitDetailsSectionProps> = ({
catalogCode,
vehicleId,
unitId,
ssd: ssd || ''
ssd
},
skip: !catalogCode || !vehicleId || !unitId,
errorPolicy: 'all'
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !unitId || !ssd || ssd.trim() === '',
errorPolicy: 'all',
fetchPolicy: 'no-cache', // Отключаем кэширование для получения актуальных данных
notifyOnNetworkStatusChange: true
}
);
// Получаем детали узла
console.log('🔍 UnitDetailsSection - GET_LAXIMO_UNIT_DETAILS SSD:', {
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length,
unitId,
unitName
});
const { data: unitDetailsData, loading: unitDetailsLoading, error: unitDetailsError } = useQuery<{ laximoUnitDetails: LaximoUnitDetail[] }>(
GET_LAXIMO_UNIT_DETAILS,
{
@ -52,14 +77,23 @@ const UnitDetailsSection: React.FC<UnitDetailsSectionProps> = ({
catalogCode,
vehicleId,
unitId,
ssd: ssd || ''
ssd
},
skip: !catalogCode || !vehicleId || !unitId,
errorPolicy: 'all'
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !unitId || !ssd || ssd.trim() === '',
errorPolicy: 'all',
fetchPolicy: 'no-cache', // Отключаем кэширование для получения актуального SSD
notifyOnNetworkStatusChange: true
}
);
// Получаем карту изображений узла
console.log('🔍 UnitDetailsSection - GET_LAXIMO_UNIT_IMAGE_MAP SSD:', {
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length,
unitId,
unitName
});
const { data: unitImageMapData, loading: unitImageMapLoading, error: unitImageMapError } = useQuery<{ laximoUnitImageMap: LaximoUnitImageMap }>(
GET_LAXIMO_UNIT_IMAGE_MAP,
{
@ -67,10 +101,12 @@ const UnitDetailsSection: React.FC<UnitDetailsSectionProps> = ({
catalogCode,
vehicleId,
unitId,
ssd: ssd || ''
ssd
},
skip: !catalogCode || !vehicleId || !unitId,
errorPolicy: 'all'
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !unitId || !ssd || ssd.trim() === '',
errorPolicy: 'all',
fetchPolicy: 'no-cache', // Отключаем кэширование для получения актуального SSD
notifyOnNetworkStatusChange: true
}
);

View File

@ -59,7 +59,7 @@ const UnitsSection: React.FC<UnitsSectionProps> = ({
categoryId,
...(ssd && ssd.trim() !== '' && { ssd })
},
skip: !catalogCode || !vehicleId || !categoryId,
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !categoryId,
errorPolicy: 'all',
fetchPolicy: 'no-cache', // Полностью отключаем кэширование для гарантии свежих данных
notifyOnNetworkStatusChange: true

View File

@ -210,7 +210,7 @@ const VehiclePartsSearchSection: React.FC<VehiclePartsSearchSectionProps> = ({
<div className="min-h-[400px]">
{searchType === 'quickgroups' && supportsQuickGroups && (
<QuickGroupsSection
catalogCode={vehicleInfo.catalog}
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
ssd={vehicleInfo.ssd}
/>

View File

@ -47,96 +47,116 @@ const VehicleSearchResults: React.FC<VehicleSearchResultsProps> = ({
}
};
// Функция для условного отображения атрибута
const renderAttribute = (label: string, value: string | undefined) => {
if (!value || value === '' || value === 'undefined') return null
return (
<div className="flex justify-between py-1 border-b border-gray-100">
<span className="text-sm text-gray-600 font-medium">{label}:</span>
<span className="text-sm text-gray-900">{value}</span>
</div>
)
}
if (results.length === 0) {
return null;
}
return (
<div className="bg-white rounded-2xl md:my-8">
<div className="mb-2">
<h4 className="text-lg font-medium text-gray-900">
Найденные автомобили ({results.length})
</h4>
</div>
<div className="flex flex-col gap-4">
<div className="space-y-4">
<h3 className="text-lg font-semibold text-gray-900">
Найдено автомобилей: {results.length}
</h3>
<div className="flex flex-wrap flex-1 gap-5 size-full max-md:max-w-full">
{results.map((vehicle, index) => (
<div
key={vehicle.vehicleid || index}
className="pt-3 pb-3 bg-white border-b border-gray-200 hover:bg-neutral-50 transition-colors cursor-pointer flex flex-col sm:flex-row sm:items-center gap-4"
key={`${vehicle.vehicleid}-${index}`}
className="flex flex-col flex-1 shrink p-8 bg-white rounded-lg border border-solid basis-0 border-stone-300 max-w-[504px] md:min-w-[370px] sm:min-w-[340px] min-w-[200px] max-md:px-5 cursor-pointer transition-shadow hover:shadow-lg"
onClick={() => handleSelectVehicle(vehicle)}
>
<div className="flex-1 min-w-0">
<div className="flex flex-wrap items-center gap-3 mb-2">
<h4 className="text-lg font-semibold text-gray-900 truncate">
{vehicle.name || `${vehicle.brand || 'Unknown'} ${vehicle.model || 'Vehicle'}`}
</h4>
{vehicle.year && (
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-50 text-red-700">
{vehicle.year}
</span>
)}
</div>
{/* Заголовок автомобиля */}
<div className="">
<h4 className="text-lg font-semibold text-red-600 mb-1 truncate">
{vehicle.name || `${vehicle.brand} ${vehicle.model}`}
</h4>
{/* <p className="text-sm text-gray-500 truncate">
{vehicle.modification} ({vehicle.year})
</p> */}
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 text-sm mb-2">
{vehicle.modification && (
<div>
<span className="text-gray-500">Модификация:</span>
<span className="ml-2 font-medium text-gray-900">{vehicle.modification}</span>
</div>
)}
{vehicle.bodytype && (
<div>
<span className="text-gray-500">Тип кузова:</span>
<span className="ml-2 font-medium text-gray-900">{vehicle.bodytype}</span>
</div>
)}
{vehicle.engine && (
<div>
<span className="text-gray-500">Двигатель:</span>
<span className="ml-2 font-medium text-gray-900">{vehicle.engine}</span>
</div>
)}
</div>
{/* Основные характеристики */}
<div className="space-y-1 mb-4">
<h5 className="text-base font-semibold text-gray-900 mb-2">Основные характеристики</h5>
{renderAttribute('Марка', vehicle.brand)}
{renderAttribute('Модель', vehicle.model)}
{renderAttribute('Двигатель', vehicle.engine)}
</div>
{vehicle.notes && (
<div className="mt-3 p-3 bg-yellow-50 rounded-lg">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<p className="text-sm text-yellow-800">
<span className="font-medium">Примечание:</span> {vehicle.notes}
</p>
</div>
{/* Все атрибуты из API */}
{vehicle.attributes && vehicle.attributes.length > 0 && (
<div className="space-y-1 mb-4">
<h5 className="text-base font-semibold text-gray-900 mb-2">Дополнительные характеристики</h5>
{vehicle.attributes.map((attr, attrIndex) => (
<div key={attrIndex} className="flex justify-between py-1 border-b border-gray-100">
<span className="text-sm text-gray-600 font-medium">{attr.name || attr.key}:</span>
<span className="text-sm text-gray-900">{attr.value}</span>
</div>
))}
</div>
)}
{/* Технические характеристики (fallback для старых данных) */}
{(!vehicle.attributes || vehicle.attributes.length === 0) && (
<>
<div className="space-y-1 mb-4">
<h5 className="text-base font-semibold text-gray-900 mb-2">Дополнительные характеристики</h5>
{renderAttribute('Год', vehicle.year)}
{renderAttribute('Кузов', vehicle.bodytype)}
{renderAttribute('Трансмиссия', vehicle.transmission)}
{renderAttribute('Класс', vehicle.grade)}
{renderAttribute('Цвет кузова', vehicle.framecolor)}
{renderAttribute('Цвет салона', vehicle.trimcolor)}
{renderAttribute('Рынок', vehicle.market)}
{renderAttribute('Регион производства', vehicle.creationregion)}
{renderAttribute('Регион назначения', vehicle.destinationregion)}
</div>
)}
</div>
<div className="flex-shrink-0 flex items-center justify-end">
<button
onClick={e => {
e.stopPropagation();
handleSelectVehicle(vehicle);
}}
className="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-lg bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 shadow transition"
style={{ color: '#fff' }}
>
Выбрать
</button>
</div>
<div className="space-y-1 mb-4">
<h5 className="text-base font-semibold text-gray-900 mb-2">Технические характеристики</h5>
{renderAttribute('Информация о двигателе', vehicle.engine_info)}
{renderAttribute('Номер двигателя', vehicle.engineno)}
{renderAttribute('Дата производства', vehicle.date)}
{renderAttribute('Произведен', vehicle.manufactured)}
{renderAttribute('Период производства', vehicle.prodPeriod)}
{renderAttribute('Диапазон производства', vehicle.prodRange)}
</div>
<div className="space-y-1 mb-4">
<h5 className="text-base font-semibold text-gray-900 mb-2">Даты и периоды</h5>
{renderAttribute('Дата с', vehicle.datefrom)}
{renderAttribute('Дата по', vehicle.dateto)}
{renderAttribute('Модельный год с', vehicle.modelyearfrom)}
{renderAttribute('Модельный год по', vehicle.modelyearto)}
</div>
{/* Опции и описание */}
{(vehicle.options || vehicle.description || vehicle.notes) && (
<div className="space-y-1 mb-4">
<h5 className="text-base font-semibold text-gray-900 mb-2">Опции и описание</h5>
{renderAttribute('Опции', vehicle.options)}
{renderAttribute('Описание', vehicle.description)}
{renderAttribute('Примечания', vehicle.notes)}
</div>
)}
</>
)}
{/* Системная информация */}
</div>
))}
</div>
<div className="bg-gray-50 rounded-xl pt-4 pb-4 mt-6 flex flex-col sm:flex-row items-center justify-between text-sm text-gray-600">
<span>Показано {results.length} результат{results.length === 1 ? '' : results.length < 5 ? 'а' : 'ов'}</span>
<span>Кликните на автомобиль для подбора запчастей</span>
</div>
</div>
);
};

View File

@ -20,11 +20,17 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
const [error, setError] = useState<string>('');
const [queries, setQueries] = useState<Record<string, string>>({});
const buttonRefs = useRef<Record<string, React.RefObject<HTMLButtonElement | null>>>({});
const inputRefs = useRef<Record<string, React.RefObject<HTMLInputElement | null>>>({});
const [showSearchButton, setShowSearchButton] = React.useState(true);
const [getWizard2] = useLazyQuery(GET_LAXIMO_WIZARD2, {
onCompleted: (data) => {
if (data.laximoWizard2) {
console.log('🔄 Wizard обновлен:', {
steps: data.laximoWizard2.length,
selectedParams: Object.keys(selectedParams).length,
currentSsd
});
setWizardSteps(data.laximoWizard2);
setIsLoading(false);
}
@ -75,18 +81,28 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
// --- Автовыбор единственного варианта для всех шагов ---
React.useEffect(() => {
// Предотвращаем автовыбор во время загрузки
if (isLoading) return;
wizardSteps.forEach(step => {
const options = step.options || [];
const selectedKey = selectedParams[step.conditionid]?.key || (step.determined ? options.find(o => o.value === step.value)?.key : '');
if (options.length === 1 && selectedKey !== options[0].key) {
// Автовыбираем только если есть единственный вариант и он еще не выбран
if (options.length === 1 && selectedKey !== options[0].key && !selectedParams[step.conditionid]) {
handleParamSelect(step, options[0].key, options[0].value);
}
});
// eslint-disable-next-line
}, [wizardSteps, selectedParams]);
}, [wizardSteps, selectedParams, isLoading]);
// Обработка выбора параметра
const handleParamSelect = async (step: LaximoWizardStep, optionKey: string, optionValue: string) => {
// Проверяем, не выбран ли уже этот параметр
if (selectedParams[step.conditionid]?.key === optionKey) {
return;
}
setIsLoading(true);
setError('');
@ -117,6 +133,13 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
// Сброс параметра
const handleParamReset = async (step: LaximoWizardStep) => {
console.log('🔄 Сброс параметра:', {
stepName: step.name,
conditionId: step.conditionid,
currentSsd,
selectedParamsBefore: Object.keys(selectedParams)
});
setIsLoading(true);
setError('');
@ -125,8 +148,33 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
delete newSelectedParams[step.conditionid];
setSelectedParams(newSelectedParams);
// Используем SSD для сброса параметра, если он есть
const resetSsd = step.ssd || '';
// Находим правильный SSD для сброса этого параметра
// Нужно найти SSD, который соответствует состоянию до выбора этого параметра
let resetSsd = '';
// Ищем среди шагов wizard тот, который имеет правильный SSD для восстановления
const currentStepIndex = wizardSteps.findIndex(s => s.conditionid === step.conditionid);
// Если есть предыдущие шаги с выбранными параметрами, используем их SSD
for (let i = currentStepIndex - 1; i >= 0; i--) {
const prevStep = wizardSteps[i];
if (newSelectedParams[prevStep.conditionid]) {
resetSsd = newSelectedParams[prevStep.conditionid].key;
break;
}
}
// Если не нашли предыдущий SSD, используем step.ssd или пустую строку
if (!resetSsd) {
resetSsd = step.ssd || '';
}
console.log('🔄 Новый SSD для сброса:', {
resetSsd,
selectedParamsAfter: Object.keys(newSelectedParams),
stepSsd: step.ssd
});
setCurrentSsd(resetSsd);
try {
@ -220,14 +268,18 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
? options.filter(option => option.value.toLowerCase().includes(query.toLowerCase()))
: options;
const buttonRef = buttonRefs.current[step.conditionid];
// Создаём ref для инпута, если его ещё нет
if (!inputRefs.current[step.conditionid]) {
inputRefs.current[step.conditionid] = React.createRef<HTMLInputElement>();
}
const inputRef = inputRefs.current[step.conditionid];
// Определяем выбранный ключ
const selectedKey = selectedParams[step.conditionid]?.key || (step.determined ? options.find(o => o.value === step.value)?.key : '');
// Определяем отображаемый label
const selectedLabel =
options.find(o => o.key === selectedKey)?.value ||
selectedParams[step.conditionid]?.value ||
step.value ||
'';
step.value || '';
// Если единственный вариант уже выбран — не рендерим селект
if (options.length === 1 && (selectedKey === options[0].key || step.determined)) {
@ -252,7 +304,21 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
disabled={isLoading || options.length === 0}
>
<div className="relative">
{/* Невидимая кнопка поверх инпута */}
<button
type="button"
className="absolute top-0 left-0 w-full h-full opacity-0 z-10 cursor-pointer"
tabIndex={0}
aria-label="Открыть список опций"
onClick={() => {
inputRef.current?.focus();
if (inputRef.current) {
inputRef.current.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
}
}}
/>
<Combobox.Input
ref={inputRef}
id={`wizard-combobox-${step.conditionid}`}
className={`w-full px-6 py-4 rounded text-sm text-gray-950 placeholder:text-neutral-500 outline-none focus:shadow-none transition-colors pr-12 ${selectedLabel ? 'bg-gray-50 border-gray-200' : 'bg-white border border-stone-300'}`}
displayValue={() => selectedLabel}
@ -264,7 +330,7 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
{selectedLabel ? (
<button
type="button"
className="absolute inset-y-0 right-0 w-12 flex items-center justify-center text-gray-400 hover:text-red-600 focus:outline-none"
className="absolute inset-y-0 right-0 w-12 flex items-center justify-center text-gray-400 hover:text-red-600 focus:outline-none z-10"
aria-label="Сбросить"
tabIndex={0}
onClick={() => handleParamReset(step)}
@ -306,36 +372,36 @@ const WizardSearchForm: React.FC<WizardSearchFormProps> = ({
</div>
)}
{/* Кнопка поиска автомобилей */}
{!isLoading && canListVehicles && showSearchButton && (
<div className="pt-4 border-t">
{/* Информация о недостаточности параметров и кнопка поиска */}
{!isLoading && wizardSteps.length > 0 && (
<div className="flex flex-row gap-4 items-center w-full mx-auto max-sm:flex-col max-sm:items-stretch">
<button
onClick={() => {
handleFindVehicles();
setShowSearchButton(false);
}}
disabled={isLoading}
className="w-full sm:w-auto px-8 py-3 bg-red-600 !text-white font-medium rounded-lg shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
disabled={!canListVehicles || isLoading}
className="w-full sm:w-auto px-8 py-3 bg-red-600 !text-white font-medium rounded-lg shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center max-sm:w-full"
style={{ minWidth: 180 }}
>
<svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
Найти автомобили
Найти
</button>
<div className="mt-3 text-sm text-gray-600">
Определено параметров: {wizardSteps.filter(s => s.determined).length} из {wizardSteps.length}
<div
layer-name="Выберите больше параметров для поиска автомобилей"
className="box-border inline-flex gap-5 items-center px-10 py-4 rounded-xl bg-slate-50 h-[52px] max-md:px-8 max-md:py-3.5 max-md:w-full max-md:h-auto max-md:max-w-[524px] max-md:min-h-[52px] max-sm:gap-3 max-sm:px-5 max-sm:py-3 max-sm:w-full max-sm:rounded-lg max-sm:justify-center"
>
<div>
<img src="/images/info.svg" alt="info" style={{ width: 18, height: 20, flexShrink: 0 }} />
</div>
<div
layer-name="Выберите больше параметров для поиска автомобилей"
className="relative text-base font-medium leading-5 text-center text-gray-950 max-md:text-sm max-sm:text-sm max-sm:leading-4 max-sm:text-center"
>
Выберите больше параметров для поиска автомобилей
</div>
</div>
</div>
)}
{/* Информация о недостаточности параметров */}
{!isLoading && !canListVehicles && wizardSteps.length > 0 && (
<div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
<p className="text-yellow-800 text-sm">
Выберите больше параметров для поиска автомобилей
</p>
</div>
)}
</div>
);
};

View File

@ -23,7 +23,7 @@ export default function InfoCard({
currency = 'RUB',
image
}: InfoCardProps) {
const { addToFavorites, removeFromFavorites, isFavorite } = useFavorites();
const { addToFavorites, removeFromFavorites, isFavorite, favorites } = useFavorites();
// Проверяем, есть ли товар в избранном
const isItemFavorite = isFavorite(productId, offerKey, articleNumber, brand);
@ -34,9 +34,18 @@ export default function InfoCard({
e.stopPropagation();
if (isItemFavorite) {
// Создаем ID для удаления
const id = `${productId || offerKey || ''}:${articleNumber}:${brand}`;
removeFromFavorites(id);
// Находим товар в избранном по правильному ID
const favoriteItem = favorites.find((fav: any) => {
// Проверяем по разным комбинациям идентификаторов
if (productId && fav.productId === productId) return true;
if (offerKey && fav.offerKey === offerKey) return true;
if (fav.article === articleNumber && fav.brand === brand) return true;
return false;
});
if (favoriteItem) {
removeFromFavorites(favoriteItem.id);
}
} else {
// Добавляем в избранное
addToFavorites({

View File

@ -1,6 +1,7 @@
import React, { useState } from "react";
import { useCart } from "@/contexts/CartContext";
import { toast } from "react-hot-toast";
import CartIcon from "../CartIcon";
interface ProductBuyBlockProps {
offer?: any;
@ -37,7 +38,7 @@ const ProductBuyBlock = ({ offer }: ProductBuyBlockProps) => {
}
// Добавляем товар в корзину
addItem({
const result = await addItem({
productId: offer.id ? String(offer.id) : undefined,
offerKey: offer.offerKey || undefined,
name: offer.name || `${offer.brand} ${offer.articleNumber}`,
@ -45,6 +46,7 @@ const ProductBuyBlock = ({ offer }: ProductBuyBlockProps) => {
price: offer.price,
currency: 'RUB',
quantity: quantity,
stock: offer.quantity, // передаем информацию о наличии
image: offer.image || undefined,
brand: offer.brand,
article: offer.articleNumber,
@ -53,17 +55,22 @@ const ProductBuyBlock = ({ offer }: ProductBuyBlockProps) => {
isExternal: offer.type === 'external'
});
// Показываем успешный тоастер
toast.success(
<div>
<div className="font-semibold">Товар добавлен в корзину!</div>
<div className="text-sm text-gray-600">{offer.name || `${offer.brand} ${offer.articleNumber}`}</div>
</div>,
{
duration: 3000,
icon: '🛒',
}
);
if (result.success) {
// Показываем успешный тоастер
toast.success(
<div>
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{offer.name || `${offer.brand} ${offer.articleNumber}`}</div>
</div>,
{
duration: 3000,
icon: <CartIcon size={20} color="#fff" />,
}
);
} else {
// Показываем ошибку
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
}
} catch (error) {
console.error('Ошибка добавления в корзину:', error);
toast.error('Ошибка при добавлении товара в корзину');

View File

@ -1,96 +1,47 @@
import React from "react";
import React, { useEffect, useState } from "react";
import { useQuery } from "@apollo/client";
import { PARTS_INDEX_SEARCH_BY_ARTICLE } from "@/lib/graphql";
interface ProductCharacteristicsProps {
result?: any;
}
const ProductCharacteristics = ({ result }: ProductCharacteristicsProps) => {
const [partsIndexData, setPartsIndexData] = useState<any>(null);
// Функция для рендеринга характеристик из нашей базы данных
const renderInternalCharacteristics = () => {
if (!result?.characteristics || result.characteristics.length === 0) return null;
// Запрос к Parts Index для получения дополнительных характеристик
const { data: partsIndexResult, loading: partsIndexLoading } = useQuery(PARTS_INDEX_SEARCH_BY_ARTICLE, {
variables: {
articleNumber: result?.articleNumber || '',
brandName: result?.brand || '',
lang: 'ru'
},
skip: !result?.articleNumber || !result?.brand,
errorPolicy: 'ignore'
});
return (
<div className="w-layout-vflex flex-block-53">
<div className="w-layout-hflex flex-block-55">
<span className="text-block-29" style={{ fontWeight: 'bold', color: '#333' }}>
Характеристики товара:
</span>
</div>
{result.characteristics.map((char: any, index: number) => (
<div key={index} className="w-layout-hflex flex-block-55">
<span className="text-block-29">{char.characteristic.name}:</span>
<span className="text-block-28">{char.value}</span>
useEffect(() => {
if (partsIndexResult?.partsIndexSearchByArticle) {
setPartsIndexData(partsIndexResult.partsIndexSearchByArticle);
}
}, [partsIndexResult]);
// Функция для рендеринга параметров из Parts Index
const renderPartsIndexParameters = () => {
if (!partsIndexData?.parameters) return null;
return partsIndexData.parameters.map((paramGroup: any, groupIndex: number) => (
<div key={groupIndex} className="w-layout-vflex flex-block-53">
{paramGroup.params?.map((param: any, paramIndex: number) => (
<div key={paramIndex} className="w-layout-hflex flex-block-55">
<span className="text-block-29">{param.title}:</span>
<span className="text-block-28">
{param.values?.map((value: any) => value.value).join(', ') || 'Нет данных'}
</span>
</div>
))}
</div>
);
};
// Функция для рендеринга характеристик из Parts Index
const renderPartsIndexCharacteristics = () => {
if (!result?.partsIndexCharacteristics || result.partsIndexCharacteristics.length === 0) return null;
return (
<div className="w-layout-vflex flex-block-53">
<div className="w-layout-hflex flex-block-55">
<span className="text-block-29" style={{ fontWeight: 'bold', color: '#333' }}>
Дополнительные характеристики:
</span>
</div>
{result.partsIndexCharacteristics.map((char: any, index: number) => (
<div key={index} className="w-layout-hflex flex-block-55">
<span className="text-block-29">{char.name}:</span>
<span className="text-block-28">{char.value}</span>
</div>
))}
</div>
);
};
// Функция для рендеринга изображений из нашей базы данных
const renderInternalImages = () => {
if (!result?.images || result.images.length === 0) return null;
return (
<div className="w-layout-vflex flex-block-53" style={{ marginTop: '20px' }}>
<div className="w-layout-hflex flex-block-55">
<span className="text-block-29" style={{ fontWeight: 'bold', color: '#333' }}>
Изображения товара:
</span>
</div>
<div className="w-layout-hflex" style={{ flexWrap: 'wrap', gap: '10px', marginTop: '10px' }}>
{result.images.slice(0, 6).map((image: any, index: number) => (
<div key={image.id || index} style={{
border: '1px solid #e0e0e0',
borderRadius: '8px',
overflow: 'hidden',
width: '120px',
height: '120px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#f9f9f9'
}}>
<img
src={image.url}
alt={image.alt || `${result?.brand} ${result?.articleNumber} - изображение ${index + 1}`}
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
cursor: 'pointer'
}}
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
}}
onClick={() => window.open(image.url, '_blank')}
/>
</div>
))}
</div>
</div>
);
));
};
return (
@ -111,27 +62,33 @@ const ProductCharacteristics = ({ result }: ProductCharacteristicsProps) => {
<span className="text-block-29">Название:</span>
<span className="text-block-28">{result.name}</span>
</div>
{result?.description && (
{partsIndexData?.originalName && (
<div className="w-layout-hflex flex-block-55">
<span className="text-block-29">Оригинальное название:</span>
<span className="text-block-28">{partsIndexData.originalName}</span>
</div>
)}
{partsIndexData?.description && (
<div className="w-layout-hflex flex-block-55">
<span className="text-block-29">Описание:</span>
<span className="text-block-28" style={{ maxWidth: '400px', wordWrap: 'break-word' }}>
{result.description}
</span>
<span className="text-block-28">{partsIndexData.description}</span>
</div>
)}
</div>
{/* Характеристики из нашей базы данных */}
{renderInternalCharacteristics()}
{/* Дополнительные характеристики из Parts Index */}
{renderPartsIndexCharacteristics()}
{partsIndexLoading ? (
<div className="w-layout-vflex flex-block-53">
<div className="w-layout-hflex flex-block-55">
<span className="text-block-29">Загрузка характеристик...</span>
</div>
</div>
) : (
renderPartsIndexParameters()
)}
</>
)}
</div>
{/* Изображения из нашей базы данных */}
{renderInternalImages()}
</>
);
};

View File

@ -15,8 +15,10 @@ const DEFAULT_MAX = 32000;
const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(v, max));
const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max = DEFAULT_MAX, isMobile = false, value = null, onChange }) => {
const [from, setFrom] = useState(value ? value[0] : min);
const [to, setTo] = useState(value ? value[1] : max);
const [from, setFrom] = useState<string>(value ? String(value[0]) : String(min));
const [to, setTo] = useState<string>(value ? String(value[1]) : String(max));
const [confirmedFrom, setConfirmedFrom] = useState<number>(value ? value[0] : min);
const [confirmedTo, setConfirmedTo] = useState<number>(value ? value[1] : max);
const [dragging, setDragging] = useState<null | "from" | "to">(null);
const [trackWidth, setTrackWidth] = useState(0);
const [open, setOpen] = useState(true);
@ -25,11 +27,15 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
// Обновляем локальное состояние при изменении внешнего значения
useEffect(() => {
if (value) {
setFrom(value[0]);
setTo(value[1]);
setFrom(String(value[0]));
setTo(String(value[1]));
setConfirmedFrom(value[0]);
setConfirmedTo(value[1]);
} else {
setFrom(min);
setTo(max);
setFrom(String(min));
setTo(String(max));
setConfirmedFrom(min);
setConfirmedTo(max);
}
}, [value, min, max]);
@ -61,15 +67,15 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
x = clamp(x, 0, trackWidth);
const value = clamp(pxToValue(x), min, max);
if (dragging === "from") {
setFrom(v => clamp(Math.min(value, to), min, to));
setFrom(v => String(clamp(Math.min(value, Number(to)), min, Number(to))));
} else {
setTo(v => clamp(Math.max(value, from), from, max));
setTo(v => String(clamp(Math.max(value, Number(from)), Number(from), max)));
}
};
const onUp = () => {
setDragging(null);
if (onChange) {
onChange([from, to]);
onChange([Number(from), Number(to)]);
}
};
window.addEventListener("mousemove", onMove);
@ -82,25 +88,48 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
// Input handlers
const handleFromInput = (e: React.ChangeEvent<HTMLInputElement>) => {
let v = Number(e.target.value.replace(/\D/g, ""));
if (isNaN(v)) v = min;
setFrom(clamp(Math.min(v, to), min, to));
let v = e.target.value.replace(/\D/g, "");
setFrom(v);
};
const handleToInput = (e: React.ChangeEvent<HTMLInputElement>) => {
let v = Number(e.target.value.replace(/\D/g, ""));
if (isNaN(v)) v = max;
setTo(clamp(Math.max(v, from), from, max));
let v = e.target.value.replace(/\D/g, "");
setTo(v);
};
const handleInputBlur = () => {
if (onChange) {
onChange([from, to]);
const handleFromBlur = () => {
let v = Number(from);
if (isNaN(v) || v < min) v = min;
// если больше max — оставлять как есть
setFrom(String(v));
if (onChange) onChange([v, to === "" ? max : Number(to)]);
setConfirmedFrom(v);
};
const handleToBlur = () => {
let v = Number(to);
if (isNaN(v) || v < min) v = min;
if (v > max) v = max;
setTo(String(v));
if (onChange) onChange([from === "" ? min : Number(from), v]);
setConfirmedTo(v);
};
const handleFromKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
handleFromBlur();
(e.target as HTMLInputElement).blur();
}
};
const handleToKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
handleToBlur();
(e.target as HTMLInputElement).blur();
}
};
// px позиции для точек
const pxFrom = valueToPx(from);
const pxTo = valueToPx(to);
const pxFrom = valueToPx(dragging ? Number(from) : confirmedFrom);
const pxTo = valueToPx(dragging ? Number(to) : confirmedTo);
// Мобильная версия - без dropdown
if (isMobile) {
@ -124,7 +153,8 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
id="from"
value={from}
onChange={handleFromInput}
onBlur={handleInputBlur}
onBlur={handleFromBlur}
onKeyDown={handleFromKeyDown}
style={{ padding: '8px 10px 8px 36px', fontSize: 16, width: '100%' }}
/>
</div>
@ -139,7 +169,8 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
id="to"
value={to}
onChange={handleToInput}
onBlur={handleInputBlur}
onBlur={handleToBlur}
onKeyDown={handleToKeyDown}
style={{ padding: '8px 10px 8px 36px', fontSize: 16, width: '100%' }}
/>
</div>
@ -214,7 +245,8 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
id="from"
value={from}
onChange={handleFromInput}
onBlur={handleInputBlur}
onBlur={handleFromBlur}
onKeyDown={handleFromKeyDown}
/>
</div>
<div className="div-block-5">
@ -228,7 +260,8 @@ const FilterRange: React.FC<FilterRangeProps> = ({ title, min = DEFAULT_MIN, max
id="to"
value={to}
onChange={handleToInput}
onBlur={handleInputBlur}
onBlur={handleToBlur}
onKeyDown={handleToKeyDown}
/>
</div>
</form>

View File

@ -2,53 +2,55 @@ import React from "react";
import Link from "next/link";
const AvailableParts = () => (
<section>
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex flex-block-5">
<div className="w-layout-hflex flex-block-31">
<h2 className="heading-4">Автозапчасти в наличии</h2>
<div className="w-layout-hflex flex-block-29">
<Link href="/catalog" className="text-block-18">
Ко всем автозапчастям
</Link>
<img src="/images/Arrow_right.svg" loading="lazy" alt="" />
</div>
</div>
<div className="w-layout-hflex flex-block-6">
<Link href="/catalog" className="div-block-12" id="w-node-bc394713-4b8e-44e3-8ddf-3edc1c31a743-3b3232bc">
<h1 className="heading-7">Аксессуары</h1>
<img src="/images/IMG_1.png" loading="lazy" alt="" className="image-22" />
<section>
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex flex-block-5">
<div className="w-layout-hflex flex-block-31">
<h2 className="heading-4">Автозапчасти в наличии</h2>
<div className="w-layout-hflex flex-block-29">
<Link href="/catalog" className="text-block-18">
Ко всем автозапчастям
</Link>
<Link href="/catalog" className="div-block-12-copy">
<h1 className="heading-7">Воздушные фильтры</h1>
<img src="/images/IMG_2.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12">
<h1 className="heading-7">Шины</h1>
<img src="/images/IMG_3.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-123">
<h1 className="heading-7-white">Аккумуляторы</h1>
<img src="/images/IMG_4.png" loading="lazy" alt="" className="image-22" />
</Link>
<div className="w-layout-hflex flex-block-35" id="w-node-_8908a890-8c8f-e12c-999f-08d5da3bcc01-3b3232bc">
<Link href="/catalog" className="div-block-12 small">
<h1 className="heading-7">Диски</h1>
<img src="/images/IMG_5.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12 small">
<h1 className="heading-7">Свечи</h1>
<img src="/images/IMG_6.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-red small">
<h1 className="heading-7-white">Масла</h1>
<img src="/images/IMG_7.png" loading="lazy" alt="" className="image-22" />
</Link>
</div>
<img src="/images/Arrow_right.svg" loading="lazy" alt="" />
</div>
</div>
<div className="w-layout-hflex flex-block-6">
<Link href="/catalog" className="div-block-12">
<h1 className="heading-7">Аксессуары</h1>
<img src="/images/IMG_1.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12-copy">
<h1 className="heading-7">Воздушные фильтры</h1>
<img src="/images/IMG_2.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12">
<h1 className="heading-7">Шины</h1>
<img src="/images/IMG_3.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-123">
<h1 className="heading-7-white">Аккумуляторы</h1>
<img src="/images/IMG_4.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12 small">
<h1 className="heading-7">Диски</h1>
<img src="/images/IMG_5.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12 small">
<h1 className="heading-7">Свечи</h1>
<img src="/images/IMG_6.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-red small">
<h1 className="heading-7-white">Масла</h1>
<img src="/images/IMG_7.png" loading="lazy" alt="" className="image-22" />
</Link>
<Link href="/catalog" className="div-block-12 small">
<h1 className="heading-7">Диски</h1>
<img src="/images/IMG_5.png" loading="lazy" alt="" className="image-22" />
</Link>
</div>
</div>
</section>
</div>
</section>
);
export default AvailableParts;

View File

@ -0,0 +1,43 @@
import React from "react";
const BestPriceSection: React.FC = () => (
<section className="main">
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-hflex flex-block-118">
<div className="w-layout-vflex flex-block-119">
<h1 className="heading-20">ЛУЧШАЯ ЦЕНА!</h1>
<div className="text-block-58">Подборка лучших предложенийпо цене</div>
<a href="#" className="button-24 w-button">Показать все</a>
</div>
<div className="w-layout-hflex flex-block-121">
{[...Array(8)].map((_, i) => (
<div className="w-layout-vflex bestpriceitem" key={i}>
<div className="favcardcat">
<div className="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path></svg></div>
</div>
<div className="imgitembp"><img width="auto" height="auto" alt="" src="images/162615.webp" loading="lazy" srcSet="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" className="image-5" />
<div className="saletagbp">-35%</div>
</div>
<div className="div-block-3">
<div className="w-layout-hflex pricecartbp">
<div className="actualprice">от 17 087 </div>
<div className="oldpricebp">22 347 </div>
</div>
<div className="w-layout-hflex flex-block-120">
<div className="nameitembp">Аккумуляторная батарея TYUMEN BATTERY "STANDARD", 6CT-60L, 60</div>
<a href="#" className="button-icon w-inline-block">
<div className="div-block-26">
<div className="icon-setting w-embed"><svg width="currentWidht" height="currentHeight" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z" fill="currentColor"></path></svg></div>
</div>
</a>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
);
export default BestPriceSection;

View File

@ -0,0 +1,158 @@
import React, { useState } from "react";
import { useRouter } from "next/router";
import { useQuery } from "@apollo/client";
import { GET_LAXIMO_BRANDS } from "@/lib/graphql";
import { LaximoBrand } from "@/types/laximo";
const tabs = [
"Техническое обслуживание",
"Легковые",
"Грузовые",
"Коммерческие",
];
type Brand = { name: string; code?: string };
const BrandSelectionSection: React.FC = () => {
const [activeTab, setActiveTab] = useState(0);
const [selectedBrand, setSelectedBrand] = useState<string>("");
const router = useRouter();
const { data, loading, error } = useQuery<{ laximoBrands: LaximoBrand[] }>(GET_LAXIMO_BRANDS, {
errorPolicy: 'all'
});
const staticBrands: Brand[] = [
{ name: "Audi" },
{ name: "BMW" },
{ name: "Cadillac" },
{ name: "Chevrolet" },
{ name: "Citroen" },
{ name: "Fiat" },
{ name: "Mazda" }
];
let brands: Brand[] = staticBrands;
if (data?.laximoBrands && data.laximoBrands.length > 0) {
brands = data.laximoBrands.map(brand => ({
name: brand.name,
code: brand.code
}));
} else if (error) {
console.warn('Laximo API недоступен, используются статические данные:', error.message);
}
const handleBrandClick = (brand: Brand) => {
if (brand.code) {
router.push(`/brands?selected=${brand.code}`);
} else {
console.warn('Brand code not available for', brand.name);
}
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (selectedBrand) {
const found = brands.find(b => b.code === selectedBrand || b.name === selectedBrand);
if (found && found.code) {
router.push(`/brands?selected=${found.code}`);
return;
}
}
router.push("/brands");
};
if (loading) {
return (
<section>
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex inbt">
<h2 className="heading-4">Подбор по маркам</h2>
<div className="text-center">Загрузка брендов...</div>
</div>
</div>
</section>
);
}
return (
<section className="main">
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex inbt">
<h2 className="heading-4">Подбор по маркам</h2>
<div className="w-layout-hflex flex-block-6-copy">
<div className="w-layout-hflex brandsortb">
<div className="w-layout-hflex tabson">
{tabs.map((tab, idx) => (
<div
className={activeTab === idx ? "tab_c tab_card-activ" : "tab_c tab_card"}
key={idx}
onClick={() => setActiveTab(idx)}
style={{ cursor: "pointer" }}
>
{tab}
</div>
))}
</div>
<div className="w-layout-hflex brandsort">
{[...Array(5)].map((_, colIdx) => (
<div className="w-layout-vflex flex-block-26" key={colIdx}>
{brands.slice(colIdx * Math.ceil(brands.length / 5), (colIdx + 1) * Math.ceil(brands.length / 5)).map((brand, idx) => (
<button
onClick={() => handleBrandClick(brand)}
className="link-block-6 w-inline-block text-left"
key={idx}
style={{ background: 'none', border: 'none', padding: 0 }}
>
<div className="indexbrandblock">{brand.name}</div>
</button>
))}
</div>
))}
</div>
<button
onClick={() => router.push('/brands')}
className="w-layout-hflex flex-block-29 cursor-pointer hover:opacity-80 transition-opacity"
style={{ background: 'none', border: 'none', padding: 0 }}
>
<div className="text-block-18">Все марки</div>
<img src="/images/Arrow_right.svg" loading="lazy" alt="Стрелка вправо" />
</button>
</div>
<div className="w-layout-vflex flex-block-124">
<h1 className="heading-21">ПОДБОР АВТОЗАПЧАСТЕЙ ПО МАРКЕ АВТО</h1>
<div className="form-block-4 w-form">
<form id="email-form" name="email-form" data-name="Email Form" method="post" data-wf-page-id="685be6dfd87db2e01cbdb7a2" data-wf-element-id="e673036c-0caf-d251-3b66-9ba9cb85064c" onSubmit={handleSubmit}>
<select
id="field-7"
name="field-7"
data-name="Field 7"
className="select-copy w-select"
value={selectedBrand}
onChange={e => setSelectedBrand(e.target.value)}
>
<option value="">Марка</option>
{brands.map((brand, idx) => (
<option value={brand.code || brand.name} key={idx}>{brand.name}</option>
))}
</select>
<div className="div-block-10-copy">
<input type="submit" data-wait="Please wait..." className="button-3-copy w-button" value="Далее" />
</div>
</form>
<div className="w-form-done">
<div>Thank you! Your submission has been received!</div>
</div>
<div className="w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default BrandSelectionSection;

View File

@ -0,0 +1,39 @@
import React from "react";
const CategoryNavSection: React.FC = () => (
<section className="catnav">
<div className="w-layout-blockcontainer batd w-container">
<div className="w-layout-hflex flex-block-108-copy">
<div className="ci1">
<div className="text-block-54-copy">Детали для ТО</div>
</div>
<div className="ci2">
<div className="text-block-54">Шины</div>
</div>
<div className="ci3">
<div className="text-block-54">Диски</div>
</div>
<div className="ci4">
<div className="text-block-54">Масла и жидкости</div>
</div>
<div className="ci5">
<div className="text-block-54">Инструменты</div>
</div>
<div className="ci6">
<div className="text-block-54">Автохимия</div>
</div>
<div className="ci7">
<div className="text-block-54">Аксессуары</div>
</div>
<div className="ci8">
<div className="text-block-54">Электрика</div>
</div>
<div className="ci9">
<div className="text-block-54">АКБ</div>
</div>
</div>
</div>
</section>
);
export default CategoryNavSection;

View File

@ -0,0 +1,36 @@
import React from 'react';
const IndexTopMenuNav = () => (
<section className="topmenub">
<div className="w-layout-blockcontainer tb nav w-container">
<div className="w-layout-hflex flex-block-107">
<a href="#" className="link-block-8 w-inline-block">
<div>О компании</div>
</a>
<a href="#" className="link-block-8 w-inline-block">
<div>Оплата и доставка</div>
</a>
<a href="#" className="link-block-8 w-inline-block">
<div>Гарантия и возврат</div>
</a>
<a href="#" className="link-block-8 w-inline-block">
<div>Покупателям</div>
</a>
<a href="#" className="link-block-8 w-inline-block">
<div>Оптовым клиентам</div>
</a>
<a href="#" className="link-block-8 w-inline-block">
<div>Контакты</div>
</a>
<a href="#" className="link-block-8 green w-inline-block">
<div>Новые поступления товаров</div>
</a>
<a href="#" className="link-block-8 orange w-inline-block">
<div>Распродажа</div>
</a>
</div>
</div>
</section>
);
export default IndexTopMenuNav;

View File

@ -0,0 +1,54 @@
import React from "react";
const NewArrivalsSection: React.FC = () => (
<section className="main">
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex inbt">
<div className="w-layout-hflex flex-block-31">
<h2 className="heading-4">Новое поступление</h2>
</div>
<div className="w-layout-hflex core-product-search">
{[...Array(8)].map((_, i) => (
<div className="w-layout-vflex flex-block-15-copy" key={i}>
<div className="favcardcat">
<div className="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path></svg></div>
</div>
<div className="div-block-4">
<img
src="images/162615.webp"
loading="lazy"
width="auto"
height="auto"
alt="Новое поступление: Аккумуляторная батарея TYUMEN BATTERY"
srcSet="images/162615-p-500.webp 500w, images/162615.webp 600w"
sizes="(max-width: 600px) 100vw, 600px"
className="image-5"
/>
<div className="text-block-7">-35%</div>
</div>
<div className="div-block-3">
<div className="w-layout-hflex flex-block-16">
<div className="text-block-8">от 17 087 </div>
<div className="text-block-9">22 347 </div>
</div>
<div className="w-layout-hflex flex-block-122">
<div className="w-layout-vflex">
<div className="text-block-10">Аккумуляторная батарея TYUMEN BATTERY "STANDARD", 6CT-60L, 60</div>
<div className="text-block-11">Borsehung</div>
</div>
<a href="#" className="button-icon w-inline-block">
<div className="div-block-26">
<div className="icon-setting w-embed"><svg width="currentWidht" height="currentHeight" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z" fill="currentColor"></path></svg></div>
</div>
</a>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
);
export default NewArrivalsSection;

View File

@ -3,7 +3,7 @@ import NewsCard from "@/components/news/NewsCard";
import Link from "next/link";
const NewsAndPromos = () => (
<section>
<section className="main">
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex news-index-block">
<div className="w-layout-hflex flex-block-31">

View File

@ -0,0 +1,67 @@
import React from "react";
const ProductOfDaySection: React.FC = () => (
<section className="main">
<div className="w-layout-blockcontainer batd w-container">
<div className="w-layout-hflex flex-block-108">
<div data-delay="4000" data-animation="slide" className="slider w-slider" data-autoplay="false" data-easing="ease" data-hide-arrows="false" data-disable-swipe="false" data-autoplay-limit="0" data-nav-spacing="3" data-duration="500" data-infinite="true">
<div className="mask w-slider-mask">
<div className="slide w-slide">
<div className="div-block-128"></div>
</div>
<div className="w-slide"></div>
<div className="w-slide"></div>
</div>
<div className="left-arrow w-slider-arrow-left">
<div className="div-block-34">
<div className="code-embed-14 w-embed"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6673 10H3.33398M3.33398 10L8.33398 5M3.33398 10L8.33398 15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"></path>
</svg></div>
</div>
</div>
<div className="right-arrow w-slider-arrow-right">
<div className="div-block-34 right">
<div className="code-embed-14 w-embed"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6673 10H3.33398M3.33398 10L8.33398 5M3.33398 10L8.33398 15" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"></path>
</svg></div>
</div>
</div>
<div className="slide-nav w-slider-nav w-slider-nav-invert w-round"></div>
</div>
<div className="div-block-129">
<div className="w-layout-hflex flex-block-109">
<h1 className="heading-18">ТОВАРЫ ДНЯ</h1>
<div className="saletag">-35%</div>
</div>
<div className="w-layout-hflex flex-block-110">
<div className="w-layout-vflex flex-block-111">
<div className="w-layout-hflex flex-block-16">
<div className="text-block-8">от 17 087 </div>
<div className="text-block-9">22 347 </div>
</div>
<div className="text-block-10">Аккумуляторная батарея TYUMEN BATTERY &quot;STANDARD&quot;, 6CT-60L, 60</div>
</div><img width="Auto" height="Auto" alt="" src="/images/162615.webp" loading="lazy" srcSet="/images/162615-p-500.webp 500w, /images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" className="image-5-copy" />
</div>
<div className="w-layout-hflex flex-block-125">
<div className="div-block-134">
<div className="code-embed-17 w-embed"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6673 10H3.33398M3.33398 10L8.33398 5M3.33398 10L8.33398 15" stroke="currentcolor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"></path>
</svg></div>
</div>
<div className="div-block-134-copy">
<div className="code-embed-17 w-embed"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6673 10H3.33398M3.33398 10L8.33398 5M3.33398 10L8.33398 15" stroke="currentcolor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"></path>
</svg></div>
</div>
<div className="w-layout-hflex flex-block-126">
<div className="div-block-135"></div>
<div className="div-block-135"></div>
</div>
</div>
</div>
</div>
</div>
</section>
);
export default ProductOfDaySection;

View File

@ -0,0 +1,21 @@
import React from "react";
const PromoImagesSection: React.FC = () => (
<section className="main">
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-hflex flex-block-123">
<div className="div-block-132">
<img src="images/Group-602.png" loading="lazy" alt="Промо 1" />
</div>
<div className="div-block-132">
<img src="images/Group-603.png" loading="lazy" alt="Промо 2" />
</div>
<div className="div-block-132">
<img src="images/Group-604.png" loading="lazy" alt="Промо 3" />
</div>
</div>
</div>
</section>
);
export default PromoImagesSection;

View File

@ -0,0 +1,25 @@
import React from "react";
const SupportVinSection: React.FC = () => (
<section className="main">
<div className="w-layout-blockcontainer container-copy w-container">
<img
src="images/support_img.png"
loading="lazy"
alt="Поддержка: помощь с VIN-запросом"
className="image-27"
/>
<div className="div-block-11">
<div className="w-layout-vflex flex-block-30">
<h3 className="supportheading">МЫ ВСЕГДА РАДЫ ПОМОЧЬ</h3>
<div className="text-block-19">
Если вам нужна помощь с подбором автозапчастей, то воспользуйтесь формой VIN-запроса. Введите идентификационный номер (VIN) вашего автомобиля и мы найдём нужную деталь.
</div>
</div>
<a href="#" className="submit-button-copy w-button">Отправить VIN-запрос</a>
</div>
</div>
</section>
);
export default SupportVinSection;

View File

@ -0,0 +1,44 @@
import React from "react";
const TopSalesSection: React.FC = () => (
<section className="main">
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex inbt">
<div className="w-layout-hflex flex-block-31">
<h2 className="heading-4">Топ продаж</h2>
</div>
<div className="w-layout-hflex core-product-search">
{[...Array(8)].map((_, i) => (
<div className="w-layout-vflex flex-block-15-copy" key={i}>
<div className="favcardcat">
<div className="icon-setting w-embed"><svg width="currenWidth" height="currentHeight" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.5996 3.5C15.8107 3.5 17.5 5.1376 17.5 7.19629C17.5 8.46211 16.9057 9.65758 15.7451 11.0117C14.8712 12.0314 13.7092 13.1034 12.3096 14.3311L10.833 15.6143L10.832 15.6152L10 16.3369L9.16797 15.6152L9.16699 15.6143L7.69043 14.3311C6.29084 13.1034 5.12883 12.0314 4.25488 11.0117C3.09428 9.65758 2.50003 8.46211 2.5 7.19629C2.5 5.1376 4.18931 3.5 6.40039 3.5C7.6497 3.50012 8.85029 4.05779 9.62793 4.92188L10 5.33398L10.3721 4.92188C11.1497 4.05779 12.3503 3.50012 13.5996 3.5Z" fill="currentColor" stroke="currentColor"></path></svg></div>
</div>
<div className="div-block-4"><img src="images/162615.webp" loading="lazy" width="auto" height="auto" alt="" srcSet="images/162615-p-500.webp 500w, images/162615.webp 600w" sizes="(max-width: 600px) 100vw, 600px" className="image-5" />
<div className="text-block-7">-35%</div>
</div>
<div className="div-block-3">
<div className="w-layout-hflex flex-block-16">
<div className="text-block-8">от 17 087 </div>
<div className="text-block-9">22 347 </div>
</div>
<div className="w-layout-hflex flex-block-122">
<div className="w-layout-vflex">
<div className="text-block-10">Аккумуляторная батарея TYUMEN BATTERY "STANDARD", 6CT-60L, 60</div>
<div className="text-block-11">Borsehung</div>
</div>
<a href="#" className="button-icon w-inline-block">
<div className="div-block-26">
<div className="icon-setting w-embed"><svg width="currentWidht" height="currentHeight" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10.1998 22.2C8.8798 22.2 7.81184 23.28 7.81184 24.6C7.81184 25.92 8.8798 27 10.1998 27C11.5197 27 12.5997 25.92 12.5997 24.6C12.5997 23.28 11.5197 22.2 10.1998 22.2ZM3 3V5.4H5.39992L9.71977 14.508L8.09982 17.448C7.90783 17.784 7.79984 18.18 7.79984 18.6C7.79984 19.92 8.8798 21 10.1998 21H24.5993V18.6H10.7037C10.5357 18.6 10.4037 18.468 10.4037 18.3L10.4397 18.156L11.5197 16.2H20.4594C21.3594 16.2 22.1513 15.708 22.5593 14.964L26.8552 7.176C26.9542 6.99286 27.004 6.78718 26.9997 6.57904C26.9955 6.37089 26.9373 6.16741 26.8309 5.98847C26.7245 5.80952 26.5736 5.66124 26.3927 5.55809C26.2119 5.45495 26.0074 5.40048 25.7992 5.4H8.05183L6.92387 3H3ZM22.1993 22.2C20.8794 22.2 19.8114 23.28 19.8114 24.6C19.8114 25.92 20.8794 27 22.1993 27C23.5193 27 24.5993 25.92 24.5993 24.6C24.5993 23.28 23.5193 22.2 22.1993 22.2Z" fill="currentColor"></path></svg></div>
</div>
</a>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
);
export default TopSalesSection;

View File

@ -110,7 +110,7 @@ const LegalEntityListBlock: React.FC<LegalEntityListBlockProps> = ({ legalEntiti
</div>
<div
layer-name="link_control_element"
className="flex relative gap-1.5 items-center cursor-pointer hover:text-red-600"
className="flex relative gap-1.5 items-center cursor-pointer group"
role="button"
tabIndex={0}
onClick={() => router.push('/profile-requisites')}
@ -130,7 +130,7 @@ const LegalEntityListBlock: React.FC<LegalEntityListBlockProps> = ({ legalEntiti
</div>
<div
layer-name="Редактировать"
className="text-sm leading-5 text-gray-600"
className="text-sm leading-5 text-gray-600 group-hover:text-red-600"
>
Реквизиты компании
</div>
@ -141,8 +141,9 @@ const LegalEntityListBlock: React.FC<LegalEntityListBlockProps> = ({ legalEntiti
<div
role="button"
tabIndex={0}
className="flex relative gap-1.5 items-center cursor-pointer hover:text-red-600"
className="flex relative gap-1.5 items-center cursor-pointer group"
onClick={() => onEdit && onEdit(entity)}
aria-label="Редактировать юридическое лицо"
>
<div className="relative h-4 w-[18px]">
<Image
@ -153,26 +154,37 @@ const LegalEntityListBlock: React.FC<LegalEntityListBlockProps> = ({ legalEntiti
className="absolute left-0.5 top-0"
/>
</div>
<div className="text-sm leading-5 text-gray-600">
<div className="text-sm leading-5 text-gray-600 group-hover:text-red-600">
Редактировать
</div>
</div>
<div
role="button"
tabIndex={0}
className="flex relative gap-1.5 items-center cursor-pointer hover:text-red-600"
className="flex relative gap-1.5 items-center cursor-pointer group"
aria-label="Удалить юридическое лицо"
onClick={() => handleDelete(entity.id, entity.shortName)}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && handleDelete(entity.id, entity.shortName)}
style={{ display: 'inline-flex', cursor: 'pointer', transition: 'color 0.2s' }}
onMouseEnter={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<div className="relative h-4 w-[18px]">
<Image
src="/images/delete.svg"
alt="Удалить"
width={16}
height={16}
className="absolute left-0.5 top-0"
/>
<div className="relative h-4 w-4">
<svg width="16" height="16" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
</div>
<div className="text-sm leading-5 text-gray-600">
<div className="text-sm leading-5 text-gray-600 group-hover:text-red-600">
Удалить
</div>
</div>

View File

@ -52,14 +52,50 @@ const ProfileAddressCard: React.FC<ProfileAddressCardProps> = ({
</div>
</div>
)}
<div className="flex justify-between items-start self-stretch">
<div className="flex gap-1.5 items-center cursor-pointer group" onClick={onEdit}>
<img src="/images/edit.svg" alt="edit" width={18} height={18} className="mr-1.5 group-hover:filter-red" />
<div className="relative text-sm leading-5 text-gray-600">Редактировать</div>
<div className="flex justify-between items-start self-stretch max-sm:flex-row max-sm:gap-4 max-sm:justify-start max-sm:items-center">
<div
className="flex gap-1.5 items-center cursor-pointer group"
onClick={onEdit}
role="button"
tabIndex={0}
aria-label="Редактировать адрес"
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onEdit && onEdit()}
onMouseEnter={e => {
const svg = (e.currentTarget as HTMLElement).querySelector('img');
if (svg) (svg as HTMLImageElement).style.filter = 'invert(32%) sepia(97%) saturate(7490%) hue-rotate(355deg) brightness(97%) contrast(108%)';
}}
onMouseLeave={e => {
const svg = (e.currentTarget as HTMLElement).querySelector('img');
if (svg) (svg as HTMLImageElement).style.filter = '';
}}
>
<img src="/images/edit.svg" alt="edit" width={18} height={18} className="mr-1.5" />
<div className="relative text-sm leading-5 text-gray-600 group-hover:text-red-600 max-sm:hidden">Редактировать</div>
</div>
<div className="flex gap-1.5 items-center cursor-pointer group" onClick={onDelete}>
<img src="/images/delete.svg" alt="delete" width={18} height={18} className="mr-1.5 group-hover:filter-red" />
<div className="relative text-sm leading-5 text-gray-600">Удалить</div>
<div
className="flex gap-1.5 items-center cursor-pointer group"
role="button"
tabIndex={0}
aria-label="Удалить адрес"
onClick={onDelete}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onDelete && onDelete()}
onMouseEnter={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<svg width="18" height="18" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
<div className="relative text-sm leading-5 text-gray-600 group-hover:text-red-600 max-sm:hidden">Удалить</div>
</div>
</div>
{onSelectMain && (

View File

@ -89,11 +89,11 @@ const ProfileBalanceCard: React.FC<ProfileBalanceCardProps> = ({
{balance}
</div>
</div>
<div className="flex flex-row gap-5 items-end mt-5 w-full max-sm:flex-col">
<div className="flex flex-row gap-5 items-end mt-5 w-full max-sm:flex-col max-sm:items-start">
<div className="flex flex-col flex-1 shrink basis-0">
<div className="flex flex-col min-w-[160px]">
<div className="text-sm leading-snug text-gray-600">Лимит отсрочки</div>
<div className="flex flex-col self-start mt-2">
<div className="flex flex-col mt-2">
<div className="text-lg font-medium leading-none text-gray-950">{limit}</div>
<div className={`text-sm leading-snug ${isOverLimit ? 'text-red-600' : 'text-gray-600'}`}>
{limitLeft.includes('Не установлен') ? limitLeft : `Осталось ${limitLeft}`}

View File

@ -179,7 +179,7 @@ const ProfileGarageMain = () => {
{!vehiclesLoading && filteredVehicles.map((vehicle) => (
<div key={vehicle.id} className="mt-8">
<div className="flex flex-col justify-center pr-5 py-3 w-full rounded-lg bg-slate-50 max-md:max-w-full">
<div className="flex flex-col justify-center px-5 py-3 w-full rounded-lg bg-slate-50 max-md:max-w-full">
<div className="flex flex-wrap gap-8 items-center w-full max-md:max-w-full">
<div className="flex gap-8 items-center self-stretch my-auto min-w-[240px] max-md:flex-col max-md:min-w-0 max-md:gap-2">
<div className="self-stretch my-auto text-xl font-bold leading-none text-gray-950">
@ -203,15 +203,29 @@ const ProfileGarageMain = () => {
<div className="flex gap-5 items-center self-stretch pr-2.5 my-auto text-sm leading-snug text-gray-600 whitespace-nowrap">
<button
type="button"
className="flex gap-1.5 items-center self-stretch my-auto cursor-pointer text-sm leading-snug text-gray-600 hover:text-red-600 transition-colors"
className="flex gap-1.5 items-center self-stretch my-auto text-sm leading-snug text-gray-600 cursor-pointer bg-transparent group"
style={{ outline: 'none' }}
aria-label="Удалить автомобиль"
tabIndex={0}
onClick={() => handleDeleteVehicle(vehicle.id)}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && handleDeleteVehicle(vehicle.id)}
onMouseEnter={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<img
loading="lazy"
src="/images/delete.svg"
className="object-contain shrink-0 self-stretch my-auto aspect-[1.12] w-[18px]"
/>
<span className="self-stretch my-auto text-gray-600">
<svg width="16" height="16" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
<span className="self-stretch my-auto text-gray-600 group-hover:text-red-600">
Удалить
</span>
</button>
@ -418,15 +432,29 @@ const ProfileGarageMain = () => {
</div>
<button
type="button"
className="flex gap-1.5 items-center self-stretch my-auto text-sm leading-snug text-gray-600 cursor-pointer bg-transparent hover:text-red-600 transition-colors"
className="flex gap-1.5 items-center self-stretch my-auto text-sm leading-snug text-gray-600 cursor-pointer bg-transparent group"
style={{ outline: 'none' }}
aria-label="Удалить из истории поиска"
tabIndex={0}
onClick={() => handleDeleteFromHistory(historyItem.id)}
onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && handleDeleteFromHistory(historyItem.id)}
onMouseEnter={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<img
loading="lazy"
src="/images/delete.svg"
className="object-contain shrink-0 self-stretch my-auto aspect-[1.12] w-[18px]"
/>
<span className="self-stretch my-auto text-gray-600">
<svg width="16" height="16" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
<span className="self-stretch my-auto text-gray-600 group-hover:text-red-600">
Удалить
</span>
</button>

View File

@ -80,24 +80,25 @@ const ProfileHistoryItem: React.FC<ProfileHistoryItemProps> = ({
<div className="w-16 text-center max-md:w-full">
<button
onClick={handleDeleteClick}
className="p-2 text-red-500 hover:text-red-700 hover:bg-red-50 rounded-lg transition-colors group"
className="flex items-center p-2 group"
title="Удалить из истории"
aria-label="Удалить из истории"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="transition-colors"
tabIndex={0}
onMouseEnter={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#ec1c24');
}}
onMouseLeave={e => {
const path = e.currentTarget.querySelector('path');
if (path) path.setAttribute('fill', '#D0D0D0');
}}
>
<path d="M3 6h18" className="group-hover:stroke-[#ec1c24]" />
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" className="group-hover:stroke-[#ec1c24]" />
<path d="M8 6V4c0-1 1-2 2-2h4c-1 0 2 1 2 2v2" className="group-hover:stroke-[#ec1c24]" />
<svg width="16" height="16" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4.625 17.5C4.14375 17.5 3.73192 17.3261 3.3895 16.9782C3.04708 16.6304 2.87558 16.2117 2.875 15.7222V4.16667H2V2.38889H6.375V1.5H11.625V2.38889H16V4.16667H15.125V15.7222C15.125 16.2111 14.9538 16.6298 14.6114 16.9782C14.269 17.3267 13.8568 17.5006 13.375 17.5H4.625ZM6.375 13.9444H8.125V5.94444H6.375V13.9444ZM9.875 13.9444H11.625V5.94444H9.875V13.9444Z"
fill="#D0D0D0"
style={{ transition: 'fill 0.2s' }}
/>
</svg>
</button>
</div>

View File

@ -15,6 +15,7 @@ import {
const ProfileHistoryMain = () => {
const [search, setSearch] = useState("");
const [activeTab, setActiveTab] = useState("Все");
const [selectedManufacturer, setSelectedManufacturer] = useState("Все");
const [sortField, setSortField] = useState<"date" | "manufacturer" | "name">("date");
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc");
const [filteredItems, setFilteredItems] = useState<PartsSearchHistoryItem[]>([]);
@ -105,6 +106,14 @@ const ProfileHistoryMain = () => {
useEffect(() => {
let filtered = [...getFilteredByTime(historyItems, activeTab)];
// Фильтрация по производителю
if (selectedManufacturer !== "Все") {
filtered = filtered.filter(item =>
item.brand === selectedManufacturer ||
item.vehicleInfo?.brand === selectedManufacturer
);
}
// Поиск
if (search.trim()) {
const searchLower = search.toLowerCase();
@ -152,7 +161,7 @@ const ProfileHistoryMain = () => {
}
setFilteredItems(filtered);
}, [historyItems, search, activeTab, sortField, sortOrder]);
}, [historyItems, search, activeTab, selectedManufacturer, sortField, sortOrder]);
const handleSort = (field: "date" | "manufacturer" | "name") => {
if (sortField === field) {
@ -263,7 +272,7 @@ const ProfileHistoryMain = () => {
return (
<div className="flex flex-col min-h-[526px]">
<div className="flex flex-wrap gap-5 items-center px-8 py-3 w-full leading-snug text-gray-400 whitespace-nowrap bg-white rounded-lg max-md:px-5 max-md:max-w-full max-md:flex-col">
<div className="flex gap-5 items-center px-8 py-3 w-full leading-snug text-gray-400 whitespace-nowrap bg-white rounded-lg max-md:px-5 max-md:max-w-full">
<div className="flex-1 shrink self-stretch my-auto text-gray-400 basis-0 text-ellipsis max-md:max-w-full max-md:w-full">
<SearchInput
value={search}
@ -271,7 +280,19 @@ const ProfileHistoryMain = () => {
placeholder="Поиск в истории..."
/>
</div>
<div className="flex gap-2">
<div className="flex gap-2 max-sm:hidden">
{(selectedManufacturer !== "Все" || search.trim() || activeTab !== "Все") && (
<button
onClick={() => {
setSelectedManufacturer("Все");
setSearch("");
setActiveTab("Все");
}}
className="px-4 py-2 text-sm text-gray-600 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
Сбросить фильтры
</button>
)}
{historyItems.length === 0 && (
<button
onClick={handleCreateTestData}
@ -297,7 +318,14 @@ const ProfileHistoryMain = () => {
</div>
<div className="flex flex-col mt-5 w-full text-lg font-medium leading-tight whitespace-nowrap text-gray-950 max-md:max-w-full">
<ProfileHistoryTabs tabs={tabOptions} activeTab={activeTab} onTabChange={setActiveTab} />
<ProfileHistoryTabs
tabs={tabOptions}
activeTab={activeTab}
onTabChange={setActiveTab}
historyItems={historyItems}
selectedManufacturer={selectedManufacturer}
onManufacturerChange={setSelectedManufacturer}
/>
</div>
<div className="flex flex-col mt-5 w-full text-gray-400 max-md:max-w-full flex-1 h-full">
@ -421,6 +449,11 @@ const ProfileHistoryMain = () => {
{filteredItems.length > 0 && (
<div className="mt-4 text-center text-sm text-gray-500">
Показано {filteredItems.length} из {historyItems.length} записей
{(selectedManufacturer !== "Все" || search.trim() || activeTab !== "Все") && (
<span className="ml-2 text-blue-600">
(применены фильтры)
</span>
)}
</div>
)}
</div>

View File

@ -1,22 +1,47 @@
import React, { useState, useRef } from "react";
import { PartsSearchHistoryItem } from '@/lib/graphql/search-history';
interface ProfileHistoryTabsProps {
tabs: string[];
activeTab: string;
onTabChange: (tab: string) => void;
historyItems: PartsSearchHistoryItem[];
selectedManufacturer: string;
onManufacturerChange: (manufacturer: string) => void;
}
const manufacturers = ["Все", "VAG", "Toyota", "Ford", "BMW"];
const ProfileHistoryTabs: React.FC<ProfileHistoryTabsProps> = ({
tabs,
activeTab,
onTabChange,
historyItems,
selectedManufacturer,
onManufacturerChange,
}) => {
const [selectedManufacturer, setSelectedManufacturer] = useState(manufacturers[0]);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
// Получаем уникальных производителей из истории поиска
const getUniqueManufacturers = () => {
const manufacturersSet = new Set<string>();
historyItems.forEach(item => {
// Добавляем бренд из поля brand
if (item.brand) {
manufacturersSet.add(item.brand);
}
// Добавляем бренд из информации об автомобиле
if (item.vehicleInfo?.brand) {
manufacturersSet.add(item.vehicleInfo.brand);
}
});
const uniqueManufacturers = Array.from(manufacturersSet).sort();
return ["Все", ...uniqueManufacturers];
};
const manufacturers = getUniqueManufacturers();
// Закрытие дропдауна при клике вне
React.useEffect(() => {
function handleClickOutside(event: MouseEvent) {
@ -34,6 +59,11 @@ const ProfileHistoryTabs: React.FC<ProfileHistoryTabsProps> = ({
};
}, [isDropdownOpen]);
const handleManufacturerSelect = (manufacturer: string) => {
onManufacturerChange(manufacturer);
setIsDropdownOpen(false);
};
return (
<div className="flex flex-wrap gap-5 w-full max-md:max-w-full">
{tabs.map((tab) => (
@ -59,7 +89,7 @@ const ProfileHistoryTabs: React.FC<ProfileHistoryTabsProps> = ({
</div>
))}
<div
className="relative w-[240px] max-w-full"
className="relative w-[240px] max-w-full max-sm:w-full"
ref={dropdownRef}
tabIndex={0}
>
@ -69,20 +99,41 @@ const ProfileHistoryTabs: React.FC<ProfileHistoryTabsProps> = ({
>
<span className="truncate">{selectedManufacturer}</span>
<span className="ml-2 flex-shrink-0 flex items-center">
<svg width="20" height="20" fill="none" viewBox="0 0 20 20"><path d="M6 8l4 4 4-4" stroke="#9CA3AF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
<svg
width="20"
height="20"
fill="none"
viewBox="0 0 20 20"
className={`transition-transform duration-200 ${isDropdownOpen ? 'rotate-180' : ''}`}
>
<path d="M6 8l4 4 4-4" stroke="#9CA3AF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</span>
</div>
{isDropdownOpen && (
<ul className="absolute left-0 top-full z-10 bg-white border-x border-b border-stone-300 rounded-b-lg shadow-lg w-full">
{manufacturers.map((option) => (
<li
key={option}
className={`px-6 py-4 cursor-pointer hover:bg-blue-100 ${option === selectedManufacturer ? 'bg-blue-50 font-semibold' : ''}`}
onMouseDown={() => { setSelectedManufacturer(option); setIsDropdownOpen(false); }}
>
{option}
<ul className="absolute left-0 top-full z-10 bg-white border-x border-b border-stone-300 rounded-b-lg shadow-lg w-full max-h-60 overflow-y-auto">
{manufacturers.length === 0 ? (
<li className="px-6 py-4 text-gray-400 text-center">
Нет данных
</li>
))}
) : (
manufacturers.map((manufacturer) => (
<li
key={manufacturer}
className={`px-6 py-4 cursor-pointer hover:bg-blue-100 transition-colors ${manufacturer === selectedManufacturer ? 'bg-blue-50 font-semibold text-blue-600' : ''}`}
onMouseDown={() => handleManufacturerSelect(manufacturer)}
>
{manufacturer}
{manufacturer !== "Все" && (
<span className="ml-2 text-xs text-gray-400">
({historyItems.filter(item =>
item.brand === manufacturer || item.vehicleInfo?.brand === manufacturer
).length})
</span>
)}
</li>
))
)}
</ul>
)}
</div>

View File

@ -10,7 +10,7 @@ const ProfileSettingsActionsBlock: React.FC<ProfileSettingsActionsBlockProps> =
Сохранить изменения
</div>
<div className="gap-2.5 self-stretch px-5 py-4 my-auto rounded-xl border border-red-600 min-h-[50px] min-w-[240px] cursor-pointer bg-white text-gray-950" onClick={onAddLegalEntity}>
Добавить юридическое лицо
Добавить юр лицо
</div>
</div>
);

View File

@ -1,39 +1,249 @@
import React from "react";
import React, { useState, useEffect, useRef } from "react";
const InfoVin = () => (
<section className="section-info">
<div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9">
<div className="w-layout-hflex flex-block-7">
<a href="#" className="link-block w-inline-block">
<div>Главная</div>
</a>
<div className="text-block-3"></div>
<a href="#" className="link-block w-inline-block">
<div>Оригинальный каталог</div>
</a>
<div className="text-block-3"></div>
<a href="#" className="link-block-2 w-inline-block">
<div>Audi Q7</div>
</a>
</div>
<div className="w-layout-hflex flex-block-8">
<div className="w-layout-hflex flex-block-10">
<h1 className="heading">Audi Q7</h1>
interface VehicleAttribute {
key: string;
name: string;
value: string;
}
interface InfoVinProps {
vehicleName?: string;
vehicleInfo?: string;
vehicleAttributes?: VehicleAttribute[];
}
const InfoVin: React.FC<InfoVinProps> = ({
vehicleName = "VIN декодирование",
vehicleInfo = "Поиск запчастей по VIN номеру автомобиля",
vehicleAttributes = []
}) => {
const [showTooltip, setShowTooltip] = useState(false);
const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const iconRef = useRef<HTMLDivElement>(null);
// Отладочный вывод атрибутов
useEffect(() => {
if (vehicleAttributes.length > 0) {
console.log('🚗 Атрибуты автомобиля:', vehicleAttributes);
console.log('🔍 Ключи атрибутов:', vehicleAttributes.map(attr => ({ key: attr.key, name: attr.name })));
}
}, [vehicleAttributes]);
// Определяем основные параметры для отображения
const getMainParameters = (attributes: VehicleAttribute[]) => {
// Приоритетные ключи для основных параметров
const priorityKeys = [
// Двигатель
{
keys: ['engine', 'enginetype', 'engine_type', 'двигатель', 'тип двигателя', 'motor'],
priority: 1
},
// VIN
{
keys: ['vin', 'вин', 'vin_code'],
priority: 2
},
// Год выпуска
{
keys: ['year', 'год', 'год выпуска', 'production_year', 'model_year'],
priority: 3
},
// Топливо
{
keys: ['fuel', 'топливо', 'тип топлива', 'fuel_type', 'fueltype'],
priority: 4
},
// Коробка передач
{
keys: ['transmission', 'коробка', 'кпп', 'gearbox', 'transmissiontype'],
priority: 5
}
];
const foundParams: Array<{ attr: VehicleAttribute; priority: number }> = [];
// Ищем атрибуты по приоритетным ключам
for (const priorityGroup of priorityKeys) {
const foundAttr = attributes.find(attr =>
priorityGroup.keys.some(key =>
attr.key.toLowerCase().includes(key.toLowerCase()) ||
attr.name.toLowerCase().includes(key.toLowerCase())
)
);
if (foundAttr) {
foundParams.push({ attr: foundAttr, priority: priorityGroup.priority });
}
}
// Сортируем по приоритету и берем максимум 4 параметра
foundParams.sort((a, b) => a.priority - b.priority);
const mainParams = foundParams.slice(0, 4).map(item => item.attr);
// Если основных параметров меньше 3, добавляем первые доступные
if (mainParams.length < 3) {
const additionalParams = attributes
.filter(attr => !mainParams.includes(attr))
.slice(0, 3 - mainParams.length);
return [...mainParams, ...additionalParams];
}
return mainParams;
};
const mainParameters = getMainParameters(vehicleAttributes);
const displayText = mainParameters.length > 0
? mainParameters.map(attr => attr.value).join(' · ')
: vehicleInfo;
// Отладочный вывод выбранных параметров
useEffect(() => {
if (mainParameters.length > 0) {
console.log('✅ Выбранные основные параметры:', mainParameters);
console.log('📝 Отображаемый текст:', displayText);
}
}, [mainParameters, displayText]);
// Вычисляем позицию tooltip
const calculateTooltipPosition = () => {
if (iconRef.current) {
const rect = iconRef.current.getBoundingClientRect();
const tooltipWidth = 500;
const tooltipHeight = 300; // примерная высота
let x = rect.left + rect.width / 2 - tooltipWidth / 2;
let y = rect.bottom + 8;
// Проверяем, не выходит ли tooltip за границы экрана
if (x < 10) x = 10;
if (x + tooltipWidth > window.innerWidth - 10) {
x = window.innerWidth - tooltipWidth - 10;
}
// Если tooltip не помещается снизу, показываем сверху
if (y + tooltipHeight > window.innerHeight - 10) {
y = rect.top - tooltipHeight - 8;
}
setTooltipPosition({ x, y });
}
};
const handleMouseEnter = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
calculateTooltipPosition();
setShowTooltip(true);
}, 300); // Задержка 300ms
};
const handleMouseLeave = () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
setShowTooltip(false);
}, 100); // Небольшая задержка перед скрытием
};
// Очищаем таймеры при размонтировании
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
};
}, []);
return (
<>
<section className="section-info">
<div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9">
<div className="w-layout-hflex flex-block-7">
<a href="#" className="link-block w-inline-block">
<div>Главная</div>
</a>
<div className="text-block-3"></div>
<a href="/brands" className="link-block w-inline-block">
<div>Оригинальный каталог</div>
</a>
<div className="text-block-3"></div>
<a href="#" className="link-block-2 w-inline-block">
<div>{vehicleName}</div>
</a>
</div>
<div className="w-layout-hflex flex-block-8">
<div className="w-layout-hflex flex-block-10">
<h1 className="heading">{vehicleName}</h1>
</div>
</div>
</div>
<div className="w-layout-hflex flex-block-112">
<div className="text-block-55">{displayText}</div>
<div className="relative inline-block">
<div
ref={iconRef}
className="w-embed cursor-pointer hover:opacity-70 transition-opacity"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
role="button"
tabIndex={0}
aria-label="Показать полную информацию об автомобиле"
onFocus={handleMouseEnter}
onBlur={handleMouseLeave}
>
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.1 13.5H9.89999V8.1H8.1V13.5ZM8.99999 6.3C9.25499 6.3 9.46889 6.2136 9.64169 6.0408C9.81449 5.868 9.90059 5.6544 9.89999 5.4C9.89939 5.1456 9.81299 4.932 9.64079 4.7592C9.46859 4.5864 9.25499 4.5 8.99999 4.5C8.745 4.5 8.53139 4.5864 8.35919 4.7592C8.187 4.932 8.1006 5.1456 8.1 5.4C8.0994 5.6544 8.1858 5.8683 8.35919 6.0417C8.53259 6.2151 8.74619 6.3012 8.99999 6.3ZM8.99999 18C7.755 18 6.585 17.7636 5.49 17.2908C4.395 16.818 3.4425 16.1769 2.6325 15.3675C1.8225 14.5581 1.1814 13.6056 0.709201 12.51C0.237001 11.4144 0.000601139 10.2444 1.13924e-06 9C-0.00059886 7.7556 0.235801 6.5856 0.709201 5.49C1.1826 4.3944 1.8237 3.4419 2.6325 2.6325C3.4413 1.8231 4.3938 1.182 5.49 0.7092C6.5862 0.2364 7.7562 0 8.99999 0C10.2438 0 11.4138 0.2364 12.51 0.7092C13.6062 1.182 14.5587 1.8231 15.3675 2.6325C16.1763 3.4419 16.8177 4.3944 17.2917 5.49C17.7657 6.5856 18.0018 7.7556 18 9C17.9982 10.2444 17.7618 11.4144 17.2908 12.51C16.8198 13.6056 16.1787 14.5581 15.3675 15.3675C14.5563 16.1769 13.6038 16.8183 12.51 17.2917C11.4162 17.7651 10.2462 18.0012 8.99999 18Z" fill="currentcolor" />
</svg>
</div>
</div>
</div>
</div>
</div>
<div className="w-layout-hflex flex-block-112">
<div className="text-block-55">WAUZZZ4M6JD010702 · 2018 · SUQ(8A) · CVMD · 3000CC / 249hp / 183kW TDI CR</div>
<div className="w-embed">
{/* SVG icon */}
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.1 13.5H9.89999V8.1H8.1V13.5ZM8.99999 6.3C9.25499 6.3 9.46889 6.2136 9.64169 6.0408C9.81449 5.868 9.90059 5.6544 9.89999 5.4C9.89939 5.1456 9.81299 4.932 9.64079 4.7592C9.46859 4.5864 9.25499 4.5 8.99999 4.5C8.745 4.5 8.53139 4.5864 8.35919 4.7592C8.187 4.932 8.1006 5.1456 8.1 5.4C8.0994 5.6544 8.1858 5.8683 8.35919 6.0417C8.53259 6.2151 8.74619 6.3012 8.99999 6.3ZM8.99999 18C7.755 18 6.585 17.7636 5.49 17.2908C4.395 16.818 3.4425 16.1769 2.6325 15.3675C1.8225 14.5581 1.1814 13.6056 0.709201 12.51C0.237001 11.4144 0.000601139 10.2444 1.13924e-06 9C-0.00059886 7.7556 0.235801 6.5856 0.709201 5.49C1.1826 4.3944 1.8237 3.4419 2.6325 2.6325C3.4413 1.8231 4.3938 1.182 5.49 0.7092C6.5862 0.2364 7.7562 0 8.99999 0C10.2438 0 11.4138 0.2364 12.51 0.7092C13.6062 1.182 14.5587 1.8231 15.3675 2.6325C16.1763 3.4419 16.8177 4.3944 17.2917 5.49C17.7657 6.5856 18.0018 7.7556 18 9C17.9982 10.2444 17.7618 11.4144 17.2908 12.51C16.8198 13.6056 16.1787 14.5581 15.3675 15.3675C14.5563 16.1769 13.6038 16.8183 12.51 17.2917C11.4162 17.7651 10.2462 18.0012 8.99999 18Z" fill="currentcolor" />
</svg>
</section>
{/* Tooltip с фиксированным позиционированием */}
{showTooltip && vehicleAttributes.length > 0 && (
<div
className="fixed w-[500px] max-w-[90vw] bg-white border border-gray-200 rounded-lg shadow-xl z-[9999] p-4 animate-in fade-in-0 zoom-in-95 duration-200"
style={{
left: `${tooltipPosition.x}px`,
top: `${tooltipPosition.y}px`,
}}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{/* Заголовок */}
<div className="mb-3 pb-2 border-b border-gray-100">
<h3 className="text-sm font-semibold text-gray-900">
Полная информация об автомобиле
</h3>
<p className="text-xs text-gray-600 mt-1">{vehicleName}</p>
</div>
{/* Атрибуты в сетке */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
{vehicleAttributes.map((attr, index) => (
<div key={index} className="flex flex-col">
<dt className="text-xs font-medium text-gray-500 mb-1">{attr.name}</dt>
<dd className="text-xs text-gray-900 break-words">{attr.value}</dd>
</div>
))}
</div>
{/* Подвал */}
<div className="mt-3 pt-2 border-t border-gray-100">
<div className="text-xs text-gray-500 text-center">
Всего параметров: {vehicleAttributes.length}
</div>
</div>
</div>
</div>
</div>
</section>
);
)}
</>
);
};
export default InfoVin;

View File

@ -1,9 +1,293 @@
import React from "react";
import React, { useRef, useState } from "react";
import { useQuery } from '@apollo/client';
import { useRouter } from 'next/router';
import { GET_LAXIMO_UNIT_INFO, GET_LAXIMO_UNIT_IMAGE_MAP } from '@/lib/graphql';
import BrandSelectionModal from '../BrandSelectionModal';
const KnotIn = () => (
<div className="knotin">
<img src="/images/image-44.jpg" loading="lazy" alt="" className="image-26" />
</div>
);
interface KnotInProps {
catalogCode?: string;
vehicleId?: string;
ssd?: string;
unitId?: string;
unitName?: string;
parts?: Array<{
detailid?: string;
codeonimage?: string | number;
oem?: string;
name?: string;
price?: string | number;
brand?: string;
availability?: string;
note?: string;
attributes?: Array<{ key: string; name?: string; value: string }>;
}>;
}
// Функция для корректного формирования URL изображения
const getImageUrl = (baseUrl: string, size: string) => {
if (!baseUrl) return '';
return baseUrl
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace('%size%', size);
};
const KnotIn: React.FC<KnotInProps> = ({ catalogCode, vehicleId, ssd, unitId, unitName, parts }) => {
const imgRef = useRef<HTMLImageElement>(null);
const [imageScale, setImageScale] = useState({ x: 1, y: 1 });
const selectedImageSize = 'source';
const [isBrandModalOpen, setIsBrandModalOpen] = useState(false);
const [selectedDetail, setSelectedDetail] = useState<{ oem: string; name: string } | null>(null);
const router = useRouter();
// Получаем инфо об узле (для картинки)
console.log('🔍 KnotIn - GET_LAXIMO_UNIT_INFO запрос:', {
catalogCode,
vehicleId,
unitId,
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length,
skipCondition: !catalogCode || !vehicleId || !unitId || !ssd || ssd.trim() === ''
});
const { data: unitInfoData, loading: unitInfoLoading, error: unitInfoError } = useQuery(
GET_LAXIMO_UNIT_INFO,
{
variables: {
catalogCode,
vehicleId,
unitId,
ssd
},
skip: !catalogCode || !vehicleId || !unitId || !ssd || ssd.trim() === '',
errorPolicy: 'all',
}
);
// Получаем карту координат
console.log('🔍 KnotIn - GET_LAXIMO_UNIT_IMAGE_MAP запрос:', {
catalogCode,
vehicleId,
unitId,
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length,
skipCondition: !catalogCode || !vehicleId || !unitId || !ssd || ssd.trim() === ''
});
const { data: imageMapData, loading: imageMapLoading, error: imageMapError } = useQuery(
GET_LAXIMO_UNIT_IMAGE_MAP,
{
variables: {
catalogCode,
vehicleId,
unitId,
ssd
},
skip: !catalogCode || !vehicleId || !unitId || !ssd || ssd.trim() === '',
errorPolicy: 'all',
}
);
// Если нет необходимых данных, показываем заглушку
if (!catalogCode || !vehicleId || !unitId || !ssd || ssd.trim() === '') {
console.log('⚠️ KnotIn: отсутствуют необходимые данные:', {
catalogCode: !!catalogCode,
vehicleId: !!vehicleId,
unitId: !!unitId,
ssd: !!ssd,
ssdValid: ssd ? ssd.trim() !== '' : false
});
return (
<div className="text-center py-8 text-gray-500">
<div className="text-lg font-medium mb-2">Схема узла</div>
<div className="text-sm">Выберите узел для отображения схемы</div>
{process.env.NODE_ENV === 'development' && (
<div className="text-xs text-red-500 mt-2">
Debug: catalogCode={catalogCode}, vehicleId={vehicleId}, unitId={unitId}, ssd={ssd ? 'есть' : 'нет'}
</div>
)}
</div>
);
}
const unitInfo = unitInfoData?.laximoUnitInfo;
const coordinates = imageMapData?.laximoUnitImageMap?.coordinates || [];
const imageUrl = unitInfo?.imageurl ? getImageUrl(unitInfo.imageurl, selectedImageSize) : '';
// Логируем успешную загрузку данных
React.useEffect(() => {
if (unitInfo) {
console.log('✅ KnotIn: данные узла загружены:', {
unitName: unitInfo.name,
hasImage: !!unitInfo.imageurl,
imageUrl: unitInfo.imageurl,
processedImageUrl: imageUrl
});
}
}, [unitInfo, imageUrl]);
React.useEffect(() => {
if (coordinates.length > 0) {
console.log('✅ KnotIn: координаты карты загружены:', {
coordinatesCount: coordinates.length,
firstCoordinate: coordinates[0]
});
} else if (imageMapData) {
console.log('⚠️ KnotIn: карта изображений загружена, но координаты пустые:', imageMapData);
}
}, [coordinates, imageMapData]);
// Масштабируем точки после загрузки картинки
const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {
const img = e.currentTarget;
if (!img.naturalWidth || !img.naturalHeight) return;
setImageScale({
x: img.offsetWidth / img.naturalWidth,
y: img.offsetHeight / img.naturalHeight,
});
};
// Клик по точке: найти part по codeonimage/detailid и открыть BrandSelectionModal
const handlePointClick = (codeonimage: string | number) => {
if (!parts) return;
console.log('Клик по точке:', codeonimage, 'Все детали:', parts);
const part = parts.find(
(p) =>
(p.codeonimage && p.codeonimage.toString() === codeonimage.toString()) ||
(p.detailid && p.detailid.toString() === codeonimage.toString())
);
console.log('Найдена деталь для точки:', part);
if (part?.oem) {
setSelectedDetail({ oem: part.oem, name: part.name || '' });
setIsBrandModalOpen(true);
} else {
console.warn('Нет артикула (oem) для выбранной точки:', codeonimage, part);
}
};
// Для отладки: вывести детали и координаты
React.useEffect(() => {
console.log('KnotIn parts:', parts);
console.log('KnotIn coordinates:', coordinates);
}, [parts, coordinates]);
if (unitInfoLoading || imageMapLoading) {
console.log('🔄 KnotIn: загрузка данных...', {
unitInfoLoading,
imageMapLoading,
unitInfoError: unitInfoError?.message,
imageMapError: imageMapError?.message
});
return <div className="text-center py-8 text-gray-500">Загружаем схему узла...</div>;
}
if (unitInfoError) {
console.error('❌ KnotIn: ошибка загрузки информации об узле:', unitInfoError);
return (
<div className="text-center py-8 text-red-600">
Ошибка загрузки схемы: {unitInfoError.message}
{process.env.NODE_ENV === 'development' && (
<div className="text-xs mt-2 text-gray-500">
GraphQL Error: {JSON.stringify(unitInfoError, null, 2)}
</div>
)}
</div>
);
}
if (imageMapError) {
console.error('❌ KnotIn: ошибка загрузки карты изображений:', imageMapError);
}
if (!imageUrl) {
console.log('⚠️ KnotIn: нет URL изображения:', {
unitInfo: !!unitInfo,
imageurl: unitInfo?.imageurl,
unitInfoData: !!unitInfoData
});
return (
<div className="text-center py-8 text-gray-400">
Нет изображения для этого узла
{process.env.NODE_ENV === 'development' && unitInfo && (
<div className="text-xs mt-2 text-gray-500">
Debug: unitInfo.imageurl = {unitInfo.imageurl || 'отсутствует'}
</div>
)}
</div>
);
}
return (
<>
<div className="relative inline-block">
{/* ВРЕМЕННО: выводим количество точек для быстрой проверки */}
{/* <div style={{ position: 'absolute', top: 4, left: 4, zIndex: 20, background: 'rgba(255,0,0,0.1)', color: '#c00', fontWeight: 700, fontSize: 14, padding: '2px 8px', borderRadius: 6 }}>
{coordinates.length} точек
</div> */}
<img
ref={imgRef}
src={imageUrl}
loading="lazy"
alt={unitName || unitInfo?.name || "Изображение узла"}
onLoad={handleImageLoad}
className="max-w-full h-auto mx-auto rounded"
style={{ maxWidth: 400, display: 'block' }}
/>
{/* Точки/области */}
{coordinates.map((coord: any, idx: number) => {
// Кружки всегда 32x32px, центрируем по координате
const size = 22;
const scaledX = coord.x * imageScale.x - size / 2;
const scaledY = coord.y * imageScale.y - size / 2;
return (
<div
key={`coord-${unitId}-${idx}-${coord.x}-${coord.y}`}
tabIndex={0}
aria-label={`Деталь ${coord.codeonimage}`}
onKeyDown={e => {
if (e.key === 'Enter' || e.key === ' ') handlePointClick(coord.codeonimage);
}}
className="absolute flex items-center justify-center cursor-pointer transition-colors"
style={{
left: scaledX,
top: scaledY,
width: size,
height: size,
background: '#B7CAE2',
borderRadius: '50%',
pointerEvents: 'auto',
}}
title={coord.codeonimage}
onClick={() => handlePointClick(coord.codeonimage)}
onMouseEnter={e => {
(e.currentTarget as HTMLDivElement).style.background = '#EC1C24';
(e.currentTarget.querySelector('span') as HTMLSpanElement).style.color = '#fff';
}}
onMouseLeave={e => {
(e.currentTarget as HTMLDivElement).style.background = '#B7CAE2';
(e.currentTarget.querySelector('span') as HTMLSpanElement).style.color = '#000';
}}
>
<span className="flex items-center justify-center w-full h-full text-black text-sm font-bold select-none pointer-events-none" style={{color: '#000'}}>
{coord.codeonimage}
</span>
</div>
);
})}
</div>
{/* Модалка выбора бренда */}
<BrandSelectionModal
isOpen={isBrandModalOpen}
onClose={() => setIsBrandModalOpen(false)}
articleNumber={selectedDetail?.oem || ''}
detailName={selectedDetail?.name || ''}
/>
</>
);
};
export default KnotIn;

View File

@ -1,43 +1,80 @@
import React from "react";
import React, { useState } from "react";
import { useRouter } from "next/router";
const parts = [
{ n: 1, oem: "059198405B", name: "Фильтрующий элемент с проклад." },
{ n: 2, oem: "N 10196103", name: "Винт с цилиндр. скруглённой головкой Torx" },
{ n: 3, oem: "059117070J", name: "Уплотнитель" },
{ n: 4, oem: "N 10124306", name: "Винт с плоской головкой и внутренним Torx" },
{ n: 5, oem: "059117015K", name: "Масляный радиатор" },
{ n: 6, oem: "059117015K", name: "Масляный радиатор" },
{ n: 7, oem: "059117015K", name: "Масляный радиатор" },
{ n: 8, oem: "059117015K", name: "Масляный радиатор" },
{ n: 9, oem: "059117015K", name: "Масляный радиатор" },
{ n: 10, oem: "059117015K", name: "Масляный радиатор" },
{ n: 11, oem: "059117015K", name: "Масляный радиатор" },
{ n: 12, oem: "059117015K", name: "Масляный радиатор" },
{ n: 13, oem: "059117015K", name: "Масляный радиатор" },
{ n: 14, oem: "059117015K", name: "Масляный радиатор" },
{ n: 15, oem: "059117015K", name: "Масляный радиатор" },
];
interface KnotPartsProps {
parts?: Array<{
detailid?: string;
codeonimage?: string | number;
oem?: string;
name?: string;
price?: string | number;
brand?: string;
availability?: string;
note?: string;
attributes?: Array<{ key: string; name?: string; value: string }>;
}>;
selectedCodeOnImage?: string | number;
catalogCode?: string;
vehicleId?: string;
}
const KnotParts = () => (
<div className="knot-parts">
{parts.map((part, idx) => (
<div className="w-layout-hflex knotlistitem" key={idx}>
<div className="w-layout-hflex flex-block-116">
<div className="nuberlist">{part.n}</div>
<div className="oemnuber">{part.oem}</div>
</div>
<div className="partsname">{part.name}</div>
<div className="w-layout-hflex flex-block-117">
<a href="#" className="button-3 w-button">Цена</a>
<div className="code-embed-16 w-embed">
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.1 13.5H9.89999V8.1H8.1V13.5ZM8.99999 6.3C9.25499 6.3 9.46889 6.2136 9.64169 6.0408C9.81449 5.868 9.90059 5.6544 9.89999 5.4C9.89939 5.1456 9.81299 4.932 9.64079 4.7592C9.46859 4.5864 9.25499 4.5 8.99999 4.5C8.745 4.5 8.53139 4.5864 8.35919 4.7592C8.187 4.932 8.1006 5.1456 8.1 5.4C8.0994 5.6544 8.1858 5.8683 8.35919 6.0417C8.53259 6.2151 8.74619 6.3012 8.99999 6.3ZM8.99999 18C7.755 18 6.585 17.7636 5.49 17.2908C4.395 16.818 3.4425 16.1769 2.6325 15.3675C1.8225 14.5581 1.1814 13.6056 0.709201 12.51C0.237001 11.4144 0.000601139 10.2444 1.13924e-06 9C-0.00059886 7.7556 0.235801 6.5856 0.709201 5.49C1.1826 4.3944 1.8237 3.4419 2.6325 2.6325C3.4413 1.8231 4.3938 1.182 5.49 0.7092C6.5862 0.2364 7.7562 0 8.99999 0C10.2438 0 11.4138 0.2364 12.51 0.7092C13.6062 1.182 14.5587 1.8231 15.3675 2.6325C16.1763 3.4419 16.8177 4.3944 17.2917 5.49C17.7657 6.5856 18.0018 7.7556 18 9C17.9982 10.2444 17.7618 11.4144 17.2908 12.51C16.8198 13.6056 16.1787 14.5581 15.3675 15.3675C14.5563 16.1769 13.6038 16.8183 12.51 17.2917C11.4162 17.7651 10.2462 18.0012 8.99999 18Z" fill="currentcolor" />
</svg>
</div>
const KnotParts: React.FC<KnotPartsProps> = ({ parts = [], selectedCodeOnImage, catalogCode, vehicleId }) => {
const router = useRouter();
const handlePriceClick = (part: any) => {
if (part.oem && catalogCode && vehicleId !== undefined) {
// Переходим на страницу выбора бренда
const url = `/vehicle-search/${catalogCode}/${vehicleId}/part/${part.oem}/brands?detailName=${encodeURIComponent(part.name || '')}`;
router.push(url);
}
};
// Если нет деталей, показываем заглушку
if (!parts || parts.length === 0) {
return (
<div className="knot-parts">
<div className="text-center py-8 text-gray-500">
<div className="text-lg font-medium mb-2">Список деталей</div>
<div className="text-sm">Выберите узел для отображения деталей</div>
</div>
</div>
))}
</div>
);
);
}
return (
<>
<div className="knot-parts">
{parts.map((part, idx) => {
const isSelected = part.codeonimage && part.codeonimage === selectedCodeOnImage;
return (
<div
className={`w-layout-hflex knotlistitem border rounded transition-colors duration-150 ${isSelected ? 'bg-yellow-100 border-yellow-400' : 'border-transparent'}`}
key={part.detailid || idx}
>
<div className="w-layout-hflex flex-block-116">
<div className="nuberlist">{part.codeonimage || idx + 1}</div>
<div className="oemnuber">{part.oem}</div>
</div>
<div className="partsname">{part.name}</div>
<div className="w-layout-hflex flex-block-117">
<button
className="button-3 w-button"
onClick={() => handlePriceClick(part)}
>
Цена
</button>
<div className="code-embed-16 w-embed">
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.1 13.5H9.89999V8.1H8.1V13.5ZM8.99999 6.3C9.25499 6.3 9.46889 6.2136 9.64169 6.0408C9.81449 5.868 9.90059 5.6544 9.89999 5.4C9.89939 5.1456 9.81299 4.932 9.64079 4.7592C9.46859 4.5864 9.25499 4.5 8.99999 4.5C8.745 4.5 8.53139 4.5864 8.35919 4.7592C8.187 4.932 8.1006 5.1456 8.1 5.4C8.0994 5.6544 8.1858 5.8683 8.35919 6.0417C8.53259 6.2151 8.74619 6.3012 8.99999 6.3ZM8.99999 18C7.755 18 6.585 17.7636 5.49 17.2908C4.395 16.818 3.4425 16.1769 2.6325 15.3675C1.8225 14.5581 1.1814 13.6056 0.709201 12.51C0.237001 11.4144 0.000601139 10.2444 1.13924e-06 9C-0.00059886 7.7556 0.235801 6.5856 0.709201 5.49C1.1826 4.3944 1.8237 3.4419 2.6325 2.6325C3.4413 1.8231 4.3938 1.182 5.49 0.7092C6.5862 0.2364 7.7562 0 8.99999 0C10.2438 0 11.4138 0.2364 12.51 0.7092C13.6062 1.182 14.5587 1.8231 15.3675 2.6325C16.1763 3.4419 16.8177 4.3944 17.2917 5.49C17.7657 6.5856 18.0018 7.7556 18 9C17.9982 10.2444 17.7618 11.4144 17.2908 12.51C16.8198 13.6056 16.1787 14.5581 15.3675 15.3675C14.5563 16.1769 13.6038 16.8183 12.51 17.2917C11.4162 17.7651 10.2462 18.0012 8.99999 18Z" fill="currentcolor" />
</svg>
</div>
</div>
</div>
);
})}
</div>
</>
);
};
export default KnotParts;

View File

@ -1,40 +1,192 @@
import React from "react";
const categories = [
"Детали для ТО",
"Двигатель",
"Топливная система",
"Система охлаждения",
"Система выпуска",
"Трансмиссия",
"Ходовая часть",
"Рулевое управление",
"Тормозная система",
"Электрооборудование",
"Отопление / кондиционирование",
"Детали салона",
"Детали кузова",
"Дополнительное оборудование"
];
import React, { useState, useEffect, useRef } from 'react';
import { useQuery, useLazyQuery } from '@apollo/client';
import { GET_LAXIMO_CATEGORIES, GET_LAXIMO_QUICK_GROUPS, GET_LAXIMO_UNITS } from '@/lib/graphql/laximo';
interface VinCategoryProps {
onCategoryClick?: (e: React.MouseEvent) => void;
catalogCode?: string;
vehicleId?: string;
ssd?: string;
onNodeSelect?: (node: any) => void;
activeTab?: 'uzly' | 'manufacturer';
onQuickGroupSelect?: (group: any) => void;
onCategoryClick?: (e?: React.MouseEvent) => void;
openedPath?: string[];
setOpenedPath?: (path: string[]) => void;
}
const VinCategory: React.FC<VinCategoryProps> = ({ onCategoryClick }) => (
<div className="w-layout-vflex flex-block-14-copy-copy">
{categories.map((cat, idx) => (
<div className="div-block-131" key={idx} onClick={onCategoryClick} style={{ cursor: onCategoryClick ? 'pointer' : undefined }}>
<div className="text-block-57">{cat}</div>
<div className="w-embed">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="24" width="24" height="24" rx="12" transform="rotate(90 24 0)" fill="currentcolor"></rect>
<path fillRule="evenodd" clipRule="evenodd" d="M10.9303 17L10 16.0825L14.1395 12L10 7.91747L10.9303 7L16 12L10.9303 17Z" fill="white"></path>
</svg>
const VinCategory: React.FC<VinCategoryProps> = ({ catalogCode, vehicleId, ssd, onNodeSelect, activeTab = 'uzly', onQuickGroupSelect, onCategoryClick, openedPath = [], setOpenedPath = () => {} }) => {
const [unitsByCategory, setUnitsByCategory] = useState<{ [key: string]: any[] }>({});
const lastCategoryIdRef = useRef<string | null>(null);
// Запрос для "Общие" (QuickGroups)
const { data: quickGroupsData, loading: quickGroupsLoading, error: quickGroupsError } = useQuery(GET_LAXIMO_QUICK_GROUPS, {
variables: { catalogCode: catalogCode || '', vehicleId: vehicleId || '', ssd: ssd || '' },
skip: !catalogCode || !vehicleId || activeTab !== 'uzly',
errorPolicy: 'all'
});
// Запрос для "От производителя" (Categories)
const { data: categoriesData, loading: categoriesLoading, error: categoriesError } = useQuery(GET_LAXIMO_CATEGORIES, {
variables: { catalogCode: catalogCode || '', vehicleId: vehicleId || '', ssd: ssd || '' },
skip: !catalogCode || !vehicleId || activeTab !== 'manufacturer',
errorPolicy: 'all'
});
// Запрос для получения units (подкатегорий) в режиме "От производителя"
const [getUnits] = useLazyQuery(GET_LAXIMO_UNITS, {
onCompleted: (data) => {
if (data && data.laximoUnits && lastCategoryIdRef.current) {
setUnitsByCategory(prev => ({
...prev,
[lastCategoryIdRef.current!]: data.laximoUnits || []
}));
}
},
onError: (error) => {
console.error('Error loading units:', error);
}
});
// categories теперь зависят от activeTab
let categories = activeTab === 'uzly' ? (quickGroupsData?.laximoQuickGroups || []) : (categoriesData?.laximoCategories || []);
let selectedCategory: any = null;
let currentLevel = 0;
let currentList = categories;
while (openedPath[currentLevel]) {
const found = currentList.find((cat: any) => (cat.quickgroupid || cat.categoryid || cat.id) === openedPath[currentLevel]);
if (!found) break;
selectedCategory = found;
currentList = found.children || [];
currentLevel++;
}
const loading = activeTab === 'uzly' ? quickGroupsLoading : categoriesLoading;
const error = activeTab === 'uzly' ? quickGroupsError : categoriesError;
const handleBack = () => {
setOpenedPath(openedPath.slice(0, openedPath.length - 1));
};
const handleCategoryClick = (category: any, level: number) => {
if (onCategoryClick) {
onCategoryClick();
return;
}
if (category.children && category.children.length > 0) {
if (openedPath[level] === (category.quickgroupid || category.categoryid || category.id)) {
setOpenedPath(openedPath.slice(0, level));
} else {
setOpenedPath([...openedPath.slice(0, level), (category.quickgroupid || category.categoryid || category.id)]);
}
} else if (category.link && onQuickGroupSelect) {
onQuickGroupSelect(category);
} else if (onNodeSelect) {
onNodeSelect(category);
}
};
const handleSubcategoryClick = (subcat: any) => {
if (activeTab === 'manufacturer' && onNodeSelect) {
// Для режима "От производителя" при клике на подкатегорию открываем KnotIn
onNodeSelect({
...subcat,
unitid: subcat.unitid || subcat.categoryid || subcat.quickgroupid || subcat.id
});
} else {
handleCategoryClick(subcat, 0);
}
};
// Если нет данных о транспортном средстве, показываем заглушку
if (!catalogCode || !vehicleId) {
return (
<div className="w-layout-vflex flex-block-14-copy-copy">
<div className="text-center py-8 text-gray-500">
<div className="text-lg font-medium mb-2">Каталог запчастей</div>
<div className="text-sm">Выберите автомобиль для просмотра каталога</div>
</div>
</div>
))}
</div>
);
);
}
if (loading) return <div>Загрузка категорий...</div>;
if (error) return <div style={{ color: "red" }}>Ошибка: {error.message}</div>;
// Определяем, какие подкатегории показывать
let subcategories: any[] = [];
if (selectedCategory) {
if (activeTab === 'uzly') {
// Для вкладки "Общие" используем children
subcategories = selectedCategory.children || [];
} else {
// Для вкладки "От производителя" используем либо children, либо units
if (selectedCategory.children && selectedCategory.children.length > 0) {
subcategories = selectedCategory.children;
} else {
const categoryId = selectedCategory.categoryid || selectedCategory.quickgroupid || selectedCategory.id;
subcategories = unitsByCategory[categoryId] || [];
}
}
}
return (
<div className="w-layout-vflex flex-block-14-copy-copy">
{!selectedCategory ? (
// Список категорий
categories.map((cat: any, idx: number) => (
<div
className="div-block-131"
key={cat.quickgroupid || cat.categoryid || cat.id || idx}
onClick={() => handleCategoryClick(cat, 0)}
style={{ cursor: "pointer" }}
>
<div className="text-block-57">{cat.name}</div>
<div className="w-embed">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="24" width="24" height="24" rx="12" transform="rotate(90 24 0)" fill="currentcolor"></rect>
<path fillRule="evenodd" clipRule="evenodd" d="M10.9303 17L10 16.0825L14.1395 12L10 7.91747L10.9303 7L16 12L10.9303 17Z" fill="white"></path>
</svg>
</div>
</div>
))
) : (
// Список подкатегорий
<>
{(() => {
// Найти текущий уровень вложенности для selectedCategory
let level = 0;
let list = categories;
while (openedPath[level] && list) {
const found = list.find((cat: any) => (cat.quickgroupid || cat.categoryid || cat.id) === openedPath[level]);
if (!found) break;
if (found === selectedCategory) break;
list = found.children || [];
level++;
}
// Теперь level - это уровень selectedCategory, подкатегории будут на level+1
const subcategories = selectedCategory.children || [];
if (subcategories.length === 0) return <div style={{ color: "#888", padding: 8 }}>Нет подкатегорий</div>;
return subcategories.map((subcat: any, idx: number) => (
<div
className="div-block-131"
key={subcat.quickgroupid || subcat.categoryid || subcat.unitid || subcat.id || idx}
onClick={() => handleCategoryClick(subcat, level + 1)}
style={{ cursor: "pointer" }}
>
<div className="text-block-57">{subcat.name}</div>
<div className="w-embed">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="24" width="24" height="24" rx="12" transform="rotate(90 24 0)" fill="currentcolor"></rect>
<path fillRule="evenodd" clipRule="evenodd" d="M10.9303 17L10 16.0825L14.1395 12L10 7.91747L10.9303 7L16 12L10.9303 17Z" fill="white"></path>
</svg>
</div>
</div>
));
})()}
</>
)}
</div>
);
};
export default VinCategory;

View File

@ -1,35 +1,230 @@
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { useLazyQuery, useQuery } from '@apollo/client';
import { GET_LAXIMO_FULLTEXT_SEARCH, GET_LAXIMO_CATEGORIES, GET_LAXIMO_UNITS, GET_LAXIMO_QUICK_GROUPS, GET_LAXIMO_QUICK_DETAIL } from '@/lib/graphql/laximo';
const dropdownTitles = [
"Детали для ТО",
"Двигатель",
"Топливная система",
"Система охлаждения",
"Система выпуска",
"Трансмиссия",
"Ходовая часть",
"Рулевое управление",
"Тормозная система",
"Электрооборудование",
"Отопление / кондиционирование",
"Детали салона",
"Детали кузова",
"Дополнительное оборудование"
];
const VinLeftbar = () => {
const [openIndex, setOpenIndex] = useState<number | null>(null);
const handleToggle = (idx: number) => {
setOpenIndex(openIndex === idx ? null : idx);
interface VinLeftbarProps {
vehicleInfo?: {
catalog: string;
vehicleid: string;
ssd: string;
[key: string]: any;
};
onSearchResults?: (data: {
results: any[];
loading: boolean;
error: any;
query: string;
isSearching?: boolean;
}) => void;
onNodeSelect?: (node: any) => void;
onActiveTabChange?: (tab: 'uzly' | 'manufacturer') => void;
onQuickGroupSelect?: (group: any) => void;
activeTab?: 'uzly' | 'manufacturer';
openedPath?: string[];
setOpenedPath?: (path: string[]) => void;
}
interface QuickGroup {
quickgroupid: string;
name: string;
link?: boolean;
children?: QuickGroup[];
}
const VinLeftbar: React.FC<VinLeftbarProps> = ({ vehicleInfo, onSearchResults, onNodeSelect, onActiveTabChange, onQuickGroupSelect, activeTab: activeTabProp, openedPath = [], setOpenedPath = () => {} }) => {
const catalogCode = vehicleInfo?.catalog || '';
const vehicleId = vehicleInfo?.vehicleid || '';
const ssd = vehicleInfo?.ssd || '';
const [searchQuery, setSearchQuery] = useState('');
const [executeSearch, { data, loading, error }] = useLazyQuery(GET_LAXIMO_FULLTEXT_SEARCH, { errorPolicy: 'all' });
const { data: categoriesData, loading: categoriesLoading, error: categoriesError } = useQuery(GET_LAXIMO_CATEGORIES, {
variables: { catalogCode, vehicleId, ssd },
skip: !catalogCode || vehicleId === undefined || vehicleId === null,
errorPolicy: 'all'
});
const categories = categoriesData?.laximoCategories || [];
const [unitsByCategory, setUnitsByCategory] = useState<{ [key: string]: any[] }>({});
const [getUnits] = useLazyQuery(GET_LAXIMO_UNITS, {
onCompleted: (data) => {
if (data && data.laximoUnits && lastCategoryIdRef.current) {
setUnitsByCategory(prev => ({
...prev,
[lastCategoryIdRef.current!]: data.laximoUnits || []
}));
}
}
});
const lastCategoryIdRef = React.useRef<string | null>(null);
const handleToggle = (categoryId: string, level: number) => {
if (openedPath[level] === categoryId) {
setOpenedPath(openedPath.slice(0, level));
} else {
setOpenedPath([...openedPath.slice(0, level), categoryId]);
// Загружаем units для категории, если они еще не загружены
if (activeTabProp === 'manufacturer' && !unitsByCategory[categoryId]) {
lastCategoryIdRef.current = categoryId;
getUnits({
variables: {
catalogCode,
vehicleId,
ssd,
categoryId
}
});
}
}
};
const handleSearch = () => {
if (!searchQuery.trim()) return;
if (!ssd || ssd.trim() === '') {
console.error('SSD обязателен для поиска по названию');
return;
}
executeSearch({
variables: {
catalogCode,
vehicleId,
searchQuery: searchQuery.trim(),
ssd
}
});
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault();
handleSearch();
}
};
const searchResults = data?.laximoFulltextSearch;
useEffect(() => {
if (onSearchResults) {
onSearchResults({
results: searchResults?.details || [],
loading: loading,
error: error,
query: searchQuery
});
}
}, [searchResults, loading, error, searchQuery]);
// --- Новый блок: вычисляем доступность поиска ---
const isSearchAvailable = !!catalogCode && vehicleId !== undefined && vehicleId !== null && !!ssd && ssd.trim() !== '';
const showWarning = !isSearchAvailable;
const showError = !!error && isSearchAvailable && searchQuery.trim();
const showNotFound = isSearchAvailable && searchQuery.trim() && !loading && data && searchResults && searchResults.details && searchResults.details.length === 0;
const showTips = isSearchAvailable && !searchQuery.trim() && !loading;
// --- QuickGroups (от производителя) ---
const { data: quickGroupsData, loading: quickGroupsLoading, error: quickGroupsError } = useQuery(GET_LAXIMO_QUICK_GROUPS, {
variables: { catalogCode, vehicleId, ssd },
skip: !catalogCode || vehicleId === undefined || vehicleId === null,
errorPolicy: 'all'
});
const quickGroups = quickGroupsData?.laximoQuickGroups || [];
const handleQuickGroupToggle = (groupId: string, level: number) => {
if (openedPath[level] === groupId) {
setOpenedPath(openedPath.slice(0, level));
} else {
setOpenedPath([...openedPath.slice(0, level), groupId]);
}
};
// === Полнотекстовый поиск деталей (аналогично FulltextSearchSection) ===
const [fulltextQuery, setFulltextQuery] = useState('');
const [executeFulltextSearch, { data: fulltextData, loading: fulltextLoading, error: fulltextError }] = useLazyQuery(GET_LAXIMO_FULLTEXT_SEARCH, { errorPolicy: 'all' });
const handleFulltextSearch = () => {
if (!fulltextQuery.trim()) {
if (onSearchResults) {
onSearchResults({
results: [],
loading: false,
error: null,
query: '',
isSearching: false
});
}
return;
}
if (!ssd || ssd.trim() === '') {
console.error('SSD обязателен для поиска по названию');
return;
}
// Отправляем начальное состояние поиска родителю
if (onSearchResults) {
onSearchResults({
results: [],
loading: true,
error: null,
query: fulltextQuery.trim(),
isSearching: true
});
}
executeFulltextSearch({
variables: {
catalogCode,
vehicleId,
searchQuery: fulltextQuery.trim(),
ssd
}
});
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
setFulltextQuery(newValue);
};
useEffect(() => {
if (onSearchResults && (fulltextData || fulltextLoading || fulltextError)) {
onSearchResults({
results: fulltextData?.laximoFulltextSearch?.details || [],
loading: fulltextLoading,
error: fulltextError,
query: fulltextQuery,
isSearching: true
});
}
}, [fulltextData, fulltextLoading, fulltextError, fulltextQuery]);
const handleFulltextKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault();
handleFulltextSearch();
}
};
const fulltextResults = fulltextData?.laximoFulltextSearch?.details || [];
// Если нет данных о транспортном средстве, показываем заглушку
if (!vehicleInfo) {
return (
<div className="w-layout-vflex vinleftbar">
<div className="text-center py-8 text-gray-500">
<div className="text-lg font-medium mb-2">Поиск запчастей</div>
<div className="text-sm">Выберите автомобиль для поиска запчастей</div>
</div>
</div>
);
}
return (
<div className="w-layout-vflex vinleftbar">
{/* === Форма полнотекстового поиска === */}
<div className="div-block-2">
<div className="form-block w-form">
<form id="wf-form-search" name="wf-form-search" data-name="search" action="http://search" method="post" className="form" data-wf-page-id="685d5478c4ebd5c8793f8c54" data-wf-element-id="14d3a852-00ba-b161-8849a97059b3785d">
<a href="#" className="link-block-3 w-inline-block">
<form id="vin-form-search" name="vin-form-search" data-name="vin-form-search" action="#" method="post" className="form" onSubmit={e => { e.preventDefault(); handleFulltextSearch(); }}>
<a href="#" className="link-block-3 w-inline-block" onClick={e => { e.preventDefault(); handleFulltextSearch(); }}>
<div className="code-embed-6 w-embed">
{/* SVG */}
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -38,48 +233,271 @@ const VinLeftbar = () => {
</svg>
</div>
</a>
<input className="text-field w-input" maxLength={256} name="Search" data-name="Search" placeholder="Поиск по названию детали" type="text" id="Search-4" required />
<input
className="text-field w-input"
maxLength={256}
name="VinSearch"
data-name="VinSearch"
placeholder="Поиск по названию детали"
type="text"
id="VinSearchInput"
required
value={fulltextQuery}
onChange={handleInputChange}
onKeyDown={handleFulltextKeyDown}
disabled={fulltextLoading}
/>
</form>
<div className="success-message w-form-done">
<div>Thank you! Your submission has been received!</div>
</div>
<div className="error-message w-form-fail">
<div>Oops! Something went wrong while submitting the form.</div>
</div>
{(!ssd || ssd.trim() === '') && (
<div className="mt-3 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
<div className="flex">
<svg className="h-5 w-5 text-yellow-400 flex-shrink-0" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
<div className="ml-3">
<h3 className="text-sm font-medium text-yellow-800">
Полнотекстовый поиск недоступен
</h3>
<p className="text-sm text-yellow-700 mt-1">
Для поиска по названию деталей необходимо сначала выбрать конкретный автомобиль через поиск по VIN или мастер подбора.
</p>
</div>
</div>
</div>
)}
</div>
</div>
<div className="w-layout-vflex flex-block-113">
<div className="w-layout-hflex flex-block-114">
<a href="#" className="button-3 w-button">Узлы</a>
<a href="#" className="button-23 w-button">От производителя</a>
<a
href="#"
className={
searchQuery
? 'button-23 w-button'
: activeTabProp === 'uzly'
? 'button-3 w-button'
: 'button-23 w-button'
}
onClick={e => {
e.preventDefault();
if (searchQuery) setSearchQuery('');
if (onActiveTabChange) onActiveTabChange('uzly');
if (onQuickGroupSelect) onQuickGroupSelect(null);
}}
>
Узлы
</a>
<a
href="#"
className={
searchQuery
? 'button-23 w-button'
: activeTabProp === 'manufacturer'
? 'button-3 w-button'
: 'button-23 w-button'
}
onClick={e => {
e.preventDefault();
if (searchQuery) setSearchQuery('');
if (onActiveTabChange) onActiveTabChange('manufacturer');
if (onQuickGroupSelect) onQuickGroupSelect(null);
}}
>
От производителя
</a>
</div>
{/* Dropdowns start */}
{dropdownTitles.map((title, idx) => {
const isOpen = openIndex === idx;
return (
<div
key={idx}
data-hover="false"
data-delay="0"
className={`dropdown-4 w-dropdown${isOpen ? " w--open" : ""}`}
>
<div
className={`dropdown-toggle-3 w-dropdown-toggle${isOpen ? " w--open" : ""}`}
onClick={() => handleToggle(idx)}
style={{ cursor: "pointer" }}
>
<div className="w-icon-dropdown-toggle"></div>
<div className="text-block-56">{title}</div>
</div>
<nav className={`dropdown-list-4 w-dropdown-list${isOpen ? " w--open" : ""}`}>
<a href="#" className="dropdown-link-3 w-dropdown-link">Link 1</a>
<a href="#" className="dropdown-link-3 w-dropdown-link">Link 2</a>
<a href="#" className="dropdown-link-3 w-dropdown-link">Link 3</a>
</nav>
</div>
);
})}
{/* Dropdowns end */}
{/* Tab content start */}
{activeTabProp === 'uzly' ? (
// Общие (QuickGroups - бывшие "От производителя")
quickGroupsLoading ? (
<div style={{ padding: 16, textAlign: 'center' }}>Загружаем группы быстрого поиска...</div>
) : quickGroupsError ? (
<div style={{ color: 'red', padding: 16 }}>Ошибка загрузки групп: {quickGroupsError.message}</div>
) : (
<>
{(quickGroups as QuickGroup[]).map((group: QuickGroup) => {
const hasChildren = group.children && group.children.length > 0;
const isOpen = openedPath.includes(group.quickgroupid);
if (!hasChildren) {
return (
<a
href="#"
key={group.quickgroupid}
className="dropdown-link-3 w-dropdown-link"
onClick={(e) => {
e.preventDefault();
// Если это конечная группа с link=true, открываем QuickGroup
if (group.link && onQuickGroupSelect) {
onQuickGroupSelect(group);
} else {
handleQuickGroupToggle(group.quickgroupid, 0);
}
}}
>
{group.name}
</a>
);
}
return (
<div
key={group.quickgroupid}
data-hover="false"
data-delay="0"
className={`dropdown-4 w-dropdown${isOpen ? " w--open" : ""}`}
>
<div
className={`dropdown-toggle-3 w-dropdown-toggle${isOpen ? " w--open active" : ""}`}
onClick={(e) => {
e.preventDefault();
handleQuickGroupToggle(group.quickgroupid, 0);
}}
style={{ cursor: "pointer" }}
>
<div className="w-icon-dropdown-toggle"></div>
<div className="text-block-56">{group.name}</div>
</div>
<nav className={`dropdown-list-4 w-dropdown-list${isOpen ? " w--open" : ""}`}>
{group.children?.map((child: QuickGroup) => {
const hasSubChildren = child.children && child.children.length > 0;
const isChildOpen = openedPath.includes(child.quickgroupid);
if (!hasSubChildren) {
return (
<a
href="#"
key={child.quickgroupid}
className="dropdown-link-3 w-dropdown-link"
onClick={(e) => {
e.preventDefault();
// Если это конечная группа с link=true, открываем QuickGroup
if (child.link && onQuickGroupSelect) {
onQuickGroupSelect(child);
} else {
handleQuickGroupToggle(child.quickgroupid, 1);
}
}}
>
{child.name}
</a>
);
}
return (
<div
key={child.quickgroupid}
data-hover="false"
data-delay="0"
className={`dropdown-4 w-dropdown pl-0${isChildOpen ? " w--open" : ""}`}
>
<div
className={`dropdown-toggle-card w-dropdown-toggle pl-0${isChildOpen ? " w--open active" : ""}`}
onClick={(e) => {
e.preventDefault();
handleQuickGroupToggle(child.quickgroupid, 2);
}}
style={{ cursor: "pointer" }}
>
<div className="w-icon-dropdown-toggle"></div>
<div className="text-block-56">{child.name}</div>
</div>
<nav className={`dropdown-list-4 w-dropdown-list pl-0${isChildOpen ? " w--open" : ""}`}>
{child.children?.map((subChild: QuickGroup) => (
<a
href="#"
key={subChild.quickgroupid}
className="dropdown-link-3 w-dropdown-link"
onClick={(e) => {
e.preventDefault();
// Если это конечная группа с link=true, открываем QuickGroup
if (subChild.link && onQuickGroupSelect) {
onQuickGroupSelect(subChild);
} else {
handleQuickGroupToggle(subChild.quickgroupid, 3);
}
}}
>
{subChild.name}
</a>
))}
</nav>
</div>
);
})}
</nav>
</div>
);
})}
</>
)
) : (
// От производителя (Categories - узлы)
categoriesLoading ? (
<div style={{ padding: 16, textAlign: 'center' }}>Загружаем категории...</div>
) : categoriesError ? (
<div style={{ color: 'red', padding: 16 }}>Ошибка загрузки категорий: {categoriesError.message}</div>
) : (
<>
{categories.map((category: any, idx: number) => {
const isOpen = openedPath.includes(category.quickgroupid);
const subcategories = category.children && category.children.length > 0
? category.children
: unitsByCategory[category.quickgroupid] || [];
return (
<div
key={category.quickgroupid}
data-hover="false"
data-delay="0"
className={`dropdown-4 w-dropdown${isOpen ? " w--open" : ""}`}
>
<div
className={`dropdown-toggle-3 w-dropdown-toggle${isOpen ? " w--open" : ""}`}
onClick={(e) => {
e.preventDefault();
handleToggle(category.quickgroupid, 0);
}}
style={{ cursor: "pointer" }}
>
<div className="w-icon-dropdown-toggle"></div>
<div className="text-block-56">{category.name}</div>
</div>
<nav className={`dropdown-list-4 w-dropdown-list${isOpen ? " w--open" : ""}`}>
{subcategories.length > 0 ? (
subcategories.map((subcat: any) => (
<a
href="#"
key={subcat.quickgroupid || subcat.unitid}
className="dropdown-link-3 w-dropdown-link pl-0"
onClick={e => {
e.preventDefault();
// Если это конечная категория с link=true, открываем QuickGroup
if (subcat.link && onQuickGroupSelect) {
onQuickGroupSelect(subcat);
} else if (onNodeSelect) {
onNodeSelect({
...subcat,
unitid: subcat.unitid || subcat.quickgroupid || subcat.id
});
}
}}
>
{subcat.name}
</a>
))
) : (
<span style={{ color: '#888', padding: 8 }}>Нет подкатегорий</span>
)}
</nav>
</div>
);
})}
</>
)
)}
{/* Tab content end */}
</div>
</div>
);

View File

@ -0,0 +1,48 @@
import React from "react";
import { useRouter } from 'next/router';
interface VinPartCardProps {
n?: number;
oem: string;
name: string;
onPriceClick?: () => void;
catalogCode?: string;
vehicleId?: string;
}
const VinPartCard: React.FC<VinPartCardProps> = ({ n, oem, name, onPriceClick, catalogCode, vehicleId }) => {
const router = useRouter();
const handlePriceClick = (e: React.MouseEvent) => {
e.preventDefault();
if (onPriceClick) onPriceClick();
if (catalogCode && vehicleId !== undefined) {
// Переходим на страницу выбора бренда
const url = `/vehicle-search/${catalogCode}/${vehicleId}/part/${oem}/brands?detailName=${encodeURIComponent(name || '')}`;
router.push(url);
}
};
return (
<>
<div className="w-layout-hflex knotlistitem">
<div className="w-layout-hflex flex-block-116">
{n !== undefined && <div className="nuberlist">{n}</div>}
<div className="oemnuber">{oem}</div>
</div>
<div className="partsname">{name}</div>
<div className="w-layout-hflex flex-block-117">
<a href="#" className="button-3 w-button" onClick={handlePriceClick}>Цена</a>
<div className="code-embed-16 w-embed">
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.1 13.5H9.89999V8.1H8.1V13.5ZM8.99999 6.3C9.25499 6.3 9.46889 6.2136 9.64169 6.0408C9.81449 5.868 9.90059 5.6544 9.89999 5.4C9.89939 5.1456 9.81299 4.932 9.64079 4.7592C9.46859 4.5864 9.25499 4.5 8.99999 4.5C8.745 4.5 8.53139 4.5864 8.35919 4.7592C8.187 4.932 8.1006 5.1456 8.1 5.4C8.0994 5.6544 8.1858 5.8683 8.35919 6.0417C8.53259 6.2151 8.74619 6.3012 8.99999 6.3ZM8.99999 18C7.755 18 6.585 17.7636 5.49 17.2908C4.395 16.818 3.4425 16.1769 2.6325 15.3675C1.8225 14.5581 1.1814 13.6056 0.709201 12.51C0.237001 11.4144 0.000601139 10.2444 1.13924e-06 9C-0.00059886 7.7556 0.235801 6.5856 0.709201 5.49C1.1826 4.3944 1.8237 3.4419 2.6325 2.6325C3.4413 1.8231 4.3938 1.182 5.49 0.7092C6.5862 0.2364 7.7562 0 8.99999 0C10.2438 0 11.4138 0.2364 12.51 0.7092C13.6062 1.182 14.5587 1.8231 15.3675 2.6325C16.1763 3.4419 16.8177 4.3944 17.2917 5.49C17.7657 6.5856 18.0018 7.7556 18 9C17.9982 10.2444 17.7618 11.4144 17.2908 12.51C16.8198 13.6056 16.1787 14.5581 15.3675 15.3675C14.5563 16.1769 13.6038 16.8183 12.51 17.2917C11.4162 17.7651 10.2462 18.0012 8.99999 18Z" fill="currentcolor" />
</svg>
</div>
</div>
</div>
</>
);
};
export default VinPartCard;

View File

@ -0,0 +1,94 @@
import React, { useState } from 'react';
import { useQuery } from '@apollo/client';
import { useRouter } from 'next/router';
import { GET_LAXIMO_QUICK_DETAIL } from '@/lib/graphql/laximo';
interface VinQuickProps {
quickGroup: any;
catalogCode: string;
vehicleId: string;
ssd: string;
onBack: () => void;
onNodeSelect: (unit: any) => void;
}
const VinQuick: React.FC<VinQuickProps> = ({ quickGroup, catalogCode, vehicleId, ssd, onBack, onNodeSelect }) => {
const router = useRouter();
const { data, loading, error } = useQuery(GET_LAXIMO_QUICK_DETAIL, {
variables: {
catalogCode,
vehicleId,
quickGroupId: quickGroup.quickgroupid,
ssd
},
skip: !quickGroup || !quickGroup.quickgroupid
});
const quickDetail = data?.laximoQuickDetail;
const handleUnitClick = (unit: any) => {
onNodeSelect({
...unit,
unitid: unit.unitid,
name: unit.name,
catalogCode,
vehicleId,
ssd: unit.ssd || ssd // Используем SSD узла, а не родительский
});
};
const handleDetailClick = (detail: any) => {
if (detail.oem) {
// Переходим на страницу выбора бренда
const url = `/vehicle-search/${catalogCode}/${vehicleId}/part/${detail.oem}/brands?detailName=${encodeURIComponent(detail.name || '')}`;
router.push(url);
}
};
return (
<div className="w-full">
{/* <button onClick={onBack} className="mb-4 px-4 py-2 bg-gray-200 rounded self-start">Назад</button> */}
{loading ? (
<div className="text-center py-4">Загружаем детали...</div>
) : error ? (
<div className="text-red-600 py-4">Ошибка загрузки деталей: {error.message}</div>
) : quickDetail && quickDetail.units ? (
quickDetail.units.map((unit: any) => (
<div key={unit.unitid} className="w-layout-vflex flex-block-14-copy-copy">
<div className="knotinfo">
{unit.imageurl || unit.largeimageurl ? (
<img
src={unit.largeimageurl ? unit.largeimageurl.replace('%size%', '250') : unit.imageurl.replace('%size%', '250')}
alt={unit.name}
className="image-26"
onError={e => { (e.currentTarget as HTMLImageElement).src = '/images/image-44.jpg'; }}
onClick={() => handleUnitClick(unit)}
style={{ cursor: 'pointer' }}
/>
) : (
<img src="/images/image-44.jpg" alt="Нет изображения" className="image-26" />
)}
</div>
<div className="knot-img">
<h1 className="heading-19">{unit.name}</h1>
{unit.details && unit.details.length > 0 && unit.details.map((detail: any, index: number) => (
<div className="w-layout-hflex flex-block-115" key={`${unit.unitid}-${detail.detailid || index}`}>
<div className="oemnuber">{detail.oem}</div>
<div className="partsname">{detail.name}</div>
<a href="#" className="button-3 w-button" onClick={e => { e.preventDefault(); handleDetailClick(detail); }}>Показать цены</a>
</div>
))}
<a href="#" className="showallparts w-button" onClick={e => { e.preventDefault(); handleUnitClick(unit); }}>Подробнее</a>
</div>
</div>
))
) : (
<div className="text-center text-gray-500 py-4">Нет деталей для этой группы</div>
)}
</div>
);
};
export default VinQuick;

View File

@ -25,6 +25,8 @@ const initialState: CartState = {
// Типы действий
type CartAction =
| { type: 'ADD_ITEM'; payload: Omit<CartItem, 'id' | 'selected' | 'favorite'> }
| { type: 'ADD_ITEM_SUCCESS'; payload: { items: CartItem[]; summary: any } }
| { type: 'ADD_ITEM_ERROR'; payload: string }
| { type: 'REMOVE_ITEM'; payload: string }
| { type: 'UPDATE_QUANTITY'; payload: { id: string; quantity: number } }
| { type: 'TOGGLE_SELECT'; payload: string }
@ -44,6 +46,16 @@ type CartAction =
// Функция для генерации ID
const generateId = () => Math.random().toString(36).substr(2, 9)
// Утилитарная функция для парсинга количества в наличии
const parseStock = (stockStr: string | number | undefined): number => {
if (typeof stockStr === 'number') return stockStr;
if (typeof stockStr === 'string') {
const match = stockStr.match(/\d+/);
return match ? parseInt(match[0]) : 0;
}
return 0;
};
// Функция для расчета итогов
const calculateSummary = (items: CartItem[], deliveryPrice: number) => {
const selectedItems = items.filter(item => item.selected)
@ -78,9 +90,12 @@ const cartReducer = (state: CartState, action: CartAction): CartState => {
if (existingItemIndex >= 0) {
// Увеличиваем количество существующего товара
const existingItem = state.items[existingItemIndex];
const totalQuantity = existingItem.quantity + action.payload.quantity;
newItems = state.items.map((item, index) =>
index === existingItemIndex
? { ...item, quantity: item.quantity + action.payload.quantity }
? { ...item, quantity: totalQuantity }
: item
)
} else {
@ -335,8 +350,31 @@ export const CartProvider: React.FC<{ children: React.ReactNode }> = ({ children
}, [state.items, state.delivery, state.orderComment, isInitialized])
// Функции для работы с корзиной
const addItem = (item: Omit<CartItem, 'id' | 'selected' | 'favorite'>) => {
const addItem = async (item: Omit<CartItem, 'id' | 'selected' | 'favorite'>) => {
// Проверяем наличие товара на складе перед добавлением
const existingItemIndex = state.items.findIndex(
existingItem =>
(existingItem.productId && existingItem.productId === item.productId) ||
(existingItem.offerKey && existingItem.offerKey === item.offerKey)
)
let totalQuantity = item.quantity;
if (existingItemIndex >= 0) {
const existingItem = state.items[existingItemIndex];
totalQuantity = existingItem.quantity + item.quantity;
}
// Проверяем наличие товара на складе
const availableStock = parseStock(item.stock);
if (availableStock > 0 && totalQuantity > availableStock) {
const errorMessage = `Недостаточно товара в наличии. Доступно: ${availableStock} шт., запрошено: ${totalQuantity} шт.`;
dispatch({ type: 'SET_ERROR', payload: errorMessage });
return { success: false, error: errorMessage };
}
// Если проверка прошла успешно, добавляем товар
dispatch({ type: 'ADD_ITEM', payload: item })
return { success: true }
}
const removeItem = (id: string) => {
@ -344,6 +382,17 @@ export const CartProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
const updateQuantity = (id: string, quantity: number) => {
// Найдем товар для проверки наличия
const item = state.items.find(item => item.id === id);
if (item) {
const availableStock = parseStock(item.stock);
if (availableStock > 0 && quantity > availableStock) {
// Показываем ошибку, но не изменяем количество
dispatch({ type: 'SET_ERROR', payload: `Недостаточно товара в наличии. Доступно: ${availableStock} шт.` });
return;
}
}
dispatch({ type: 'UPDATE_QUANTITY', payload: { id, quantity } })
}
@ -388,6 +437,10 @@ export const CartProvider: React.FC<{ children: React.ReactNode }> = ({ children
}
}
const clearError = () => {
dispatch({ type: 'SET_ERROR', payload: '' })
}
const contextValue: CartContextType = {
state,
addItem,
@ -401,7 +454,8 @@ export const CartProvider: React.FC<{ children: React.ReactNode }> = ({ children
removeAll,
removeSelected,
updateDelivery,
clearCart
clearCart,
clearError
}
return (

View File

@ -4,6 +4,7 @@ import React, { createContext, useContext, useReducer, useEffect, ReactNode } fr
import { useMutation, useQuery } from '@apollo/client'
import toast from 'react-hot-toast'
import { GET_FAVORITES, ADD_TO_FAVORITES, REMOVE_FROM_FAVORITES, CLEAR_FAVORITES } from '@/lib/favorites-queries'
import DeleteCartIcon from '@/components/DeleteCartIcon'
// Типы
export interface FavoriteItem {
@ -133,7 +134,9 @@ const FavoritesProvider: React.FC<FavoritesProviderProps> = ({ children }) => {
const [removeFavoriteMutation] = useMutation(REMOVE_FROM_FAVORITES, {
onCompleted: () => {
toast.success('Товар удален из избранного')
toast.success('Товар удален из избранного', {
icon: <DeleteCartIcon size={20} color="#ec1c24" />,
})
},
onError: (error) => {
console.error('Ошибка удаления из избранного:', error)

View File

@ -18,7 +18,7 @@ export const useArticleImage = (
artId: string | undefined | null,
options: UseArticleImageOptions = {}
): UseArticleImageReturn => {
const { enabled = true, fallbackImage = '' } = options;
const { enabled = true, fallbackImage = '/images/image-10.png' } = options;
const [imageUrl, setImageUrl] = useState<string>(fallbackImage);
// Проверяем что artId валидный

View File

@ -231,6 +231,7 @@ export const useCatalogPrices = (): UseCatalogPricesReturn => {
price: cheapestOffer.price,
currency: cheapestOffer.currency || 'RUB',
quantity: 1,
stock: cheapestOffer.quantity, // передаем информацию о наличии
deliveryTime: cheapestOffer.deliveryDays?.toString() || '0',
warehouse: cheapestOffer.warehouse || 'Склад',
supplier: cheapestOffer.supplierName || 'Неизвестный поставщик',
@ -238,10 +239,14 @@ export const useCatalogPrices = (): UseCatalogPricesReturn => {
image: '', // Убираем мокап-фотку, изображения будут загружаться отдельно
};
addItem(itemToAdd);
const result = await addItem(itemToAdd);
// Показываем уведомление
toast.success(`Товар "${brand} ${articleNumber}" добавлен в корзину за ${cheapestOffer.price}`);
if (result.success) {
// Показываем уведомление
toast.success(`Товар "${brand} ${articleNumber}" добавлен в корзину за ${cheapestOffer.price}`);
} else {
toast.error(result.error || 'Ошибка добавления товара в корзину');
}
} catch (error) {
console.error('Ошибка добавления в корзину:', error);

View File

@ -540,7 +540,9 @@ export const FIND_LAXIMO_VEHICLE_BY_WIZARD = gql`
query FindLaximoVehicleByWizard($catalogCode: String!, $ssd: String!) {
laximoFindVehicleByWizard(catalogCode: $catalogCode, ssd: $ssd) {
vehicleid
name
brand
catalog
model
modification
year
@ -548,12 +550,34 @@ export const FIND_LAXIMO_VEHICLE_BY_WIZARD = gql`
engine
notes
ssd
transmission
date
manufactured
framecolor
trimcolor
engine_info
engineno
market
prodRange
prodPeriod
destinationregion
creationregion
datefrom
dateto
modelyearfrom
modelyearto
options
description
grade
attributes {
key
name
value
}
}
}
`;
export const FIND_LAXIMO_VEHICLE_BY_PLATE = gql`
query FindLaximoVehicleByPlate($catalogCode: String!, $plateNumber: String!) {
laximoFindVehicleByPlate(catalogCode: $catalogCode, plateNumber: $plateNumber) {
@ -587,6 +611,11 @@ export const FIND_LAXIMO_VEHICLE_BY_PLATE = gql`
options
description
grade
attributes {
key
name
value
}
}
}
`;
@ -624,12 +653,15 @@ export const FIND_LAXIMO_VEHICLE_BY_PLATE_GLOBAL = gql`
options
description
grade
attributes {
key
name
value
}
}
}
`;
export const FIND_LAXIMO_PART_REFERENCES = gql`
query FindLaximoPartReferences($partNumber: String!) {
laximoFindPartReferences(partNumber: $partNumber)
@ -669,6 +701,11 @@ export const FIND_LAXIMO_APPLICABLE_VEHICLES = gql`
options
description
grade
attributes {
key
name
value
}
}
}
`;
@ -695,6 +732,30 @@ export const FIND_LAXIMO_VEHICLES_BY_PART_NUMBER = gql`
engine
notes
ssd
transmission
date
manufactured
framecolor
trimcolor
engine_info
engineno
market
prodRange
prodPeriod
destinationregion
creationregion
datefrom
dateto
modelyearfrom
modelyearto
options
description
grade
attributes {
key
name
value
}
}
}
}
@ -799,6 +860,7 @@ export const GET_LAXIMO_UNITS = gql`
code
imageurl
largeimageurl
ssd
children {
quickgroupid
name
@ -806,6 +868,7 @@ export const GET_LAXIMO_UNITS = gql`
code
imageurl
largeimageurl
ssd
children {
quickgroupid
name
@ -813,6 +876,7 @@ export const GET_LAXIMO_UNITS = gql`
code
imageurl
largeimageurl
ssd
}
}
}
@ -831,6 +895,7 @@ export const GET_LAXIMO_QUICK_DETAIL = gql`
description
imageurl
largeimageurl
ssd
details {
detailid
name

View File

@ -84,6 +84,7 @@ export const GET_LAXIMO_UNITS = gql`
code
imageurl
largeimageurl
ssd
children {
quickgroupid
name
@ -91,6 +92,7 @@ export const GET_LAXIMO_UNITS = gql`
code
imageurl
largeimageurl
ssd
children {
quickgroupid
name
@ -98,6 +100,7 @@ export const GET_LAXIMO_UNITS = gql`
code
imageurl
largeimageurl
ssd
}
}
}
@ -135,6 +138,7 @@ export const GET_LAXIMO_QUICK_DETAIL = gql`
code
imageurl
largeimageurl
ssd
details {
detailid
name
@ -180,23 +184,6 @@ export const SEARCH_LAXIMO_OEM = gql`
}
`;
export const SEARCH_LAXIMO_FULLTEXT = gql`
query SearchLaximoFulltext($catalogCode: String!, $vehicleId: String!, $searchText: String!, $ssd: String!) {
laximoFulltextSearch(catalogCode: $catalogCode, vehicleId: $vehicleId, searchText: $searchText, ssd: $ssd) {
details {
codeonimage
code
name
note
filter
oem
price
availability
}
}
}
`;
export const GET_LAXIMO_FULLTEXT_SEARCH = gql`
query GetLaximoFulltextSearch($catalogCode: String!, $vehicleId: String!, $searchQuery: String!, $ssd: String!) {
laximoFulltextSearch(catalogCode: $catalogCode, vehicleId: $vehicleId, searchQuery: $searchQuery, ssd: $ssd) {
@ -208,6 +195,10 @@ export const GET_LAXIMO_FULLTEXT_SEARCH = gql`
parttype
filter
note
codeonimage
code
price
availability
attributes {
key
name

View File

@ -60,8 +60,12 @@ export default function App({ Component, pageProps }: AppProps) {
},
success: {
duration: 3000,
style: {
background: '#22c55e', // Зеленый фон для успешных уведомлений
color: '#fff', // Белый текст
},
iconTheme: {
primary: '#4ade80',
primary: '#22c55e',
secondary: '#fff',
},
},

View File

@ -7,9 +7,10 @@ import CartSummary from "@/components/CartSummary";
import CartRecommended from "../components/CartRecommended";
import CatalogSubscribe from "@/components/CatalogSubscribe";
import MobileMenuBottomSection from "@/components/MobileMenuBottomSection";
import CartDebug from "@/components/CartDebug";
import React, { useState } from "react";
export default function CartPage() {
const [step, setStep] = useState(1);
return (
<><Head>
@ -27,8 +28,8 @@ export default function CartPage() {
<div className="w-layout-blockcontainer container w-container">
<div className="w-layout-vflex cart-list">
<div className="w-layout-hflex core-product-card">
<CartList />
<CartSummary />
<CartList isSummaryStep={step === 2} />
<CartSummary step={step} setStep={setStep} />
</div>
<CartRecommended />
</div>
@ -39,7 +40,6 @@ export default function CartPage() {
</section>
<Footer />
<MobileMenuBottomSection />
<CartDebug />
</>
);
}

View File

@ -23,6 +23,7 @@ import { useProductPrices } from '@/hooks/useProductPrices';
import { PriceSkeleton } from '@/components/skeletons/ProductListSkeleton';
import { useCart } from '@/contexts/CartContext';
import toast from 'react-hot-toast';
import CartIcon from '@/components/CartIcon';
const mockData = Array(12).fill({
image: "",
@ -720,7 +721,7 @@ export default function Catalog() {
productId={entity.id}
artId={entity.id}
offerKey={priceData?.offerKey}
onAddToCart={() => {
onAddToCart={async () => {
// Если цена не загружена, загружаем её и добавляем в корзину
if (!priceData && !isLoadingPriceData) {
loadPriceOnDemand(productForPrice);
@ -740,6 +741,7 @@ export default function Catalog() {
price: priceData.price,
currency: priceData.currency || 'RUB',
quantity: 1,
stock: undefined, // информация о наличии не доступна для PartsIndex
deliveryTime: '1-3 дня',
warehouse: 'Parts Index',
supplier: 'Parts Index',
@ -747,10 +749,23 @@ export default function Catalog() {
image: entity.images?.[0] || '',
};
addItem(itemToAdd);
const result = await addItem(itemToAdd);
// Показываем уведомление
toast.success(`Товар "${entity.brand.name} ${entity.code}" добавлен в корзину за ${priceData.price.toLocaleString('ru-RU')}`);
if (result.success) {
// Показываем уведомление
toast.success(
<div>
<div className="font-semibold" style={{ color: '#fff' }}>Товар добавлен в корзину!</div>
<div className="text-sm" style={{ color: '#fff', opacity: 0.9 }}>{`${entity.brand.name} ${entity.code} за ${priceData.price.toLocaleString('ru-RU')}`}</div>
</div>,
{
duration: 3000,
icon: <CartIcon size={20} color="#fff" />,
}
);
} else {
toast.error(result.error || 'Ошибка при добавлении товара в корзину');
}
} else {
toast.error('Цена товара еще загружается. Попробуйте снова через несколько секунд.');
}

View File

@ -16,7 +16,7 @@ export default function Favorite() {
const [showFiltersMobile, setShowFiltersMobile] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [filterValues, setFilterValues] = useState<{[key: string]: any}>({});
const [sortBy, setSortBy] = useState<'name' | 'brand' | 'price' | 'date'>('date');
const [sortBy, setSortBy] = useState<'name' | 'brand' | 'date'>('date');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
// Создаем динамические фильтры на основе данных избранного

44
src/pages/home-new.tsx Normal file
View File

@ -0,0 +1,44 @@
import React from 'react';
import Head from 'next/head';
import CatalogSubscribe from "@/components/CatalogSubscribe";
import MobileMenuBottomSection from "@/components/MobileMenuBottomSection";
import NewsAndPromos from "@/components/index/NewsAndPromos";
import Footer from "@/components/Footer";
import IndexTopMenuNav from "@/components/index/IndexTopMenuNav";
import ProductOfDaySection from "@/components/index/ProductOfDaySection";
import CategoryNavSection from "@/components/index/CategoryNavSection";
import BrandSelectionSection from "@/components/index/BrandSelectionSection";
import BestPriceSection from "@/components/index/BestPriceSection";
import TopSalesSection from "@/components/index/TopSalesSection";
import PromoImagesSection from "@/components/index/PromoImagesSection";
import NewArrivalsSection from '@/components/index/NewArrivalsSection';
import SupportVinSection from '@/components/index/SupportVinSection';
export default function HomeNew () {
return (
<>
<Head>
<title>Home New</title>
<link href="https://fonts.googleapis.com" rel="preconnect" />
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
<link href="images/webclip.png" rel="apple-touch-icon" />
</Head>
<IndexTopMenuNav />
<ProductOfDaySection />
<CategoryNavSection />
<BrandSelectionSection />
<BestPriceSection />
<TopSalesSection />
<PromoImagesSection />
<NewArrivalsSection />
<SupportVinSection />
<NewsAndPromos />
<section className="section-3">
<CatalogSubscribe />
</section>
<Footer />
<MobileMenuBottomSection />
</>
);
}

View File

@ -1,11 +1,11 @@
import React, { useEffect, useState } from "react";
import Head from "next/head";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { useRouter } from "next/router";
import { useMutation, ApolloProvider } from "@apollo/client";
import { gql } from "@apollo/client";
import { apolloClient } from "@/lib/apollo";
import toast from "react-hot-toast";
const CONFIRM_PAYMENT = gql`
mutation ConfirmPayment($orderId: ID!) {
@ -51,8 +51,15 @@ function PaymentSuccessContent() {
}
}).then(() => {
console.log('Оплата заказа подтверждена');
toast.success('Оплата успешно подтверждена!', {
duration: 3000,
icon: '✅',
});
}).catch((error: any) => {
console.error('Ошибка подтверждения оплаты:', error);
toast.error('Ошибка подтверждения оплаты: ' + error.message, {
duration: 5000,
});
});
}
}, [router.query, confirmPayment]);
@ -76,7 +83,7 @@ function PaymentSuccessContent() {
<link href="/images/webclip.png" rel="apple-touch-icon" />
</Head>
<Header />
<div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9">

View File

@ -1,4 +1,8 @@
import * as React from "react";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useQuery } from '@apollo/client';
import { GET_CLIENT_ME } from '@/lib/graphql';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import ProfileSidebar from '@/components/ProfileSidebar';
@ -11,8 +15,50 @@ import NotificationMane from "@/components/profile/NotificationMane";
import Head from "next/head";
const ProfileActsPage = () => {
const router = useRouter();
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const { data: clientData, loading: clientLoading } = useQuery(GET_CLIENT_ME, {
skip: !isAuthenticated,
onCompleted: (data) => {
// Проверяем есть ли у клиента юридические лица
if (!data?.clientMe?.legalEntities?.length) {
// Если нет юридических лиц, перенаправляем на настройки
router.push('/profile-settings?tab=legal');
return;
}
},
onError: (error) => {
console.error('Ошибка загрузки данных клиента:', error);
// Если ошибка авторизации, перенаправляем на главную
router.push('/');
}
});
useEffect(() => {
// Проверяем авторизацию
const token = localStorage.getItem('authToken');
if (!token) {
router.push('/');
return;
}
setIsAuthenticated(true);
}, [router]);
// Показываем загрузку пока проверяем авторизацию и данные
if (!isAuthenticated || clientLoading) {
return (
<div className="page-wrapper">
<div className="flex flex-col justify-center items-center min-h-[400px]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-red-600"></div>
<div className="mt-4 text-gray-600">Загрузка...</div>
</div>
<Footer />
</div>
);
}
return (
<div className="page-wrapper">
<>
<Head>
<title>ProfileActs</title>
<meta content="ProfileActs" property="og:title" />
@ -32,7 +78,7 @@ const ProfileActsPage = () => {
</section>
<MobileMenuBottomSection />
<Footer />
</div>
</>
);
};

View File

@ -1,4 +1,8 @@
import * as React from "react";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useQuery } from '@apollo/client';
import { GET_CLIENT_ME } from '@/lib/graphql';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import CatalogSubscribe from '@/components/CatalogSubscribe';
@ -8,9 +12,49 @@ import ProfileRequisitiesMain from '@/components/profile/ProfileRequisitiesMain'
import ProfileInfo from '@/components/profile/ProfileInfo';
import Head from "next/head";
const ProfileRequisitiesPage = () => {
const router = useRouter();
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const { data: clientData, loading: clientLoading } = useQuery(GET_CLIENT_ME, {
skip: !isAuthenticated,
onCompleted: (data) => {
// Проверяем есть ли у клиента юридические лица
if (!data?.clientMe?.legalEntities?.length) {
// Если нет юридических лиц, перенаправляем на настройки
router.push('/profile-settings?tab=legal');
return;
}
},
onError: (error) => {
console.error('Ошибка загрузки данных клиента:', error);
// Если ошибка авторизации, перенаправляем на главную
router.push('/');
}
});
useEffect(() => {
// Проверяем авторизацию
const token = localStorage.getItem('authToken');
if (!token) {
router.push('/');
return;
}
setIsAuthenticated(true);
}, [router]);
// Показываем загрузку пока проверяем авторизацию и данные
if (!isAuthenticated || clientLoading) {
return (
<div className="page-wrapper">
<div className="flex flex-col justify-center items-center min-h-[400px]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-red-600"></div>
<div className="mt-4 text-gray-600">Загрузка...</div>
</div>
<Footer />
</div>
);
}
return (
<div className="page-wrapper">
<Head>

View File

@ -424,12 +424,12 @@ export default function SearchResult() {
<title>Поиск предложений {searchQuery} - Protek</title>
</Head>
<main className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-red-600 mx-auto"></div>
<p className="mt-4 text-lg text-gray-600">Поиск предложений...</p>
<div className="fixed inset-0 z-50 bg-gray-50 bg-opacity-90 flex items-center justify-center min-h-screen" aria-live="polite">
<div className="flex flex-col items-center justify-center">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-red-600 mb-4"></div>
<p className="text-lg text-gray-600">Поиск предложений...</p>
</div>
</main>
</div>
<Footer />
</>
);
@ -502,6 +502,7 @@ export default function SearchResult() {
price={`${offer.price.toLocaleString()}`}
delivery={`${offer.deliveryDuration} ${offer.deliveryDuration === 1 ? 'день' : 'дней'}`}
stock={`${offer.quantity} шт.`}
offer={offer}
/>
))}
</div>
@ -605,12 +606,11 @@ export default function SearchResult() {
return true; // Показываем загружающиеся аналоги
}
const analogOffers = transformOffersForCard(
filteredOffers.filter(o => o.isAnalog && o.articleNumber === analog.articleNumber)
);
// Проверяем, есть ли предложения у аналога
const hasInternalOffers = loadedAnalogData.internalOffers && loadedAnalogData.internalOffers.length > 0;
const hasExternalOffers = loadedAnalogData.externalOffers && loadedAnalogData.externalOffers.length > 0;
// Показываем аналог только если у него есть предложения
return analogOffers.length > 0;
return hasInternalOffers || hasExternalOffers;
});
// Если нет аналогов с предложениями, не показываем секцию
@ -624,11 +624,79 @@ export default function SearchResult() {
const analogKey = `${analog.brand}-${analog.articleNumber}`;
const loadedAnalogData = loadedAnalogs[analogKey];
const analogOffers = loadedAnalogData
? transformOffersForCard(
filteredOffers.filter(o => o.isAnalog && o.articleNumber === analog.articleNumber)
)
: [];
// Если данные аналога загружены, формируем предложения из всех его данных
const analogOffers = loadedAnalogData ? (() => {
const allAnalogOffers: any[] = [];
// Добавляем внутренние предложения
if (loadedAnalogData.internalOffers) {
loadedAnalogData.internalOffers.forEach((offer: any) => {
allAnalogOffers.push({
...offer,
type: 'internal',
brand: loadedAnalogData.brand,
articleNumber: loadedAnalogData.articleNumber,
name: loadedAnalogData.name,
isAnalog: true,
deliveryDuration: offer.deliveryDays
});
});
}
// Добавляем внешние предложения
if (loadedAnalogData.externalOffers) {
loadedAnalogData.externalOffers.forEach((offer: any) => {
allAnalogOffers.push({
...offer,
type: 'external',
brand: offer.brand || loadedAnalogData.brand,
articleNumber: offer.code || loadedAnalogData.articleNumber,
name: offer.name || loadedAnalogData.name,
isAnalog: true,
deliveryDuration: offer.deliveryTime
});
});
}
// Применяем фильтры только если они активны
const filteredAnalogOffers = allAnalogOffers.filter(offer => {
// Фильтр по бренду
if (selectedBrands.length > 0 && !selectedBrands.includes(offer.brand)) {
return false;
}
// Фильтр по цене
if (priceRange && (offer.price < priceRange[0] || offer.price > priceRange[1])) {
return false;
}
// Фильтр по сроку доставки
if (deliveryRange) {
const deliveryDays = offer.deliveryDuration;
if (deliveryDays < deliveryRange[0] || deliveryDays > deliveryRange[1]) {
return false;
}
}
// Фильтр по количеству наличия
if (quantityRange) {
const quantity = offer.quantity;
if (quantity < quantityRange[0] || quantity > quantityRange[1]) {
return false;
}
}
// Фильтр по поисковой строке
if (filterSearchTerm) {
const searchTerm = filterSearchTerm.toLowerCase();
const brandMatch = offer.brand.toLowerCase().includes(searchTerm);
const articleMatch = offer.articleNumber.toLowerCase().includes(searchTerm);
const nameMatch = offer.name.toLowerCase().includes(searchTerm);
if (!brandMatch && !articleMatch && !nameMatch) {
return false;
}
}
return true;
});
return transformOffersForCard(filteredAnalogOffers);
})() : [];
return (
<CoreProductCard
@ -646,20 +714,7 @@ export default function SearchResult() {
{(() => {
// Проверяем, есть ли еще аналоги с предложениями для загрузки
const remainingAnalogs = result.analogs.slice(visibleAnalogsCount);
const hasMoreAnalogsWithOffers = remainingAnalogs.some((analog: any) => {
const analogKey = `${analog.brand}-${analog.articleNumber}`;
const loadedAnalogData = loadedAnalogs[analogKey];
if (!loadedAnalogData) {
return true; // Могут быть предложения у незагруженных аналогов
}
const analogOffers = transformOffersForCard(
filteredOffers.filter(o => o.isAnalog && o.articleNumber === analog.articleNumber)
);
return analogOffers.length > 0;
});
const hasMoreAnalogsWithOffers = remainingAnalogs.length > 0;
return hasMoreAnalogsWithOffers && (
<div className="w-layout-hflex pagination">

View File

@ -105,6 +105,14 @@ const VehicleSearchResultsPage: React.FC<VehicleSearchResultsPageProps> = () =>
ssdLength: ssd.length
});
// Создаем базовые параметры URL
const urlParams = new URLSearchParams();
// Добавляем VIN-номер в URL, если он есть
if (searchQuery && searchType === 'vin') {
urlParams.set('vin', searchQuery);
}
// Если есть SSD, сохраняем его в localStorage для безопасной передачи
if (ssd && ssd.trim() !== '') {
const vehicleKey = `vehicle_ssd_${catalogCode}_${vehicleId}`;
@ -121,25 +129,22 @@ const VehicleSearchResultsPage: React.FC<VehicleSearchResultsPageProps> = () =>
localStorage.setItem(vehicleKey, ssd);
// Выбираем URL в зависимости от того, нужно ли пропустить промежуточную страницу
const url = skipToCategories
? `/vehicle-search/${catalogCode}/${vehicleId}?use_storage=1&ssd_length=${ssd.length}&searchType=categories`
: `/vehicle-search/${catalogCode}/${vehicleId}?use_storage=1&ssd_length=${ssd.length}`;
console.log('🔗 Переходим на URL с localStorage:', url);
// Используем replace вместо push для моментального перехода
router.replace(url);
} else {
// Выбираем URL в зависимости от того, нужно ли пропустить промежуточную страницу
const url = skipToCategories
? `/vehicle-search/${catalogCode}/${vehicleId}?searchType=categories`
: `/vehicle-search/${catalogCode}/${vehicleId}`;
console.log('🔗 Переходим на URL без SSD:', url);
// Используем replace вместо push для моментального перехода
router.replace(url);
urlParams.set('use_storage', '1');
urlParams.set('ssd_length', ssd.length.toString());
}
}, [router]);
if (skipToCategories) {
urlParams.set('searchType', 'categories');
}
// Формируем URL с параметрами
const baseUrl = `/vehicle-search/${catalogCode}/${vehicleId}`;
const url = urlParams.toString() ? `${baseUrl}?${urlParams.toString()}` : baseUrl;
console.log('🔗 Переходим на URL:', url);
// Используем replace вместо push для моментального перехода
router.replace(url);
}, [router, searchQuery, searchType]);
// Предзагрузка и автоматический переход при поиске по VIN, если найден только один автомобиль
useEffect(() => {

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import { useQuery } from '@apollo/client';
import Head from 'next/head';
@ -6,8 +6,20 @@ import Footer from '@/components/Footer';
import Layout from '@/components/Layout';
import VehiclePartsSearchSection from '@/components/VehiclePartsSearchSection';
import LaximoDiagnostic from '@/components/LaximoDiagnostic';
import { GET_LAXIMO_VEHICLE_INFO, GET_LAXIMO_CATALOG_INFO } from '@/lib/graphql';
import { GET_LAXIMO_VEHICLE_INFO, GET_LAXIMO_CATALOG_INFO, GET_LAXIMO_UNIT_DETAILS } from '@/lib/graphql';
import { LaximoCatalogInfo } from '@/types/laximo';
import InfoVin from '@/components/vin/InfoVin';
import VinLeftbar from '@/components/vin/VinLeftbar';
import VinKnot from '@/components/vin/VinKnot';
import VinCategory from '@/components/vin/VinCategory';
import PartDetailCard from '@/components/PartDetailCard';
import VinPartCard from '@/components/vin/VinPartCard';
import KnotIn from '@/components/vin/KnotIn';
import KnotParts from '@/components/vin/KnotParts';
import VinQuick from '@/components/vin/VinQuick';
import CatalogSubscribe from '@/components/CatalogSubscribe';
import MobileMenuBottomSection from '@/components/MobileMenuBottomSection';
interface LaximoVehicleInfo {
vehicleid: string;
@ -34,14 +46,48 @@ const VehicleDetailsPage = () => {
if (searchTypeParam === 'categories') {
// В URL categories, но мы используем quickgroups для групп быстрого поиска
defaultSearchType = 'quickgroups';
console.log('🔄 URL содержит searchType=categories, интерпретируем как quickgroups (группы быстрого поиска)');
} else if (searchTypeParam === 'quickgroups') {
defaultSearchType = 'quickgroups';
} else if (searchTypeParam === 'fulltext') {
defaultSearchType = 'fulltext';
}
// ====== ВСЕ ХУКИ В НАЧАЛЕ КОМПОНЕНТА ======
const [searchType, setSearchType] = useState<'quickgroups' | 'categories' | 'fulltext'>(defaultSearchType);
const [showKnot, setShowKnot] = useState(false);
const [foundParts, setFoundParts] = useState<any[]>([]);
const [activeTab, setActiveTab] = useState<'uzly' | 'manufacturer'>('uzly');
const [openedPath, setOpenedPath] = useState<string[]>([]);
const [searchState, setSearchState] = useState<{
loading: boolean;
error: any;
query: string;
isSearching: boolean;
}>({
loading: false,
error: null,
query: '',
isSearching: false
});
const [selectedNode, setSelectedNode] = useState<any | null>(null);
const [selectedQuickGroup, setSelectedQuickGroup] = useState<any | null>(null);
const handleCategoryClick = (e?: React.MouseEvent) => {
if (e) e.preventDefault();
setShowKnot(true);
};
useEffect(() => {
const handler = (e: Event) => {
const target = e.target as HTMLElement;
if (target.classList.contains('link-2')) {
e.preventDefault();
setShowKnot(true);
}
};
document.addEventListener('click', handler);
return () => document.removeEventListener('click', handler);
}, []);
// ====== КОНЕЦ ХУКОВ ======
// Получаем информацию о каталоге
const { data: catalogData } = useQuery<{ laximoCatalogInfo: LaximoCatalogInfo }>(
@ -64,27 +110,14 @@ const VehicleDetailsPage = () => {
const storedSsd = localStorage.getItem(vehicleKey);
if (storedSsd) {
finalSsd = storedSsd;
console.log('🔧 SSD получен из localStorage, длина:', storedSsd.length);
// НЕ ОЧИЩАЕМ SSD сразу, оставляем на случай перезагрузки страницы
// localStorage.removeItem(vehicleKey);
} else {
console.log('⚠️ SSD не найден в localStorage, ключ:', vehicleKey);
console.log('🔍 Все ключи localStorage:', Object.keys(localStorage));
}
} else if (ssdFromQuery && ssdFromQuery.trim() !== '') {
finalSsd = ssdFromQuery;
console.log('🔧 SSD получен из URL');
}
console.log('🔍 Vehicle page params:', {
brand,
vehicleId,
useStorage,
ssdLengthFromUrl,
ssdFromQuery: ssdFromQuery ? `${ssdFromQuery.substring(0, 50)}...` : 'отсутствует',
finalSsd: finalSsd ? `${finalSsd.substring(0, 50)}...` : 'отсутствует',
ssdLength: finalSsd.length
});
const { data: vehicleData, loading: vehicleLoading, error: vehicleError } = useQuery<{ laximoVehicleInfo: LaximoVehicleInfo }>(
GET_LAXIMO_VEHICLE_INFO,
@ -95,10 +128,79 @@ const VehicleDetailsPage = () => {
...(finalSsd && { ssd: finalSsd }),
localized: true
},
skip: !brand || !vehicleId,
errorPolicy: 'all'
skip: !brand || vehicleId === undefined || vehicleId === null,
errorPolicy: 'all',
onCompleted: (data) => {
console.log('🔍 VehicleInfo GraphQL completed:', {
requestedVehicleId: vehicleId,
returnedVehicleId: data?.laximoVehicleInfo?.vehicleid,
vehicleName: data?.laximoVehicleInfo?.name,
ssdUsed: finalSsd?.substring(0, 50) + '...',
fullData: data
});
if (data?.laximoVehicleInfo?.vehicleid !== vehicleId) {
console.log('🚨 ОБНАРУЖЕНО НЕСООТВЕТСТВИЕ VEHICLE ID!');
console.log(`📍 URL vehicleId: ${vehicleId}`);
console.log(`📍 API vehicleId: ${data?.laximoVehicleInfo?.vehicleid}`);
} else {
console.log('✅ Vehicle ID соответствует URL');
}
},
onError: (error) => {
console.error('❌ VehicleInfo GraphQL error:', error);
}
}
);
// Автоматическое перенаправление на правильный vehicleId если API вернул другой ID
useEffect(() => {
if (vehicleData?.laximoVehicleInfo && vehicleData.laximoVehicleInfo.vehicleid !== vehicleId) {
const correctVehicleId = vehicleData.laximoVehicleInfo.vehicleid;
console.log(`🔄 Автоматическое перенаправление: ${vehicleId} -> ${correctVehicleId}`);
// Обновляем localStorage с правильным ключом
if (finalSsd && typeof window !== 'undefined') {
const oldKey = `vehicle_ssd_${brand}_${vehicleId}`;
const newKey = `vehicle_ssd_${brand}_${correctVehicleId}`;
// Перемещаем SSD на правильный ключ
localStorage.setItem(newKey, finalSsd);
localStorage.removeItem(oldKey);
console.log(`💾 SSD перемещен: ${oldKey} -> ${newKey}`);
}
// Строим новый URL с правильным vehicleId
const currentParams = new URLSearchParams(window.location.search);
const newUrl = `/vehicle-search/${brand}/${correctVehicleId}?${currentParams.toString()}`;
// Перенаправляем на правильный URL
router.replace(newUrl);
return;
}
}, [vehicleData, vehicleId, brand, finalSsd, router]);
// Получаем детали выбранного узла, если он выбран
const {
data: unitDetailsData,
loading: unitDetailsLoading,
error: unitDetailsError
} = useQuery(
GET_LAXIMO_UNIT_DETAILS,
{
variables: selectedNode
? {
catalogCode: selectedNode.catalogCode || selectedNode.catalog || brand,
vehicleId: selectedNode.vehicleId || vehicleId,
unitId: selectedNode.unitid || selectedNode.unitId,
ssd: selectedNode.ssd || finalSsd || '',
}
: { catalogCode: '', vehicleId: '', unitId: '', ssd: '' },
skip: !selectedNode,
errorPolicy: 'all',
}
);
const unitDetails = unitDetailsData?.laximoUnitDetails || [];
// Логируем ошибки
if (vehicleError) {
@ -107,24 +209,24 @@ const VehicleDetailsPage = () => {
if (vehicleLoading) {
return (
<Layout>
<>
<Head>
<title>Загрузка автомобиля...</title>
</Head>
<main className="min-h-screen bg-gray-50 flex items-center justify-center">
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#f9fafb' }}>
<div className="text-center">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-red-600 mx-auto"></div>
<p className="mt-4 text-lg text-gray-600">Загружаем информацию об автомобиле...</p>
</div>
</main>
</Layout>
</div>
</>
);
}
// Если информация о каталоге недоступна, показываем ошибку
if (!catalogData?.laximoCatalogInfo) {
return (
<Layout>
<>
<Head>
<title>Каталог не найден</title>
</Head>
@ -140,33 +242,224 @@ const VehicleDetailsPage = () => {
</button>
</div>
</main>
</Layout>
</>
);
}
// Если информация об автомобиле недоступна, создаем заглушку
const vehicleInfo = vehicleData?.laximoVehicleInfo || {
vehicleid: vehicleId as string,
// Если vehicleId отсутствует или пустой, показываем предупреждение
// Важно: vehicleId может быть '0' для некоторых автомобилей, найденных по VIN
if (!vehicleId || vehicleId === '') {
return (
<main className="min-h-screen bg-yellow-50 flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold text-yellow-900 mb-4">Автомобиль не выбран</h1>
<p className="text-yellow-700 mb-8">Для поиска по деталям необходимо выбрать конкретный автомобиль через VIN или мастер подбора.</p>
<button
onClick={() => router.back()}
className="bg-yellow-600 text-white px-6 py-3 rounded-lg hover:bg-yellow-700 transition-colors"
>
Назад к поиску
</button>
</div>
</main>
);
}
// Гарантируем, что vehicleId — строка
const vehicleIdStr = Array.isArray(vehicleId) ? (vehicleId[0] || '') : (vehicleId || '');
// Для Laximo API vehicleId может быть '0' для автомобилей, найденных по VIN
const fallbackVehicleId = vehicleIdStr;
let vehicleInfo = vehicleData?.laximoVehicleInfo || {
vehicleid: fallbackVehicleId,
name: `Автомобиль ${catalogData.laximoCatalogInfo.name}`,
ssd: finalSsd,
brand: catalogData.laximoCatalogInfo.brand,
catalog: catalogData.laximoCatalogInfo.code,
attributes: []
attributes: [] as never[]
};
// Убеждаемся, что vehicleid соответствует параметру из URL
if (vehicleInfo.vehicleid !== fallbackVehicleId && fallbackVehicleId) {
vehicleInfo = { ...vehicleInfo, vehicleid: fallbackVehicleId };
}
// Если нет данных автомобиля и есть ошибка, показываем предупреждение
const hasError = vehicleError && !vehicleData?.laximoVehicleInfo;
const catalogInfo = catalogData.laximoCatalogInfo;
return (
<Layout>
<>
<Head>
<title>{vehicleInfo.name} - Поиск запчастей</title>
<meta name="description" content={`Поиск запчастей для ${vehicleInfo.name} в каталоге ${catalogInfo.name}`} />
<title>VIN</title>
<meta content="vin" property="og:title" />
<meta content="vin" property="twitter:title" />
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
<link href="images/webclip.png" rel="apple-touch-icon" />
</Head>
<main className="min-h-screen bg-gray-50">
{/* Навигация */}
{/* ====== ВРЕМЕННЫЙ МАКЕТ ДЛЯ ВЕРСТКИ (начало) ====== */}
<InfoVin
vehicleName={
vehicleInfo.brand && vehicleInfo.name && vehicleInfo.name.indexOf(vehicleInfo.brand) !== 0
? `${vehicleInfo.brand} ${vehicleInfo.name}`
: vehicleInfo.name
}
vehicleInfo={
vehicleInfo.attributes && vehicleInfo.attributes.length > 0
? vehicleInfo.attributes.map(attr => attr.value).join(' · ')
: ''
}
vehicleAttributes={vehicleInfo.attributes || []}
/>
<div className="w-layout-blockcontainer container-vin w-container">
{!selectedNode ? (
<div className="w-layout-hflex flex-block-13">
{vehicleInfo && vehicleInfo.catalog && vehicleInfo.vehicleid && vehicleInfo.ssd && (
<>
<VinLeftbar
vehicleInfo={vehicleInfo}
onSearchResults={({ results, loading, error, query, isSearching }) => {
setFoundParts(results);
setSearchState({ loading, error, query, isSearching: isSearching || false });
}}
onNodeSelect={setSelectedNode}
onActiveTabChange={(tab) => setActiveTab(tab)}
onQuickGroupSelect={setSelectedQuickGroup}
activeTab={activeTab}
openedPath={openedPath}
setOpenedPath={setOpenedPath}
/>
{searchState.isSearching ? (
<div className="knot-parts">
{searchState.loading ? (
<div className="text-center py-12">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-red-600 mx-auto"></div>
<p className="mt-4 text-gray-600">Выполняется поиск...</p>
</div>
) : searchState.error ? (
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mt-3">
<div className="flex">
<div className="flex-shrink-0">
<svg className="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" />
</svg>
</div>
<div className="ml-3">
<h3 className="text-sm font-medium text-red-800">
Ошибка поиска
</h3>
<div className="mt-2 text-sm text-red-700">
<p>{searchState.error.message}</p>
</div>
</div>
</div>
</div>
) : foundParts.length > 0 ? (
foundParts.map((detail, idx) => (
<VinPartCard
key={detail.oem + idx}
n={idx + 1}
name={detail.name}
oem={detail.oem}
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
/>
))
) : (
<div className="text-center py-12">
<svg className="w-12 h-12 mx-auto text-gray-400 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.172 16.172a4 4 0 015.656 0M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
<p className="text-gray-600">
По запросу "{searchState.query}" ничего не найдено
</p>
<p className="text-sm text-gray-500 mt-1">
Попробуйте изменить поисковый запрос
</p>
</div>
)}
</div>
) : showKnot ? (
<VinKnot />
) : selectedQuickGroup ? (
<VinQuick
quickGroup={selectedQuickGroup}
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
ssd={vehicleInfo.ssd}
onBack={() => setSelectedQuickGroup(null)}
onNodeSelect={setSelectedNode}
/>
) : (
<VinCategory
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
ssd={vehicleInfo.ssd}
onNodeSelect={setSelectedNode}
activeTab={activeTab}
onQuickGroupSelect={setSelectedQuickGroup}
openedPath={openedPath}
setOpenedPath={setOpenedPath}
/>
)}
</>
)}
</div>
) : (
<div className="w-layout-hflex flex-block-13">
<div className="w-layout-vflex flex-block-14-copy-copy">
{/* <button onClick={() => setSelectedNode(null)} style={{ marginBottom: 16 }}>Назад</button> */}
{/* ОТЛАДКА: Логируем передачу SSD в KnotIn */}
{(() => {
const knotSsd = selectedNode.ssd || vehicleInfo.ssd;
console.log('🔍 [vehicleId].tsx передает в KnotIn:', {
selectedNodeSsd: selectedNode.ssd ? `${selectedNode.ssd.substring(0, 50)}...` : 'отсутствует',
vehicleInfoSsd: vehicleInfo.ssd ? `${vehicleInfo.ssd.substring(0, 50)}...` : 'отсутствует',
finalSsd: knotSsd ? `${knotSsd.substring(0, 50)}...` : 'отсутствует',
unitId: selectedNode.unitid,
unitName: selectedNode.name
});
return null;
})()}
<KnotIn
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
ssd={selectedNode.ssd || vehicleInfo.ssd} // ИСПРАВЛЕНИЕ: Используем SSD узла, fallback на родительский SSD
unitId={selectedNode.unitid}
unitName={selectedNode.name}
parts={unitDetails}
/>
{unitDetailsLoading ? (
<div style={{ padding: 24, textAlign: 'center' }}>Загружаем детали узла...</div>
) : unitDetailsError ? (
<div style={{ color: 'red', padding: 24 }}>Ошибка загрузки деталей: {unitDetailsError.message}</div>
) : unitDetails.length > 0 ? (
<KnotParts
parts={unitDetails}
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
/>
) : (
<div style={{ padding: 24, textAlign: 'center' }}>Детали не найдены</div>
)}
</div>
</div>
)}
</div>
<section className="section-3">
<CatalogSubscribe />
</section>
<Footer />
<MobileMenuBottomSection />
{/* ====== ВРЕМЕННЫЙ МАКЕТ ДЛЯ ВЕРСТКИ (конец) ====== */}
{/* Навигация
<nav className="bg-white border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex items-center justify-between h-16">
@ -194,7 +487,7 @@ const VehicleDetailsPage = () => {
</div>
</nav>
{/* Информация об автомобиле */}
Информация об автомобиле
<div className="bg-white border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div className="flex items-center space-x-4 mb-6">
@ -214,7 +507,7 @@ const VehicleDetailsPage = () => {
</div>
</div>
{/* Предупреждение об ошибке */}
Предупреждение об ошибке
{hasError && (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
<div className="flex">
@ -235,7 +528,7 @@ const VehicleDetailsPage = () => {
</div>
)}
{/* Отладочная информация */}
Отладочная информация
<div className="bg-gray-50 border border-gray-200 rounded-lg p-4 mb-6">
<h4 className="text-sm font-medium text-gray-900 mb-3">
🔧 Отладочная информация
@ -266,7 +559,7 @@ const VehicleDetailsPage = () => {
</div>
</div>
{/* Характеристики автомобиля */}
Характеристики автомобиля
{vehicleInfo.attributes && vehicleInfo.attributes.length > 0 && (
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{vehicleInfo.attributes.map((attr, index) => (
@ -280,7 +573,7 @@ const VehicleDetailsPage = () => {
</div>
</div>
{/* Способы поиска запчастей */}
Способы поиска запчастей
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="mb-6">
<h2 className="text-xl font-bold text-gray-900 mb-2">Поиск запчастей</h2>
@ -289,7 +582,7 @@ const VehicleDetailsPage = () => {
</p>
</div>
{/* Диагностический компонент */}
Диагностический компонент
<LaximoDiagnostic
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
@ -302,9 +595,8 @@ const VehicleDetailsPage = () => {
searchType={searchType}
onSearchTypeChange={setSearchType}
/>
</div>
</main>
</Layout>
</div> */}
</>
);
};

View File

@ -74,12 +74,12 @@ const PartDetailPage = () => {
oemNumber: oemNumber,
ssd: finalSsd
},
skip: !brand || !vehicleId || !oemNumber || !finalSsd,
skip: !brand || vehicleId === undefined || vehicleId === null || !oemNumber || !finalSsd,
errorPolicy: 'all'
}
);
if (!brand || !vehicleId || !oemNumber) {
if (!brand || vehicleId === undefined || vehicleId === null || !oemNumber) {
return (
<>
<Head>

View File

@ -0,0 +1,235 @@
import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/router';
import { useQuery } from '@apollo/client';
import Head from 'next/head';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import MobileMenuBottomSection from '@/components/MobileMenuBottomSection';
import { GET_BRANDS_BY_CODE, GET_LAXIMO_CATALOG_INFO } from '@/lib/graphql';
import { LaximoCatalogInfo } from '@/types/laximo';
const InfoBrandSelection = ({
brandName,
oemNumber,
detailName
}: {
brandName: string;
oemNumber: string;
detailName?: string;
}) => (
<section className="section-info">
<div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9">
<div className="w-layout-hflex flex-block-7">
<a href="/" className="link-block w-inline-block">
<div>Главная</div>
</a>
<div className="text-block-3"></div>
<a href="#" className="link-block-2 w-inline-block">
<div>Каталог</div>
</a>
<div className="text-block-3"></div>
<div>{brandName}</div>
<div className="text-block-3"></div>
<div>Деталь {oemNumber}</div>
<div className="text-block-3"></div>
<div>Выбор производителя</div>
</div>
<div className="w-layout-hflex flex-block-8">
<div className="w-layout-hflex flex-block-10">
<h1 className="heading">Выберите производителя для {oemNumber}</h1>
</div>
</div>
</div>
</div>
</section>
);
const BrandSelectionPage = () => {
const router = useRouter();
const { brand, vehicleId, oemNumber, detailName } = router.query;
// Получаем информацию о каталоге
const { data: catalogData, loading: catalogLoading } = useQuery<{ laximoCatalogInfo: LaximoCatalogInfo }>(
GET_LAXIMO_CATALOG_INFO,
{
variables: { catalogCode: brand },
skip: !brand,
errorPolicy: 'all',
}
);
// Получаем список брендов по артикулу
const { data, loading, error } = useQuery(GET_BRANDS_BY_CODE, {
variables: { code: oemNumber },
skip: !oemNumber,
errorPolicy: 'all'
});
if (!brand || vehicleId === undefined || vehicleId === null || !oemNumber) {
return (
<>
<Head>
<title>Выбор производителя</title>
</Head>
<main style={{ minHeight: '100vh', backgroundColor: '#f9fafb' }}>
<div style={{ textAlign: 'center', padding: '4rem 1rem' }}>
<h1 style={{ fontSize: '2rem', fontWeight: 'bold', color: '#1f2937', marginBottom: '1rem' }}>
Неверные параметры
</h1>
<p style={{ color: '#6b7280', marginBottom: '2rem' }}>
Неверные параметры для выбора производителя
</p>
<button
onClick={() => router.back()}
style={{
backgroundColor: '#dc2626',
color: 'white',
padding: '0.75rem 1.5rem',
borderRadius: '0.5rem',
border: 'none',
cursor: 'pointer'
}}
>
Назад
</button>
</div>
</main>
<Footer />
</>
);
}
const catalogInfo = catalogData?.laximoCatalogInfo;
const brandsData = data?.getBrandsByCode;
const brands = brandsData?.brands || [];
const hasError = brandsData?.error || error;
const hasNoBrands = brandsData?.success && brands.length === 0;
const handleBrandSelect = (selectedBrand: string) => {
console.log('🎯 Выбран бренд:', { articleNumber: oemNumber, brand: selectedBrand });
router.push(`/search-result?article=${encodeURIComponent(String(oemNumber))}&brand=${encodeURIComponent(selectedBrand)}`);
};
const handleBack = () => {
router.back();
};
return (
<>
<Head>
<title>Выбор производителя для {oemNumber} - {catalogInfo?.name || 'Каталог запчастей'}</title>
<meta name="description" content={`Выберите производителя для детали ${oemNumber} в каталоге ${catalogInfo?.name}`} />
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
<link href="images/webclip.png" rel="apple-touch-icon" />
</Head>
<InfoBrandSelection
brandName={catalogInfo?.name || String(brand)}
oemNumber={String(oemNumber)}
detailName={String(detailName || '')}
/>
<div className="page-wrapper bg-[#F5F8FB] min-h-screen">
<div className="w-full max-w-[1580px] mx-auto px-8 max-md:px-5 pt-10 pb-16">
{/* Кнопка назад */}
<div className="mb-6">
<button
onClick={handleBack}
className="flex items-center gap-2 text-gray-600 hover:text-gray-900 transition-colors"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
Назад к деталям
</button>
</div>
{/* Обработка ошибок */}
{hasError && !loading && (
<div className="bg-red-50 border border-red-200 rounded-2xl shadow p-10 mb-6">
<div className="flex items-center">
<svg className="w-6 h-6 text-red-600 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<div>
<h3 className="text-lg font-medium text-red-800">Ошибка загрузки</h3>
<p className="text-red-700 mt-1">
{brandsData?.error || error?.message || 'Не удалось загрузить список производителей'}
</p>
</div>
</div>
</div>
)}
{/* Загрузка */}
{(catalogLoading || loading) && (
<div className="bg-white rounded-2xl shadow p-10 flex flex-col items-center justify-center min-h-[300px]">
<div className="animate-spin rounded-full h-24 w-24 border-b-2 border-red-600 mb-6"></div>
<p className="text-lg text-gray-600">Загружаем производителей...</p>
</div>
)}
{/* Результаты */}
{!loading && !hasError && (
<div className="space-y-6">
{hasNoBrands ? (
<div className="bg-[#eaf0fa] border border-[#b3c6e6] rounded-2xl shadow p-10 text-center">
<svg className="w-16 h-16 mx-auto mb-4" style={{ color: '#0d336c' }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 15.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
<h3 className="text-xl font-semibold mb-2" style={{ color: '#0d336c' }}>
Производители не найдены
</h3>
<p className="mb-4" style={{ color: '#0d336c' }}>
По артикулу <span className="font-mono font-semibold">{oemNumber}</span> производители не найдены.
</p>
<p className="text-sm" style={{ color: '#3b5a99' }}>
Попробуйте изменить запрос или обратитесь к нашим менеджерам.
</p>
</div>
) : brands.length > 0 && (
<div className="bg-white rounded-2xl shadow p-10">
<div className="border-b border-gray-200 pb-4">
<h2 className="text-xl font-semibold text-gray-900">
Выбор производителя для артикула: {oemNumber}
</h2>
<p className="text-sm text-gray-600 mt-1">
{detailName && <span>Деталь: {detailName} </span>}
Найдено производителей: <span className="font-medium">{brands.length}</span>
</p>
</div>
<div className="divide-y divide-gray-200">
{brands.map((brandItem: any, index: number) => (
<div key={index}>
<button
onClick={() => handleBrandSelect(brandItem.brand)}
className="w-full text-left p-4 hover:bg-gray-50 transition-colors block group"
>
<div className="flex w-full items-center gap-2">
<div className="w-1/5 max-md:w-1/3 font-bold text-left truncate" style={{ color: 'rgb(77, 180, 94)' }}>
{brandItem.brand}
</div>
<div className="w-1/5 max-md:text-center max-md:w-1/3 font-bold text-left truncate group-hover:text-[#EC1C24] transition-colors">
{oemNumber}
</div>
<div className="w-3/5 max-md:w-1/3 text-left truncate">
{brandItem.name && brandItem.name !== brandItem.brand ? brandItem.name : detailName || 'Запчасть'}
</div>
</div>
</button>
</div>
))}
</div>
</div>
)}
</div>
)}
</div>
<MobileMenuBottomSection />
<Footer />
</div>
</>
);
};
export default BrandSelectionPage;

View File

@ -56,7 +56,7 @@ export default function Vin() {
<div className="w-layout-hflex flex-block-13">
<div className="w-layout-vflex flex-block-14-copy-copy">
<KnotIn />
<KnotParts />
<KnotParts catalogCode="" vehicleId="" />
</div>

View File

@ -38,10 +38,6 @@ export default function Vin() {
<meta content="vin" property="og:title" />
<meta content="vin" property="twitter:title" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<meta content="Webflow" name="generator" />
<link href="/css/normalize.css" rel="stylesheet" type="text/css" />
<link href="/css/webflow.css" rel="stylesheet" type="text/css" />
<link href="/css/protekproject.webflow.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com" rel="preconnect" />
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />

View File

@ -386,16 +386,17 @@ input.input-receiver:focus {
color: var(--_fonts---color--light-blue-grey);
}
.knotin {
height: 100%;
/* .knotin {
max-width: 100%;
display: flex;
align-items: stretch;
}
.knotin img {
height: 100%;
width: auto;
object-fit: contain; /* или cover */
}
max-width: 100%;
object-fit: contain;
} */
.tabs-menu.w-tab-menu {
scrollbar-width: none;
@ -403,4 +404,340 @@ input.input-receiver:focus {
}
.tabs-menu.w-tab-menu::-webkit-scrollbar {
display: none;
}
input.text-field,
input.w-input,
input#VinSearchInput {
background: #fff !important;
}
.text-block-56, .dropdown-link-3 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
max-width: 90%;
}
.text-block-55 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
max-height: 2.8em;
line-height: 1.4em;
}
.heading-9-copy,
.text-block-21-copy {
width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@media (max-width: 767px) {
.w-layout-hflex.flex-block-6 {
flex-direction: column !important;
}
@media (max-width: 767px) {
.div-block-12,
.div-block-12.small,
.div-block-12-copy,
.div-block-12-copy.small,
.div-block-123,
.div-block-123.small,
.div-block-red,
.div-block-red.small {
width: 100% !important;
max-width: 100% !important;
}
}
}
@media (max-width: 767px) {
.flex-block-6 {
grid-template-columns: 1fr !important;
grid-template-rows: none !important;
grid-template-areas: none !important;
grid-auto-flow: row !important; /* <--- ВАЖНО! */
}
}
.dropdown-toggle-card {
align-self: stretch;
margin-bottom: 5px;
margin-left: 0;
margin-right: 0;
padding: 6px 15px;
padding-left: 0 !important;
margin-left: 0 !important;
}
.dropdown-link-3 {
margin-left: 0 !important;
}
.div-block-131 {
max-width: 230px;
}
.dropdown-toggle-3.active{
background-color: var(--background);
font-weight: 700;
}
.dropdown-toggle-card.active {
background-color: var(--background);
}
.dropdown-toggle-3.active {
border-left: 2px solid var(--red);
}
.news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 0;
margin-bottom: 60px;
}
.news-index-block {
grid-column-gap: 40px;
grid-row-gap: 40px;
flex: 1;
max-width: 100%;
margin-bottom: 100px;
}
@media screen and (max-width: 767px) {
.news-index-block {
grid-column-gap: 20px;
grid-row-gap: 20px;
}
.inbt, .news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
}
}
.news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 0;
margin-bottom: 60px;
}
.bottom_head {
padding-left: 30px;
padding-right: 30px;
}
@media screen and (max-width: 479px) {
.bottom_head {
padding-left: 15px;
padding-right: 15px;
}
}
.bottom_head {
background-color: var(--back);
flex-flow: column;
justify-content: center;
align-items: flex-start;
width: 100%;
height: auto;
margin-top: -15px;
padding-left: 60px;
padding-right: 60px;
display: flex;
}
body {
background-color: var(--background);
--_fonts---font-family: Onest, sans-serif;
--_fonts---color--dark-blue: #0d336c;
--_fonts---font-size--core: 14px;
--_fonts---font-size--small-font-size: 14px;
--_fonts---color--black: #000;
--_fonts---font-size--bigger: 18px;
--_fonts---color--white: white;
--_fonts---color--light-blue-grey: #8e9aac;
--_fonts---h1: 36px;
--_fonts---color--light-blue: #b7cae2;
--_fonts---color--grey: #747474;
--_fonts---font-size--heading-3: 24px;
--_fonts---font-size--heading-2: 30px;
--_fonts---color--green: #4db45e;
--_fonts---font-size--supersmall: 12px;
font-family: Onest, sans-serif;
}
.menu-button.w--open {
z-index: 2000;
background-color: var(--red);
color: var(--white);
justify-content: center;
align-items: center;
height: 50px;
padding-top: 15px;
padding-bottom: 15px;
left: auto;
}
.heading-7 {
z-index: 999;
color: var(--_fonts---color--black);
font-size: var(--_fonts---font-size--heading-3);
width: 200px;
margin-top: 30px;
margin-bottom: 0;
margin-left: 30px;
line-height: 130%;
position: absolute;
}
.heading-7-white {
z-index: 999;
color: var(--_fonts---color--white);
font-size: var(--_fonts---font-size--heading-3);
width: 200px;
margin-top: 30px;
margin-bottom: 0;
margin-left: 30px;
line-height: 130%;
position: absolute;
}
.mobile-menu-buttom-section {
z-index: 1900;
background-color: var(--white);
display: none;
position: fixed;
inset: auto 0% 0%;
}
.nav-menu-3 {
z-index: 1900;
background-color: #0000;
width: 100%;
height: auto;
display: none;
position: relative;
left: auto;
}
.dropdown-toggle-2 {
z-index: 999;
display: flex;
}
.dropdown-toggle-2.w--open {
z-index: 999998;
}
.div-block-28 {
background-color: var(--background);
height: auto;
margin-top: 60px;
padding-bottom: 60px;
padding-left: 60px;
position: relative;
bottom: auto;
left: 0%;
right: 0%;
}
@media screen and (max-width: 991px) {
.nav-menu-2 {
float: none;
flex-flow: row;
justify-content: flex-start;
align-items: center;
width: 100%;
display: block;
position: relative;
top: 20px;
left: -30px;
right: 0;
}
.div-block-28 {
padding-left: 30px;
}
}
.heading-8-copy {
height: 40px;
}
.flex-block-108 , .flex-block-108-copy, .w-layout-hflex.flex-block-121, .core-product-search{
overflow-x: scroll;
overflow-y: hidden;
}
/* .flex-block-108-copy::-webkit-scrollbar {
display: none;
}
.flex-block-121::-webkit-scrollbar {
display: none;
} */
.flex-block-108 , .flex-block-108-copy, .w-layout-hflex.flex-block-121, .core-product-search {
overflow-x: scroll;
overflow-y: hidden;
scrollbar-width: none; /* Firefox */
}
.flex-block-108::-webkit-scrollbar, .flex-block-108-copy::-webkit-scrollbar, .w-layout-hflex.flex-block-121::-webkit-scrollbar, .core-product-search::-webkit-scrollbar {
display: none; /* Chrome, Safari */
}
.flex-block-44 {
max-width: 33%;
}
.text-block-21 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.flex-block-45 {
width: 80%;
}
.flex-block-39 {
max-width: 100%;
}
.heading-9-copy {
min-width: 100px;
}
@media screen and (max-width: 767px) {
.flex-block-15-copy {
grid-column-gap: 5px;
grid-row-gap: 5px;
width: 190px;
padding: 15px;
}
}
.flex-block-15-copy {
width: 230px;
}

View File

@ -3,7 +3,7 @@
--back: #0d336c;
--_fonts---font-family: Onest, sans-serif;
--_fonts---color--dark-blue: #0d336c;
--_fonts---font-size--core: 14px;
--_fonts---font-size--core: 16px;
--_fonts---font-size--small-font-size: 14px;
--_fonts---color--black: #000;
--_fonts---font-size--bigger: 18px;
@ -17,7 +17,6 @@
--_button---dark_blue: #0d336c;
--_fonts---color--white: white;
--_button---hover-dark_blue: #00245b;
--_button---black: #000;
--_button---color: white;
--_round---big-20: 20px;
--_fonts---color--light-blue-grey: #8e9aac;
@ -34,6 +33,7 @@
--_fonts---font-size--heading-2: 30px;
--light-grey: #ececec;
--_button---light-blue: #e6edf6;
--_button---black: #000;
--_fonts---color--green: #4db45e;
--_fonts---font-size--supersmall: 12px;
--light-blue: #dae5ef;
@ -824,8 +824,8 @@
}
body {
background-color: var(--background);
--_fonts---font-family: Onest, sans-serif;
color: #333;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
line-height: 20px;
}
@ -933,7 +933,7 @@ body {
.flex-block {
grid-column-gap: 15px;
grid-row-gap: 15px;
display: flex;
display: none;
}
.flex-block-2 {
@ -964,14 +964,14 @@ body {
display: flex;
}
.bottom_head {
.topmenuh {
background-color: var(--back);
flex-flow: column;
justify-content: center;
align-items: flex-start;
width: 100%;
height: auto;
margin-top: -15px;
margin-top: 0;
padding-left: 60px;
padding-right: 60px;
display: flex;
@ -991,7 +991,9 @@ body {
background-color: #fff;
justify-content: center;
align-items: center;
padding: 12px 16px 13px;
width: 50px;
height: 44px;
padding: 13px 12px;
display: flex;
}
@ -1001,7 +1003,7 @@ body {
}
.menu-button.w--open {
z-index: 2000;
z-index: 9999999;
background-color: var(--red);
color: var(--white);
justify-content: center;
@ -1110,6 +1112,7 @@ body {
cursor: pointer;
justify-content: flex-start;
align-items: center;
height: 44px;
padding: 6px 15px;
text-decoration: none;
display: flex;
@ -1138,18 +1141,22 @@ body {
.left-arrow {
justify-content: space-between;
align-items: center;
margin-left: -40px;
margin-left: 0;
padding-left: 40px;
display: flex;
position: absolute;
}
.left-arrow:hover {
display: flex;
}
.icon-2 {
color: var(--_button---black);
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
margin: 0;
width: 18px;
height: 18px;
margin: auto;
font-size: 24px;
font-weight: 700;
display: flex;
@ -1164,28 +1171,28 @@ body {
background-color: var(--back);
border: 1px #000;
flex: 1;
min-width: 100%;
max-width: 100%;
height: 480px;
height: 220px;
margin-left: 0;
margin-right: 0;
overflow: hidden;
}
.flex-block-5 {
grid-column-gap: 40px;
grid-row-gap: 40px;
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 20px;
}
.flex-block-6 {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex-flow: wrap;
grid-template: ". ."
". ."
"Area Area"
/ 1fr 1fr;
grid-template: "."
"."
/ 1fr 1fr 1fr 1fr;
grid-auto-columns: 1fr;
align-self: stretch;
display: grid;
@ -1510,7 +1517,7 @@ body {
padding: 5px;
font-weight: 600;
position: relative;
top: -45px;
top: -35px;
}
.text-block-8 {
@ -1553,7 +1560,7 @@ body {
box-sizing: content-box;
object-fit: contain;
width: 100%;
height: 100%;
height: 180px;
overflow: hidden;
}
@ -1881,9 +1888,11 @@ body {
.flex-block-24 {
grid-column-gap: 40px;
grid-row-gap: 40px;
border-radius: var(--_round---big-20);
background-color: var(--white);
flex-flow: column;
flex: 1;
padding-top: 30px;
padding: 30px 40px;
}
.flex-block-25 {
@ -1897,9 +1906,13 @@ body {
text-decoration: none;
}
.link-block-6:hover {
color: var(--_button---primary);
}
.flex-block-26 {
grid-column-gap: 26px;
grid-row-gap: 26px;
grid-column-gap: 22px;
grid-row-gap: 22px;
flex: 1;
min-width: 140px;
}
@ -1938,8 +1951,8 @@ body {
border-radius: var(--_round---supersmall-4);
background-color: var(--white);
color: var(--_fonts---color--grey);
height: 52px;
margin-bottom: 18px;
height: 46px;
margin-bottom: 12px;
padding: 12px 24px;
}
@ -2005,7 +2018,7 @@ body {
align-self: stretch;
align-items: center;
max-width: 100%;
padding: 30px 40px;
padding: 60px 40px;
display: flex;
}
@ -2027,7 +2040,7 @@ body {
.flex-block-30 {
grid-column-gap: 10px;
grid-row-gap: 10px;
max-width: 840px;
max-width: 540px;
}
.flex-block-31 {
@ -2042,22 +2055,23 @@ body {
flex: 1;
justify-content: flex-start;
align-items: flex-start;
min-width: 480px;
height: 260px;
min-width: 240px;
height: 140px;
padding-top: 0;
padding-left: 0;
display: flex;
overflow: hidden;
}
.div-block-12.small {
min-width: 300px;
min-width: 240px;
}
.heading-7 {
z-index: 999;
color: var(--_fonts---color--black);
font-size: var(--_fonts---font-size--heading-3);
width: 200px;
font-size: var(--_fonts---font-size--bigger);
width: 160px;
margin-top: 30px;
margin-bottom: 0;
margin-left: 30px;
@ -2084,13 +2098,15 @@ body {
}
.heading_news {
font-size: var(--_fonts---font-size--heading-3);
font-size: var(--_fonts---font-size--bigger);
margin-top: 0;
margin-bottom: 0;
line-height: 130%;
}
.text-block-20 {
color: var(--_fonts---color--grey);
font-size: var(--_fonts---font-size--small-font-size);
}
.div-block-13 {
@ -2154,12 +2170,18 @@ body {
.slide-nav {
margin-bottom: -55px;
display: none;
}
.right-arrow {
justify-content: flex-end;
align-items: center;
margin-right: -40px;
margin-right: 0;
padding-right: 40px;
display: flex;
}
.right-arrow:hover {
display: flex;
}
@ -2461,7 +2483,7 @@ body {
.delivery-time-search {
font-size: var(--_fonts---font-size--core);
width: 160px;
width: 120px;
max-height: 40px;
overflow: hidden;
}
@ -2474,7 +2496,7 @@ body {
}
.price.opencard {
width: 170px;
width: 70px;
}
.add-to-cart-block {
@ -2615,7 +2637,7 @@ body {
color: var(--_fonts---color--black);
font-size: var(--_fonts---font-size--core);
text-align: left;
width: 200px;
width: 60px;
max-height: 40px;
overflow: hidden;
}
@ -2862,7 +2884,7 @@ body {
color: var(--_fonts---color--black);
font-size: var(--_fonts---font-size--bigger);
text-align: right;
width: 100px;
margin-top: 0;
margin-bottom: 0;
font-weight: 700;
@ -3143,7 +3165,7 @@ body {
.sort-item-brand {
color: var(--_fonts---color--light-blue-grey);
font-size: var(--_fonts---font-size--small-font-size);
width: 120px;
width: 100px;
}
.sort-item-brand.first {
@ -3195,7 +3217,7 @@ body {
align-items: center;
margin-bottom: 20px;
padding-left: 10px;
padding-right: 15px;
padding-right: 10px;
}
.flex-block-62 {
@ -3603,7 +3625,7 @@ body {
}
.code-embed-5 {
width: 30px;
width: 26px;
height: 20px;
}
@ -3990,7 +4012,7 @@ body {
}
.mobile-menu-buttom-section {
z-index: 1900;
z-index: 9999999;
background-color: var(--white);
display: none;
position: fixed;
@ -4100,7 +4122,7 @@ body {
margin-top: 60px;
padding-bottom: 60px;
padding-left: 60px;
position: relative;
position: absolute;
bottom: auto;
left: 0%;
right: 0%;
@ -4214,12 +4236,12 @@ body {
}
.nav-menu-3 {
z-index: 1900;
z-index: 99999999;
background-color: #0000;
width: 100%;
height: auto;
display: none;
position: relative;
position: absolute;
left: auto;
}
@ -4579,7 +4601,6 @@ body {
justify-content: flex-start;
align-self: auto;
align-items: flex-start;
margin-bottom: 80px;
display: flex;
}
@ -4867,9 +4888,10 @@ body {
flex: 0 auto;
justify-content: space-between;
align-self: stretch;
align-items: flex-start;
align-items: center;
margin: -20px;
padding: 20px 20px 40px;
padding: 20px;
overflow: hidden;
}
.mask {
@ -4879,14 +4901,25 @@ body {
.div-block-34 {
border: 1px solid var(--light-blue);
background-color: var(--white);
opacity: 0;
color: var(--back);
border-radius: 100px;
width: 60px;
height: 60px;
position: absolute;
flex: none;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
display: flex;
}
.div-block-34:hover {
background-color: var(--_button---primary);
color: var(--white);
border-style: none;
}
.div-block-34.right {
transform: rotate(180deg);
}
.heading-17 {
@ -5007,9 +5040,10 @@ body {
flex: 1;
justify-content: flex-start;
align-items: flex-start;
min-width: 480px;
height: 260px;
min-width: 240px;
height: 140px;
display: flex;
overflow: hidden;
}
.div-block-12-copy.small {
@ -5022,8 +5056,9 @@ body {
flex: 1;
justify-content: flex-start;
align-items: flex-start;
height: 260px;
height: 140px;
display: flex;
overflow: hidden;
}
.div-block-123.small {
@ -5033,7 +5068,7 @@ body {
.heading-7-white {
z-index: 999;
color: var(--_fonts---color--white);
font-size: var(--_fonts---font-size--heading-3);
font-size: var(--_fonts---font-size--bigger);
width: 200px;
margin-top: 30px;
margin-bottom: 0;
@ -5062,18 +5097,28 @@ body {
background-image: none;
justify-content: flex-start;
align-items: flex-start;
min-width: 340px;
min-width: 240px;
height: 140px;
padding-top: 0;
padding-left: 0;
display: flex;
overflow: hidden;
}
.image-22 {
box-sizing: border-box;
object-fit: contain;
object-position: 100% 100%;
max-width: 80%;
height: 100%;
margin-left: auto;
margin-right: 0;
display: block;
position: relative;
top: auto;
bottom: 0;
right: 0;
overflow: clip;
}
.section-5 {
@ -5198,11 +5243,12 @@ body {
}
.news-index-block {
grid-column-gap: 40px;
grid-row-gap: 40px;
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-bottom: 100px;
margin-top: 20px;
margin-bottom: 60px;
}
.section-6 {
@ -5278,6 +5324,7 @@ body {
}
.div-block-127 {
border: 1px solid var(--_icon---light-blue-grey);
color: var(--_icon---light-blue-grey);
border-radius: 50px;
flex: none;
@ -5291,7 +5338,7 @@ body {
}
.div-block-127:hover {
border-color: var(--_button---primary);
color: var(--_button---primary);
}
@ -5356,8 +5403,9 @@ body {
}
.favcardcat {
border: 1px none var(--_icon---light-blue-grey);
background-color: var(--white);
color: var(--_icon---light-blue-grey);
color: var(--_fonts---color--white);
border-radius: 50px;
flex: none;
justify-content: center;
@ -5372,6 +5420,7 @@ body {
}
.favcardcat:hover {
border-color: var(--_button---primary);
color: var(--_button---primary);
}
@ -5379,6 +5428,1118 @@ body {
flex: none;
}
.tabson {
grid-column-gap: 20px;
grid-row-gap: 20px;
display: none;
}
.code-embed-14 {
width: 28px;
height: 28px;
margin: auto;
}
.code-embed-15 {
margin-top: 20px;
position: absolute;
}
.topnav {
background-color: #0000;
flex-flow: column;
margin-left: 220px;
margin-right: 0;
display: block;
position: static;
}
.searcj {
border-radius: var(--_round---small-8);
flex: 1;
align-self: stretch;
height: 44px;
margin-bottom: 0;
padding: 0;
}
.searcj.big {
padding-top: 5px;
padding-bottom: 5px;
}
.topmenub {
flex-flow: column;
justify-content: center;
align-items: flex-start;
width: 100%;
height: auto;
margin-top: 0;
padding-left: 60px;
padding-right: 60px;
display: flex;
}
.tb {
justify-content: space-between;
align-items: center;
width: 100%;
min-width: auto;
max-width: 1580px;
margin-left: auto;
margin-right: auto;
padding-top: 40px;
display: block;
}
.tb.nav {
height: auto;
padding-top: 15px;
padding-bottom: 15px;
}
.tb.info {
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
}
.tb.subscribe {
padding-top: 40px;
padding-bottom: 40px;
}
.tb.footer {
background-color: var(--back);
padding-top: 50px;
padding-bottom: 50px;
}
.link-block-8 {
border-radius: var(--_round---supersmall-4);
background-color: var(--white);
color: #000;
font-size: var(--_fonts---font-size--core);
flex: none;
padding: 4px 8px;
text-decoration: none;
}
.link-block-8.green {
background-color: var(--green);
color: var(--_fonts---color--white);
}
.link-block-8.orange {
color: var(--_fonts---color--white);
background-color: #ff5f00;
}
.flex-block-107 {
grid-column-gap: 10px;
grid-row-gap: 10px;
overflow: hidden;
}
.batd {
justify-content: space-between;
align-items: center;
width: 100%;
min-width: auto;
max-width: 1580px;
margin-left: auto;
margin-right: auto;
display: block;
}
.batd.nav {
height: auto;
padding-top: 0;
}
.batd.info {
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
}
.batd.subscribe {
padding-top: 40px;
padding-bottom: 40px;
}
.batd.footer {
background-color: var(--back);
padding-top: 50px;
padding-bottom: 50px;
}
.div-block-128 {
background-image: url('/images/bannertop.jpg');
background-position: 0%;
background-repeat: no-repeat;
background-size: cover;
width: 100%;
height: 100%;
}
.div-block-129 {
border-radius: var(--_round---big-20);
background-color: var(--white);
flex-flow: column;
flex: none;
justify-content: flex-start;
align-items: flex-start;
width: 330px;
height: 220px;
padding: 30px;
display: flex;
}
.flex-block-108 {
grid-column-gap: 18px;
grid-row-gap: 18px;
justify-content: space-between;
align-items: flex-start;
overflow: scroll;
}
.heading-18 {
font-size: var(--_fonts---font-size--core);
margin-top: 0;
margin-bottom: 0;
font-weight: 900;
}
.flex-block-109 {
grid-column-gap: 16px;
grid-row-gap: 16px;
flex: 0 auto;
grid-template-rows: auto auto;
grid-template-columns: 1fr 1fr;
grid-auto-columns: 1fr;
justify-content: space-between;
align-self: stretch;
align-items: center;
height: 30px;
padding-top: 0;
padding-bottom: 0;
display: flex;
}
.saletag {
border-radius: var(--_round---small-8);
background-color: var(--green);
color: var(--_fonts---color--white);
padding: 4px 5px;
font-size: 12px;
font-weight: 600;
}
.flex-block-110 {
justify-content: flex-start;
align-self: stretch;
align-items: center;
}
.flex-block-111 {
grid-column-gap: 6px;
grid-row-gap: 6px;
}
.arbd {
border: 1px solid var(--light-blue);
background-color: var(--white);
opacity: 0;
color: var(--back);
border-radius: 100px;
flex: none;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
display: flex;
}
.arbd:hover {
background-color: var(--_button---primary);
color: var(--white);
border-style: none;
}
.arbd.right {
transform: rotate(180deg);
}
.catnav {
flex-flow: column;
justify-content: flex-start;
align-items: center;
width: 100%;
padding-top: 40px;
padding-left: 60px;
padding-right: 60px;
display: flex;
}
.ci1 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.text-block-54 {
color: var(--_fonts---color--black);
flex: 1;
padding-top: 20px;
padding-left: 20px;
padding-right: 20px;
font-weight: 700;
line-height: 18px;
}
.image-25 {
margin: auto 0 0 auto;
display: block;
position: relative;
bottom: 0;
right: 36px;
}
.text-block-55 {
color: var(--_fonts---color--light-blue-grey);
}
.flex-block-112 {
grid-column-gap: 10px;
grid-row-gap: 10px;
color: var(--red);
margin-top: 10px;
}
.flex-block-113 {
border-radius: var(--_round---big-20);
background-color: var(--white);
flex: 0 auto;
align-self: stretch;
padding: 20px;
}
.button-3 {
border-radius: var(--_button---round-12px);
background-color: var(--_button---primary);
flex: none;
justify-content: center;
align-items: center;
padding: 10px 15px;
display: flex;
}
.button-3:hover {
background-color: var(--_button---hover-red);
}
.button-23 {
border-radius: var(--_button---round-12px);
background-color: var(--_button---light-blue);
color: var(--_fonts---color--black);
flex: none;
justify-content: center;
align-items: center;
padding: 10px 25px;
display: flex;
}
.button-23:hover {
background-color: var(--_button---primary);
color: var(--_fonts---color--white);
}
.flex-block-114 {
grid-column-gap: 10px;
grid-row-gap: 10px;
align-self: stretch;
margin-bottom: 30px;
}
.dropdown-4 {
flex-flow: column;
justify-content: space-between;
align-self: stretch;
align-items: center;
margin-left: 0;
margin-right: 0;
display: flex;
}
.dropdown-toggle-3 {
border-top-right-radius: var(--_round---normal);
border-bottom-right-radius: var(--_round---normal);
border-left: 2px solid #0000;
flex: 1;
align-self: stretch;
margin-bottom: 5px;
margin-left: 0;
margin-right: 0;
padding: 6px 15px;
}
.dropdown-toggle-3:hover {
border-left: 2px solid var(--red);
}
.dropdown-toggle-3:active {
background-color: var(--background);
}
.dropdown-list-4 {
background-color: #0000;
flex: 1;
align-self: stretch;
margin-top: 5px;
margin-bottom: 10px;
padding-left: 25px;
display: none;
position: static;
top: 40px;
}
.dropdown-link-3 {
color: var(--_fonts---color--black);
padding: 5px 0;
}
.dropdown-link-3:hover {
color: var(--red);
}
.text-block-56 {
color: var(--_fonts---color--black);
}
.div-block-131 {
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--red);
flex-flow: column;
flex: 1;
justify-content: space-between;
align-items: flex-start;
min-width: 230px;
min-height: 180px;
padding: 20px;
display: flex;
}
.div-block-131:hover {
background-color: var(--light-blue);
color: var(--_button---hover-red);
}
.text-block-57 {
color: var(--_fonts---color--black);
font-size: var(--_fonts---font-size--core);
word-break: break-all;
-webkit-hyphens: auto;
hyphens: auto;
font-weight: 600;
}
.vinleftbar {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: none;
width: 320px;
}
.container-vin {
justify-content: space-between;
align-items: center;
width: 100%;
min-width: auto;
max-width: 1580px;
margin-bottom: 60px;
margin-left: auto;
margin-right: auto;
padding-top: 40px;
display: block;
}
.container-vin.nav {
height: auto;
padding-top: 0;
}
.container-vin.info {
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
}
.container-vin.subscribe {
padding-top: 40px;
padding-bottom: 40px;
}
.container-vin.footer {
background-color: var(--back);
padding-top: 50px;
padding-bottom: 50px;
}
.knot-img {
grid-column-gap: 20px;
grid-row-gap: 20px;
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--black);
flex-flow: column;
flex: 1;
justify-content: flex-start;
align-items: flex-start;
min-width: 320px;
min-height: 180px;
padding: 40px;
display: flex;
}
.knotinfo {
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--red);
flex-flow: column;
justify-content: space-between;
align-items: flex-start;
max-width: 240px;
padding: 20px;
display: flex;
}
.heading-19 {
color: var(--_fonts---color--black);
margin-top: 0;
margin-bottom: 0;
font-size: 24px;
font-weight: 600;
line-height: 36px;
}
.partsname {
flex: 1;
max-width: 240px;
max-height: 40px;
overflow: hidden;
}
.oemnuber {
width: 100px;
}
.flex-block-115 {
grid-column-gap: 15px;
grid-row-gap: 15px;
justify-content: space-between;
align-self: stretch;
align-items: flex-start;
margin-left: -20px;
margin-right: -20px;
padding: 5px 20px;
}
.showallparts {
border-radius: var(--_button---round-12px);
background-color: var(--_button---light-blue);
color: var(--_fonts---color--black);
flex: none;
justify-content: center;
align-self: stretch;
align-items: center;
padding: 10px 25px;
display: flex;
}
.showallparts:hover {
background-color: var(--_button---primary);
color: var(--_fonts---color--white);
}
.image-26 {
object-fit: contain;
flex: 0 auto;
align-self: auto;
min-width: 200px;
}
.knotin {
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--red);
flex-flow: column;
justify-content: space-between;
align-items: flex-start;
max-width: 480px;
padding: 20px;
display: flex;
}
.knot-parts {
grid-column-gap: 5px;
grid-row-gap: 5px;
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--black);
flex-flow: column;
flex: 1;
justify-content: flex-start;
align-items: flex-start;
min-width: 320px;
min-height: 180px;
padding: 40px;
display: flex;
}
.nuberlist {
justify-content: center;
align-items: center;
width: 20px;
display: flex;
}
.knotlistitem {
grid-column-gap: 15px;
grid-row-gap: 15px;
justify-content: space-between;
align-self: stretch;
align-items: center;
margin-left: -20px;
margin-right: -20px;
padding: 5px 20px;
}
.code-embed-16 {
color: var(--_fonts---color--light-blue-grey);
justify-content: center;
align-items: center;
display: flex;
}
.code-embed-16:hover {
color: var(--_button---primary);
}
.flex-block-116 {
grid-column-gap: 15px;
grid-row-gap: 15px;
}
.flex-block-117 {
grid-column-gap: 15px;
grid-row-gap: 15px;
justify-content: flex-start;
align-items: center;
}
.brandsort {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex-flow: wrap;
align-self: stretch;
height: 148px;
overflow: hidden;
}
.brandsortb {
grid-column-gap: 30px;
grid-row-gap: 30px;
border-radius: var(--_round---big-20);
background-color: var(--white);
flex-flow: column;
flex: 1;
padding: 40px;
}
.flex-block-118 {
grid-column-gap: 40px;
grid-row-gap: 40px;
border-radius: var(--_round---big-20);
background-image: url('/images/Group-601.png'), linear-gradient(13deg, #0d336c, #182334);
background-position: 100px, 0 0;
background-repeat: no-repeat, repeat;
background-size: cover, auto;
justify-content: flex-start;
align-items: center;
padding: 30px;
}
.heading-20 {
color: var(--_fonts---color--white);
font-size: var(--_fonts---h1);
margin-top: 0;
margin-bottom: 0;
font-weight: 900;
}
.text-block-58 {
color: var(--_fonts---color--white);
font-size: var(--_fonts---font-size--core);
margin-bottom: 10px;
}
.button-24 {
border-radius: var(--_round---normal);
background-color: var(--_button---color);
color: var(--_fonts---color--black);
padding: 14px 30px;
}
.button-24:hover {
background-color: var(--_button---primary);
color: var(--_fonts---color--white);
}
.flex-block-119 {
grid-column-gap: 20px;
grid-row-gap: 20px;
width: 560px;
}
.bestpriceitem {
grid-column-gap: 10px;
grid-row-gap: 10px;
border-radius: var(--_round---normal);
background-color: var(--white);
flex: 1;
justify-content: flex-start;
align-items: center;
min-width: 196px;
max-width: 196px;
padding: 15px;
}
.bestpriceitem:hover {
box-shadow: 0 0 15px #0000004d;
}
.bestpriceitem.end {
display: none;
}
.pricecartbp {
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.actualprice {
font-size: var(--_fonts---font-size--bigger);
font-weight: 800;
}
.oldpricebp {
color: var(--_fonts---color--light-blue-grey);
font-size: var(--_fonts---font-size--supersmall);
text-decoration: line-through;
}
.flex-block-120 {
justify-content: flex-start;
align-items: flex-end;
}
.nameitembp {
flex: 0 auto;
align-self: auto;
max-height: 60px;
overflow: hidden;
}
.saletagbp {
border-radius: var(--_round---small-8);
background-color: var(--green);
color: var(--_fonts---color--white);
font-size: var(--_fonts---font-size--supersmall);
padding: 3px 5px;
font-weight: 600;
position: relative;
top: -30px;
}
.imgitembp {
flex-flow: column;
justify-content: flex-start;
align-items: flex-start;
width: 100%;
max-height: 160px;
padding: 0;
display: flex;
}
.flex-block-121 {
grid-column-gap: 20px;
grid-row-gap: 20px;
overflow: scroll;
}
.flex-block-122 {
justify-content: flex-start;
align-items: flex-end;
}
.inbt {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 0;
}
.div-block-132 {
border-radius: var(--_round---big-20);
flex: 1;
}
.flex-block-123 {
grid-column-gap: 40px;
grid-row-gap: 40px;
}
.submit-button-copy {
border-radius: var(--_round---normal);
background-color: var(--_button---primary);
font-size: var(--_fonts---font-size--bigger);
padding: 16px 30px;
}
.submit-button-copy.fill {
font-size: var(--_fonts---font-size--core);
justify-content: center;
align-self: stretch;
align-items: center;
padding-top: 15px;
padding-bottom: 15px;
display: flex;
}
.supportheading {
color: var(--_fonts---color--white);
font-size: var(--_fonts---h1);
margin-top: 0;
margin-bottom: 0;
line-height: 120%;
}
.div-block-133 {
box-sizing: content-box;
object-fit: contain;
position: relative;
}
.text-block-54-copy {
color: var(--_fonts---color--black);
flex: 1;
padding-top: 20px;
padding-left: 20px;
padding-right: 20px;
font-weight: 700;
}
.ci2 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item2.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci3 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item3.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci4 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item4.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci5 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item5.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci6 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item6.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci7 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item7.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci8 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item8.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci9 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item9.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.image-5-copy {
box-sizing: content-box;
object-fit: contain;
width: 100%;
overflow: hidden;
}
.flex-block-124 {
grid-column-gap: 30px;
grid-row-gap: 30px;
border-radius: var(--_round---big-20);
background-image: url('/images/carvin.png'), linear-gradient(45deg, #1b283b, #0d336c);
background-position: 150px, 0 0;
background-repeat: no-repeat, repeat;
background-size: auto, auto;
justify-content: center;
align-self: stretch;
align-items: flex-start;
width: 440px;
padding: 30px;
}
.heading-21 {
color: var(--_fonts---color--white);
flex: 0 auto;
align-self: stretch;
margin-top: 0;
margin-bottom: 0;
font-size: 24px;
line-height: 34px;
}
.button-3-copy {
border-radius: var(--_button---round-12px);
background-color: var(--_button---primary);
flex: none;
justify-content: center;
align-items: center;
padding: 12px 25px;
display: flex;
}
.button-3-copy:hover {
background-color: var(--_button---hover-red);
}
.select-copy {
border: 1px solid var(--grey);
border-radius: var(--_round---supersmall-4);
background-color: var(--white);
color: var(--_fonts---color--grey);
width: 180px;
height: 46px;
margin-bottom: 0;
padding: 12px 24px;
}
.div-block-10-copy {
justify-content: space-between;
align-items: center;
margin-top: 20px;
display: flex;
}
.image-27 {
width: 160px;
margin-bottom: -232px;
margin-left: 600px;
}
.news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 0;
margin-bottom: 60px;
}
.container-copy {
justify-content: space-between;
align-items: center;
width: 100%;
min-width: auto;
max-width: 1580px;
margin-left: auto;
margin-right: auto;
padding-top: 20px;
display: block;
}
.container-copy.nav {
height: auto;
padding-top: 0;
}
.container-copy.info {
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
}
.container-copy.subscribe {
padding-top: 40px;
padding-bottom: 40px;
}
.container-copy.footer {
background-color: var(--back);
padding-top: 50px;
padding-bottom: 50px;
}
.div-block-134 {
border: 1px solid var(--_fonts---color--light-blue);
color: var(--_fonts---color--black);
border-radius: 40px;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
display: flex;
transform: rotate(0);
}
.div-block-134:hover {
background-color: var(--red);
color: var(--white);
border-style: none;
}
.code-embed-17 {
width: 20px;
height: 20px;
}
.div-block-134-copy {
border: 1px solid var(--_fonts---color--light-blue);
color: var(--_fonts---color--black);
border-radius: 40px;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
display: flex;
transform: rotate(180deg);
}
.div-block-134-copy:hover {
background-color: var(--red);
color: var(--white);
border-style: none;
}
.flex-block-125 {
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.div-block-135 {
background-color: var(--light-blue);
border-radius: 40px;
width: 8px;
height: 8px;
}
.div-block-135:hover {
background-color: var(--red);
}
.flex-block-126 {
grid-column-gap: 4px;
grid-row-gap: 4px;
justify-content: flex-start;
align-self: stretch;
align-items: center;
margin-left: 30px;
}
.flex-block-108-copy {
grid-column-gap: 18px;
grid-row-gap: 18px;
justify-content: space-between;
align-items: flex-start;
overflow: scroll;
}
@media screen and (min-width: 1440px) {
.body {
--_fonts---font-family: Onest, sans-serif;
@ -5684,6 +6845,10 @@ body {
margin-top: 0;
}
.ci1:hover {
background-color: var(--light-blue);
}
.vinleftbar {
width: 320px;
}
@ -5701,18 +6866,32 @@ body {
max-width: none;
}
.flex-block-118 {
grid-column-gap: 0px;
grid-row-gap: 0px;
}
.heading-20 {
font-size: 48px;
}
.flex-block-119 {
width: 520px;
width: 480px;
}
.bestpriceitem.end {
display: flex;
}
.flex-block-121 {
grid-column-gap: 15px;
grid-row-gap: 15px;
}
.ci2:hover, .ci3:hover, .ci4:hover, .ci5:hover, .ci6:hover, .ci7:hover, .ci8:hover, .ci9:hover {
background-color: var(--light-blue);
}
.flex-block-124 {
width: 540px;
}
@ -6097,6 +7276,7 @@ body {
}
.slider {
align-self: stretch;
height: auto;
display: flex;
}
@ -6194,6 +7374,8 @@ body {
flex-flow: column;
justify-content: space-between;
align-items: flex-start;
padding-top: 40px;
padding-bottom: 40px;
}
.div-block-12, .div-block-12.small {
@ -6878,8 +8060,12 @@ body {
margin-top: 0;
}
.code-embed-15 {
width: 160px;
}
.topnav {
margin-left: 0;
margin-left: 190px;
}
.topmenub {
@ -6907,6 +8093,10 @@ body {
padding-bottom: 40px;
}
.div-block-128 {
background-position: 0%;
}
.catnav {
padding-left: 30px;
padding-right: 30px;
@ -6935,10 +8125,19 @@ body {
flex-flow: row;
}
.supportheading {
font-size: 30px;
}
.image-5-copy {
object-fit: contain;
}
.image-27 {
margin-bottom: -280px;
margin-left: 530px;
}
.container-copy, .container-copy.nav, .container-copy.info {
padding-left: 0;
padding-right: 0;
@ -7170,6 +8369,10 @@ body {
align-items: center;
}
.flex-block-26 {
min-width: 120px;
}
.container2 {
padding: 20px 30px;
}
@ -7822,6 +9025,18 @@ body {
padding-bottom: 90px;
}
.div-block-129 {
justify-content: flex-start;
align-self: stretch;
align-items: center;
}
.flex-block-108 {
flex-flow: column;
justify-content: space-between;
align-items: center;
}
.container-vin {
padding-top: 20px;
}
@ -7835,7 +9050,24 @@ body {
padding-bottom: 90px;
}
.inbt, .news-index-block-copy {
.inbt {
grid-column-gap: 20px;
grid-row-gap: 20px;
}
.flex-block-123 {
flex-flow: column;
}
.flex-block-124 {
flex: 1;
}
.image-27 {
margin-left: 330px;
}
.news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
}
@ -8195,7 +9427,7 @@ body {
}
.heading_news {
line-height: 28px;
line-height: 20px;
}
.text-block-20 {
@ -8727,6 +9959,10 @@ body {
padding-bottom: 5px;
}
.icon-setting {
border: 0 #000;
}
.section-3 {
padding-left: 15px;
padding-right: 15px;
@ -9092,11 +10328,16 @@ body {
}
.favcardcat {
border-style: none;
width: 30px;
height: 30px;
margin-top: 0;
}
.code-embed-15 {
display: none;
}
.topnav {
margin-left: 0;
top: 58px;
@ -9165,6 +10406,17 @@ body {
padding: 40px 0 90px;
}
.div-block-129 {
justify-content: flex-start;
align-items: flex-start;
width: 100%;
height: auto;
}
.flex-block-109 {
margin-bottom: 10px;
}
.saletag {
padding-top: 3px;
padding-bottom: 3px;
@ -9172,6 +10424,15 @@ body {
top: -15px;
}
.flex-block-110 {
grid-column-gap: 10px;
grid-row-gap: 10px;
flex-flow: column-reverse;
justify-content: flex-start;
align-items: flex-start;
margin-bottom: 20px;
}
.catnav {
padding-left: 15px;
padding-right: 15px;
@ -9298,16 +10559,17 @@ body {
}
.submit-button-copy {
align-self: stretch;
padding: 15px 30px;
align-self: auto;
padding: 15px 25px;
}
.supportheading {
font-size: var(--_fonts---font-size--heading-2);
width: 220px;
}
.image-5-copy {
width: 100%;
width: 60%;
height: 100%;
min-height: auto;
}
@ -9316,6 +10578,10 @@ body {
margin-bottom: 10px;
}
.image-27 {
display: none;
}
.container-copy {
max-width: 100%;
margin-left: 0;
@ -9346,20 +10612,10 @@ body {
}
}
#w-node-bc394713-4b8e-44e3-8ddf-3edc1c31a743-3b3232bc {
#w-node-_5428604d-3026-96c9-8306-ab3c3dd9acb7-3b3232bc {
justify-self: stretch;
}
#w-node-_8908a890-8c8f-e12c-999f-08d5da3bcc01-3b3232bc {
grid-area: Area;
}
@media screen and (min-width: 1920px) {
#w-node-_8908a890-8c8f-e12c-999f-08d5da3bcc01-3b3232bc {
grid-area: Area;
}
}
@media screen and (max-width: 991px) {
#w-node-_2eb32dc9-d3cb-cbbb-db81-4205d4e11f12-659ca3b9 {
grid-area: span 1 / span 3 / span 1 / span 3;
@ -9372,810 +10628,4 @@ body {
}
}
.flex-block-113 {
border-radius: var(--_round---big-20);
background-color: var(--white);
flex: 0 auto;
align-self: stretch;
padding: 20px;
}
.button-3 {
border-radius: var(--_button---round-12px);
background-color: var(--_button---primary);
flex: none;
justify-content: center;
align-items: center;
padding: 10px 15px;
display: flex;
}
.button-3:hover {
background-color: var(--_button---hover-red);
}
.button-23 {
border-radius: var(--_button---round-12px);
background-color: var(--_button---light-blue);
color: var(--_fonts---color--black);
flex: none;
justify-content: center;
align-items: center;
padding: 10px 25px;
display: flex;
}
.button-23:hover {
background-color: var(--_button---primary);
color: var(--_fonts---color--white);
}
.flex-block-114 {
grid-column-gap: 10px;
grid-row-gap: 10px;
align-self: stretch;
margin-bottom: 30px;
}
.dropdown-4 {
flex-flow: column;
justify-content: space-between;
align-self: stretch;
align-items: center;
margin-left: 0;
margin-right: 0;
display: flex;
}
.dropdown-toggle-3 {
border-top-right-radius: var(--_round---normal);
border-bottom-right-radius: var(--_round---normal);
border-left: 2px solid #0000;
flex: 1;
align-self: stretch;
margin-bottom: 5px;
margin-left: 0;
margin-right: 0;
padding: 6px 15px;
}
.dropdown-toggle-3:hover {
border-left: 2px solid var(--red);
}
.dropdown-toggle-3:active {
background-color: var(--background);
}
.dropdown-list-4 {
background-color: #0000;
flex: 1;
align-self: stretch;
margin-top: 5px;
margin-bottom: 10px;
padding-left: 25px;
display: none;
position: static;
top: 40px;
}
.dropdown-link-3 {
color: var(--_fonts---color--black);
padding: 5px 0;
}
.dropdown-link-3:hover {
color: var(--red);
}
.text-block-56 {
color: var(--_fonts---color--black);
}
.div-block-131 {
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--red);
flex-flow: column;
flex: 1;
justify-content: space-between;
align-items: flex-start;
min-width: 230px;
min-height: 180px;
padding: 20px;
display: flex;
}
.div-block-131:hover {
background-color: var(--light-blue);
color: var(--_button---hover-red);
}
.text-block-57 {
color: var(--_fonts---color--black);
font-size: var(--_fonts---font-size--core);
word-break: break-all;
-webkit-hyphens: auto;
hyphens: auto;
font-weight: 600;
}
.vinleftbar {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: none;
width: 320px;
}
.container-vin {
justify-content: space-between;
align-items: center;
width: 100%;
min-width: auto;
max-width: 1580px;
margin-bottom: 60px;
margin-left: auto;
margin-right: auto;
padding-top: 40px;
display: block;
}
.container-vin.nav {
height: auto;
padding-top: 0;
}
.container-vin.info {
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
}
.container-vin.subscribe {
padding-top: 40px;
padding-bottom: 40px;
}
.container-vin.footer {
background-color: var(--back);
padding-top: 50px;
padding-bottom: 50px;
}
.knot-img {
grid-column-gap: 20px;
grid-row-gap: 20px;
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--black);
flex-flow: column;
flex: 1;
justify-content: flex-start;
align-items: flex-start;
min-width: 320px;
min-height: 180px;
padding: 40px;
display: flex;
}
.knotinfo {
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--red);
flex-flow: column;
justify-content: space-between;
align-items: flex-start;
max-width: 240px;
padding: 20px;
display: flex;
}
.heading-19 {
color: var(--_fonts---color--black);
margin-top: 0;
margin-bottom: 0;
font-size: 24px;
font-weight: 600;
line-height: 36px;
}
.partsname {
flex: 1;
max-width: 240px;
max-height: 40px;
overflow: hidden;
}
.oemnuber {
width: 100px;
}
.flex-block-115 {
grid-column-gap: 15px;
grid-row-gap: 15px;
justify-content: space-between;
align-self: stretch;
align-items: flex-start;
margin-left: -20px;
margin-right: -20px;
padding: 5px 20px;
}
.showallparts {
border-radius: var(--_button---round-12px);
background-color: var(--_button---light-blue);
color: var(--_fonts---color--black);
flex: none;
justify-content: center;
align-self: stretch;
align-items: center;
padding: 10px 25px;
display: flex;
}
.showallparts:hover {
background-color: var(--_button---primary);
color: var(--_fonts---color--white);
}
.image-26 {
object-fit: contain;
flex: 0 auto;
align-self: auto;
min-width: 200px;
}
.knotin {
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--red);
flex-flow: column;
justify-content: space-between;
align-items: flex-start;
max-width: 480px;
padding: 20px;
display: flex;
}
.knot-parts {
grid-column-gap: 5px;
grid-row-gap: 5px;
border-radius: var(--_round---big-20);
background-color: var(--white);
color: var(--black);
flex-flow: column;
flex: 1;
justify-content: flex-start;
align-items: flex-start;
min-width: 320px;
min-height: 180px;
padding: 40px;
display: flex;
}
.nuberlist {
justify-content: center;
align-items: center;
width: 20px;
display: flex;
}
.knotlistitem {
grid-column-gap: 15px;
grid-row-gap: 15px;
justify-content: space-between;
align-self: stretch;
align-items: center;
margin-left: -20px;
margin-right: -20px;
padding: 5px 20px;
}
.code-embed-16 {
color: var(--_fonts---color--light-blue-grey);
justify-content: center;
align-items: center;
display: flex;
}
.code-embed-16:hover {
color: var(--_button---primary);
}
.flex-block-116 {
grid-column-gap: 15px;
grid-row-gap: 15px;
}
.flex-block-117 {
grid-column-gap: 15px;
grid-row-gap: 15px;
justify-content: flex-start;
align-items: center;
}
.brandsort {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex-flow: wrap;
align-self: stretch;
height: 148px;
overflow: hidden;
}
.brandsortb {
grid-column-gap: 30px;
grid-row-gap: 30px;
border-radius: var(--_round---big-20);
background-color: var(--white);
flex-flow: column;
flex: 1;
padding: 40px;
}
.flex-block-118 {
grid-column-gap: 40px;
grid-row-gap: 40px;
border-radius: var(--_round---big-20);
background-image: url('/images/Group-601.png'), linear-gradient(13deg, #0d336c, #182334);
background-position: 100px, 0 0;
background-repeat: no-repeat, repeat;
background-size: cover, auto;
justify-content: flex-start;
align-items: center;
padding: 30px;
}
.heading-20 {
color: var(--_fonts---color--white);
font-size: var(--_fonts---h1);
margin-top: 0;
margin-bottom: 0;
font-weight: 900;
}
.text-block-58 {
color: var(--_fonts---color--white);
font-size: var(--_fonts---font-size--core);
margin-bottom: 10px;
}
.button-24 {
border-radius: var(--_round---normal);
background-color: var(--_button---color);
color: var(--_fonts---color--black);
padding: 14px 30px;
}
.button-24:hover {
background-color: var(--_button---primary);
color: var(--_fonts---color--white);
}
.flex-block-119 {
grid-column-gap: 20px;
grid-row-gap: 20px;
width: 560px;
}
.bestpriceitem {
grid-column-gap: 10px;
grid-row-gap: 10px;
border-radius: var(--_round---normal);
background-color: var(--white);
flex: 1;
justify-content: flex-start;
align-items: center;
min-width: 196px;
max-width: 196px;
padding: 15px;
}
.bestpriceitem:hover {
box-shadow: 0 0 15px #0000004d;
}
.bestpriceitem.end {
display: none;
}
.pricecartbp {
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.actualprice {
font-size: var(--_fonts---font-size--bigger);
font-weight: 800;
}
.oldpricebp {
color: var(--_fonts---color--light-blue-grey);
font-size: var(--_fonts---font-size--supersmall);
text-decoration: line-through;
}
.flex-block-120 {
justify-content: flex-start;
align-items: flex-end;
}
.nameitembp {
flex: 0 auto;
align-self: auto;
max-height: 60px;
overflow: hidden;
}
.saletagbp {
border-radius: var(--_round---small-8);
background-color: var(--green);
color: var(--_fonts---color--white);
font-size: var(--_fonts---font-size--supersmall);
padding: 3px 5px;
font-weight: 600;
position: relative;
top: -30px;
}
.imgitembp {
flex-flow: column;
justify-content: flex-start;
align-items: flex-start;
width: 100%;
max-height: 160px;
padding: 0;
display: flex;
}
.flex-block-121 {
grid-column-gap: 20px;
grid-row-gap: 20px;
overflow: scroll;
}
.flex-block-122 {
justify-content: flex-start;
align-items: flex-end;
}
.inbt {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 0;
}
.div-block-132 {
border-radius: var(--_round---big-20);
flex: 1;
}
.flex-block-123 {
grid-column-gap: 40px;
grid-row-gap: 40px;
}
.submit-button-copy {
border-radius: var(--_round---normal);
background-color: var(--_button---primary);
font-size: var(--_fonts---font-size--bigger);
padding: 16px 30px;
}
.submit-button-copy.fill {
font-size: var(--_fonts---font-size--core);
justify-content: center;
align-self: stretch;
align-items: center;
padding-top: 15px;
padding-bottom: 15px;
display: flex;
}
.supportheading {
color: var(--_fonts---color--white);
font-size: var(--_fonts---h1);
margin-top: 0;
margin-bottom: 0;
line-height: 120%;
}
.div-block-133 {
box-sizing: content-box;
object-fit: contain;
position: relative;
}
.text-block-54-copy {
color: var(--_fonts---color--black);
flex: 1;
padding-top: 20px;
padding-left: 20px;
padding-right: 20px;
font-weight: 700;
}
.ci2 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item2.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci3 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item3.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci4 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item4.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci5 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item5.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci6 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item6.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci7 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item7.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci8 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item8.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.ci9 {
border-radius: var(--_round---big-20);
background-color: var(--white);
background-image: url('/images/catalog_item9.png');
background-position: 100% 100%;
background-repeat: no-repeat;
background-size: auto;
flex: 1;
min-width: 160px;
height: 180px;
display: flex;
}
.image-5-copy {
box-sizing: content-box;
object-fit: contain;
width: 100%;
overflow: hidden;
}
.flex-block-124 {
grid-column-gap: 30px;
grid-row-gap: 30px;
border-radius: var(--_round---big-20);
/* background-image: url('/images/carvin.png'), linear-gradient(45deg, #1b283b, #0d336c);
background-position: 150px, 0 0; */
background-repeat: no-repeat, repeat;
background-size: auto, auto;
justify-content: center;
align-self: stretch;
align-items: flex-start;
width: 440px;
padding: 30px;
}
.heading-21 {
color: var(--_fonts---color--white);
flex: 0 auto;
align-self: stretch;
margin-top: 0;
margin-bottom: 0;
font-size: 24px;
line-height: 34px;
}
.button-3-copy {
border-radius: var(--_button---round-12px);
background-color: var(--_button---primary);
flex: none;
justify-content: center;
align-items: center;
padding: 12px 25px;
display: flex;
}
.button-3-copy:hover {
background-color: var(--_button---hover-red);
}
.select-copy {
border: 1px solid var(--grey);
border-radius: var(--_round---supersmall-4);
background-color: var(--white);
color: var(--_fonts---color--grey);
width: 180px;
height: 46px;
margin-bottom: 0;
padding: 12px 24px;
}
.div-block-10-copy {
justify-content: space-between;
align-items: center;
margin-top: 20px;
display: flex;
}
.image-27 {
width: 160px;
margin-bottom: -232px;
margin-left: 600px;
}
.news-index-block-copy {
grid-column-gap: 20px;
grid-row-gap: 20px;
flex: 1;
max-width: 100%;
margin-top: 0;
margin-bottom: 60px;
}
.container-copy {
justify-content: space-between;
align-items: center;
width: 100%;
min-width: auto;
max-width: 1580px;
margin-left: auto;
margin-right: auto;
padding-top: 20px;
display: block;
}
.container-copy.nav {
height: auto;
padding-top: 0;
}
.container-copy.info {
width: 100%;
padding-top: 30px;
padding-bottom: 30px;
}
.container-copy.subscribe {
padding-top: 40px;
padding-bottom: 40px;
}
.container-copy.footer {
background-color: var(--back);
padding-top: 50px;
padding-bottom: 50px;
}
.div-block-134 {
border: 1px solid var(--_fonts---color--light-blue);
color: var(--_fonts---color--black);
border-radius: 40px;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
display: flex;
transform: rotate(0);
}
.div-block-134:hover {
background-color: var(--red);
color: var(--white);
border-style: none;
}
.code-embed-17 {
width: 20px;
height: 20px;
}
.div-block-134-copy {
border: 1px solid var(--_fonts---color--light-blue);
color: var(--_fonts---color--black);
border-radius: 40px;
justify-content: center;
align-items: center;
width: 36px;
height: 36px;
display: flex;
transform: rotate(180deg);
}
.div-block-134-copy:hover {
background-color: var(--red);
color: var(--white);
border-style: none;
}
.flex-block-125 {
grid-column-gap: 10px;
grid-row-gap: 10px;
}
.div-block-135 {
background-color: var(--light-blue);
border-radius: 40px;
width: 8px;
height: 8px;
}
.div-block-135:hover {
background-color: var(--red);
}
.flex-block-126 {
grid-column-gap: 4px;
grid-row-gap: 4px;
justify-content: flex-start;
align-self: stretch;
align-items: center;
margin-left: 30px;
}

View File

@ -10,6 +10,7 @@ export interface CartItem {
originalPrice?: number
currency: string
quantity: number
stock?: string | number // количество товара в наличии на складе
deliveryTime?: string
deliveryDate?: string
warehouse?: string
@ -52,7 +53,7 @@ export interface CartState {
export interface CartContextType {
state: CartState
addItem: (item: Omit<CartItem, 'id' | 'selected' | 'favorite'>) => void
addItem: (item: Omit<CartItem, 'id' | 'selected' | 'favorite'>) => Promise<{ success: boolean; error?: string }>
removeItem: (id: string) => void
updateQuantity: (id: string, quantity: number) => void
toggleSelect: (id: string) => void
@ -64,4 +65,5 @@ export interface CartContextType {
removeSelected: () => void
updateDelivery: (delivery: Partial<DeliveryInfo>) => void
clearCart: () => void
clearError: () => void
}

View File

@ -88,7 +88,6 @@ export interface LaximoVehicleSearchResult {
// Дополнительные атрибуты из документации Laximo
grade?: string
transmission?: string
doors?: string
creationregion?: string
destinationregion?: string
date?: string
@ -97,12 +96,6 @@ export interface LaximoVehicleSearchResult {
trimcolor?: string
datefrom?: string
dateto?: string
frame?: string
frames?: string
framefrom?: string
frameto?: string
engine1?: string
engine2?: string
engine_info?: string
engineno?: string
options?: string
@ -112,8 +105,10 @@ export interface LaximoVehicleSearchResult {
market?: string
prodRange?: string
prodPeriod?: string
carpet_color?: string
seat_combination_code?: string
// Дополнительные атрибуты (могут приходить в виде массива attributes)
sales_code?: string
attributes: LaximoVehicleAttribute[]
}
export interface LaximoVehicleInfo {
@ -154,6 +149,7 @@ export interface LaximoUnit {
description?: string
imageurl?: string
largeimageurl?: string
ssd?: string // 🎯 ДОБАВЛЕНИЕ: SSD для узла
details?: LaximoDetail[]
attributes?: LaximoDetailAttribute[]
}
@ -279,6 +275,7 @@ export interface LaximoUnitInfo {
description?: string
imageurl?: string
largeimageurl?: string
ssd?: string // 🎯 ДОБАВЛЕНИЕ: SSD для узла
attributes?: LaximoDetailAttribute[]
}