pravki 29.06
This commit is contained in:
@ -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>
|
||||
);
|
||||
|
Reference in New Issue
Block a user