"use client"; import React, { useEffect, useRef, useState, useId } from "react"; import { type FieldErrors, type FieldValues, type Path, type UseFormRegisterReturn, } from "react-hook-form"; interface Option { value: string; text: string; selected: boolean; } type MultiSelectProps = { label: string; items: { value: string; text: string }[]; errors?: FieldErrors; required?: boolean; placeholder?: string; className?: string; } & UseFormRegisterReturn>; function MultiSelect({ name, label, items, errors, required, placeholder = "Select an option", className, onChange, onBlur, ref, }: MultiSelectProps) { const id = useId(); const error = errors && errors[name]; const [options, setOptions] = useState([]); const [selected, setSelected] = useState([]); const [show, setShow] = useState(false); const dropdownRef = useRef(null); const trigger = useRef(null); useEffect(() => { setOptions( items.map((item) => ({ ...item, selected: false, })), ); }, [items]); const open = () => { setShow(true); }; const isOpen = () => { return show === true; }; const combinedRef = (el: HTMLDivElement) => { trigger.current = el; if (typeof ref === "function") { ref(el); } }; const handleSelect = (index: number) => { const newOptions = [...options]; let newSelected = [...selected]; if (!newOptions[index].selected) { newOptions[index].selected = true; newSelected.push(index); } else { newOptions[index].selected = false; newSelected = newSelected.filter((i) => i !== index); } setOptions(newOptions); setSelected(newSelected); const selectedValues = newSelected.map((i) => options[i].value); onChange?.({ target: { name, value: selectedValues } }); }; const remove = (index: number, event: React.MouseEvent) => { event.stopPropagation(); const newOptions = [...options]; const newSelected = selected.filter((i) => i !== index); newOptions[index].selected = false; setOptions(newOptions); setSelected(newSelected); const selectedValues = newSelected.map((i) => options[i].value); onChange?.({ target: { name, value: selectedValues } }); }; useEffect(() => { const clickHandler = ({ target }: MouseEvent) => { if (!dropdownRef.current) return; if ( !show || dropdownRef.current.contains(target as Node) || trigger.current?.contains(target as Node) ) return; setShow(false); }; document.addEventListener("click", clickHandler); return () => document.removeEventListener("click", clickHandler); }, [show]); return (
{selected.map((index) => (
{options[index]?.text}
remove(index, e)} className="hover:text-red cursor-pointer pl-2" >
))} {selected.length === 0 && (
{placeholder}
)}
{options.map((option, index) => (
handleSelect(index)} >
{option.text}
))}
{error && (

{error.message as string}

)}
); } export default MultiSelect;