534 lines
18 KiB
TypeScript
534 lines
18 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import React from 'react';
|
||
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||
|
|
import { Badge } from '@/components/ui/badge';
|
||
|
|
import { Progress } from '@/components/ui/progress';
|
||
|
|
import {
|
||
|
|
Activity,
|
||
|
|
FileText,
|
||
|
|
Clock,
|
||
|
|
TrendingUp,
|
||
|
|
TrendingDown,
|
||
|
|
Minus,
|
||
|
|
Info,
|
||
|
|
CheckCircle,
|
||
|
|
AlertTriangle,
|
||
|
|
XCircle
|
||
|
|
} from 'lucide-react';
|
||
|
|
import { cn } from '@/lib/utils';
|
||
|
|
import {
|
||
|
|
ActivityScore,
|
||
|
|
ContentScore,
|
||
|
|
TimelinessScore,
|
||
|
|
TimeEntryAnalysis,
|
||
|
|
AggregateAnalysis
|
||
|
|
} from '@/lib/types/analytics';
|
||
|
|
|
||
|
|
interface ScoreCardProps {
|
||
|
|
title: string;
|
||
|
|
score: number;
|
||
|
|
description?: string;
|
||
|
|
trend?: 'up' | 'down' | 'neutral';
|
||
|
|
trendValue?: number;
|
||
|
|
icon?: React.ReactNode;
|
||
|
|
size?: 'sm' | 'md' | 'lg';
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ScoreCard({
|
||
|
|
title,
|
||
|
|
score,
|
||
|
|
description,
|
||
|
|
trend,
|
||
|
|
trendValue,
|
||
|
|
icon,
|
||
|
|
size = 'md',
|
||
|
|
className
|
||
|
|
}: ScoreCardProps) {
|
||
|
|
const percentage = Math.round(score * 100);
|
||
|
|
const scoreColor = getScoreColor(score);
|
||
|
|
const scoreLabel = getScoreLabel(score);
|
||
|
|
|
||
|
|
const sizeClasses = {
|
||
|
|
sm: 'p-4',
|
||
|
|
md: 'p-6',
|
||
|
|
lg: 'p-8',
|
||
|
|
};
|
||
|
|
|
||
|
|
const titleSizeClasses = {
|
||
|
|
sm: 'text-sm',
|
||
|
|
md: 'text-base',
|
||
|
|
lg: 'text-lg',
|
||
|
|
};
|
||
|
|
|
||
|
|
const scoreSizeClasses = {
|
||
|
|
sm: 'text-2xl',
|
||
|
|
md: 'text-3xl',
|
||
|
|
lg: 'text-4xl',
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card className={cn(sizeClasses[size], className)}>
|
||
|
|
<CardHeader className="pb-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<CardTitle className={cn("flex items-center gap-2", titleSizeClasses[size])}>
|
||
|
|
{icon}
|
||
|
|
{title}
|
||
|
|
</CardTitle>
|
||
|
|
|
||
|
|
{trend && (
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
{trend === 'up' && <TrendingUp className="h-4 w-4 text-green-500" />}
|
||
|
|
{trend === 'down' && <TrendingDown className="h-4 w-4 text-red-500" />}
|
||
|
|
{trend === 'neutral' && <Minus className="h-4 w-4 text-gray-500" />}
|
||
|
|
{(trendValue !== undefined) && (
|
||
|
|
<span className={cn(
|
||
|
|
"text-sm font-medium",
|
||
|
|
trendValue > 0 ? "text-green-600" : trendValue < 0 ? "text-red-600" : "text-gray-600"
|
||
|
|
)}>
|
||
|
|
{trendValue > 0 ? '+' : ''}{trendValue}%
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{description && (
|
||
|
|
<p className="text-sm text-gray-600">{description}</p>
|
||
|
|
)}
|
||
|
|
</CardHeader>
|
||
|
|
|
||
|
|
<CardContent>
|
||
|
|
<div className="space-y-4">
|
||
|
|
{/* Score Display */}
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<span className={cn(scoreSizeClasses[size], "font-bold", scoreColor.text)}>
|
||
|
|
{percentage}%
|
||
|
|
</span>
|
||
|
|
<Badge variant="outline" className={scoreColor.badge}>
|
||
|
|
{scoreLabel}
|
||
|
|
</Badge>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center gap-1">
|
||
|
|
{getScoreIcon(score)}
|
||
|
|
<span className="text-sm text-gray-500">{scoreLabel}</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Progress Bar */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Progress
|
||
|
|
value={percentage}
|
||
|
|
className="h-2"
|
||
|
|
/>
|
||
|
|
<div className="flex justify-between text-xs text-gray-500">
|
||
|
|
<span>Poor</span>
|
||
|
|
<span>Average</span>
|
||
|
|
<span>Excellent</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
interface ActivityScoreCardProps {
|
||
|
|
title: string;
|
||
|
|
score: ActivityScore;
|
||
|
|
icon?: React.ReactNode;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ActivityScoreCard({ title, score, icon, className }: ActivityScoreCardProps) {
|
||
|
|
return (
|
||
|
|
<Card className={className}>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle className="flex items-center gap-2">
|
||
|
|
{icon || <Activity className="h-5 w-5 text-blue-500" />}
|
||
|
|
{title}
|
||
|
|
</CardTitle>
|
||
|
|
</CardHeader>
|
||
|
|
|
||
|
|
<CardContent className="space-y-4">
|
||
|
|
{/* Overall Score */}
|
||
|
|
<div className="text-center">
|
||
|
|
<div className="text-3xl font-bold text-blue-600">
|
||
|
|
{Math.round(score.score * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Activity Score</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Breakdown */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<h4 className="font-medium text-sm">Score Breakdown</h4>
|
||
|
|
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Completeness</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.completeness * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.completeness * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Consistency</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.consistency * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.consistency * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Duration</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.duration * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.duration * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Categorization</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.categorization * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.categorization * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Positive Factors */}
|
||
|
|
{score.factors.length > 0 && (
|
||
|
|
<div className="space-y-2">
|
||
|
|
<h4 className="font-medium text-sm flex items-center gap-1">
|
||
|
|
<CheckCircle className="h-4 w-4 text-green-500" />
|
||
|
|
Positive Factors
|
||
|
|
</h4>
|
||
|
|
<div className="flex flex-wrap gap-1">
|
||
|
|
{score.factors.map((factor: string, index: number) => (
|
||
|
|
<Badge key={index} variant="secondary" className="text-xs">
|
||
|
|
{factor}
|
||
|
|
</Badge>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
interface ContentScoreCardProps {
|
||
|
|
title: string;
|
||
|
|
score: ContentScore;
|
||
|
|
icon?: React.ReactNode;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function ContentScoreCard({ title, score, icon, className }: ContentScoreCardProps) {
|
||
|
|
return (
|
||
|
|
<Card className={className}>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle className="flex items-center gap-2">
|
||
|
|
{icon || <FileText className="h-5 w-5 text-green-500" />}
|
||
|
|
{title}
|
||
|
|
</CardTitle>
|
||
|
|
</CardHeader>
|
||
|
|
|
||
|
|
<CardContent className="space-y-4">
|
||
|
|
{/* Overall Score */}
|
||
|
|
<div className="text-center">
|
||
|
|
<div className="text-3xl font-bold text-green-600">
|
||
|
|
{Math.round(score.score * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Content Score</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Breakdown */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<h4 className="font-medium text-sm">Score Breakdown</h4>
|
||
|
|
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Notes Quality</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.notesQuality * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.notesQuality * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Title Clarity</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.titleClarity * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.titleClarity * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Internal Notes</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.internalNotes * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.internalNotes * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Technical Detail</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.technicalDetail * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.technicalDetail * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Positive Factors */}
|
||
|
|
{score.factors.length > 0 && (
|
||
|
|
<div className="space-y-2">
|
||
|
|
<h4 className="font-medium text-sm flex items-center gap-1">
|
||
|
|
<CheckCircle className="h-4 w-4 text-green-500" />
|
||
|
|
Positive Factors
|
||
|
|
</h4>
|
||
|
|
<div className="flex flex-wrap gap-1">
|
||
|
|
{score.factors.map((factor: string, index: number) => (
|
||
|
|
<Badge key={index} variant="secondary" className="text-xs">
|
||
|
|
{factor}
|
||
|
|
</Badge>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
interface TimelinessScoreCardProps {
|
||
|
|
title: string;
|
||
|
|
score: TimelinessScore;
|
||
|
|
icon?: React.ReactNode;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function TimelinessScoreCard({ title, score, icon, className }: TimelinessScoreCardProps) {
|
||
|
|
return (
|
||
|
|
<Card className={className}>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle className="flex items-center gap-2">
|
||
|
|
{icon || <Clock className="h-5 w-5 text-orange-500" />}
|
||
|
|
{title}
|
||
|
|
</CardTitle>
|
||
|
|
</CardHeader>
|
||
|
|
|
||
|
|
<CardContent className="space-y-4">
|
||
|
|
{/* Overall Score */}
|
||
|
|
<div className="text-center">
|
||
|
|
<div className="text-3xl font-bold text-orange-600">
|
||
|
|
{Math.round(score.score * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Timeliness Score</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Breakdown */}
|
||
|
|
<div className="space-y-3">
|
||
|
|
<h4 className="font-medium text-sm">Score Breakdown</h4>
|
||
|
|
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Entry Delay</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.entryDelay * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.entryDelay * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Business Hours</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.businessHours * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.businessHours * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Regularity</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.regularity * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.regularity * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<span className="text-sm">Approval Time</span>
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Progress value={score.breakdown.approvalTimeliness * 100} className="w-20 h-2" />
|
||
|
|
<span className="text-sm font-medium w-10 text-right">
|
||
|
|
{Math.round(score.breakdown.approvalTimeliness * 100)}%
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Positive Factors */}
|
||
|
|
{score.factors.length > 0 && (
|
||
|
|
<div className="space-y-2">
|
||
|
|
<h4 className="font-medium text-sm flex items-center gap-1">
|
||
|
|
<CheckCircle className="h-4 w-4 text-green-500" />
|
||
|
|
Positive Factors
|
||
|
|
</h4>
|
||
|
|
<div className="flex flex-wrap gap-1">
|
||
|
|
{score.factors.map((factor: string, index: number) => (
|
||
|
|
<Badge key={index} variant="secondary" className="text-xs">
|
||
|
|
{factor}
|
||
|
|
</Badge>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
interface AggregateScoreCardProps {
|
||
|
|
analysis: AggregateAnalysis;
|
||
|
|
className?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function AggregateScoreCard({ analysis, className }: AggregateScoreCardProps) {
|
||
|
|
return (
|
||
|
|
<Card className={className}>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle className="flex items-center gap-2">
|
||
|
|
<TrendingUp className="h-5 w-5 text-purple-500" />
|
||
|
|
Overall Performance
|
||
|
|
</CardTitle>
|
||
|
|
</CardHeader>
|
||
|
|
|
||
|
|
<CardContent className="space-y-6">
|
||
|
|
{/* Overall Score */}
|
||
|
|
<div className="text-center">
|
||
|
|
<div className="text-4xl font-bold text-purple-600">
|
||
|
|
{Math.round(analysis.scores.overall * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Overall Score</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Individual Scores */}
|
||
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||
|
|
<div className="text-center p-3 bg-blue-50 rounded-lg">
|
||
|
|
<div className="text-2xl font-bold text-blue-600">
|
||
|
|
{Math.round(analysis.scores.activity * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Activity</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="text-center p-3 bg-green-50 rounded-lg">
|
||
|
|
<div className="text-2xl font-bold text-green-600">
|
||
|
|
{Math.round(analysis.scores.content * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Content</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="text-center p-3 bg-orange-50 rounded-lg">
|
||
|
|
<div className="text-2xl font-bold text-orange-600">
|
||
|
|
{Math.round(analysis.scores.timeliness * 100)}%
|
||
|
|
</div>
|
||
|
|
<div className="text-sm text-gray-600">Timeliness</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Summary Stats */}
|
||
|
|
<div className="grid grid-cols-2 gap-4 text-sm">
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-gray-600">Total Entries:</span>
|
||
|
|
<span className="font-medium">{analysis.totalEntries}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-gray-600">Total Hours:</span>
|
||
|
|
<span className="font-medium">{Number(analysis.totalHours).toFixed(1)}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-gray-600">Avg Hours/Entry:</span>
|
||
|
|
<span className="font-medium">{Number(analysis.averageHoursPerEntry).toFixed(1)}</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex justify-between">
|
||
|
|
<span className="text-gray-600">Date Range:</span>
|
||
|
|
<span className="font-medium">
|
||
|
|
{analysis.dateRange.latest.toLocaleDateString()}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Helper functions
|
||
|
|
function getScoreColor(score: number) {
|
||
|
|
if (score >= 0.8) {
|
||
|
|
return {
|
||
|
|
text: 'text-green-600',
|
||
|
|
badge: 'bg-green-100 text-green-800 border-green-200',
|
||
|
|
progress: 'bg-green-500',
|
||
|
|
};
|
||
|
|
}
|
||
|
|
if (score >= 0.6) {
|
||
|
|
return {
|
||
|
|
text: 'text-yellow-600',
|
||
|
|
badge: 'bg-yellow-100 text-yellow-800 border-yellow-200',
|
||
|
|
progress: 'bg-yellow-500',
|
||
|
|
};
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
text: 'text-red-600',
|
||
|
|
badge: 'bg-red-100 text-red-800 border-red-200',
|
||
|
|
progress: 'bg-red-500',
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function getScoreLabel(score: number) {
|
||
|
|
if (score >= 0.8) return 'Excellent';
|
||
|
|
if (score >= 0.6) return 'Good';
|
||
|
|
if (score >= 0.4) return 'Average';
|
||
|
|
return 'Poor';
|
||
|
|
}
|
||
|
|
|
||
|
|
function getScoreIcon(score: number) {
|
||
|
|
if (score >= 0.8) {
|
||
|
|
return <CheckCircle className="h-4 w-4 text-green-500" />;
|
||
|
|
}
|
||
|
|
if (score >= 0.6) {
|
||
|
|
return <AlertTriangle className="h-4 w-4 text-yellow-500" />;
|
||
|
|
}
|
||
|
|
return <XCircle className="h-4 w-4 text-red-500" />;
|
||
|
|
}
|