first commit
This commit is contained in:
334
src/components/GroupDetailsSection.tsx
Normal file
334
src/components/GroupDetailsSection.tsx
Normal file
@ -0,0 +1,334 @@
|
||||
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(`Функция "Добавить в корзину" будет реализована в ближайшее время.\nДеталь: ${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: {
|
||||
catalogCode,
|
||||
vehicleId,
|
||||
quickGroupId,
|
||||
ssd
|
||||
},
|
||||
skip: !catalogCode || !vehicleId || !quickGroupId || !ssd,
|
||||
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;
|
Reference in New Issue
Block a user