Удален файл интеграции с Parts Index API и обновлены компоненты для работы с корзиной и избранным. Добавлены функции для обработки добавления товаров в корзину с уведомлениями, улучшена логика работы с избранным, а также добавлены фильтры для истории поиска по производителю.

This commit is contained in:
Bivekich
2025-06-29 03:36:21 +03:00
parent d268bb3359
commit 7f91da525f
23 changed files with 685 additions and 780 deletions

View File

@ -7,7 +7,6 @@ import CartSummary from "@/components/CartSummary";
import CartRecommended from "../components/CartRecommended";
import CatalogSubscribe from "@/components/CatalogSubscribe";
import MobileMenuBottomSection from "@/components/MobileMenuBottomSection";
import CartDebug from "@/components/CartDebug";
export default function CartPage() {
@ -39,7 +38,6 @@ export default function CartPage() {
</section>
<Footer />
<MobileMenuBottomSection />
<CartDebug />
</>
);
}

View File

@ -16,7 +16,7 @@ export default function Favorite() {
const [showFiltersMobile, setShowFiltersMobile] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
const [filterValues, setFilterValues] = useState<{[key: string]: any}>({});
const [sortBy, setSortBy] = useState<'name' | 'brand' | 'price' | 'date'>('date');
const [sortBy, setSortBy] = useState<'name' | 'brand' | 'date'>('date');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc');
// Создаем динамические фильтры на основе данных избранного

View File

@ -1,11 +1,11 @@
import React, { useEffect, useState } from "react";
import Head from "next/head";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import { useRouter } from "next/router";
import { useMutation, ApolloProvider } from "@apollo/client";
import { gql } from "@apollo/client";
import { apolloClient } from "@/lib/apollo";
import toast from "react-hot-toast";
const CONFIRM_PAYMENT = gql`
mutation ConfirmPayment($orderId: ID!) {
@ -51,8 +51,15 @@ function PaymentSuccessContent() {
}
}).then(() => {
console.log('Оплата заказа подтверждена');
toast.success('Оплата успешно подтверждена!', {
duration: 3000,
icon: '✅',
});
}).catch((error: any) => {
console.error('Ошибка подтверждения оплаты:', error);
toast.error('Ошибка подтверждения оплаты: ' + error.message, {
duration: 5000,
});
});
}
}, [router.query, confirmPayment]);
@ -76,7 +83,7 @@ function PaymentSuccessContent() {
<link href="/images/webclip.png" rel="apple-touch-icon" />
</Head>
<Header />
<div className="w-layout-blockcontainer container info w-container">
<div className="w-layout-vflex flex-block-9">

View File

@ -1,4 +1,8 @@
import * as React from "react";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useQuery } from '@apollo/client';
import { GET_CLIENT_ME } from '@/lib/graphql';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import ProfileSidebar from '@/components/ProfileSidebar';
@ -11,6 +15,48 @@ import NotificationMane from "@/components/profile/NotificationMane";
import Head from "next/head";
const ProfileActsPage = () => {
const router = useRouter();
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const { data: clientData, loading: clientLoading } = useQuery(GET_CLIENT_ME, {
skip: !isAuthenticated,
onCompleted: (data) => {
// Проверяем есть ли у клиента юридические лица
if (!data?.clientMe?.legalEntities?.length) {
// Если нет юридических лиц, перенаправляем на настройки
router.push('/profile-settings?tab=legal');
return;
}
},
onError: (error) => {
console.error('Ошибка загрузки данных клиента:', error);
// Если ошибка авторизации, перенаправляем на главную
router.push('/');
}
});
useEffect(() => {
// Проверяем авторизацию
const token = localStorage.getItem('authToken');
if (!token) {
router.push('/');
return;
}
setIsAuthenticated(true);
}, [router]);
// Показываем загрузку пока проверяем авторизацию и данные
if (!isAuthenticated || clientLoading) {
return (
<div className="page-wrapper">
<div className="flex flex-col justify-center items-center min-h-[400px]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-red-600"></div>
<div className="mt-4 text-gray-600">Загрузка...</div>
</div>
<Footer />
</div>
);
}
return (
<div className="page-wrapper">
<Head>

View File

@ -1,4 +1,8 @@
import * as React from "react";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { useQuery } from '@apollo/client';
import { GET_CLIENT_ME } from '@/lib/graphql';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import CatalogSubscribe from '@/components/CatalogSubscribe';
@ -8,9 +12,49 @@ import ProfileRequisitiesMain from '@/components/profile/ProfileRequisitiesMain'
import ProfileInfo from '@/components/profile/ProfileInfo';
import Head from "next/head";
const ProfileRequisitiesPage = () => {
const router = useRouter();
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const { data: clientData, loading: clientLoading } = useQuery(GET_CLIENT_ME, {
skip: !isAuthenticated,
onCompleted: (data) => {
// Проверяем есть ли у клиента юридические лица
if (!data?.clientMe?.legalEntities?.length) {
// Если нет юридических лиц, перенаправляем на настройки
router.push('/profile-settings?tab=legal');
return;
}
},
onError: (error) => {
console.error('Ошибка загрузки данных клиента:', error);
// Если ошибка авторизации, перенаправляем на главную
router.push('/');
}
});
useEffect(() => {
// Проверяем авторизацию
const token = localStorage.getItem('authToken');
if (!token) {
router.push('/');
return;
}
setIsAuthenticated(true);
}, [router]);
// Показываем загрузку пока проверяем авторизацию и данные
if (!isAuthenticated || clientLoading) {
return (
<div className="page-wrapper">
<div className="flex flex-col justify-center items-center min-h-[400px]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-red-600"></div>
<div className="mt-4 text-gray-600">Загрузка...</div>
</div>
<Footer />
</div>
);
}
return (
<div className="page-wrapper">
<Head>

View File

@ -502,6 +502,7 @@ export default function SearchResult() {
price={`${offer.price.toLocaleString()}`}
delivery={`${offer.deliveryDuration} ${offer.deliveryDuration === 1 ? 'день' : 'дней'}`}
stock={`${offer.quantity} шт.`}
offer={offer}
/>
))}
</div>

View File

@ -105,6 +105,14 @@ const VehicleSearchResultsPage: React.FC<VehicleSearchResultsPageProps> = () =>
ssdLength: ssd.length
});
// Создаем базовые параметры URL
const urlParams = new URLSearchParams();
// Добавляем VIN-номер в URL, если он есть
if (searchQuery && searchType === 'vin') {
urlParams.set('vin', searchQuery);
}
// Если есть SSD, сохраняем его в localStorage для безопасной передачи
if (ssd && ssd.trim() !== '') {
const vehicleKey = `vehicle_ssd_${catalogCode}_${vehicleId}`;
@ -121,25 +129,22 @@ const VehicleSearchResultsPage: React.FC<VehicleSearchResultsPageProps> = () =>
localStorage.setItem(vehicleKey, ssd);
// Выбираем URL в зависимости от того, нужно ли пропустить промежуточную страницу
const url = skipToCategories
? `/vehicle-search/${catalogCode}/${vehicleId}?use_storage=1&ssd_length=${ssd.length}&searchType=categories`
: `/vehicle-search/${catalogCode}/${vehicleId}?use_storage=1&ssd_length=${ssd.length}`;
console.log('🔗 Переходим на URL с localStorage:', url);
// Используем replace вместо push для моментального перехода
router.replace(url);
} else {
// Выбираем URL в зависимости от того, нужно ли пропустить промежуточную страницу
const url = skipToCategories
? `/vehicle-search/${catalogCode}/${vehicleId}?searchType=categories`
: `/vehicle-search/${catalogCode}/${vehicleId}`;
console.log('🔗 Переходим на URL без SSD:', url);
// Используем replace вместо push для моментального перехода
router.replace(url);
urlParams.set('use_storage', '1');
urlParams.set('ssd_length', ssd.length.toString());
}
}, [router]);
if (skipToCategories) {
urlParams.set('searchType', 'categories');
}
// Формируем URL с параметрами
const baseUrl = `/vehicle-search/${catalogCode}/${vehicleId}`;
const url = urlParams.toString() ? `${baseUrl}?${urlParams.toString()}` : baseUrl;
console.log('🔗 Переходим на URL:', url);
// Используем replace вместо push для моментального перехода
router.replace(url);
}, [router, searchQuery, searchType]);
// Предзагрузка и автоматический переход при поиске по VIN, если найден только один автомобиль
useEffect(() => {