/* eslint-disable @typescript-eslint/no-explicit-any */ // CustomizedSelect: Proper select box component styled like SelectField import React, { useState, useRef, useEffect } from "react"; import ThreeDotsLoader from "../Loader/ThreeDotsLoader"; interface Options { id: string; name: string; code: string; } interface Option { id: string; name: string; } interface CustomizedSelectProps { options: Options[]; value: string | Option | null; onChange: (value: string | Option | null) => void; errors?: string; placeholder?: string; className?: string; width?: string; icon?: React.ReactNode; label?: string; allowNewOption?: boolean; isCreatable?: boolean; isLoading?: boolean; name?: string; referenceData?: { road?: { id: number; name: string; code?: string; }; block?: { id: number; name: string; code?: string; } } | any; } export const CustomizedSelect: React.FC = ({ options = [], value, onChange, errors, placeholder = "Select an option", className = "", width = "", icon, label, allowNewOption = false, isCreatable = false, isLoading = false, name = "", referenceData }) => { const [showDropdown, setShowDropdown] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const selectRef = useRef(null); const [localOptions, setLocalOptions] = useState(options); useEffect(() => { setLocalOptions(options); }, [options]); useEffect(() => { if (!showDropdown) return; const handleClickOutside = (event: MouseEvent) => { if (selectRef.current && !selectRef.current.contains(event.target as Node)) { setShowDropdown(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [showDropdown]); const handleOptionSelect = (option: Option) => { onChange(option); setShowDropdown(false); setSearchQuery(""); }; const handleToggleDropdown = () => { if (!isLoading) { setShowDropdown(!showDropdown); if (!showDropdown) setSearchQuery(""); } }; const handleClearSelection = () => { onChange(null); setSearchQuery(""); }; const getDisplayValue = () => { if (typeof value === 'object' && value !== null) { return value.name; } return value || placeholder; }; const isOptionSelected = typeof value === 'object' && value !== null; // Filter options by search query (code or name, case-insensitive) const filteredOptions = localOptions.filter(option => { const q = searchQuery.trim().toLowerCase(); if (!q) return true; return ( option.name.toLowerCase().includes(q) || (option.code && option.code.toLowerCase().includes(q)) ); }); const handleAddNewOption = () => { const trimmedQuery = searchQuery.trim(); if (!trimmedQuery) return; // Prevent duplicate const exists = localOptions.some( (option) => option.name.toLowerCase() === trimmedQuery.toLowerCase() ); if (exists) return; const newOption = { id: trimmedQuery, name: trimmedQuery, code: '', }; const updatedOptions = [...localOptions, newOption]; setLocalOptions(updatedOptions); onChange(newOption); setShowDropdown(false); setSearchQuery(""); }; return ( <>
{/* Icon */} {icon && (
)}
{getDisplayValue()}
{/* Actions: clear, loader, arrow */}
{isOptionSelected && ( )} {isLoading && (
)}
{/* Dropdown */} {showDropdown && (
{/* Search input */}
setSearchQuery(e.target.value)} placeholder="Search by no. or name..." style={{ width: "100%", padding: "6px 8px", paddingLeft: "8px", border: "1px solid #ddd", borderRadius: "4px", fontSize: "14px", }} className="padding-left-8" autoFocus onClick={e => e.stopPropagation()} />
{isCreatable && ( <>
)} {!allowNewOption && filteredOptions.length === 0 && (
No options available
)} {filteredOptions.length > 0 && ( <> {filteredOptions.map((option) => (
handleOptionSelect(option)} > {option?.id === "add-new" ? (<>

+ Add new

{/*
*/} ) : <>

{option?.code} - {option.name}

}
))} )}
)} {/* Label */} {label && ( )}
); };