Фильтры в каталоге, интеграция

This commit is contained in:
Sergey Bolshakov 2025-12-14 23:24:18 +03:00
parent 7f6c6d1107
commit b45f9885ab
3 changed files with 74 additions and 18 deletions

View File

@ -203,6 +203,12 @@ export default function CatalogPage() {
params.set("arrivalTime", filters.arrivalTime);
}
// Сохраняем сортировку, если она установлена
const sortByPrice = searchParams.get("sortByPrice");
if (sortByPrice) {
params.set("sortByPrice", sortByPrice);
}
// Обновляем URL без прокрутки страницы
const newUrl = params.toString()
? `${pathname}?${params.toString()}`
@ -219,11 +225,29 @@ export default function CatalogPage() {
useEffect(() => {
(async () => {
const params: Record<string, string> = {
const allParams: Record<string, string> = {
search: searchParams.get("search") ?? "",
minLength: searchParams.get("lengthMin") ?? "",
maxLength: searchParams.get("lengthMax") ?? "",
minPrice: searchParams.get("priceMin") ?? "",
maxPrice: searchParams.get("priceMax") ?? "",
minYear: searchParams.get("yearMin") ?? "",
maxYear: searchParams.get("yearMax") ?? "",
guests: searchParams.get("adults") && searchParams.get("children") ? `${Number(searchParams.get("adults")) + Number(searchParams.get("children"))}` : "",
paymentType: searchParams.get("paymentType") ?? "",
quickBooking: searchParams.get("quickBooking") ?? "",
hasToilet: searchParams.get("hasToilet") ?? "",
date: searchParams.get("date") ?? "",
departureTime: searchParams.get("departureTime") ?? "",
arrivalTime: searchParams.get("arrivalTime") ?? "",
sortByPrice: searchParams.get("sortByPrice") ?? "",
};
const response = await client.get<CatalogFilteredResponseDto>("/catalog/filtered/", {
const params = Object.fromEntries(
Object.entries(allParams).filter(([_, value]) => value !== "")
);
const response = await client.get<CatalogFilteredResponseDto>("/catalog/filter/", {
params,
});
@ -346,7 +370,21 @@ export default function CatalogPage() {
<div className="text-base text-[#999999]">
Сортировка:
</div>
<Select defaultValue="default">
<Select
value={searchParams.get("sortByPrice") || "default"}
onValueChange={(value) => {
const params = new URLSearchParams(searchParams.toString());
if (value === "default") {
params.delete("sortByPrice");
} else {
params.set("sortByPrice", value);
}
const newUrl = params.toString()
? `${pathname}?${params.toString()}`
: pathname;
router.replace(newUrl, { scroll: false });
}}
>
<SelectTrigger
className="w-full"
variant="ghost"
@ -357,18 +395,12 @@ export default function CatalogPage() {
<SelectItem value="default">
По умолчанию
</SelectItem>
<SelectItem value="price-asc">
<SelectItem value="asc">
Цена: по возрастанию
</SelectItem>
<SelectItem value="price-desc">
<SelectItem value="desc">
Цена: по убыванию
</SelectItem>
<SelectItem value="length-asc">
Длина: по возрастанию
</SelectItem>
<SelectItem value="length-desc">
Длина: по убыванию
</SelectItem>
</SelectContent>
</Select>
</div>

View File

@ -12,6 +12,9 @@ import Link from "next/link";
export default function Hero() {
const [adults, setAdults] = useState<number>(0);
const [children, setChildren] = useState<number>(0);
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const [departureTime, setDepartureTime] = useState<string>("12:00");
const [arrivalTime, setArrivalTime] = useState<string>("13:00");
return (
<section className="relative h-[600px] rounded-[24px] mx-[16px] overflow-hidden flex text-white">
<Image
@ -63,7 +66,14 @@ export default function Hero() {
{/* Дата и время */}
<div className="flex-1">
<DatePicker />
<DatePicker
value={selectedDate || undefined}
departureTime={departureTime}
arrivalTime={arrivalTime}
onDateChange={(date) => setSelectedDate(date || null)}
onDepartureTimeChange={setDepartureTime}
onArrivalTimeChange={setArrivalTime}
/>
</div>
{/* Количество гостей */}
@ -79,9 +89,20 @@ export default function Hero() {
</div>
{/* Кнопка поиска */}
<Link href={(() => {
const params = new URLSearchParams();
if (adults > 0) params.append('adults', adults.toString());
if (children > 0) params.append('children', children.toString());
if (selectedDate) params.append('date', selectedDate.toString());
if (departureTime && departureTime !== "12:00") params.append('departureTime', departureTime);
if (arrivalTime && arrivalTime !== "13:00") params.append('arrivalTime', arrivalTime);
const queryString = params.toString();
return queryString ? `/catalog?${queryString}` : '/catalog';
})()}>
<Button variant="gradient" className="font-bold text-white h-[64px] w-[176px] px-8">
Найти
</Button>
</Link>
</div>
</CardContent>
</Card>

View File

@ -42,6 +42,9 @@ export function DatePicker({
const [internalArrivalTime, setInternalArrivalTime] = React.useState("13:00");
const [open, setOpen] = React.useState(false);
// Определяем, является ли компонент контролируемым
const isControlled = value !== undefined || externalDepartureTime !== undefined || externalArrivalTime !== undefined;
// Используем внешние значения, если они предоставлены, иначе внутренние
const date = value !== undefined ? (value || undefined) : internalDate;
const departureTime = externalDepartureTime !== undefined ? externalDepartureTime : internalDepartureTime;
@ -50,7 +53,7 @@ export function DatePicker({
const handleDateChange = (newDate: Date | undefined) => {
if (onDateChange) {
onDateChange(newDate);
} else {
} else if (!isControlled) {
setInternalDate(newDate);
}
};
@ -58,7 +61,7 @@ export function DatePicker({
const handleDepartureTimeChange = (time: string) => {
if (onDepartureTimeChange) {
onDepartureTimeChange(time);
} else {
} else if (!isControlled) {
setInternalDepartureTime(time);
}
};
@ -66,7 +69,7 @@ export function DatePicker({
const handleArrivalTimeChange = (time: string) => {
if (onArrivalTimeChange) {
onArrivalTimeChange(time);
} else {
} else if (!isControlled) {
setInternalArrivalTime(time);
}
};