import { SyntheticEvent, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import userService from '../api/services/userService'; import Duplicate from '../assets/duplicate.svg'; import Edit from '../assets/edit.svg'; import Link from '../assets/link-gray.svg'; import Monitoring from '../assets/monitoring.svg'; import Pin from '../assets/pin.svg'; import Trash from '../assets/red-trash.svg'; import ThreeDots from '../assets/three-dots.svg'; import UnPin from '../assets/unpin.svg'; import AgentImage from '../components/AgentImage'; import ContextMenu, { MenuOption } from '../components/ContextMenu'; import ConfirmationModal from '../modals/ConfirmationModal'; import { ActiveState } from '../models/misc'; import { selectAgents, selectToken, setAgents, setSelectedAgent, } from '../preferences/preferenceSlice'; import { Agent } from './types'; type AgentCardProps = { agent: Agent; agents: Agent[]; updateAgents?: (agents: Agent[]) => void; section: string; }; export default function AgentCard({ agent, agents, updateAgents, section, }: AgentCardProps) { const navigate = useNavigate(); const dispatch = useDispatch(); const token = useSelector(selectToken); const userAgents = useSelector(selectAgents); const [isMenuOpen, setIsMenuOpen] = useState(false); const [deleteConfirmation, setDeleteConfirmation] = useState('INACTIVE'); const menuRef = useRef(null); const menuOptionsConfig: Record = { template: [ { icon: Duplicate, label: 'Duplicate', onClick: (e: SyntheticEvent) => { e.stopPropagation(); handleDuplicate(); }, variant: 'primary', iconWidth: 18, iconHeight: 18, }, ], user: [ { icon: Monitoring, label: 'Logs', onClick: (e: SyntheticEvent) => { e.stopPropagation(); navigate(`/agents/logs/${agent.id}`); }, variant: 'primary', iconWidth: 14, iconHeight: 14, }, { icon: Edit, label: 'Edit', onClick: (e: SyntheticEvent) => { e.stopPropagation(); navigate(`/agents/edit/${agent.id}`); }, variant: 'primary', iconWidth: 14, iconHeight: 14, }, ...(agent.status === 'published' ? [ { icon: agent.pinned ? UnPin : Pin, label: agent.pinned ? 'Unpin' : 'Pin agent', onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); }, variant: 'primary' as const, iconWidth: 18, iconHeight: 18, }, ] : []), { icon: Trash, label: 'Delete', onClick: (e: SyntheticEvent) => { e.stopPropagation(); setDeleteConfirmation('ACTIVE'); }, variant: 'danger', iconWidth: 13, iconHeight: 13, }, ], shared: [ { icon: Link, label: 'Open', onClick: (e: SyntheticEvent) => { e.stopPropagation(); navigate(`/agents/shared/${agent.shared_token}`); }, variant: 'primary', iconWidth: 12, iconHeight: 12, }, { icon: agent.pinned ? UnPin : Pin, label: agent.pinned ? 'Unpin' : 'Pin agent', onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); }, variant: 'primary', iconWidth: 18, iconHeight: 18, }, { icon: Trash, label: 'Remove', onClick: (e: SyntheticEvent) => { e.stopPropagation(); handleHideSharedAgent(); }, variant: 'danger', iconWidth: 13, iconHeight: 13, }, ], }; const menuOptions = menuOptionsConfig[section] || []; const handleClick = () => { if (section === 'user') { if (agent.status === 'published') { dispatch(setSelectedAgent(agent)); navigate(`/`); } } if (section === 'shared') { navigate(`/agents/shared/${agent.shared_token}`); } }; const togglePin = async () => { try { const response = await userService.togglePinAgent(agent.id ?? '', token); if (!response.ok) throw new Error('Failed to pin agent'); const updatedAgents = agents.map((prevAgent) => { if (prevAgent.id === agent.id) return { ...prevAgent, pinned: !prevAgent.pinned }; return prevAgent; }); updateAgents?.(updatedAgents); } catch (error) { console.error('Error:', error); } }; const handleHideSharedAgent = async () => { try { const response = await userService.removeSharedAgent( agent.id ?? '', token, ); if (!response.ok) throw new Error('Failed to hide shared agent'); const updatedAgents = agents.filter( (prevAgent) => prevAgent.id !== agent.id, ); updateAgents?.(updatedAgents); } catch (error) { console.error('Error:', error); } }; const handleDelete = async () => { try { const response = await userService.deleteAgent(agent.id ?? '', token); if (!response.ok) throw new Error('Failed to delete agent'); const updatedAgents = agents.filter( (prevAgent) => prevAgent.id !== agent.id, ); updateAgents?.(updatedAgents); } catch (error) { console.error('Error:', error); } }; const handleDuplicate = async () => { try { const response = await userService.adoptAgent(agent.id ?? '', token); if (!response.ok) throw new Error('Failed to duplicate agent'); const data = await response.json(); if (userAgents) { const updatedAgents = [...userAgents, data.agent]; dispatch(setAgents(updatedAgents)); } else dispatch(setAgents([data.agent])); } catch (error) { console.error('Error:', error); } }; return (
{ e.stopPropagation(); handleClick(); }} >
{ e.stopPropagation(); setIsMenuOpen(true); }} className="absolute top-4 right-4 z-10 cursor-pointer" > {'use-agent'}
{agent.status === 'draft' && (

{`(Draft)`}

)}

{agent.name}

{agent.description}

{ handleDelete(); setDeleteConfirmation('INACTIVE'); }} cancelLabel="Cancel" variant="danger" />
); }