Files
protekauto-frontend/src/components/GroupDetailsSection.tsx

334 lines
13 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 { useRouter } from 'next/router';
import { useQuery } from '@apollo/client';
import { GET_LAXIMO_QUICK_DETAIL } from '@/lib/graphql';
import { LaximoQuickDetail, LaximoUnit, LaximoDetail } from '@/types/laximo';
import BrandSelectionModal from './BrandSelectionModal';
interface GroupDetailsSectionProps {
catalogCode: string;
vehicleId: string;
quickGroupId: string;
groupName: string;
ssd: string;
onBack: () => void;
}
interface DetailCardProps {
detail: LaximoDetail;
}
const DetailCard: React.FC<DetailCardProps> = ({ detail }) => {
const [isBrandModalOpen, setIsBrandModalOpen] = useState(false);
const handleDetailClick = () => {
const articleNumber = detail.oem;
console.log('🔍 Клик по детали для выбора бренда:', { articleNumber, name: detail.name });
setIsBrandModalOpen(true);
};
const handleCloseBrandModal = () => {
setIsBrandModalOpen(false);
};
const handleAddToCart = () => {
// TODO: Реализовать добавление в корзину
console.log('Добавить в корзину:', detail.oem);
alert(`Функция "Добавить в корзину" будет реализована в ближайшее время.\еталь: ${detail.name}\nOEM: ${detail.oem}`);
};
return (
<div className="bg-white border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<h4 className="text-lg font-semibold text-gray-900 mb-1">{detail.name}</h4>
<div className="flex items-center space-x-2 text-sm text-gray-600">
<span className="font-medium">OEM:</span>
<span className="bg-blue-100 text-blue-800 px-2 py-1 rounded text-xs font-mono">
{detail.oem}
</span>
</div>
</div>
{detail.brand && (
<div className="flex-shrink-0 ml-4">
<span className="bg-green-100 text-green-800 px-2 py-1 rounded text-xs font-medium">
{detail.brand}
</span>
</div>
)}
</div>
{detail.description && (
<p className="text-gray-700 text-sm mb-3">{detail.description}</p>
)}
{detail.applicablemodels && (
<div className="mb-3">
<span className="text-xs font-medium text-gray-500 uppercase tracking-wide">
Применимые модели:
</span>
<p className="text-sm text-gray-700 mt-1">{detail.applicablemodels}</p>
</div>
)}
{detail.note && (
<div className="mb-3">
<span className="text-xs font-medium text-gray-500 uppercase tracking-wide">
Примечание:
</span>
<p className="text-sm text-gray-700 mt-1">{detail.note}</p>
</div>
)}
{detail.attributes && detail.attributes.length > 0 && (
<div className="mt-3 pt-3 border-t border-gray-100">
<div className="flex flex-wrap gap-2">
{detail.attributes.map((attr, index) => (
<div key={index} className="text-xs">
<span className="text-gray-500">{attr.name || attr.key}:</span>
<span className="ml-1 text-gray-700">{attr.value}</span>
</div>
))}
</div>
</div>
)}
<div className="mt-4 flex items-center justify-between">
<button
className="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors"
onClick={handleDetailClick}
>
Найти предложения
</button>
<button
className="text-gray-500 hover:text-gray-700 text-sm transition-colors"
onClick={handleAddToCart}
>
Добавить в корзину
</button>
</div>
<BrandSelectionModal
isOpen={isBrandModalOpen}
onClose={handleCloseBrandModal}
articleNumber={detail.oem}
detailName={detail.name}
/>
</div>
);
};
interface UnitSectionProps {
unit: LaximoUnit;
}
const UnitSection: React.FC<UnitSectionProps> = ({ unit }) => {
return (
<div className="mb-8">
<div className="bg-gray-50 border border-gray-200 rounded-lg p-4 mb-4">
<div className="flex items-center justify-between">
<div>
<h3 className="text-lg font-semibold text-gray-900">{unit.name}</h3>
{unit.code && (
<p className="text-sm text-gray-600 mt-1">Код: {unit.code}</p>
)}
{unit.description && (
<p className="text-sm text-gray-700 mt-2">{unit.description}</p>
)}
</div>
{unit.details && unit.details.length > 0 && (
<div className="text-sm text-gray-500">
{unit.details.length} {unit.details.length === 1 ? 'деталь' : 'деталей'}
</div>
)}
</div>
</div>
{unit.details && unit.details.length > 0 ? (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{unit.details.map((detail) => (
<DetailCard key={detail.detailid} detail={detail} />
))}
</div>
) : (
<div className="text-center py-8 text-gray-500">
<svg className="w-12 h-12 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2 2v-5m16 0H4m0 0l4-4m0 8l4-4" />
</svg>
<p>В этом узле пока нет доступных деталей</p>
</div>
)}
</div>
);
};
const GroupDetailsSection: React.FC<GroupDetailsSectionProps> = ({
catalogCode,
vehicleId,
quickGroupId,
groupName,
ssd,
onBack
}) => {
console.log('🔍 GroupDetailsSection получил параметры:', {
catalogCode,
vehicleId,
quickGroupId,
quickGroupIdType: typeof quickGroupId,
quickGroupIdLength: quickGroupId?.length,
groupName,
ssd: ssd ? `${ssd.substring(0, 30)}...` : 'отсутствует'
});
const { data, loading, error } = useQuery<{ laximoQuickDetail: LaximoQuickDetail }>(
GET_LAXIMO_QUICK_DETAIL,
{
variables: quickGroupId ? {
catalogCode,
vehicleId,
quickGroupId,
ssd
} : undefined,
skip: !catalogCode || vehicleId === undefined || vehicleId === null || !quickGroupId || !ssd || ssd.trim() === '',
errorPolicy: 'all'
}
);
if (loading) {
return (
<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-lg text-gray-600">Загружаем детали группы...</p>
<p className="text-sm text-gray-500 mt-1">{groupName}</p>
</div>
);
}
if (error) {
console.error('Ошибка загрузки деталей группы:', error);
// Определяем тип ошибки для показа соответствующего сообщения
const isInvalidParameterError = error.message.includes('E_INVALIDPARAMETER') ||
error.message.includes('INVALIDPARAMETER') ||
error.message.includes('QuickGroupId');
return (
<div className="text-center py-12">
<div className="text-red-600 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 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
{isInvalidParameterError ? (
<>
<h3 className="text-lg font-medium text-red-600 mb-2">Неподдерживаемая группа</h3>
<p className="text-gray-600 mb-4">
Группа "{groupName}" (ID: {quickGroupId}) не поддерживается API Laximo для данного автомобиля.
</p>
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6 text-left max-w-md mx-auto">
<h4 className="font-medium text-yellow-800 mb-2">💡 Рекомендации:</h4>
<ul className="text-sm text-yellow-700 space-y-1">
<li> Попробуйте использовать "Категории каталога"</li>
<li> Воспользуйтесь поиском по артикулу</li>
<li> Попробуйте поиск по названию детали</li>
<li> Используйте "Группы быстрого поиска"</li>
</ul>
</div>
</>
) : (
<>
<h3 className="text-lg font-medium text-red-600 mb-2">Ошибка загрузки деталей</h3>
<p className="text-gray-600 mb-4">Не удалось загрузить детали для группы "{groupName}"</p>
<p className="text-sm text-gray-500 mb-4">Ошибка: {error.message}</p>
</>
)}
<button
onClick={onBack}
className="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 transition-colors"
>
Вернуться к группам
</button>
</div>
);
}
if (!data?.laximoQuickDetail) {
return (
<div className="text-center py-12">
<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="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2 2v-5m16 0H4m0 0l4-4m0 8l4-4" />
</svg>
</div>
<h3 className="text-lg font-medium text-gray-600 mb-2">Детали не найдены</h3>
<p className="text-gray-500 mb-4">Для группы "{groupName}" не найдено доступных деталей</p>
<button
onClick={onBack}
className="bg-gray-600 text-white px-4 py-2 rounded-lg hover:bg-gray-700 transition-colors"
>
Вернуться к группам
</button>
</div>
);
}
const quickDetail = data.laximoQuickDetail;
const totalDetails = quickDetail.units?.reduce((total, unit) => total + (unit.details?.length || 0), 0) || 0;
return (
<div className="space-y-6">
{/* Шапка */}
<div className="bg-white border border-gray-200 rounded-lg p-6">
<div className="flex items-center justify-between">
<div>
<button
onClick={onBack}
className="flex items-center text-blue-600 hover:text-blue-800 mb-2 transition-colors"
>
<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="M15 19l-7-7 7-7" />
</svg>
Вернуться к группам
</button>
<h2 className="text-2xl font-bold text-gray-900">{quickDetail.name || groupName}</h2>
<p className="text-gray-600 mt-1">ID группы: {quickDetail.quickgroupid}</p>
</div>
<div className="text-right">
<p className="text-sm text-gray-500">Найдено</p>
<p className="text-2xl font-bold text-blue-600">{totalDetails}</p>
<p className="text-sm text-gray-500">{totalDetails === 1 ? 'деталь' : 'деталей'}</p>
</div>
</div>
</div>
{/* Список узлов и деталей */}
{quickDetail.units && quickDetail.units.length > 0 ? (
<div>
{quickDetail.units.map((unit) => (
<UnitSection key={unit.unitid} unit={unit} />
))}
</div>
) : (
<div className="bg-white border border-gray-200 rounded-lg p-12 text-center">
<div className="text-gray-400 mb-4">
<svg className="w-16 h-16 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2 2v-5m16 0H4m0 0l4-4m0 8l4-4" />
</svg>
</div>
<h3 className="text-xl font-medium text-gray-600 mb-2">Узлы не найдены</h3>
<p className="text-gray-500">В этой группе пока нет доступных узлов и деталей</p>
</div>
)}
</div>
);
};
export default GroupDetailsSection;