- 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>
226 lines
6.2 KiB
TypeScript
226 lines
6.2 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { AlertTriangle, Wifi, WifiOff, Loader2 } from 'lucide-react';
|
|
import { cn } from '@/lib/utils';
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipProvider,
|
|
TooltipTrigger,
|
|
} from '@/components/ui/tooltip';
|
|
|
|
type ConnectionStatus = 'connected' | 'connecting' | 'error' | 'idle';
|
|
|
|
interface StatusIndicatorProps {
|
|
/** Current connection status */
|
|
status: ConnectionStatus;
|
|
/** Whether MCP (Model Context Protocol) is connected */
|
|
mcpConnected?: boolean;
|
|
/** Optional custom label to display */
|
|
label?: string;
|
|
}
|
|
|
|
/**
|
|
* Status configuration for each connection state
|
|
*/
|
|
const STATUS_CONFIG: Record<
|
|
ConnectionStatus,
|
|
{
|
|
color: string;
|
|
bgColor: string;
|
|
pulseColor?: string;
|
|
text: string;
|
|
icon: React.ReactNode;
|
|
}
|
|
> = {
|
|
connected: {
|
|
color: 'bg-green-500',
|
|
bgColor: 'bg-green-100',
|
|
pulseColor: 'bg-green-400',
|
|
text: 'Connected',
|
|
icon: <Wifi className="w-3.5 h-3.5 text-green-600" />,
|
|
},
|
|
connecting: {
|
|
color: 'bg-yellow-500',
|
|
bgColor: 'bg-yellow-100',
|
|
pulseColor: 'bg-yellow-400',
|
|
text: 'Connecting...',
|
|
icon: <Loader2 className="w-3.5 h-3.5 text-yellow-600 animate-spin" />,
|
|
},
|
|
error: {
|
|
color: 'bg-red-500',
|
|
bgColor: 'bg-red-100',
|
|
text: 'Connection Error',
|
|
icon: <WifiOff className="w-3.5 h-3.5 text-red-600" />,
|
|
},
|
|
idle: {
|
|
color: 'bg-gray-400',
|
|
bgColor: 'bg-gray-100',
|
|
text: 'Idle',
|
|
icon: <Wifi className="w-3.5 h-3.5 text-gray-500" />,
|
|
},
|
|
};
|
|
|
|
/**
|
|
* StatusIndicator - Shows connection status for the Control Center
|
|
*
|
|
* Displays a colored dot indicator with tooltip showing detailed status.
|
|
* Also shows warning if MCP is not connected.
|
|
*/
|
|
export const StatusIndicator: React.FC<StatusIndicatorProps> = ({
|
|
status,
|
|
mcpConnected = true,
|
|
label,
|
|
}) => {
|
|
const config = STATUS_CONFIG[status];
|
|
const showMcpWarning = !mcpConnected;
|
|
|
|
return (
|
|
<TooltipProvider>
|
|
<div className="flex items-center gap-2">
|
|
{/* Main status indicator */}
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<div
|
|
className={cn(
|
|
'flex items-center gap-2',
|
|
'px-3 py-1.5',
|
|
'bg-[#F0F4F8]',
|
|
'rounded-full',
|
|
'shadow-[3px_3px_6px_#c5c9d1,-3px_-3px_6px_#ffffff]',
|
|
'cursor-default',
|
|
'transition-all duration-200'
|
|
)}
|
|
>
|
|
{/* Status dot with pulse animation for active states */}
|
|
<div className="relative flex items-center justify-center">
|
|
<span
|
|
className={cn(
|
|
'w-2.5 h-2.5',
|
|
'rounded-full',
|
|
config.color,
|
|
'relative z-10'
|
|
)}
|
|
/>
|
|
{config.pulseColor && (
|
|
<span
|
|
className={cn(
|
|
'absolute',
|
|
'w-2.5 h-2.5',
|
|
'rounded-full',
|
|
config.pulseColor,
|
|
'animate-ping',
|
|
'opacity-75'
|
|
)}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* Status text/label */}
|
|
<span className="text-xs font-medium text-gray-600">
|
|
{label || config.text}
|
|
</span>
|
|
</div>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom" className="text-xs">
|
|
<div className="flex items-center gap-2">
|
|
{config.icon}
|
|
<span>{config.text}</span>
|
|
</div>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
|
|
{/* MCP Warning indicator */}
|
|
{showMcpWarning && (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<div
|
|
className={cn(
|
|
'flex items-center gap-1.5',
|
|
'px-2.5 py-1.5',
|
|
'bg-amber-50',
|
|
'border border-amber-200',
|
|
'rounded-full',
|
|
'cursor-default',
|
|
'transition-all duration-200'
|
|
)}
|
|
>
|
|
<AlertTriangle className="w-3.5 h-3.5 text-amber-600" />
|
|
<span className="text-xs font-medium text-amber-700">
|
|
Limited
|
|
</span>
|
|
</div>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom" className="max-w-[200px] text-xs">
|
|
<div className="flex flex-col gap-1">
|
|
<span className="font-medium text-amber-700">
|
|
MCP Not Connected
|
|
</span>
|
|
<span className="text-gray-600">
|
|
Some features may be unavailable. Tool execution will be limited.
|
|
</span>
|
|
</div>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
)}
|
|
</div>
|
|
</TooltipProvider>
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Compact version of StatusIndicator - just shows the dot
|
|
*/
|
|
export const StatusDot: React.FC<{
|
|
status: ConnectionStatus;
|
|
className?: string;
|
|
}> = ({ status, className }) => {
|
|
const config = STATUS_CONFIG[status];
|
|
|
|
return (
|
|
<TooltipProvider>
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<div
|
|
className={cn(
|
|
'relative flex items-center justify-center',
|
|
'w-4 h-4',
|
|
className
|
|
)}
|
|
>
|
|
<span
|
|
className={cn(
|
|
'w-2.5 h-2.5',
|
|
'rounded-full',
|
|
config.color,
|
|
'relative z-10'
|
|
)}
|
|
/>
|
|
{config.pulseColor && (
|
|
<span
|
|
className={cn(
|
|
'absolute',
|
|
'w-2.5 h-2.5',
|
|
'rounded-full',
|
|
config.pulseColor,
|
|
'animate-ping',
|
|
'opacity-75'
|
|
)}
|
|
/>
|
|
)}
|
|
</div>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="right" className="text-xs">
|
|
<div className="flex items-center gap-2">
|
|
{config.icon}
|
|
<span>{config.text}</span>
|
|
</div>
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</TooltipProvider>
|
|
);
|
|
};
|
|
|
|
export default StatusIndicator;
|