127 lines
No EOL
5.8 KiB
TypeScript
Executable file
127 lines
No EOL
5.8 KiB
TypeScript
Executable file
import React from 'react';
|
|
import type { ReviewStatus, AgentName, AgentStatus } from '../types';
|
|
import { AGENT_NAMES } from '../constants';
|
|
import { LegalIcon } from './icons/LegalIcon';
|
|
import { BrandIcon } from './icons/BrandIcon';
|
|
import { CopyIcon } from './icons/CopyIcon';
|
|
import { CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon } from './icons/StatusIcons';
|
|
import { ChannelIcon } from './icons/ChannelIcon';
|
|
import { BestPracticeIcon } from './icons/BestPracticeIcon';
|
|
import { SpinnerIcon } from './icons/SpinnerIcon';
|
|
|
|
interface StatusDashboardProps {
|
|
status: ReviewStatus;
|
|
variant?: 'default' | 'hero';
|
|
}
|
|
|
|
interface StatusInfoProps {
|
|
status: string;
|
|
isHeroVariant?: boolean;
|
|
}
|
|
|
|
// FIX: Storing components instead of instantiated elements to avoid React.cloneElement type issues.
|
|
// Fix: Removed 'Best Practice' as it does not exist on AgentName type.
|
|
const agentIcons: Record<AgentName, React.FC<React.SVGProps<SVGSVGElement>>> = {
|
|
'Legal Agent': LegalIcon,
|
|
'Brand Agent': BrandIcon,
|
|
'Tone Agent': CopyIcon,
|
|
'Channel Agent': ChannelIcon,
|
|
};
|
|
|
|
const StatusInfo: React.FC<StatusInfoProps> = ({ status, isHeroVariant = false }) => {
|
|
const colors = isHeroVariant ? {
|
|
complete: 'text-green-300',
|
|
issues: 'text-yellow-300',
|
|
error: 'text-red-300',
|
|
pending: 'text-gray-400'
|
|
} : {
|
|
complete: 'text-green-600',
|
|
issues: 'text-yellow-600',
|
|
error: 'text-red-600',
|
|
pending: 'text-gray-500'
|
|
};
|
|
|
|
switch (status) {
|
|
case 'complete':
|
|
return <div className={`flex items-center ${colors.complete}`}><CheckCircleIcon className="h-5 w-5 mr-2" /> Pass</div>;
|
|
case 'issues-found':
|
|
return <div className={`flex items-center ${colors.issues}`}><ExclamationTriangleIcon className="h-5 w-5 mr-2" /> Issues Found</div>;
|
|
case 'error':
|
|
return <div className={`flex items-center ${colors.error}`}><InformationCircleIcon className="h-5 w-5 mr-2" /> Error</div>;
|
|
default:
|
|
return <div className={`flex items-center ${colors.pending}`}><InformationCircleIcon className="h-5 w-5 mr-2" /> Pending</div>;
|
|
}
|
|
};
|
|
|
|
export const StatusDashboard: React.FC<StatusDashboardProps> = ({ status, variant = 'default' }) => {
|
|
if (Object.keys(status).length === 0) return null;
|
|
|
|
const isHeroVariant = variant === 'hero';
|
|
|
|
const getTileClassName = (agentStatus: AgentStatus, isHero: boolean): string => {
|
|
const baseClasses = 'rounded-lg flex flex-col text-center transition-colors duration-500 ease-in-out';
|
|
|
|
if (isHero) {
|
|
const heroBase = `${baseClasses} p-4`;
|
|
switch (agentStatus) {
|
|
case 'complete':
|
|
return `${heroBase} bg-green-400/20`;
|
|
case 'issues-found':
|
|
return `${heroBase} bg-yellow-400/20`;
|
|
case 'error':
|
|
return `${heroBase} bg-red-400/20`;
|
|
default: // 'pending' or 'in-progress'
|
|
return `${heroBase} bg-white/10`;
|
|
}
|
|
} else {
|
|
const defaultBase = `${baseClasses} p-6 shadow-lg border`;
|
|
switch (agentStatus) {
|
|
case 'complete':
|
|
return `${defaultBase} bg-green-50 border-green-200`;
|
|
case 'issues-found':
|
|
return `${defaultBase} bg-yellow-50 border-yellow-200`;
|
|
case 'error':
|
|
return `${defaultBase} bg-red-50 border-red-200`;
|
|
default: // 'pending' or 'in-progress'
|
|
return `${defaultBase} bg-gray-50 border-gray-200`;
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={isHeroVariant ? '' : "mb-12"}>
|
|
<h3 className={`text-2xl font-bold text-center mb-8 ${isHeroVariant ? 'text-white' : 'text-brand-dark-blue'}`}>Review Progress</h3>
|
|
<div className={`grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 ${isHeroVariant ? 'gap-4' : 'gap-6'}`}>
|
|
{AGENT_NAMES.map((agentName) => {
|
|
const agentStatus = status[agentName] || 'pending';
|
|
const iconColor = isHeroVariant ? 'text-brand-light-blue' : 'text-brand-accent';
|
|
const Icon = agentIcons[agentName];
|
|
|
|
return (
|
|
<div key={agentName} className={getTileClassName(agentStatus, isHeroVariant)}>
|
|
<div className="flex-grow flex flex-col items-center justify-center">
|
|
<div className="mb-3 h-8 w-8 flex items-center justify-center">
|
|
<Icon className={`h-8 w-8 ${iconColor}`} />
|
|
</div>
|
|
<h4 className={`text-base font-bold ${isHeroVariant ? 'text-white' : 'text-brand-dark-blue'}`}>{agentName}</h4>
|
|
</div>
|
|
<div className="font-semibold text-xs mt-2 h-6 flex items-center justify-center">
|
|
{agentStatus === 'in-progress' ? (
|
|
<div className={`flex items-center ${isHeroVariant ? 'text-white/80' : 'text-gray-500'}`}>
|
|
<SpinnerIcon className="h-4 w-4 mr-2 custom-spinner" />
|
|
<span>Analyzing...</span>
|
|
</div>
|
|
) : (
|
|
<StatusInfo
|
|
status={agentStatus}
|
|
isHeroVariant={isHeroVariant}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}; |