first commit

This commit is contained in:
Bivekich
2025-06-26 06:59:59 +03:00
commit d44874775c
450 changed files with 76635 additions and 0 deletions

View 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(`Функция "Добавить в корзину" будет реализована в ближайшее время.\еталь: ${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;