import React, { useState, useEffect, useRef } from 'react'; import apiService from '../services/apiService'; interface LinkFieldProps { label: string; doctype: string; value: string; onChange: (value: string) => void; placeholder?: string; disabled?: boolean; filters?: Record; } const LinkField: React.FC = ({ label, doctype, value, onChange, placeholder, disabled = false, filters = {}, }) => { const [searchResults, setSearchResults] = useState<{ value: string; description?: string }[]>([]); const [searchText, setSearchText] = useState(''); const [isDropdownOpen, setDropdownOpen] = useState(false); const containerRef = useRef(null); // Fetch link options from ERPNext with filters const searchLink = async (text: string = '') => { try { const params = new URLSearchParams({ doctype, txt: text, }); // Add filters if provided if (filters && Object.keys(filters).length > 0) { // Convert filters to JSON string for Frappe API params.append('filters', JSON.stringify(filters)); } const response = await apiService.apiCall<{ value: string; description?: string }[]>( `/api/method/frappe.desk.search.search_link?${params.toString()}` ); setSearchResults(response || []); } catch (error) { console.error(`Error fetching ${doctype} links:`, error); setSearchResults([]); } }; // Fetch default options when dropdown opens or filters change useEffect(() => { if (isDropdownOpen) { searchLink(searchText || ''); } }, [isDropdownOpen, filters]); // Re-fetch when filters change // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(event.target as Node)) { setDropdownOpen(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, []); return (
!disabled && setDropdownOpen(true)} onChange={(e) => { const text = e.target.value; setSearchText(text); searchLink(text); onChange(text); }} /> {isDropdownOpen && searchResults.length > 0 && !disabled && (
    {searchResults.map((item, idx) => (
  • { onChange(item.value); setDropdownOpen(false); }} className={`px-3 py-2 cursor-pointer text-gray-900 dark:text-gray-100 hover:bg-blue-500 dark:hover:bg-blue-600 hover:text-white ${value === item.value ? 'bg-blue-50 dark:bg-blue-700 font-semibold' : ''}`} > {item.value} {item.description && ( {item.description} )}
  • ))}
)} {/* Show message when no results found */} {isDropdownOpen && searchResults.length === 0 && !disabled && (
No results found
)}
); }; export default LinkField; // import React, { useState, useEffect, useRef } from 'react'; // import apiService from '../services/apiService'; // ✅ your ApiService // interface LinkFieldProps { // label: string; // doctype: string; // value: string; // onChange: (value: string) => void; // placeholder?: string; // disabled?: boolean; // filters?: Record // } // const LinkField: React.FC = ({ // label, // doctype, // value, // onChange, // placeholder, // disabled = false, // }) => { // const [searchResults, setSearchResults] = useState<{ value: string; description?: string }[]>([]); // const [searchText, setSearchText] = useState(''); // const [isDropdownOpen, setDropdownOpen] = useState(false); // const containerRef = useRef(null); // // Fetch link options from ERPNext // const searchLink = async (text: string = '') => { // try { // const params = new URLSearchParams({ doctype, txt: text }); // const response = await apiService.apiCall<{ value: string; description?: string }[]>( // `/api/method/frappe.desk.search.search_link?${params.toString()}` // ); // setSearchResults(response || []); // } catch (error) { // console.error(`Error fetching ${doctype} links:`, error); // } // }; // // Fetch default options when dropdown opens // useEffect(() => { // if (isDropdownOpen) searchLink(''); // }, [isDropdownOpen]); // // Close dropdown when clicking outside // useEffect(() => { // const handleClickOutside = (event: MouseEvent) => { // if (containerRef.current && !containerRef.current.contains(event.target as Node)) { // setDropdownOpen(false); // } // }; // document.addEventListener('mousedown', handleClickOutside); // return () => document.removeEventListener('mousedown', handleClickOutside); // }, []); // return ( //
// // !disabled && setDropdownOpen(true)} // onChange={(e) => { // const text = e.target.value; // setSearchText(text); // searchLink(text); // onChange(text); // }} // /> // {isDropdownOpen && searchResults.length > 0 && !disabled && ( //
    // {searchResults.map((item, idx) => ( //
  • { // onChange(item.value); // setDropdownOpen(false); // }} // className={`px-3 py-2 cursor-pointer // text-gray-900 dark:text-gray-100 // hover:bg-blue-500 dark:hover:bg-blue-600 // ${value === item.value ? 'bg-blue-50 dark:bg-blue-700 font-semibold' : ''}`} // > // {item.value} // {item.description && ( // {item.description} // )} //
  • // ))} //
// )} //
// ); // }; // export default LinkField;