diff --git a/components/ObjektSelector.tsx b/components/ObjektSelector.tsx index aa98104..616c11c 100644 --- a/components/ObjektSelector.tsx +++ b/components/ObjektSelector.tsx @@ -12,8 +12,6 @@ export default function ObjektSelector({ selected, onChange }: Props) { const [all, setAll] = useState([]); const [search, setSearch] = useState(''); const [dropdownOpen, setDropdownOpen] = useState(false); - const [newName, setNewName] = useState(''); - const [showNewInput, setShowNewInput] = useState(false); const wrapperRef = useRef(null); useEffect(() => { @@ -39,29 +37,44 @@ export default function ObjektSelector({ selected, onChange }: Props) { ? available.filter((o) => o.Name.toLowerCase().startsWith(search.toLowerCase())) : available; + const searchTrimmed = search.trim(); + const alreadySelected = searchTrimmed !== '' && selectedNames.has(searchTrimmed.toLowerCase()); + const exactAvailableMatch = available.find((o) => o.Name.toLowerCase() === searchTrimmed.toLowerCase()); + const showAddNew = searchTrimmed !== '' && !alreadySelected && !exactAvailableMatch; + function add(obj: ObjektOption) { onChange([...selected, { ID: obj.ID, Name: obj.Name }]); setSearch(''); setDropdownOpen(false); } - function addNew() { - const name = newName.trim(); - if (!name || selectedNames.has(name.toLowerCase())) return; - const existing = all.find((o) => o.Name.toLowerCase() === name.toLowerCase()); + function addNew(name: string) { + const trimmed = name.trim(); + if (!trimmed || selectedNames.has(trimmed.toLowerCase())) return; + const existing = all.find((o) => o.Name.toLowerCase() === trimmed.toLowerCase()); if (existing) { onChange([...selected, { ID: existing.ID, Name: existing.Name }]); } else { - onChange([...selected, { ID: null, Name: name }]); + onChange([...selected, { ID: null, Name: trimmed }]); } - setNewName(''); - setShowNewInput(false); + setSearch(''); + setDropdownOpen(false); } function remove(name: string) { onChange(selected.filter((o) => o.Name !== name)); } + function handleKeyDown(e: React.KeyboardEvent) { + if (e.key !== 'Enter') return; + e.preventDefault(); + if (filtered.length === 1 && !showAddNew) { + add(filtered[0]); + } else if (filtered.length === 0 && searchTrimmed) { + addNew(searchTrimmed); + } + } + return (
@@ -83,69 +96,40 @@ export default function ObjektSelector({ selected, onChange }: Props) { ))}
-
- {available.length > 0 && ( -
- { setSearch(e.target.value); setDropdownOpen(true); }} - onFocus={() => setDropdownOpen(true)} - placeholder="Objekt suchen..." - className="w-full px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm text-gray-900 focus:border-blue-500 focus:outline-none" - /> - {dropdownOpen && filtered.length > 0 && ( -
- {filtered.map((o) => ( - - ))} -
+
+ { setSearch(e.target.value); setDropdownOpen(true); }} + onFocus={() => setDropdownOpen(true)} + onKeyDown={handleKeyDown} + placeholder="Objekt suchen oder neu eingeben..." + className="w-full px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm text-gray-900 focus:border-blue-500 focus:outline-none" + /> + {dropdownOpen && (filtered.length > 0 || showAddNew) && ( +
+ {filtered.map((o) => ( + + ))} + {showAddNew && ( + )}
)} -
- - {showNewInput && ( -
- setNewName(e.target.value)} - onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addNew(); } }} - placeholder="Objektname eingeben" - className="flex-1 px-3 py-2 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none" - autoFocus - /> - - -
- )}
); }