Files
tripwithbonus/frontend/app/(urls)/search/components/ClientResults.tsx
2025-05-28 12:30:08 +03:00

153 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import React, { useState, useMemo } from 'react'
import SearchCard from './SearchCard'
import { SearchCardProps } from '@/app/types'
import SearchFilters from './SearchFilters'
import { fetchRoutes } from '@/lib/search/fetchRoutes'
import { usePathname, useSearchParams } from 'next/navigation'
import Pagination from './Pagination'
interface ClientResultsProps {
initialResults: SearchCardProps[]
initialCount?: number
initialNext?: string | null
initialPrevious?: string | null
}
export default function ClientResults({
initialResults,
initialCount = 0,
initialNext = null,
initialPrevious = null,
}: ClientResultsProps) {
const [selectedTransport, setSelectedTransport] = useState<number[]>([])
const [selectedPackageTypes, setSelectedPackageTypes] = useState<number[]>([])
const [results, setResults] = useState(initialResults)
const [isLoading, setIsLoading] = useState(false)
const [currentPage, setCurrentPage] = useState(1)
const [hasNext, setHasNext] = useState(!!initialNext)
const [hasPrevious, setHasPrevious] = useState(!!initialPrevious)
const [totalCount, setTotalCount] = useState(initialCount)
const pathname = usePathname()
const searchParams = useSearchParams()
const filteredResults = useMemo(() => {
let filtered = [...results]
if (selectedTransport.length > 0) {
filtered = filtered.filter(item =>
selectedTransport.some(id => {
switch (id) {
case 1:
return item.type_transport === 'road'
case 2:
return item.type_transport === 'avia'
case 3:
return true // 'both' отдает все
default:
return false
}
})
)
}
if (selectedPackageTypes.length > 0) {
filtered = filtered.filter(item => {
return selectedPackageTypes.some(id => {
const match = (() => {
switch (id) {
case 1:
return item.formatted_cargo_type === 'Письмо или Документы'
case 2:
return item.formatted_cargo_type === 'Посылка (до 30кг)'
case 3:
return item.formatted_cargo_type === 'Попутчик'
case 4:
return item.formatted_cargo_type === 'Бандероль (до 5кг)'
case 5:
return item.formatted_cargo_type === 'Груз (свыше 30 кг)'
default:
return false
}
})()
return match
})
})
}
return filtered
}, [results, selectedTransport, selectedPackageTypes])
const handleFiltersChange = ({
transport,
packageTypes,
}: {
transport: number[]
packageTypes: number[]
}) => {
setSelectedTransport(transport)
setSelectedPackageTypes(packageTypes)
}
const handlePageChange = async (newPage: number) => {
setIsLoading(true)
try {
const category = pathname.split('/')[2] // получаем категорию из URL
const params = new URLSearchParams(searchParams.toString())
const {
results: newResults,
next,
previous,
count,
} = await fetchRoutes(category, params.toString(), newPage)
setResults(newResults)
setCurrentPage(newPage)
setHasNext(!!next)
setHasPrevious(!!previous)
setTotalCount(count)
} catch (error) {
console.error('Error fetching page:', error)
} finally {
setIsLoading(false)
}
}
const totalPages = Math.ceil(totalCount / 10) // 10 - размер страницы
return (
<div className="space-y-6">
<SearchFilters onFiltersChange={handleFiltersChange} />
{isLoading ? (
<div className="flex justify-center">
<div className="h-8 w-8 animate-spin rounded-full border-b-2 border-gray-900"></div>
</div>
) : (
<>
<div className="grid gap-4">
{filteredResults.map(result => (
<SearchCard key={result.id} {...result} />
))}
</div>
<Pagination
currentPage={currentPage}
totalPages={totalPages}
hasNext={hasNext}
hasPrevious={hasPrevious}
isLoading={isLoading}
onPageChange={handlePageChange}
/>
{filteredResults.length === 0 && (
<div className="text-center text-gray-500">Результаты не найдены</div>
)}
</>
)}
</div>
)
}