TradingAgents/frontend/components/shared/ErrorAlert.tsx

128 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Error Alert Component
* Displays user-friendly error messages with special handling for rate limits
*/
"use client";
import { AlertCircle, Clock, TrendingUp } from "lucide-react";
import { Card } from "@/components/ui/card";
interface ErrorAlertProps {
error: string | {
error: string;
error_type?: string;
retry_after?: number;
quota_limit?: number;
};
}
export function ErrorAlert({ error }: ErrorAlertProps) {
// Parse error data
const isRateLimit = typeof error === "object" && error.error_type === "rate_limit";
const errorMessage = typeof error === "string" ? error : error.error;
const retryAfter = typeof error === "object" ? error.retry_after : null;
const quotaLimit = typeof error === "object" ? error.quota_limit : null;
// Calculate retry time display
const getRetryTimeDisplay = (seconds: number | null) => {
if (!seconds) return null;
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
if (minutes > 0) {
return `${minutes}${remainingSeconds}`;
}
return `${remainingSeconds}`;
};
return (
<Card className={`p-6 border-2 ${
isRateLimit
? "bg-orange-50 dark:bg-orange-900/20 border-orange-300 dark:border-orange-700"
: "bg-red-50 dark:bg-red-900/20 border-red-300 dark:border-red-700"
}`}>
<div className="flex items-start gap-4">
<div className={`flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center ${
isRateLimit
? "bg-orange-100 dark:bg-orange-800"
: "bg-red-100 dark:bg-red-800"
}`}>
{isRateLimit ? (
<Clock className="w-5 h-5 text-orange-600 dark:text-orange-400" />
) : (
<AlertCircle className="w-5 h-5 text-red-600 dark:text-red-400" />
)}
</div>
<div className="flex-1">
<h3 className={`font-semibold text-lg mb-2 ${
isRateLimit
? "text-orange-900 dark:text-orange-200"
: "text-red-900 dark:text-red-200"
}`}>
{isRateLimit ? "API 請求額度已達上限" : "錯誤"}
</h3>
<p className={`mb-4 ${
isRateLimit
? "text-orange-800 dark:text-orange-300"
: "text-red-800 dark:text-red-300"
}`}>
{errorMessage}
</p>
{isRateLimit && (
<div className="space-y-3 mt-4">
{/* Retry Information */}
{retryAfter && (
<div className="flex items-start gap-2 bg-white/50 dark:bg-gray-900/50 p-3 rounded-lg">
<Clock className="w-4 h-4 text-orange-600 dark:text-orange-400 mt-0.5 flex-shrink-0" />
<div>
<p className="text-sm font-medium text-gray-900 dark:text-gray-100">
</p>
<p className="text-sm text-gray-700 dark:text-gray-300">
<span className="font-bold text-orange-600 dark:text-orange-400">
{getRetryTimeDisplay(retryAfter)}
</span>
</p>
</div>
</div>
)}
{/* Quota Information */}
{quotaLimit && (
<div className="flex items-start gap-2 bg-white/50 dark:bg-gray-900/50 p-3 rounded-lg">
<TrendingUp className="w-4 h-4 text-orange-600 dark:text-orange-400 mt-0.5 flex-shrink-0" />
<div>
<p className="text-sm font-medium text-gray-900 dark:text-gray-100">
</p>
<p className="text-sm text-gray-700 dark:text-gray-300">
{quotaLimit}
</p>
</div>
</div>
)}
{/* Solutions */}
<div className="bg-blue-50 dark:bg-blue-900/30 border border-blue-200 dark:border-blue-800 p-4 rounded-lg mt-4">
<p className="text-sm font-semibold text-blue-900 dark:text-blue-200 mb-2">
💡
</p>
<ul className="text-sm text-blue-800 dark:text-blue-300 space-y-1.5 list-disc list-inside">
<li></li>
<li></li>
<li> API </li>
<li>使 API </li>
</ul>
</div>
</div>
)}
</div>
</div>
</Card>
);
}