128 lines
3.7 KiB
TypeScript
128 lines
3.7 KiB
TypeScript
import React, { useState, useEffect, useRef } from "react";
|
|
|
|
interface DropdownProps {
|
|
header: string;
|
|
options: string[];
|
|
onSelect: (option: string) => void;
|
|
search?: boolean;
|
|
onClick?: () => void;
|
|
onChange?: () => void;
|
|
}
|
|
|
|
const RegularDropDown: React.FC<DropdownProps> = ({
|
|
header,
|
|
options,
|
|
onSelect,
|
|
search = true,
|
|
onClick,
|
|
onChange,
|
|
}) => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [selectedOption, setSelectedOption] = useState<string | null>(null);
|
|
const [searchTerm, setSearchTerm] = useState(""); // State to store search term
|
|
const [filteredOptions, setFilteredOptions] = useState<string[]>(options); // State for filtered options
|
|
const dropdownRef = useRef<HTMLDivElement>(null); // Ref for the dropdown container
|
|
|
|
// Reset selectedOption when the dropdown closes
|
|
useEffect(() => {
|
|
if (!isOpen) {
|
|
setSelectedOption(null);
|
|
setSearchTerm(""); // Clear the search term when the dropdown closes
|
|
setFilteredOptions(options); // Reset filtered options when the dropdown closes
|
|
}
|
|
}, [isOpen, options]);
|
|
|
|
// Reset selectedOption when the header prop changes
|
|
useEffect(() => {
|
|
setSelectedOption(null);
|
|
setSearchTerm(""); // Reset search term if header changes
|
|
setFilteredOptions(options); // Reset options if header changes
|
|
}, [header, options]);
|
|
|
|
// Close dropdown if clicked outside
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (
|
|
dropdownRef.current &&
|
|
!dropdownRef.current.contains(event.target as Node)
|
|
) {
|
|
setIsOpen(false);
|
|
}
|
|
};
|
|
|
|
document.addEventListener("click", handleClickOutside);
|
|
|
|
return () => {
|
|
document.removeEventListener("click", handleClickOutside);
|
|
};
|
|
}, []);
|
|
|
|
// Toggle the dropdown
|
|
const toggleDropdown = () => {
|
|
setIsOpen((prev) => !prev);
|
|
};
|
|
|
|
// Handle option selection
|
|
const handleOptionClick = (option: string) => {
|
|
setSelectedOption(option);
|
|
onSelect(option);
|
|
setIsOpen(false);
|
|
};
|
|
|
|
// Handle search input change
|
|
const handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const term = event.target.value;
|
|
setSearchTerm(term);
|
|
|
|
// Filter options based on the search term
|
|
const filtered = options.filter((option) =>
|
|
option.toLowerCase().includes(term.toLowerCase())
|
|
);
|
|
setFilteredOptions(filtered);
|
|
};
|
|
|
|
return (
|
|
<div className="regularDropdown-container" ref={dropdownRef}>
|
|
{/* Dropdown Header */}
|
|
<div className="dropdown-header flex-sb" onClick={toggleDropdown}>
|
|
<div className="key">{selectedOption || header}</div>
|
|
<div className="icon">▾</div>
|
|
</div>
|
|
|
|
{/* Dropdown Options */}
|
|
{isOpen && (
|
|
<div className="dropdown-options">
|
|
{/* Search Bar */}
|
|
{search && (
|
|
<div className="dropdown-search">
|
|
<input
|
|
type="text"
|
|
placeholder="Search..."
|
|
value={searchTerm}
|
|
onChange={handleSearchChange}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{/* Filtered Options */}
|
|
{filteredOptions.length > 0 ? (
|
|
filteredOptions.map((option, index) => (
|
|
<div
|
|
className="option"
|
|
key={index}
|
|
onClick={() => handleOptionClick(option)}
|
|
>
|
|
{option}
|
|
</div>
|
|
))
|
|
) : (
|
|
<div className="no-options">No options found</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default RegularDropDown;
|