import React, { useEffect, useRef, useState, useLayoutEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { selectToken } from '../preferences/preferenceSlice'; import userService from '../api/services/userService'; import { UserToolType } from '../settings/types'; import Input from './Input'; import RedirectIcon from '../assets/redirect.svg'; import NoFilesIcon from '../assets/no-files.svg'; import NoFilesDarkIcon from '../assets/no-files-dark.svg'; import CheckmarkIcon from '../assets/checkmark.svg'; import { useDarkTheme } from '../hooks'; interface ToolsPopupProps { isOpen: boolean; onClose: () => void; anchorRef: React.RefObject; } export default function ToolsPopup({ isOpen, onClose, anchorRef, }: ToolsPopupProps) { const { t } = useTranslation(); const token = useSelector(selectToken); const [userTools, setUserTools] = React.useState([]); const [loading, setLoading] = React.useState(false); const [searchTerm, setSearchTerm] = useState(''); const [isDarkTheme] = useDarkTheme(); const popupRef = useRef(null); const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0, maxHeight: 0, showAbove: false, }); useLayoutEffect(() => { if (!isOpen || !anchorRef.current) return; const updatePosition = () => { if (!anchorRef.current) return; const rect = anchorRef.current.getBoundingClientRect(); const viewportHeight = window.innerHeight; const viewportWidth = window.innerWidth; const spaceAbove = rect.top; const spaceBelow = viewportHeight - rect.bottom; const showAbove = spaceAbove > spaceBelow && spaceAbove >= 300; const maxHeight = showAbove ? spaceAbove - 16 : spaceBelow - 16; const left = Math.min( rect.left, viewportWidth - Math.min(462, viewportWidth * 0.95) - 10, ); setPopupPosition({ top: showAbove ? rect.top - 8 : rect.bottom + 8, left, maxHeight: Math.min(600, maxHeight), showAbove, }); }; updatePosition(); window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); }, [isOpen, anchorRef]); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( popupRef.current && !popupRef.current.contains(event.target as Node) && anchorRef.current && !anchorRef.current.contains(event.target as Node) ) { onClose(); } }; if (isOpen) { document.addEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [onClose, anchorRef, isOpen]); useEffect(() => { if (isOpen) { getUserTools(); } }, [isOpen, token]); const getUserTools = () => { setLoading(true); userService .getUserTools(token) .then((res) => { return res.json(); }) .then((data) => { setUserTools(data.tools); setLoading(false); }) .catch((error) => { console.error('Error fetching tools:', error); setLoading(false); }); }; const updateToolStatus = (toolId: string, newStatus: boolean) => { userService .updateToolStatus({ id: toolId, status: newStatus }, token) .then(() => { setUserTools((prevTools) => prevTools.map((tool) => tool.id === toolId ? { ...tool, status: newStatus } : tool, ), ); }) .catch((error) => { console.error('Failed to update tool status:', error); }); }; if (!isOpen) return null; const filteredTools = userTools.filter((tool) => tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()), ); return (

{t('settings.tools.label')}

setSearchTerm(e.target.value)} placeholder={t('settings.tools.searchPlaceholder')} labelBgClassName="bg-lotion dark:bg-charleston-green-2" borderVariant="thin" className="mb-4" />
{loading ? (
) : (
{filteredTools.length === 0 ? (
No tools found

{t('settings.tools.noToolsFound')}

) : ( filteredTools.map((tool) => (
updateToolStatus(tool.id, !tool.status)} className="dark:border-dim-gray dark:hover:bg-charleston-green-3 flex items-center justify-between border-b border-[#D9D9D9] p-3 hover:bg-gray-100" >
{`${tool.displayName}

{tool.customName || tool.displayName}

{tool.status && ( Tool enabled )}
)) )}
)}
); }