search filter component

This commit is contained in:
2025-05-27 14:02:50 +03:00
parent 7915221fc4
commit c897d25a7d
5 changed files with 126 additions and 131 deletions

View File

@@ -2,6 +2,7 @@ import React, { Suspense } from 'react'
import type { Metadata } from 'next'
import SearchCard from '../../components/SearchCard'
import { SearchCardProps, RouteSearchPageProps } from '@/app/types'
import SearchFilters from '../../components/SearchFilters'
async function fetchSearch(category: string, from: string, to: string) {
const response = await fetch(
@@ -66,7 +67,7 @@ export default async function SearchPage(props: RouteSearchPageProps) {
const { results, count } = await fetchSearch(category, fromCity, toCity)
return (
<div className="container mx-auto p-4">
<div className="container mx-auto space-y-10 p-4">
<h1 className="mb-4 text-2xl font-bold">
{results.length > 0
? category === 'mover'
@@ -75,6 +76,8 @@ export default async function SearchPage(props: RouteSearchPageProps) {
: 'Результаты не найдены'}
</h1>
<SearchFilters />
<Suspense fallback={<div>Загрузка результатов...</div>}>
<div className="space-y-4">
{results.length > 0 ? (

View File

@@ -3,6 +3,7 @@ import type { Metadata } from 'next'
import SearchCard from '../components/SearchCard'
import { SearchCardProps, SearchPageProps } from '@/app/types'
import { fetchRoutes } from '@/lib/search/fetchRoutes'
import SearchFilters from '../components/SearchFilters'
export async function generateMetadata(): Promise<Metadata> {
return {
@@ -57,7 +58,7 @@ export default async function SearchPage(props: SearchPageProps) {
<h1 className="mb-4 text-2xl font-bold">
{params.category === 'mover' ? 'Поиск перевозчика' : 'Поиск посылки'}
</h1>
<SearchFilters />
<Suspense fallback={<div>Загрузка результатов...</div>}>
<div className="space-y-4">
{results.length > 0 ? (

View File

@@ -0,0 +1,110 @@
'use client'
import React, { useState } from 'react'
import MultiSelect from '@/components/ui/Selector'
const transportOptions = [
{ id: 1, value: 'road', label: 'Авто' },
{ id: 2, value: 'avia', label: 'Авиа' },
{ id: 3, value: 'both', label: 'Любой' },
]
const packageTypeOptions = [
{ id: 1, value: 'letter', label: 'Письмо или Документы' },
{ id: 2, value: 'package', label: 'Посылка (до 30кг)' },
{ id: 3, value: 'passenger', label: 'Попутчик' },
{ id: 4, value: 'parcel', label: 'Бандероль (до 5кг)' },
{ id: 5, value: 'cargo', label: 'Груз (свыше 30 кг)' },
]
interface SearchFiltersProps {
onFiltersChange?: (filters: { transport: number[]; packageTypes: number[] }) => void
}
const SearchFilters: React.FC<SearchFiltersProps> = ({ onFiltersChange }) => {
const [selectedTransport, setSelectedTransport] = useState<number[]>([])
const [selectedPackageTypes, setSelectedPackageTypes] = useState<number[]>([])
const handleTransportChange = (e: { target: { value: number[] } }) => {
setSelectedTransport(e.target.value)
onFiltersChange?.({
transport: e.target.value,
packageTypes: selectedPackageTypes,
})
}
const handlePackageTypesChange = (e: { target: { value: number[] } }) => {
setSelectedPackageTypes(e.target.value)
onFiltersChange?.({
transport: selectedTransport,
packageTypes: e.target.value,
})
}
const handleReset = () => {
setSelectedTransport([])
setSelectedPackageTypes([])
onFiltersChange?.({
transport: [],
packageTypes: [],
})
}
const hasActiveFilters = selectedTransport.length > 0 || selectedPackageTypes.length > 0
return (
<div className="w-full rounded-2xl bg-white p-6 shadow-sm">
<div className="mb-6 flex items-center justify-between">
<h2 className="text-lg font-semibold text-gray-900">Ищете что-то конкретное?</h2>
{hasActiveFilters && (
<button
onClick={handleReset}
className="hover:text-orange/80 flex items-center text-sm font-medium text-blue-600"
>
<svg
className="mr-2 h-4 w-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Сбросить фильтры
</button>
)}
</div>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-2">
<MultiSelect
value={selectedTransport}
handleChange={handleTransportChange}
label="Способ перевозки"
placeholder="Выберите способ перевозки"
name="transport"
options={transportOptions}
className="w-full"
/>
</div>
<div className="space-y-2">
<MultiSelect
value={selectedPackageTypes}
handleChange={handlePackageTypesChange}
label="Тип посылки"
placeholder="Выберите тип посылки"
name="packageType"
options={packageTypeOptions}
className="w-full"
/>
</div>
</div>
</div>
)
}
export default SearchFilters

View File

@@ -1,4 +1,6 @@
import React from 'react'
'use client'
import React, { useState, useEffect } from 'react'
import Select from 'react-select'
import { MultiSelectProps } from '@/app/types'
@@ -12,6 +14,12 @@ const MultiSelect = ({
className = '',
noOptionsMessage = 'Нет доступных опций',
}: MultiSelectProps) => {
const [portalTarget, setPortalTarget] = useState<HTMLElement | null>(null)
useEffect(() => {
setPortalTarget(document.body)
}, [])
return (
<div className={className}>
{label && (
@@ -103,7 +111,7 @@ const MultiSelect = ({
},
}),
}}
menuPortalTarget={document.body}
menuPortalTarget={portalTarget}
menuPosition="fixed"
/>
</div>