- Build complete Next.js CRM for commercial real estate - Add authentication with JWT sessions and role-based access - Add GoHighLevel API integration for contacts, conversations, opportunities - Add AI-powered Control Center with tool calling - Add Setup page with onboarding checklist (/setup) - Add sidebar navigation with Setup menu item - Fix type errors in onboarding API, GHL services, and control center tools - Add Prisma schema with SQLite for local development - Add UI components with clay morphism design system Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
111 lines
3.2 KiB
TypeScript
111 lines
3.2 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import { Wrench, ChevronDown, ChevronUp, Loader2 } from 'lucide-react';
|
|
import type { ToolCall } from '@/types/control-center';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface ToolCallCardProps {
|
|
toolCall: ToolCall;
|
|
isExecuting?: boolean;
|
|
}
|
|
|
|
export const ToolCallCard: React.FC<ToolCallCardProps> = ({
|
|
toolCall,
|
|
isExecuting = false,
|
|
}) => {
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
|
|
const hasInput = toolCall.input && Object.keys(toolCall.input).length > 0;
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'bg-[#E8EDF2] rounded-2xl border-2 border-transparent',
|
|
'shadow-[4px_4px_8px_#c5c9d1,-4px_-4px_8px_#ffffff]',
|
|
'transition-all duration-300',
|
|
isExecuting && 'border-amber-400'
|
|
)}
|
|
>
|
|
{/* Header */}
|
|
<div
|
|
className={cn(
|
|
'flex items-center gap-3 p-4',
|
|
hasInput && 'cursor-pointer'
|
|
)}
|
|
onClick={() => hasInput && setIsExpanded(!isExpanded)}
|
|
>
|
|
{/* Tool Icon */}
|
|
<div
|
|
className={cn(
|
|
'p-2.5 rounded-xl',
|
|
isExecuting
|
|
? 'bg-amber-100 text-amber-600'
|
|
: 'bg-indigo-100 text-indigo-600'
|
|
)}
|
|
>
|
|
{isExecuting ? (
|
|
<Loader2 size={18} className="animate-spin" />
|
|
) : (
|
|
<Wrench size={18} />
|
|
)}
|
|
</div>
|
|
|
|
{/* Tool Name */}
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2">
|
|
<span className="font-semibold text-gray-800 truncate">
|
|
{toolCall.name}
|
|
</span>
|
|
{isExecuting && (
|
|
<span className="text-xs text-amber-600 font-medium">
|
|
Executing...
|
|
</span>
|
|
)}
|
|
</div>
|
|
{!isExpanded && hasInput && (
|
|
<p className="text-xs text-gray-500 mt-0.5 truncate">
|
|
{Object.keys(toolCall.input).length} parameter
|
|
{Object.keys(toolCall.input).length !== 1 ? 's' : ''}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Expand/Collapse Toggle */}
|
|
{hasInput && (
|
|
<button
|
|
className={cn(
|
|
'p-1.5 rounded-lg transition-colors',
|
|
'hover:bg-gray-200 text-gray-500'
|
|
)}
|
|
aria-label={isExpanded ? 'Collapse parameters' : 'Expand parameters'}
|
|
>
|
|
{isExpanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
{/* Collapsible Parameters */}
|
|
{isExpanded && hasInput && (
|
|
<div className="px-4 pb-4">
|
|
<div
|
|
className={cn(
|
|
'bg-[#F5F8FA] rounded-xl p-3',
|
|
'shadow-[inset_2px_2px_4px_rgba(0,0,0,0.05),inset_-2px_-2px_4px_rgba(255,255,255,0.7)]'
|
|
)}
|
|
>
|
|
<p className="text-xs font-medium text-gray-500 uppercase tracking-wide mb-2">
|
|
Parameters
|
|
</p>
|
|
<pre className="text-xs text-gray-700 overflow-x-auto whitespace-pre-wrap break-words font-mono">
|
|
{JSON.stringify(toolCall.input, null, 2)}
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ToolCallCard;
|