diff --git a/src/components/CartInfo.tsx b/src/components/CartInfo.tsx index 93a8e63..dfa10bd 100644 --- a/src/components/CartInfo.tsx +++ b/src/components/CartInfo.tsx @@ -32,7 +32,7 @@ const CartInfo: React.FC = () => {

Корзина

{summary.totalItems > 0 ? ( - <>В вашей корзине {summary.totalItems} товара на {formatPrice(summary.finalPrice)} + <>В вашей корзине {summary.totalItems} товара на {formatPrice(summary.totalPrice - summary.totalDiscount)} ) : ( 'Ваша корзина пуста' )} diff --git a/src/components/CartList.tsx b/src/components/CartList.tsx index e837081..a6a083f 100644 --- a/src/components/CartList.tsx +++ b/src/components/CartList.tsx @@ -170,7 +170,7 @@ const CartList: React.FC = ({ isSummaryStep = false }) => { description={item.description} delivery={item.deliveryTime || 'Уточняется'} deliveryDate={item.deliveryDate || ''} - price={formatPrice(item.price, item.currency)} + price={formatPrice(item.price * item.quantity, item.currency)} pricePerItem={`${formatPrice(item.price, item.currency)}/шт`} count={item.quantity} comment={item.comment || ''} diff --git a/src/components/CartSummary.tsx b/src/components/CartSummary.tsx index a4c98eb..0aefe19 100644 --- a/src/components/CartSummary.tsx +++ b/src/components/CartSummary.tsx @@ -657,9 +657,7 @@ const CartSummary: React.FC = ({ step, setStep }) => {
Итого

- {formatPrice( - summary.totalPrice - summary.totalDiscount + (selectedDeliveryAddress ? 0 : summary.deliveryPrice) - )} + {formatPrice(summary.totalPrice - summary.totalDiscount)}

@@ -835,9 +833,7 @@ const CartSummary: React.FC = ({ step, setStep }) => {
Итого

- {formatPrice( - summary.totalPrice - summary.totalDiscount + (selectedDeliveryAddress ? 0 : summary.deliveryPrice) - )} + {formatPrice(summary.totalPrice - summary.totalDiscount)}

diff --git a/src/components/vin/VinCategory.tsx b/src/components/vin/VinCategory.tsx index eff227c..9ff25ca 100644 --- a/src/components/vin/VinCategory.tsx +++ b/src/components/vin/VinCategory.tsx @@ -65,8 +65,31 @@ const VinCategory: React.FC = ({ catalogCode, vehicleId, ssd, const loading = activeTab === 'uzly' ? quickGroupsLoading : categoriesLoading; const error = activeTab === 'uzly' ? quickGroupsError : categoriesError; + // Загружаем units для категории если нет children (аналогично VinLeftbar) + useEffect(() => { + if (selectedCategory && activeTab === 'manufacturer') { + const categoryId = selectedCategory.categoryid || selectedCategory.quickgroupid || selectedCategory.id; + + // Если нет children и нет загруженных units - загружаем units + if ((!selectedCategory.children || selectedCategory.children.length === 0) && + !unitsByCategory[categoryId]) { + console.log('🔄 VinCategory: Загружаем units для категории', categoryId); + lastCategoryIdRef.current = categoryId; + getUnits({ + variables: { + catalogCode, + vehicleId, + ssd, + categoryId + } + }); + } + } + }, [selectedCategory, activeTab, catalogCode, vehicleId, ssd, getUnits, unitsByCategory]); + // Функция для обновления openedPath и catpath в URL const updatePath = (newPath: string[]) => { + console.log('🔄 VinCategory: updatePath вызван с newPath:', newPath); setOpenedPath(newPath); if (router) { router.push( @@ -86,16 +109,45 @@ const VinCategory: React.FC = ({ catalogCode, vehicleId, ssd, onCategoryClick(); return; } - if (category.children && category.children.length > 0) { - if (openedPath[level] === (category.quickgroupid || category.categoryid || category.id)) { + + const categoryId = category.quickgroupid || category.categoryid || category.id; + + // Если это режим "От производителя", всегда пытаемся войти в категорию + if (activeTab === 'manufacturer') { + // Проверяем, открыта ли уже эта категория + if (openedPath[level] === categoryId) { + // Если уже открыта - закрываем updatePath(openedPath.slice(0, level)); } else { - updatePath([...openedPath.slice(0, level), (category.quickgroupid || category.categoryid || category.id)]); + // Если не открыта - открываем (добавляем в path) + updatePath([...openedPath.slice(0, level), categoryId]); + + // Если у категории нет children, загружаем units + if ((!category.children || category.children.length === 0) && !unitsByCategory[categoryId]) { + console.log('🔄 VinCategory: handleCategoryClick загружает units для категории', categoryId); + lastCategoryIdRef.current = categoryId; + getUnits({ + variables: { + catalogCode, + vehicleId, + ssd, + categoryId + } + }); + } + } + } else { + // Режим "Общие" - используем старую логику + if (category.children && category.children.length > 0) { + if (openedPath[level] === categoryId) { + updatePath(openedPath.slice(0, level)); + } else { + updatePath([...openedPath.slice(0, level), categoryId]); + } + } else if (category.link && onQuickGroupSelect) { + // Для вкладки "Общие" с link=true используем QuickGroup + onQuickGroupSelect(category); } - } else if (category.link && onQuickGroupSelect) { - onQuickGroupSelect(category); - } else if (onNodeSelect) { - onNodeSelect(category); } }; @@ -177,14 +229,35 @@ const VinCategory: React.FC = ({ catalogCode, vehicleId, ssd, list = found.children || []; level++; } - // Теперь level - это уровень selectedCategory, подкатегории будут на level+1 - const subcategories = selectedCategory.children || []; - if (subcategories.length === 0) return
Нет подкатегорий
; + + // Показываем либо children, либо units + if (subcategories.length === 0) { + // Если загружаются units для категории без children + const categoryId = selectedCategory.categoryid || selectedCategory.quickgroupid || selectedCategory.id; + if (activeTab === 'manufacturer' && + (!selectedCategory.children || selectedCategory.children.length === 0) && + !unitsByCategory[categoryId]) { + return
Загружаем узлы...
; + } + return
Нет подкатегорий
; + } + return subcategories.map((subcat: any, idx: number) => (
handleCategoryClick(subcat, level + 1)} + onClick={() => { + // Для узлов (units) из режима "От производителя" сразу открываем KnotIn + if (activeTab === 'manufacturer' && subcat.unitid && onNodeSelect) { + console.log('🔍 VinCategory: Открываем узел напрямую:', subcat); + onNodeSelect({ + ...subcat, + unitid: subcat.unitid || subcat.quickgroupid || subcat.categoryid || subcat.id + }); + } else { + handleCategoryClick(subcat, level + 1); + } + }} style={{ cursor: "pointer" }} >
{subcat.name}
diff --git a/src/components/vin/VinLeftbar.tsx b/src/components/vin/VinLeftbar.tsx index 27013ea..ae65561 100644 --- a/src/components/vin/VinLeftbar.tsx +++ b/src/components/vin/VinLeftbar.tsx @@ -90,13 +90,20 @@ const VinLeftbar: React.FC = ({ vehicleInfo, onSearchResults, o }, [router.query.catpath]); const handleToggle = (categoryId: string, level: number) => { + console.log('🔄 VinLeftbar: handleToggle вызван для categoryId:', categoryId, 'level:', level, 'текущий openedPath:', openedPath); + if (openedPath[level] === categoryId) { - setOpenedPathAndUrl(openedPath.slice(0, level)); + const newPath = openedPath.slice(0, level); + console.log('🔄 VinLeftbar: Закрываем категорию, новый path:', newPath); + setOpenedPathAndUrl(newPath); } else { - setOpenedPathAndUrl([...openedPath.slice(0, level), categoryId]); + const newPath = [...openedPath.slice(0, level), categoryId]; + console.log('🔄 VinLeftbar: Открываем категорию, новый path:', newPath); + setOpenedPathAndUrl(newPath); // Загружаем units для категории, если они еще не загружены if (activeTabProp === 'manufacturer' && !unitsByCategory[categoryId]) { + console.log('🔄 VinLeftbar: Загружаем units для categoryId:', categoryId); lastCategoryIdRef.current = categoryId; getUnits({ variables: { @@ -330,7 +337,8 @@ const VinLeftbar: React.FC = ({ vehicleInfo, onSearchResults, o e.preventDefault(); if (searchQuery) setSearchQuery(''); if (onActiveTabChange) onActiveTabChange('manufacturer'); - if (onQuickGroupSelect) onQuickGroupSelect(null); + // Не вызываем onQuickGroupSelect с null - это вызывает ошибку + // Просто переключаем вкладку, а обработка отображения происходит через activeTab }} > От производителя @@ -472,13 +480,15 @@ const VinLeftbar: React.FC = ({ vehicleInfo, onSearchResults, o ) : ( <> {categories.map((category: any, idx: number) => { - const isOpen = openedPath.includes(category.quickgroupid); + // ИСПРАВЛЕНИЕ: Используем тот же приоритет ID, что и в VinCategory + const categoryId = category.quickgroupid || category.categoryid || category.id; + const isOpen = openedPath.includes(categoryId); const subcategories = category.children && category.children.length > 0 ? category.children - : unitsByCategory[category.quickgroupid] || []; + : unitsByCategory[categoryId] || []; return (
= ({ vehicleInfo, onSearchResults, o className={`dropdown-toggle-3 w-dropdown-toggle${isOpen ? " w--open" : ""}`} onClick={(e) => { e.preventDefault(); - handleToggle(category.quickgroupid, 0); + handleToggle(categoryId, 0); }} style={{ cursor: "pointer" }} > @@ -503,14 +513,23 @@ const VinLeftbar: React.FC = ({ vehicleInfo, onSearchResults, o className="dropdown-link-3 w-dropdown-link pl-0" onClick={e => { e.preventDefault(); - // Если это конечная категория с link=true, открываем QuickGroup - if (subcat.link && onQuickGroupSelect) { - onQuickGroupSelect(subcat); - } else if (onNodeSelect) { - onNodeSelect({ + // Для вкладки "От производителя" всегда открываем узел, не используем QuickGroup + if (onNodeSelect) { + const nodeToSelect = { ...subcat, unitid: subcat.unitid || subcat.quickgroupid || subcat.id + }; + + // ОТЛАДКА: Логируем передачу узла + console.log('🔍 VinLeftbar передает узел:', { + unitId: nodeToSelect.unitid, + unitName: nodeToSelect.name, + hasOriginalSsd: !!subcat.ssd, + originalSsd: subcat.ssd ? `${subcat.ssd.substring(0, 50)}...` : 'отсутствует', + finalSsd: nodeToSelect.ssd ? `${nodeToSelect.ssd.substring(0, 50)}...` : 'отсутствует' }); + + onNodeSelect(nodeToSelect); } }} > diff --git a/src/contexts/CartContext.tsx b/src/contexts/CartContext.tsx index 324f6d2..ba67f2a 100644 --- a/src/contexts/CartContext.tsx +++ b/src/contexts/CartContext.tsx @@ -65,7 +65,8 @@ const calculateSummary = (items: CartItem[], deliveryPrice: number) => { const discount = item.originalPrice ? (item.originalPrice - item.price) * item.quantity : 0 return sum + discount }, 0) - const finalPrice = totalPrice + deliveryPrice + // Доставка включена в стоимость товаров, поэтому добавляем её только если есть товары + const finalPrice = totalPrice + (totalPrice > 0 ? 0 : 0) // Доставка всегда включена в цену товаров return { totalItems, diff --git a/src/pages/vehicle-search/[brand]/[vehicleId].tsx b/src/pages/vehicle-search/[brand]/[vehicleId].tsx index d71456c..c0e3a09 100644 --- a/src/pages/vehicle-search/[brand]/[vehicleId].tsx +++ b/src/pages/vehicle-search/[brand]/[vehicleId].tsx @@ -74,32 +74,7 @@ const VehicleDetailsPage = () => { }); const [selectedNode, setSelectedNode] = useState(null); const [selectedQuickGroup, setSelectedQuickGroup] = useState(null); - const handleCategoryClick = (e?: React.MouseEvent) => { - if (e) e.preventDefault(); - setShowKnot(true); - }; - useEffect(() => { - const handler = (e: Event) => { - const target = e.target as HTMLElement; - if (target.classList.contains('link-2')) { - e.preventDefault(); - setShowKnot(true); - } - }; - document.addEventListener('click', handler); - return () => document.removeEventListener('click', handler); - }, []); - // ====== КОНЕЦ ХУКОВ ====== - - // Получаем информацию о каталоге - const { data: catalogData } = useQuery<{ laximoCatalogInfo: LaximoCatalogInfo }>( - GET_LAXIMO_CATALOG_INFO, - { - variables: { catalogCode: brand }, - skip: !brand - } - ); - + // Получаем информацию о выбранном автомобиле const ssdFromQuery = Array.isArray(router.query.ssd) ? router.query.ssd[0] : router.query.ssd; const useStorage = router.query.use_storage === '1'; @@ -118,9 +93,16 @@ const VehicleDetailsPage = () => { } else if (ssdFromQuery && ssdFromQuery.trim() !== '') { finalSsd = ssdFromQuery; } - - + // Получаем информацию о каталоге + const { data: catalogData } = useQuery<{ laximoCatalogInfo: LaximoCatalogInfo }>( + GET_LAXIMO_CATALOG_INFO, + { + variables: { catalogCode: brand }, + skip: !brand + } + ); + const { data: vehicleData, loading: vehicleLoading, error: vehicleError } = useQuery<{ laximoVehicleInfo: LaximoVehicleInfo }>( GET_LAXIMO_VEHICLE_INFO, { @@ -155,6 +137,27 @@ const VehicleDetailsPage = () => { } ); + // Получаем детали выбранного узла, если он выбран + const { + data: unitDetailsData, + loading: unitDetailsLoading, + error: unitDetailsError + } = useQuery( + GET_LAXIMO_UNIT_DETAILS, + { + variables: selectedNode + ? { + catalogCode: selectedNode.catalogCode || selectedNode.catalog || brand, + vehicleId: selectedNode.vehicleId || vehicleId, + unitId: selectedNode.unitid || selectedNode.unitId, + ssd: selectedNode.ssd || finalSsd || '', + } + : { catalogCode: '', vehicleId: '', unitId: '', ssd: '' }, + skip: !selectedNode, + errorPolicy: 'all', + } + ); + // Автоматическое перенаправление на правильный vehicleId если API вернул другой ID useEffect(() => { if (vehicleData?.laximoVehicleInfo && vehicleData.laximoVehicleInfo.vehicleid !== vehicleId) { @@ -181,27 +184,54 @@ const VehicleDetailsPage = () => { return; } }, [vehicleData, vehicleId, brand, finalSsd, router]); - - // Получаем детали выбранного узла, если он выбран - const { - data: unitDetailsData, - loading: unitDetailsLoading, - error: unitDetailsError - } = useQuery( - GET_LAXIMO_UNIT_DETAILS, - { - variables: selectedNode - ? { - catalogCode: selectedNode.catalogCode || selectedNode.catalog || brand, - vehicleId: selectedNode.vehicleId || vehicleId, - unitId: selectedNode.unitid || selectedNode.unitId, - ssd: selectedNode.ssd || finalSsd || '', - } - : { catalogCode: '', vehicleId: '', unitId: '', ssd: '' }, - skip: !selectedNode, - errorPolicy: 'all', + + // Следим за изменением quickgroup в URL и обновляем selectedQuickGroup + useEffect(() => { + const quickgroupId = router.query.quickgroup as string; + if (quickgroupId) { + // Используем функциональное обновление состояния для избежания dependency + setSelectedQuickGroup((prev: any) => { + if (prev && prev.quickgroupid === quickgroupId) return prev; + return { quickgroupid: quickgroupId }; + }); + } else { + setSelectedQuickGroup(null); } - ); + }, [router.query.quickgroup]); + + // Следить за изменением unitid в URL и обновлять selectedNode + useEffect(() => { + const unitid = router.query.unitid as string; + if (unitid) { + // Используем функциональное обновление состояния для избежания dependency + setSelectedNode((prev: any) => { + if (prev && (prev.unitid === unitid || prev.id === unitid)) return prev; + return { unitid }; + }); + } else { + setSelectedNode(null); + } + }, [router.query.unitid]); + + const handleCategoryClick = (e?: React.MouseEvent) => { + if (e) e.preventDefault(); + setShowKnot(true); + }; + + useEffect(() => { + const handler = (e: Event) => { + const target = e.target as HTMLElement; + if (target.classList.contains('link-2')) { + e.preventDefault(); + setShowKnot(true); + } + }; + document.addEventListener('click', handler); + return () => document.removeEventListener('click', handler); + }, []); + // ====== КОНЕЦ ХУКОВ ====== + + const unitDetails = unitDetailsData?.laximoUnitDetails || []; // Логируем ошибки @@ -312,6 +342,12 @@ const VehicleDetailsPage = () => { // --- Синхронизация selectedQuickGroup с URL --- // Функция для открытия VinQuick и добавления quickgroup в URL const openQuickGroup = (group: any) => { + // Проверяем что group не null и имеет quickgroupid + if (!group || !group.quickgroupid) { + console.warn('⚠️ openQuickGroup: получен null или группа без quickgroupid:', group); + return; + } + setSelectedQuickGroup(group); router.push( { pathname: router.pathname, query: { ...router.query, quickgroup: group.quickgroupid } }, @@ -329,24 +365,20 @@ const VehicleDetailsPage = () => { { shallow: true } ); }; - // Следим за изменением quickgroup в URL и обновляем selectedQuickGroup - useEffect(() => { - const quickgroupId = router.query.quickgroup as string; - if (quickgroupId) { - // Найти группу по id (в openedPath или где-то ещё) - // Для простоты: если есть selectedQuickGroup и id совпадает — ничего не делаем - if (selectedQuickGroup && selectedQuickGroup.quickgroupid === quickgroupId) return; - // Иначе ищем в openedPath или в категориях (можно доработать) - // Пока просто создаём объект-заглушку - setSelectedQuickGroup({ quickgroupid: quickgroupId }); - } else { - setSelectedQuickGroup(null); - } - }, [router.query.quickgroup]); // --- Синхронизация selectedNode (KnotIn) с URL --- // Открыть KnotIn и добавить unitid в URL const openKnot = (node: any) => { + // ОТЛАДКА: Логируем узел который получили + console.log('🔍 [vehicleId].tsx openKnot получил узел:', { + unitId: node.unitid, + unitName: node.name, + hasSsd: !!node.ssd, + nodeSsd: node.ssd ? `${node.ssd.substring(0, 50)}...` : 'отсутствует', + vehicleSsd: vehicleInfo.ssd ? `${vehicleInfo.ssd.substring(0, 50)}...` : 'отсутствует', + ssdLength: node.ssd?.length || 0 + }); + setSelectedNode(node); router.push( { pathname: router.pathname, query: { ...router.query, unitid: node.unitid || node.id } }, @@ -364,17 +396,6 @@ const VehicleDetailsPage = () => { { shallow: true } ); }; - // Следить за изменением unitid в URL и обновлять selectedNode - useEffect(() => { - const unitid = router.query.unitid as string; - if (unitid) { - if (selectedNode && (selectedNode.unitid === unitid || selectedNode.id === unitid)) return; - // Можно доработать: искать node по unitid в категориях/группах - setSelectedNode({ unitid }); - } else { - setSelectedNode(null); - } - }, [router.query.unitid]); return ( <> @@ -407,7 +428,22 @@ const VehicleDetailsPage = () => { setSearchState({ loading, error, query, isSearching: isSearching || false }); }} onNodeSelect={openKnot} - onActiveTabChange={(tab) => setActiveTab(tab)} + onActiveTabChange={(tab) => { + setActiveTab(tab); + // Сбрасываем состояние при смене вкладки + setSelectedQuickGroup(null); + setSelectedNode(null); + setOpenedPath([]); + // Очищаем URL от параметров quickgroup и unitid + const { quickgroup, unitid, ...rest } = router.query; + if (quickgroup || unitid) { + router.push( + { pathname: router.pathname, query: rest }, + undefined, + { shallow: true } + ); + } + }} onQuickGroupSelect={openQuickGroup} activeTab={activeTab} openedPath={openedPath} @@ -512,7 +548,6 @@ const VehicleDetailsPage = () => { unitId={selectedNode.unitid} unitName={selectedNode.name} parts={unitDetails} - onBack={closeKnot} /> {unitDetailsLoading ? (
Загружаем детали узла...