pravki 29.06

This commit is contained in:
egortriston
2025-06-29 00:39:17 +03:00
parent 1b0bbb2992
commit f6cc95e714
10 changed files with 693 additions and 237 deletions

View File

@ -1,35 +1,86 @@
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';
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 [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);
if (openIndex !== idx && !unitsByCategory[categoryId]) {
lastCategoryIdRef.current = categoryId;
getUnits({ variables: { catalogCode, vehicleId, ssd, categoryId } });
}
};
const handleSearch = () => {
if (!searchQuery.trim() || !catalogCode || !vehicleId || !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 (searchResults && onSearchResults) {
onSearchResults(searchResults.details || []);
}
if (!searchQuery.trim() && onSearchResults) {
onSearchResults([]);
}
}, [searchResults, searchQuery, onSearchResults]);
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">
<a href="#" className="link-block-3 w-inline-block" onClick={e => { e.preventDefault(); handleSearch(); }}>
<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 +89,124 @@ 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={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
onKeyDown={handleKeyDown}
disabled={!catalogCode || !vehicleId || !ssd}
/>
</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>
{error && <div style={{ color: 'red', fontSize: 12 }}>Ошибка поиска: {error.message}</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'
: 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>
{/* 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 */}
{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;
// Подкатегории: сначала children, если нет — unitsByCategory
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={() => handleToggle(idx, category.quickgroupid)}
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"
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>
</div>
);
})}
</>
)
) : (
// Manufacturer tab content (заглушка)
<div style={{ padding: '16px', color: '#888' }}>Здесь будет контент "От производителя"</div>
)}
{/* Tab content end */}
</div>
</div>
);