Удалены уведомления об удалении товара из избранного в компонентах BestPriceItem и TopSalesItem. Добавлен новый запрос GraphQL для получения новых поступлений, реализована логика загрузки и отображения данных в компоненте NewArrivalsSection. Обновлены компоненты ProfileHistoryItem и ProfileHistoryMain для поддержки новых пропсов и пагинации. Улучшено взаимодействие с пользователем через обработку кликов и отображение состояния загрузки.

This commit is contained in:
Bivekich
2025-07-11 02:42:46 +03:00
parent 9fc7d0fbf5
commit 26e4a95ae4
8 changed files with 415 additions and 51 deletions

View File

@ -1,4 +1,5 @@
import React from "react";
import { useRouter } from "next/router";
interface VehicleInfo {
brand?: string;
@ -15,6 +16,10 @@ interface ProfileHistoryItemProps {
vehicleInfo?: VehicleInfo;
resultCount?: number;
onDelete?: (id: string) => void;
// Добавляем новые пропсы для поиска
searchType?: 'TEXT' | 'ARTICLE' | 'OEM' | 'VIN' | 'PLATE' | 'WIZARD' | 'PART_VEHICLES';
articleNumber?: string;
brand?: string;
}
const ProfileHistoryItem: React.FC<ProfileHistoryItemProps> = ({
@ -26,7 +31,12 @@ const ProfileHistoryItem: React.FC<ProfileHistoryItemProps> = ({
vehicleInfo,
resultCount,
onDelete,
searchType,
articleNumber,
brand,
}) => {
const router = useRouter();
const handleDeleteClick = (e: React.MouseEvent) => {
e.stopPropagation();
if (onDelete) {
@ -34,6 +44,28 @@ const ProfileHistoryItem: React.FC<ProfileHistoryItemProps> = ({
}
};
const handleItemClick = () => {
// Определяем куда перенаправлять в зависимости от типа поиска
if (searchType === 'VIN' || searchType === 'PLATE') {
// Для VIN и госномера перенаправляем на vehicle-search-results
router.push(`/vehicle-search-results?q=${encodeURIComponent(name)}`);
} else if (searchType === 'ARTICLE' || searchType === 'OEM' || (searchType === 'TEXT' && articleNumber)) {
// Для поиска по артикулу/OEM или текстового поиска с артикулом
const searchBrand = brand || manufacturer || '';
const searchArticle = articleNumber || name;
router.push(`/search-result?article=${encodeURIComponent(searchArticle)}&brand=${encodeURIComponent(searchBrand)}`);
} else if (searchType === 'TEXT') {
// Для обычного текстового поиска
router.push(`/search?q=${encodeURIComponent(name)}&mode=parts`);
} else if (searchType === 'PART_VEHICLES') {
// Для поиска автомобилей по детали
router.push(`/vehicles-by-part?partNumber=${encodeURIComponent(name)}`);
} else {
// По умолчанию - обычный поиск
router.push(`/search?q=${encodeURIComponent(name)}&mode=parts`);
}
};
const getSearchTypeDisplay = (article: string) => {
if (article.includes('TEXT')) return 'Текстовый поиск';
if (article.includes('ARTICLE')) return 'По артикулу';
@ -48,7 +80,11 @@ const ProfileHistoryItem: React.FC<ProfileHistoryItemProps> = ({
return (
<>
<div className="mt-1.5 w-full border border-gray-200 border-solid min-h-[1px] max-md:max-w-full" />
<div className="flex justify-between items-center px-5 pt-1.5 pb-2 mt-1.5 w-full bg-white rounded-lg max-md:max-w-full max-md:flex-col max-md:min-w-0 hover:bg-gray-50 transition-colors">
<div
className="flex justify-between items-center px-5 pt-1.5 pb-2 mt-1.5 w-full bg-white rounded-lg max-md:max-w-full max-md:flex-col max-md:min-w-0 hover:bg-gray-50 transition-colors"
onClick={handleItemClick}
style={{ cursor: 'pointer' }}
>
<div className="flex flex-wrap flex-1 shrink gap-5 items-center self-stretch pr-5 my-auto w-full basis-0 max-md:max-w-full max-md:flex-col max-md:gap-2 max-md:p-0 max-md:min-w-0">
<div className="self-stretch my-auto w-40 max-md:w-full text-sm">
<div className="font-medium text-gray-900">{date}</div>

View File

@ -3,6 +3,7 @@ import { useQuery, useMutation } from '@apollo/client';
import ProfileHistoryItem from "./ProfileHistoryItem";
import SearchInput from "./SearchInput";
import ProfileHistoryTabs from "./ProfileHistoryTabs";
import Pagination from '../Pagination';
import {
GET_PARTS_SEARCH_HISTORY,
DELETE_SEARCH_HISTORY_ITEM,
@ -19,6 +20,10 @@ const ProfileHistoryMain = () => {
const [sortField, setSortField] = useState<"date" | "manufacturer" | "name">("date");
const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc");
const [filteredItems, setFilteredItems] = useState<PartsSearchHistoryItem[]>([]);
// Состояние пагинации
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(10); // Количество элементов на странице
const tabOptions = ["Все", "Сегодня", "Вчера", "Эта неделя", "Этот месяц"];
@ -26,7 +31,10 @@ const ProfileHistoryMain = () => {
const { data, loading, error, refetch } = useQuery<{ partsSearchHistory: PartsSearchHistoryResponse }>(
GET_PARTS_SEARCH_HISTORY,
{
variables: { limit: 100, offset: 0 },
variables: {
limit: 1000, // Загружаем больше для клиентской пагинации с фильтрами
offset: 0
},
fetchPolicy: 'cache-and-network',
onCompleted: (data) => {
console.log('История поиска загружена:', data);
@ -161,8 +169,32 @@ const ProfileHistoryMain = () => {
}
setFilteredItems(filtered);
// Сбрасываем страницу на первую при изменении фильтров
setCurrentPage(1);
}, [historyItems, search, activeTab, selectedManufacturer, sortField, sortOrder]);
// Вычисляем элементы для текущей страницы
const totalPages = Math.ceil(filteredItems.length / itemsPerPage);
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const currentPageItems = filteredItems.slice(startIndex, endIndex);
// Обработчик изменения страницы
const handlePageChange = (page: number) => {
setCurrentPage(page);
// Прокручиваем к началу списка при смене страницы
const historyContainer = document.querySelector('.flex.flex-col.mt-5.w-full.text-gray-400');
if (historyContainer) {
historyContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
};
// Обработчик изменения количества элементов на странице
const handleItemsPerPageChange = (newItemsPerPage: number) => {
setItemsPerPage(newItemsPerPage);
setCurrentPage(1); // Сбрасываем на первую страницу
};
const handleSort = (field: "date" | "manufacturer" | "name") => {
if (sortField === field) {
setSortOrder(sortOrder === "asc" ? "desc" : "asc");
@ -287,6 +319,7 @@ const ProfileHistoryMain = () => {
setSelectedManufacturer("Все");
setSearch("");
setActiveTab("Все");
setCurrentPage(1);
}}
className="px-4 py-2 text-sm text-gray-600 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
@ -424,7 +457,7 @@ const ProfileHistoryMain = () => {
</div>
</div>
) : (
filteredItems.map((item) => (
currentPageItems.map((item) => (
<ProfileHistoryItem
key={item.id}
id={item.id}
@ -441,18 +474,58 @@ const ProfileHistoryMain = () => {
vehicleInfo={item.vehicleInfo}
resultCount={item.resultCount}
onDelete={handleDeleteItem}
searchType={item.searchType}
articleNumber={item.articleNumber}
brand={item.brand}
/>
))
)}
</div>
{/* Пагинация */}
{filteredItems.length > 0 && (
<div className="mt-4 text-center text-sm text-gray-500">
Показано {filteredItems.length} из {historyItems.length} записей
{(selectedManufacturer !== "Все" || search.trim() || activeTab !== "Все") && (
<span className="ml-2 text-blue-600">
(применены фильтры)
</span>
<div className="mt-6 space-y-4">
{/* Селектор количества элементов на странице */}
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center space-y-2 sm:space-y-0">
<div className="flex items-center space-x-2 text-sm text-gray-500">
<span>Показывать по:</span>
<select
value={itemsPerPage}
onChange={(e) => handleItemsPerPageChange(Number(e.target.value))}
className="px-2 py-1 border border-gray-200 rounded text-gray-700 bg-white focus:outline-none focus:ring-2 focus:ring-[#ec1c24] focus:border-transparent"
style={{ cursor: 'pointer' }}
>
<option value={5}>5</option>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={50}>50</option>
</select>
<span>записей</span>
</div>
<div className="text-sm text-gray-500 text-center sm:text-right">
Показано {startIndex + 1}-{Math.min(endIndex, filteredItems.length)} из {filteredItems.length} записей
{filteredItems.length !== historyItems.length && (
<span className="ml-1">
(всего {historyItems.length})
</span>
)}
{(selectedManufacturer !== "Все" || search.trim() || activeTab !== "Все") && (
<span className="ml-2 text-blue-600">
(применены фильтры)
</span>
)}
</div>
</div>
{/* Компонент пагинации */}
{filteredItems.length > itemsPerPage && (
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
showPageInfo={true}
/>
)}
</div>
)}