4 Commits

11 changed files with 749 additions and 237 deletions

View File

@ -31,6 +31,8 @@ const FulltextSearchSection: React.FC<FulltextSearchSectionProps> = ({
return; return;
} }
console.log('SEARCH PARAMS', { catalogCode, vehicleId, searchQuery: searchQuery.trim(), ssd });
executeSearch({ executeSearch({
variables: { variables: {
catalogCode, catalogCode,
@ -199,6 +201,4 @@ const FulltextSearchSection: React.FC<FulltextSearchSectionProps> = ({
); );
}; };
export default FulltextSearchSection; export default FulltextSearchSection;

View File

@ -1,6 +1,11 @@
import React from "react"; import React from "react";
const InfoVin = () => ( interface InfoVinProps {
vehicleName: string;
vehicleInfo: string;
}
const InfoVin: React.FC<InfoVinProps> = ({ vehicleName, vehicleInfo }) => (
<section className="section-info"> <section className="section-info">
<div className="w-layout-blockcontainer container info w-container"> <div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9"> <div className="w-layout-vflex flex-block-9">
@ -9,22 +14,22 @@ const InfoVin = () => (
<div>Главная</div> <div>Главная</div>
</a> </a>
<div className="text-block-3"></div> <div className="text-block-3"></div>
<a href="#" className="link-block w-inline-block"> <a href="/brands" className="link-block w-inline-block">
<div>Оригинальный каталог</div> <div>Оригинальный каталог</div>
</a> </a>
<div className="text-block-3"></div> <div className="text-block-3"></div>
<a href="#" className="link-block-2 w-inline-block"> <a href="#" className="link-block-2 w-inline-block">
<div>Audi Q7</div> <div>{vehicleName}</div>
</a> </a>
</div> </div>
<div className="w-layout-hflex flex-block-8"> <div className="w-layout-hflex flex-block-8">
<div className="w-layout-hflex flex-block-10"> <div className="w-layout-hflex flex-block-10">
<h1 className="heading">Audi Q7</h1> <h1 className="heading">{vehicleName}</h1>
</div> </div>
</div> </div>
</div> </div>
<div className="w-layout-hflex flex-block-112"> <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="text-block-55">{vehicleInfo}</div>
<div className="w-embed"> <div className="w-embed">
{/* SVG icon */} {/* SVG icon */}
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">

View File

@ -1,9 +1,36 @@
import React from "react"; import React from "react";
const KnotIn = () => ( // Функция для корректного формирования 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 = ({ node }: { node: any }) => {
if (!node) return null;
let imageUrl = '';
if (node.imageurl) {
imageUrl = getImageUrl(node.imageurl, '250');
} else if (node.largeimageurl) {
imageUrl = node.largeimageurl;
}
return (
<div className="knotin"> <div className="knotin">
<img src="/images/image-44.jpg" loading="lazy" alt="" className="image-26" /> {imageUrl ? (
<img src={imageUrl} loading="lazy" alt={node.name || "Изображение узла"} className="image-26" />
) : (
<div style={{ width: 200, height: 200, background: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
Нет изображения
</div>
)}
{/* <div style={{ marginTop: 8, fontWeight: 500 }}>{node.name}</div> */}
</div> </div>
); );
};
export default KnotIn; export default KnotIn;

View File

@ -1,34 +1,42 @@
import React from "react"; import React from "react";
import { useRouter } from "next/router";
const parts = [ interface KnotPartsProps {
{ n: 1, oem: "059198405B", name: "Фильтрующий элемент с проклад." }, parts: Array<{
{ n: 2, oem: "N 10196103", name: "Винт с цилиндр. скруглённой головкой Torx" }, detailid?: string;
{ n: 3, oem: "059117070J", name: "Уплотнитель" }, codeonimage?: string | number;
{ n: 4, oem: "N 10124306", name: "Винт с плоской головкой и внутренним Torx" }, oem?: string;
{ n: 5, oem: "059117015K", name: "Масляный радиатор" }, name?: string;
{ n: 6, oem: "059117015K", name: "Масляный радиатор" }, price?: string | number;
{ n: 7, oem: "059117015K", name: "Масляный радиатор" }, brand?: string;
{ n: 8, oem: "059117015K", name: "Масляный радиатор" }, availability?: string;
{ n: 9, oem: "059117015K", name: "Масляный радиатор" }, note?: string;
{ n: 10, oem: "059117015K", name: "Масляный радиатор" }, attributes?: Array<{ key: string; name?: string; value: string }>;
{ 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: "Масляный радиатор" },
];
const KnotParts = () => ( const KnotParts: React.FC<KnotPartsProps> = ({ parts }) => {
const router = useRouter();
return (
<div className="knot-parts"> <div className="knot-parts">
{parts.map((part, idx) => ( {parts.map((part, idx) => (
<div className="w-layout-hflex knotlistitem" key={idx}> <div className="w-layout-hflex knotlistitem" key={part.detailid || idx}>
<div className="w-layout-hflex flex-block-116"> <div className="w-layout-hflex flex-block-116">
<div className="nuberlist">{part.n}</div> <div className="nuberlist">{part.codeonimage || idx + 1}</div>
<div className="oemnuber">{part.oem}</div> <div className="oemnuber">{part.oem}</div>
</div> </div>
<div className="partsname">{part.name}</div> <div className="partsname">{part.name}</div>
<div className="w-layout-hflex flex-block-117"> <div className="w-layout-hflex flex-block-117">
<a href="#" className="button-3 w-button">Цена</a> <button
className="button-3 w-button"
onClick={() => {
if (part.oem) {
router.push(`/search?q=${encodeURIComponent(part.oem)}&mode=parts`);
}
}}
>
Цена
</button>
<div className="code-embed-16 w-embed"> <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"> <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" /> <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" />
@ -39,5 +47,6 @@ const KnotParts = () => (
))} ))}
</div> </div>
); );
};
export default KnotParts; export default KnotParts;

View File

@ -1,31 +1,116 @@
import React from "react"; import React, { useState, useRef } from "react";
import { useQuery, useLazyQuery } from "@apollo/client";
const categories = [ import { GET_LAXIMO_CATEGORIES, GET_LAXIMO_UNITS } from "@/lib/graphql/laximo";
"Детали для ТО",
"Двигатель",
"Топливная система",
"Система охлаждения",
"Система выпуска",
"Трансмиссия",
"Ходовая часть",
"Рулевое управление",
"Тормозная система",
"Электрооборудование",
"Отопление / кондиционирование",
"Детали салона",
"Детали кузова",
"Дополнительное оборудование"
];
interface VinCategoryProps { interface VinCategoryProps {
onCategoryClick?: (e: React.MouseEvent) => void; catalogCode: string;
vehicleId: string;
ssd?: string;
onNodeSelect?: (node: any) => void;
} }
const VinCategory: React.FC<VinCategoryProps> = ({ onCategoryClick }) => ( const VinCategory: React.FC<VinCategoryProps> = ({ catalogCode, vehicleId, ssd, onNodeSelect }) => {
const { data: categoriesData, loading: categoriesLoading, error: categoriesError } = useQuery(GET_LAXIMO_CATEGORIES, {
variables: { catalogCode, vehicleId, ssd },
skip: !catalogCode || !vehicleId,
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 [selectedCategory, setSelectedCategory] = useState<any | null>(null);
const lastCategoryIdRef = useRef<string | null>(null);
// Если выбрана категория — показываем подкатегории (children или units)
let subcategories: any[] = [];
if (selectedCategory) {
if (selectedCategory.children && selectedCategory.children.length > 0) {
subcategories = selectedCategory.children;
} else {
subcategories = unitsByCategory[selectedCategory.quickgroupid] || [];
}
}
const handleCategoryClick = (cat: any) => {
if (cat.children && cat.children.length > 0) {
setSelectedCategory(cat);
} else {
// Если нет children, грузим units (подкатегории)
if (!unitsByCategory[cat.quickgroupid]) {
lastCategoryIdRef.current = cat.quickgroupid;
getUnits({ variables: { catalogCode, vehicleId, ssd, categoryId: cat.quickgroupid } });
}
setSelectedCategory(cat);
}
};
const handleBack = () => {
setSelectedCategory(null);
};
const handleSubcategoryClick = (subcat: any) => {
if (onNodeSelect) {
onNodeSelect({
...subcat,
unitid: subcat.unitid || subcat.quickgroupid || subcat.id,
});
}
};
if (categoriesLoading) return <div>Загрузка категорий...</div>;
if (categoriesError) return <div style={{ color: "red" }}>Ошибка: {categoriesError.message}</div>;
return (
<div className="w-layout-vflex flex-block-14-copy-copy"> <div className="w-layout-vflex flex-block-14-copy-copy">
{categories.map((cat, idx) => ( {!selectedCategory ? (
<div className="div-block-131" key={idx} onClick={onCategoryClick} style={{ cursor: onCategoryClick ? 'pointer' : undefined }}> // Список категорий
<div className="text-block-57">{cat}</div> categories.map((cat: any, idx: number) => (
<div
className="div-block-131"
key={cat.quickgroupid || cat.id || idx}
onClick={() => handleCategoryClick(cat)}
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>
))
) : (
// Список подкатегорий (children или units)
<>
<div className="div-block-131" onClick={handleBack} style={{ cursor: "pointer", fontWeight: 500 }}>
<div className="text-block-57"> Назад</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>
{subcategories.length === 0 && <div style={{ color: "#888", padding: 8 }}>Нет подкатегорий</div>}
{subcategories.map((subcat: any, idx: number) => (
<div
className="div-block-131"
key={subcat.quickgroupid || subcat.unitid || subcat.id || idx}
onClick={() => handleSubcategoryClick(subcat)}
style={{ cursor: "pointer" }}
>
<div className="text-block-57">{subcat.name}</div>
<div className="w-embed"> <div className="w-embed">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="24" width="24" height="24" rx="12" transform="rotate(90 24 0)" fill="currentcolor"></rect> <rect x="24" width="24" height="24" rx="12" transform="rotate(90 24 0)" fill="currentcolor"></rect>
@ -34,7 +119,10 @@ const VinCategory: React.FC<VinCategoryProps> = ({ onCategoryClick }) => (
</div> </div>
</div> </div>
))} ))}
</>
)}
</div> </div>
); );
};
export default VinCategory; export default VinCategory;

View File

@ -1,35 +1,99 @@
import React, { useState } from "react"; import React, { useState, useEffect } from "react";
import { useLazyQuery, useQuery } from '@apollo/client';
import { SEARCH_LAXIMO_FULLTEXT, GET_LAXIMO_CATEGORIES, GET_LAXIMO_UNITS } from '@/lib/graphql/laximo';
import VinPartCard from './VinPartCard';
const dropdownTitles = [ interface VinLeftbarProps {
"Детали для ТО", catalogCode?: string;
"Двигатель", vehicleId?: string;
"Топливная система", ssd?: string;
"Система охлаждения", onSearchResults?: (results: any[]) => void;
"Система выпуска", onNodeSelect?: (node: any) => void;
"Трансмиссия", }
"Ходовая часть",
"Рулевое управление",
"Тормозная система",
"Электрооборудование",
"Отопление / кондиционирование",
"Детали салона",
"Детали кузова",
"Дополнительное оборудование"
];
const VinLeftbar = () => { const VinLeftbar: React.FC<VinLeftbarProps> = ({ catalogCode, vehicleId, ssd, onSearchResults, onNodeSelect }) => {
const [openIndex, setOpenIndex] = useState<number | null>(null); const [openIndex, setOpenIndex] = useState<number | null>(null);
const [searchQuery, setSearchQuery] = useState('');
const [activeTab, setActiveTab] = useState<'uzly' | 'manufacturer'>('uzly');
const [executeSearch, { data, loading, error }] = useLazyQuery(SEARCH_LAXIMO_FULLTEXT, { errorPolicy: 'all' });
const handleToggle = (idx: number) => { const { data: categoriesData, loading: categoriesLoading, error: categoriesError } = useQuery(GET_LAXIMO_CATEGORIES, {
variables: { catalogCode, vehicleId, ssd },
skip: !catalogCode || !vehicleId,
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 = (idx: number, categoryId: string) => {
setOpenIndex(openIndex === idx ? null : idx); setOpenIndex(openIndex === idx ? null : idx);
if (openIndex !== idx && !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;
}
console.log('SEARCH PARAMS', { catalogCode, vehicleId, searchQuery: searchQuery.trim(), ssd });
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 (searchResults && onSearchResults) {
onSearchResults(searchResults.details || []);
}
if (!searchQuery.trim() && onSearchResults) {
onSearchResults([]);
}
}, [searchResults, searchQuery, onSearchResults]);
// --- Новый блок: вычисляем доступность поиска ---
const isSearchAvailable = !!catalogCode && !!vehicleId && !!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;
return ( return (
<div className="w-layout-vflex vinleftbar"> <div className="w-layout-vflex vinleftbar">
<div className="div-block-2"> <div className="div-block-2">
<div className="form-block w-form"> <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"> <form id="vin-form-search" name="vin-form-search" data-name="vin-form-search" action="#" method="post" className="form">
<a href="#" className="link-block-3 w-inline-block"> <a href="#" className="link-block-3 w-inline-block" onClick={e => { e.preventDefault(); if (!ssd || ssd.trim() === '') { return; } handleSearch(); }}>
<div className="code-embed-6 w-embed"> <div className="code-embed-6 w-embed">
{/* SVG */} {/* SVG */}
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -38,48 +102,125 @@ const VinLeftbar = () => {
</svg> </svg>
</div> </div>
</a> </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={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
onKeyDown={handleKeyDown}
disabled={loading}
/>
</form> </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>
<div className="w-layout-vflex flex-block-113"> <div className="w-layout-vflex flex-block-113">
<div className="w-layout-hflex flex-block-114"> <div className="w-layout-hflex flex-block-114">
<a href="#" className="button-3 w-button">Узлы</a> <a
<a href="#" className="button-23 w-button">От производителя</a> href="#"
className={
searchQuery
? 'button-23 w-button'
: activeTab === 'uzly'
? 'button-3 w-button'
: 'button-23 w-button'
}
onClick={e => {
e.preventDefault();
if (searchQuery) setSearchQuery('');
setActiveTab('uzly');
}}
>
Узлы
</a>
<a
href="#"
className={
searchQuery
? 'button-23 w-button'
: activeTab === 'manufacturer'
? 'button-3 w-button'
: 'button-23 w-button'
}
onClick={e => {
e.preventDefault();
if (searchQuery) setSearchQuery('');
setActiveTab('manufacturer');
}}
>
От производителя
</a>
</div> </div>
{/* Dropdowns start */} {/* Tab content start */}
{dropdownTitles.map((title, idx) => { {activeTab === 'uzly' ? (
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 = openIndex === idx; const isOpen = openIndex === idx;
// Подкатегории: сначала children, если нет — unitsByCategory
const subcategories = category.children && category.children.length > 0
? category.children
: unitsByCategory[category.quickgroupid] || [];
return ( return (
<div <div
key={idx} key={category.quickgroupid}
data-hover="false" data-hover="false"
data-delay="0" data-delay="0"
className={`dropdown-4 w-dropdown${isOpen ? " w--open" : ""}`} className={`dropdown-4 w-dropdown${isOpen ? " w--open" : ""}`}
> >
<div <div
className={`dropdown-toggle-3 w-dropdown-toggle${isOpen ? " w--open" : ""}`} className={`dropdown-toggle-3 w-dropdown-toggle${isOpen ? " w--open" : ""}`}
onClick={() => handleToggle(idx)} onClick={() => handleToggle(idx, category.quickgroupid)}
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
> >
<div className="w-icon-dropdown-toggle"></div> <div className="w-icon-dropdown-toggle"></div>
<div className="text-block-56">{title}</div> <div className="text-block-56">{category.name}</div>
</div> </div>
<nav className={`dropdown-list-4 w-dropdown-list${isOpen ? " w--open" : ""}`}> <nav className={`dropdown-list-4 w-dropdown-list${isOpen ? " w--open" : ""}`}>
<a href="#" className="dropdown-link-3 w-dropdown-link">Link 1</a> {subcategories.length > 0 ? (
<a href="#" className="dropdown-link-3 w-dropdown-link">Link 2</a> subcategories.map((subcat: any) => (
<a href="#" className="dropdown-link-3 w-dropdown-link">Link 3</a> <a
href="#"
key={subcat.quickgroupid || subcat.unitid}
className="dropdown-link-3 w-dropdown-link"
onClick={e => {
e.preventDefault();
if (onNodeSelect) {
onNodeSelect({
...subcat,
unitid: subcat.unitid || subcat.quickgroupid || subcat.id
});
}
}}
>
{subcat.name}
</a>
))
) : (
<span style={{ color: '#888', padding: 8 }}>Нет подкатегорий</span>
)}
</nav> </nav>
</div> </div>
); );
})} })}
{/* Dropdowns end */} </>
)
) : (
// Manufacturer tab content (заглушка)
<div style={{ padding: '16px', color: '#888' }}>Здесь будет контент "От производителя"</div>
)}
{/* Tab content end */}
</div> </div>
</div> </div>
); );

View File

@ -0,0 +1,38 @@
import React from "react";
import { useRouter } from 'next/router';
interface VinPartCardProps {
n?: number;
oem: string;
name: string;
onPriceClick?: () => void;
}
const VinPartCard: React.FC<VinPartCardProps> = ({ n, oem, name, onPriceClick }) => {
const router = useRouter();
const handlePriceClick = (e: React.MouseEvent) => {
e.preventDefault();
if (onPriceClick) onPriceClick();
if (oem) router.push(`/search?q=${encodeURIComponent(oem)}&mode=parts`);
};
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

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useQuery } from '@apollo/client'; import { useQuery } from '@apollo/client';
import Head from 'next/head'; import Head from 'next/head';
@ -6,8 +6,16 @@ import Footer from '@/components/Footer';
import Layout from '@/components/Layout'; import Layout from '@/components/Layout';
import VehiclePartsSearchSection from '@/components/VehiclePartsSearchSection'; import VehiclePartsSearchSection from '@/components/VehiclePartsSearchSection';
import LaximoDiagnostic from '@/components/LaximoDiagnostic'; 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 { 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';
interface LaximoVehicleInfo { interface LaximoVehicleInfo {
vehicleid: string; vehicleid: string;
@ -41,7 +49,27 @@ const VehicleDetailsPage = () => {
defaultSearchType = 'fulltext'; defaultSearchType = 'fulltext';
} }
// ====== ВСЕ ХУКИ В НАЧАЛЕ КОМПОНЕНТА ======
const [searchType, setSearchType] = useState<'quickgroups' | 'categories' | 'fulltext'>(defaultSearchType); const [searchType, setSearchType] = useState<'quickgroups' | 'categories' | 'fulltext'>(defaultSearchType);
const [showKnot, setShowKnot] = useState(false);
const [foundParts, setFoundParts] = useState<any[]>([]);
const [selectedNode, setSelectedNode] = 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 }>( const { data: catalogData } = useQuery<{ laximoCatalogInfo: LaximoCatalogInfo }>(
@ -100,6 +128,28 @@ const VehicleDetailsPage = () => {
} }
); );
// Получаем детали выбранного узла, если он выбран
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) { if (vehicleError) {
console.error('Vehicle GraphQL error:', vehicleError); console.error('Vehicle GraphQL error:', vehicleError);
@ -107,24 +157,24 @@ const VehicleDetailsPage = () => {
if (vehicleLoading) { if (vehicleLoading) {
return ( return (
<Layout> <>
<Head> <Head>
<title>Загрузка автомобиля...</title> <title>Загрузка автомобиля...</title>
</Head> </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="text-center">
<div className="animate-spin rounded-full h-32 w-32 border-b-2 border-red-600 mx-auto"></div> <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> <p className="mt-4 text-lg text-gray-600">Загружаем информацию об автомобиле...</p>
</div> </div>
</main> </div>
</Layout> </>
); );
} }
// Если информация о каталоге недоступна, показываем ошибку // Если информация о каталоге недоступна, показываем ошибку
if (!catalogData?.laximoCatalogInfo) { if (!catalogData?.laximoCatalogInfo) {
return ( return (
<Layout> <>
<Head> <Head>
<title>Каталог не найден</title> <title>Каталог не найден</title>
</Head> </Head>
@ -140,32 +190,136 @@ const VehicleDetailsPage = () => {
</button> </button>
</div> </div>
</main> </main>
</Layout> </>
); );
} }
// Если информация об автомобиле недоступна, создаем заглушку // Если vehicleId невалидный (например, '0'), показываем предупреждение и не рендерим поиск
const vehicleInfo = vehicleData?.laximoVehicleInfo || { if (!vehicleId || vehicleId === '0') {
vehicleid: vehicleId as string, 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 || '');
const fallbackVehicleId = (vehicleIdStr !== '0' ? vehicleIdStr : '');
let vehicleInfo = vehicleData?.laximoVehicleInfo || {
vehicleid: fallbackVehicleId,
name: `Автомобиль ${catalogData.laximoCatalogInfo.name}`, name: `Автомобиль ${catalogData.laximoCatalogInfo.name}`,
ssd: finalSsd, ssd: finalSsd,
brand: catalogData.laximoCatalogInfo.brand, brand: catalogData.laximoCatalogInfo.brand,
catalog: catalogData.laximoCatalogInfo.code, catalog: catalogData.laximoCatalogInfo.code,
attributes: [] attributes: [] as never[]
}; };
// Если вдруг с сервера пришёл vehicleid: '0', подменяем на корректный
if (vehicleInfo.vehicleid === '0' && fallbackVehicleId) {
vehicleInfo = { ...vehicleInfo, vehicleid: fallbackVehicleId };
}
// Логируем, что реально передаём в VinLeftbar
console.log('Передаём в VinLeftbar:', {
catalog: vehicleInfo.catalog,
vehicleid: vehicleInfo.vehicleid,
ssd: vehicleInfo.ssd
});
// Если нет данных автомобиля и есть ошибка, показываем предупреждение // Если нет данных автомобиля и есть ошибка, показываем предупреждение
const hasError = vehicleError && !vehicleData?.laximoVehicleInfo; const hasError = vehicleError && !vehicleData?.laximoVehicleInfo;
const catalogInfo = catalogData.laximoCatalogInfo; const catalogInfo = catalogData.laximoCatalogInfo;
return ( return (
<Layout> <>
<Head> <Head>
<title>{vehicleInfo.name} - Поиск запчастей</title> <title>VIN</title>
<meta name="description" content={`Поиск запчастей для ${vehicleInfo.name} в каталоге ${catalogInfo.name}`} /> <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> </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(' · ')
: ''
}
/>
<div className="w-layout-blockcontainer container-vin w-container">
{!selectedNode ? (
<div className="w-layout-hflex flex-block-13">
<VinLeftbar
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
ssd={vehicleInfo.ssd}
onSearchResults={setFoundParts}
onNodeSelect={setSelectedNode}
/>
{/* Категории или Knot или карточки */}
{foundParts.length > 0 ? (
<div className="knot-parts">
{foundParts.map((detail, idx) => (
<VinPartCard
key={detail.oem + idx}
n={idx + 1}
name={detail.name}
oem={detail.oem}
/>
))}
</div>
) : showKnot ? (
<VinKnot />
) : (
<VinCategory
catalogCode={vehicleInfo.catalog}
vehicleId={vehicleInfo.vehicleid}
ssd={vehicleInfo.ssd}
onNodeSelect={setSelectedNode}
/>
)}
</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>
<KnotIn node={selectedNode} />
{unitDetailsLoading ? (
<div style={{ padding: 24, textAlign: 'center' }}>Загружаем детали узла...</div>
) : unitDetailsError ? (
<div style={{ color: 'red', padding: 24 }}>Ошибка загрузки деталей: {unitDetailsError.message}</div>
) : unitDetails.length > 0 ? (
<KnotParts parts={unitDetails} />
) : (
<div style={{ padding: 24, textAlign: 'center' }}>Детали не найдены</div>
)}
</div>
</div>
)}
</div>
{/* ====== ВРЕМЕННЫЙ МАКЕТ ДЛЯ ВЕРСТКИ (конец) ====== */}
{/* Навигация */} {/* Навигация */}
<nav className="bg-white border-b"> <nav className="bg-white border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
@ -303,8 +457,7 @@ const VehicleDetailsPage = () => {
onSearchTypeChange={setSearchType} onSearchTypeChange={setSearchType}
/> />
</div> </div>
</main> </>
</Layout>
); );
}; };

View File

@ -38,10 +38,6 @@ export default function Vin() {
<meta content="vin" property="og:title" /> <meta content="vin" property="og:title" />
<meta content="vin" property="twitter:title" /> <meta content="vin" property="twitter:title" />
<meta content="width=device-width, initial-scale=1" name="viewport" /> <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.googleapis.com" rel="preconnect" />
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" /> <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/favicon.png" rel="shortcut icon" type="image/x-icon" />

View File

@ -387,13 +387,12 @@ input.input-receiver:focus {
} }
.knotin { .knotin {
height: 100%; max-width: 100%;
display: flex; display: flex;
align-items: stretch; align-items: stretch;
} }
.knotin img { .knotin img {
height: 100%; max-width: 100%;
width: auto;
object-fit: contain; /* или cover */ object-fit: contain; /* или cover */
} }
@ -404,3 +403,29 @@ input.input-receiver:focus {
.tabs-menu.w-tab-menu::-webkit-scrollbar { .tabs-menu.w-tab-menu::-webkit-scrollbar {
display: none; 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;
}

View File

@ -7458,31 +7458,43 @@ body {
} }
.flex-block-78 { .flex-block-78 {
flex-flow: row;
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: center;
display: none;
}
.flex-block-80 {
display: none;
} }
.flex-block-81 { .flex-block-81 {
grid-column-gap: 5px;
grid-row-gap: 5px;
flex-flow: row;
justify-content: space-between; justify-content: space-between;
align-self: stretch;
align-items: center; align-items: center;
} }
.flex-block-82 { .core-product-copy {
grid-column-gap: 30px; flex-flow: column;
grid-row-gap: 30px;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: flex-start;
} }
.sort-item-brand-copy { .core-product-search-copy {
width: 50px; flex-flow: row;
align-self: stretch;
max-width: 100%;
height: 340px;
display: flex;
overflow: scroll;
}
.raiting-copy, .pcs-copy {
display: none;
}
.item-recommend-copy {
display: block;
}
.flex-block-83 {
flex-flow: column;
} }
.flex-block-84 { .flex-block-84 {
@ -7496,40 +7508,55 @@ body {
.flex-block-85 { .flex-block-85 {
grid-column-gap: 5px; grid-column-gap: 5px;
grid-row-gap: 5px; grid-row-gap: 5px;
border-radius: var(--_round---normal); border-radius: var(--_round---small-8);
background-color: var(--white); background-color: var(--white);
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
padding: 10px 20px; padding: 8px 12px;
display: flex; display: flex;
} }
.code-embed-9 { .code-embed-9 {
color: var(--_button---primary); color: var(--_button---primary);
width: 18px; width: 16px;
height: 18px; height: 16px;
} }
.flex-block-77-copy { .image-15 {
max-width: 200px;
}
.code-embed-10 {
color: var(--white);
width: 12px;
height: 16px;
}
.flex-block-86 {
grid-column-gap: 5px;
grid-row-gap: 5px;
border-radius: var(--_round---small-8);
background-color: var(--_button---hover-dark_blue);
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
padding: 10px 15px;
} }
.flex-block-18-copy-copy { .flex-block-18-copy-copy {
grid-column-gap: 40px; grid-column-gap: 10px;
grid-row-gap: 40px; grid-row-gap: 10px;
flex-flow: column; }
.link-block-4-copy {
flex: 0 auto;
} }
.heading-8-copy { .heading-8-copy {
color: var(--_fonts---color--light-blue-grey);
font-size: var(--_fonts---font-size--small-font-size); font-size: var(--_fonts---font-size--small-font-size);
align-self: stretch; margin-left: 0;
padding-left: 0; margin-right: 0;
padding-right: 0;
font-weight: 400; font-weight: 400;
line-height: 20px;
display: block;
overflow: hidden;
} }
.dropdown-2 { .dropdown-2 {
@ -7537,95 +7564,98 @@ body {
margin-right: 0; margin-right: 0;
} }
.dropdown-list-2 {
background-color: var(--white);
box-shadow: 0 2px 5px #0003;
}
.dropdown-list-2.w--open {
border-radius: var(--_round---small-8);
}
.heading-9-copy { .heading-9-copy {
font-size: var(--_fonts---font-size--bigger); margin-top: 0;
} }
.info-block-search-copy { .info-block-search-copy {
grid-column-gap: 10px;
grid-row-gap: 10px;
flex-flow: column;
justify-content: space-between; justify-content: space-between;
align-self: stretch; align-self: stretch;
align-items: center; align-items: flex-start;
}
.heading-9-copy-copy {
font-size: var(--_fonts---font-size--small-font-size);
line-height: 18px;
}
.section-2 {
padding-left: 15px;
padding-right: 15px;
} }
.mobile-block { .mobile-block {
display: flex; flex: 0 auto;
width: auto;
} }
.flex-block-87 { .flex-block-87 {
grid-column-gap: 10px; grid-column-gap: 0px;
grid-row-gap: 10px; grid-row-gap: 0px;
flex: 1;
} }
.mobile-menu-bottom { .mobile-menu-bottom {
padding-top: 0; margin-left: 0;
padding-bottom: 0; margin-right: 0;
box-shadow: 0 0 5px #0003; padding-left: 15px;
padding-right: 15px;
} }
.mobile-menu-bottom.info { .mobile-menu-bottom.nav, .mobile-menu-bottom.info {
padding-top: 20px; padding-left: 15px;
padding-bottom: 20px; padding-right: 15px;
} }
.mobile-menu-buttom-section { .mobile-menu-bottom.subscribe, .mobile-menu-bottom.footer {
display: block; padding: 40px 15px;
} }
.name-mobile-menu-item { .name-mobile-menu-item {
color: var(--black);
font-size: var(--_fonts---font-size--small-font-size);
font-weight: 400;
}
.button-for-mobile-menu-block {
grid-column-gap: 2px;
grid-row-gap: 2px;
background-color: var(--_fonts---color--white);
color: var(--_button---light-blue-grey);
flex-flow: column;
width: 70px;
}
.button-for-mobile-menu-block:hover {
background-color: var(--_button---light-blue);
}
.icon_favorite {
color: var(--_button---light-blue-grey);
}
.block-for-moble-menu-icon {
width: 30px;
height: 30px;
}
.div-block-25 {
width: 20px;
height: 20px;
display: block; display: block;
} }
.info-satus { .button-for-mobile-menu-block {
background-color: var(--green); grid-column-gap: 0px;
color: var(--_fonts---color--white); grid-row-gap: 0px;
font-size: 10px; width: 60px;
font-weight: 400; padding-bottom: 5px;
} }
.flex-block-93 { .section-3 {
align-self: auto; padding-left: 15px;
min-height: 48px; padding-right: 15px;
} }
.sort-list-card { .nav-menu-3 {
padding-right: 30px;
display: none; display: none;
} }
.flex-block-93 {
margin-left: 0;
}
.sort-list-card {
grid-column-gap: 0px;
grid-row-gap: 0px;
padding-left: 18px;
padding-right: 18px;
}
.flex-block-49-copy { .flex-block-49-copy {
grid-column-gap: 30px; grid-column-gap: 28px;
grid-row-gap: 30px; grid-row-gap: 28px;
} }
.price-in-cart-s1 { .price-in-cart-s1 {