Files
protekauto-frontend/src/components/VehicleSearchSection.tsx
2025-06-26 06:59:59 +03:00

300 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from 'react';
import { useLazyQuery } from '@apollo/client';
import { FIND_LAXIMO_VEHICLE, FIND_LAXIMO_VEHICLE_BY_PLATE_GLOBAL } from '@/lib/graphql';
import { LaximoCatalogInfo, LaximoWizardStep, LaximoVehicleSearchResult } from '@/types/laximo';
import VinSearchForm from './VinSearchForm';
import PlateSearchForm from './PlateSearchForm';
import PartSearchForm from './PartSearchForm';
import WizardSearchForm from './WizardSearchForm';
import VehicleSearchResults from './VehicleSearchResults';
interface VehicleSearchSectionProps {
catalogInfo: LaximoCatalogInfo;
searchType: 'vin' | 'wizard' | 'parts' | 'plate';
onSearchTypeChange: (type: 'vin' | 'wizard' | 'parts' | 'plate') => void;
}
const VehicleSearchSection: React.FC<VehicleSearchSectionProps> = ({
catalogInfo,
searchType,
onSearchTypeChange
}) => {
const [searchResults, setSearchResults] = useState<LaximoVehicleSearchResult[]>([]);
const [isSearching, setIsSearching] = useState(false);
const [hasSearched, setHasSearched] = useState(false);
// Query для поиска по VIN
const [findVehicle] = useLazyQuery(FIND_LAXIMO_VEHICLE, {
onCompleted: (data) => {
setSearchResults(data.laximoFindVehicle || []);
setIsSearching(false);
setHasSearched(true);
},
onError: (error) => {
console.error('Ошибка поиска автомобиля:', error);
setSearchResults([]);
setIsSearching(false);
setHasSearched(true);
}
});
// Query для поиска по госномеру
const [findVehicleByPlate] = useLazyQuery(FIND_LAXIMO_VEHICLE_BY_PLATE_GLOBAL, {
onCompleted: (data) => {
setSearchResults(data.laximoFindVehicleByPlateGlobal || []);
setIsSearching(false);
setHasSearched(true);
},
onError: (error) => {
console.error('Ошибка поиска автомобиля по госномеру:', error);
setSearchResults([]);
setIsSearching(false);
setHasSearched(true);
}
});
const handleVinSearch = async (vin: string) => {
if (!vin.trim()) return;
setIsSearching(true);
setSearchResults([]);
setHasSearched(false);
await findVehicle({
variables: {
catalogCode: '', // Пустой для глобального поиска
vin: vin.trim()
}
});
};
const handlePlateSearch = async (plateNumber: string) => {
if (!plateNumber.trim()) return;
setIsSearching(true);
setSearchResults([]);
setHasSearched(false);
await findVehicleByPlate({
variables: {
plateNumber: plateNumber.trim()
}
});
};
const handleWizardVehicleFound = (vehicles: LaximoVehicleSearchResult[]) => {
setSearchResults(vehicles);
setIsSearching(false);
setHasSearched(true);
};
const handlePartsSearchStart = () => {
setIsSearching(true);
setSearchResults([]);
setHasSearched(false);
};
const handlePartsVehicleFound = (vehicles: LaximoVehicleSearchResult[]) => {
console.log('🔍 Найдено автомобилей по артикулу:', vehicles.length);
setSearchResults(vehicles);
setIsSearching(false);
setHasSearched(true);
};
const searchTabs = [
{
id: 'vin' as const,
name: 'Поиск по VIN/Frame',
description: 'Введите VIN или номер кузова автомобиля',
enabled: catalogInfo.supportvinsearch,
icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 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>
)
},
{
id: 'wizard' as const,
name: 'Поиск автомобиля по параметрам',
description: 'Выберите серию и тип кузова',
enabled: catalogInfo.supportparameteridentification2,
icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4" />
</svg>
)
},
{
id: 'parts' as const,
name: 'Поиск автомобилей по детали',
description: 'Введите артикул (OEM)',
enabled: catalogInfo.supportdetailapplicability,
icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
)
},
{
id: 'plate' as const,
name: 'Поиск по государственному номеру',
description: 'Введите государственный номер автомобиля',
enabled: catalogInfo.supportplateidentification ?? true,
icon: (
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 100 4m0-4v2m0-6V4" />
</svg>
)
}
];
const availableTabs = searchTabs.filter(tab => tab.enabled);
return (
<div className="space-y-6">
{/* Tabs */}
<div className="bg-white rounded-lg shadow-sm border">
<div className="border-b">
<nav className="flex space-x-8 px-6" aria-label="Tabs">
{availableTabs.map((tab) => (
<button
key={tab.id}
onClick={() => {
onSearchTypeChange(tab.id);
setSearchResults([]);
setHasSearched(false);
setIsSearching(false);
}}
className={`
group inline-flex items-center py-4 px-1 border-b-2 font-medium text-sm
${searchType === tab.id
? 'border-red-500 text-red-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}
`}
>
{tab.icon}
<span className="ml-2">{tab.name}</span>
</button>
))}
</nav>
</div>
{/* Tab Content */}
<div className="p-6">
{searchType === 'vin' && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
Поиск по VIN/Frame
</h3>
<p className="text-sm text-gray-600 mb-4">
{catalogInfo.vinexample
? `Введите VIN или номер кузова автомобиля, например: ${catalogInfo.vinexample}`
: 'Введите VIN или номер кузова автомобиля'
}
</p>
<VinSearchForm
onSearch={handleVinSearch}
isLoading={isSearching}
placeholder={catalogInfo.vinexample || 'WBS21CS0709X59107'}
/>
</div>
)}
{searchType === 'wizard' && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
Поиск автомобиля по параметрам
</h3>
<p className="text-sm text-gray-600 mb-4">
Выберите серию и тип кузова для поиска автомобиля
</p>
<WizardSearchForm
catalogCode={catalogInfo.code}
onVehicleFound={handleWizardVehicleFound}
/>
</div>
)}
{searchType === 'parts' && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
Поиск автомобилей по детали
</h3>
<p className="text-sm text-gray-600 mb-4">
Введите артикул (OEM) для поиска применимых автомобилей
</p>
<PartSearchForm
catalogCode={catalogInfo.code}
onVehiclesFound={handlePartsVehicleFound}
onSearchStart={handlePartsSearchStart}
isLoading={isSearching}
/>
</div>
)}
{searchType === 'plate' && (
<div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
Поиск по государственному номеру
</h3>
<p className="text-sm text-gray-600 mb-4">
Введите государственный номер автомобиля
</p>
<PlateSearchForm
onSearch={handlePlateSearch}
isLoading={isSearching}
placeholder={catalogInfo.plateexample || 'А123АА777'}
/>
</div>
)}
</div>
</div>
{/* Search Results */}
{searchResults.length > 0 && (
<VehicleSearchResults
results={searchResults}
catalogInfo={catalogInfo}
/>
)}
{/* No Results */}
{!isSearching && searchResults.length === 0 && !hasSearched && (
<div className="bg-white rounded-lg shadow-sm border p-8 text-center">
<div className="text-gray-400 mb-4">
<svg className="w-12 h-12 mx-auto" 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>
</div>
<p className="text-gray-600">
Выполните поиск, чтобы найти подходящий автомобиль для подбора запчастей
</p>
</div>
)}
{/* Search completed but no results */}
{!isSearching && searchResults.length === 0 && hasSearched && (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-8 text-center">
<div className="text-yellow-400 mb-4">
<svg className="w-12 h-12 mx-auto" 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.728-.833-2.498 0L4.316 14.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">Автомобили не найдены</h3>
<p className="text-gray-600 mb-4">
{searchType === 'vin' && 'По указанному VIN/Frame номеру не найдено автомобилей в данном каталоге.'}
{searchType === 'parts' && 'По указанному артикулу не найдено применимых автомобилей в данном каталоге.'}
{searchType === 'plate' && 'По указанному государственному номеру не найдено автомобилей в данном каталоге.'}
{searchType === 'wizard' && 'По заданным параметрам не найдено автомобилей в данном каталоге.'}
</p>
<p className="text-sm text-gray-500">
Попробуйте изменить параметры поиска или выберите другой каталог.
</p>
</div>
)}
</div>
);
};
export default VehicleSearchSection;