Files
protekauto-frontend/src/components/FiltersPanelMobile.tsx
2025-06-26 06:59:59 +03:00

170 lines
5.7 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.

import React, { useEffect, useState } from "react";
import FilterDropdown from "./filters/FilterDropdown";
import FilterRange from "./filters/FilterRange";
import type { FilterConfig } from "./Filters";
interface FiltersPanelMobileProps {
filters: FilterConfig[];
open: boolean;
onClose: () => void;
onApply?: () => void;
searchQuery: string;
onSearchChange: (value: string) => void;
filterValues?: {[key: string]: any};
onFilterChange?: (type: string, value: any) => void;
}
const FiltersPanelMobile: React.FC<FiltersPanelMobileProps> = ({
filters,
open,
onClose,
onApply,
searchQuery,
onSearchChange,
filterValues = {},
onFilterChange
}) => {
const [localFilterValues, setLocalFilterValues] = useState<{[key: string]: any}>({});
// Синхронизируем локальные значения с внешними при открытии панели
useEffect(() => {
if (open) {
setLocalFilterValues(filterValues);
}
}, [open, filterValues]);
useEffect(() => {
if (open) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "";
}
return () => {
document.body.style.overflow = "";
};
}, [open]);
const handleLocalFilterChange = (type: string, value: any) => {
setLocalFilterValues(prev => ({
...prev,
[type]: value
}));
};
const handleApply = () => {
// Применяем все локальные фильтры к основному состоянию
Object.entries(localFilterValues).forEach(([key, value]) => {
onFilterChange?.(key, value);
});
onApply?.();
};
const handleClearFilters = () => {
setLocalFilterValues({});
onSearchChange('');
// Сбрасываем фильтры в родительском компоненте
Object.keys(filterValues).forEach(key => {
onFilterChange?.(key, []);
});
};
return (
<>
{/* Overlay */}
<div
className={`filters-panel-mobile-overlay${open ? " open" : ""}`}
onClick={onClose}
style={{ zIndex: 1000 }}
/>
{/* Drawer */}
<div
className={`filters-panel-mobile-drawer${open ? " open" : ""}`}
aria-hidden={!open}
style={{ zIndex: 1001 }}
>
{/* Header */}
<div className="filters-panel-mobile-header">
<span className="filters-panel-mobile-title">Фильтры</span>
<button className="filters-panel-mobile-close" onClick={onClose} aria-label="Закрыть фильтры">&times;</button>
</div>
{/* Search */}
<div className="filters-panel-mobile-content-search">
<div className="div-block-2">
<div className="form-block">
<form className="form" onSubmit={e => e.preventDefault()}>
<a href="#" className="link-block-3 w-inline-block">
<span className="code-embed-6 w-embed">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.5 17.5L13.8834 13.8833" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
<path d="M9.16667 15.8333C12.8486 15.8333 15.8333 12.8486 15.8333 9.16667C15.8333 5.48477 12.8486 2.5 9.16667 2.5C5.48477 2.5 2.5 5.48477 2.5 9.16667C2.5 12.8486 5.48477 15.8333 9.16667 15.8333Z" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</span>
</a>
<input
className="text-field w-input"
maxLength={256}
name="Search"
placeholder="Поиск по названию, бренду или артикулу"
type="text"
id="Search-4"
value={searchQuery}
onChange={e => onSearchChange(e.target.value)}
/>
</form>
</div>
</div>
</div>
{/* Filters */}
<div className="filters-panel-mobile-content">
{filters.map((filter, idx) => {
if (filter.type === "dropdown") {
return (
<FilterDropdown
key={filter.title + idx}
title={filter.title}
options={filter.options}
multi={filter.multi}
showAll={filter.showAll}
selectedValues={localFilterValues[filter.title] || []}
onChange={(values) => handleLocalFilterChange(filter.title, values)}
isMobile
/>
);
}
if (filter.type === "range") {
return (
<FilterRange
key={filter.title + idx}
title={filter.title}
min={filter.min}
max={filter.max}
value={localFilterValues[filter.title] || null}
onChange={(value) => handleLocalFilterChange(filter.title, value)}
isMobile
/>
);
}
return null;
})}
</div>
{/* Apply Button */}
<div className="flex gap-2 p-4">
<button
className="filters-panel-mobile-clear flex-1 bg-gray-200 text-gray-700 py-3 px-4 rounded-lg font-medium"
onClick={handleClearFilters}
>
Сбросить
</button>
<button
className="filters-panel-mobile-apply flex-1 bg-red-600 text-white py-3 px-4 rounded-lg font-medium"
onClick={handleApply}
>
Показать
</button>
</div>
</div>
</>
);
};
export default FiltersPanelMobile;