BusyBee3333 4e6467ffb0 Add CRESync CRM application with Setup page
- 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>
2026-01-14 17:30:55 -05:00

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;