story writer backend migration complete, Blog writer SEO and story writer backend migration complete, Blog writer SEO and story writer frontend migration complete
This commit is contained in:
@@ -28,15 +28,33 @@ import {
|
||||
calculateUsagePercentage
|
||||
} from '../../services/billingService';
|
||||
|
||||
// Terminal Theme
|
||||
import {
|
||||
TerminalCard,
|
||||
TerminalCardContent,
|
||||
TerminalTypography,
|
||||
TerminalChip,
|
||||
TerminalChipSuccess,
|
||||
TerminalChipError,
|
||||
TerminalChipWarning,
|
||||
terminalColors
|
||||
} from '../SchedulerDashboard/terminalTheme';
|
||||
|
||||
interface BillingOverviewProps {
|
||||
usageStats: UsageStats;
|
||||
onRefresh: () => void;
|
||||
terminalTheme?: boolean;
|
||||
}
|
||||
|
||||
const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
usageStats,
|
||||
onRefresh
|
||||
onRefresh,
|
||||
terminalTheme = false
|
||||
}) => {
|
||||
// Conditional component selection based on terminal theme
|
||||
const CardComponent = terminalTheme ? TerminalCard : Card;
|
||||
const CardContentComponent = terminalTheme ? TerminalCardContent : CardContent;
|
||||
const TypographyComponent = terminalTheme ? TerminalTypography : Typography;
|
||||
// Debug logs removed to reduce console noise
|
||||
|
||||
const costUsagePercentage = calculateUsagePercentage(
|
||||
@@ -47,9 +65,53 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
// Debug logs removed to reduce console noise
|
||||
|
||||
const getStatusChip = () => {
|
||||
const status = usageStats.usage_status;
|
||||
const status: string = usageStats.usage_status;
|
||||
const icon = getUsageStatusIcon(status);
|
||||
|
||||
// Helper function to format status label
|
||||
const formatStatusLabel = (statusStr: string): string => {
|
||||
return statusStr.charAt(0).toUpperCase() + statusStr.slice(1).replace('_', ' ');
|
||||
};
|
||||
|
||||
if (terminalTheme) {
|
||||
if (status === 'active') {
|
||||
return (
|
||||
<TerminalChipSuccess
|
||||
icon={<span>{icon}</span>}
|
||||
label={formatStatusLabel(status)}
|
||||
size="small"
|
||||
sx={{ fontWeight: 'bold' }}
|
||||
/>
|
||||
);
|
||||
} else if (status === 'warning') {
|
||||
return (
|
||||
<TerminalChipWarning
|
||||
icon={<span>{icon}</span>}
|
||||
label={formatStatusLabel(status)}
|
||||
size="small"
|
||||
sx={{ fontWeight: 'bold' }}
|
||||
/>
|
||||
);
|
||||
} else if (status === 'limit_reached') {
|
||||
return (
|
||||
<TerminalChipError
|
||||
icon={<span>{icon}</span>}
|
||||
label={formatStatusLabel(status)}
|
||||
size="small"
|
||||
sx={{ fontWeight: 'bold' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TerminalChip
|
||||
icon={<span>{icon}</span>}
|
||||
label={formatStatusLabel(status)}
|
||||
size="small"
|
||||
sx={{ fontWeight: 'bold' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
let chipColor: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' = 'default';
|
||||
if (status === 'active') chipColor = 'success';
|
||||
else if (status === 'warning') chipColor = 'warning';
|
||||
@@ -58,7 +120,7 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
return (
|
||||
<Chip
|
||||
icon={<span>{icon}</span>}
|
||||
label={status.charAt(0).toUpperCase() + status.slice(1).replace('_', ' ')}
|
||||
label={formatStatusLabel(status)}
|
||||
color={chipColor}
|
||||
size="small"
|
||||
sx={{ fontWeight: 'bold' }}
|
||||
@@ -66,6 +128,25 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const cardStyles = terminalTheme
|
||||
? {
|
||||
height: '100%',
|
||||
backgroundColor: terminalColors.background,
|
||||
border: `1px solid ${terminalColors.border}`,
|
||||
borderRadius: 3,
|
||||
position: 'relative' as const,
|
||||
overflow: 'hidden' as const
|
||||
}
|
||||
: {
|
||||
height: '100%',
|
||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
border: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 3,
|
||||
position: 'relative' as const,
|
||||
overflow: 'hidden' as const
|
||||
};
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
@@ -73,34 +154,24 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
transition={{ duration: 0.4 }}
|
||||
whileHover={{ scale: 1.02 }}
|
||||
>
|
||||
<Card
|
||||
sx={{
|
||||
height: '100%',
|
||||
background: 'linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
border: '1px solid rgba(255,255,255,0.1)',
|
||||
borderRadius: 3,
|
||||
position: 'relative',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<CardComponent sx={cardStyles}>
|
||||
{/* Header */}
|
||||
<CardContent sx={{ pb: 1 }}>
|
||||
<CardContentComponent sx={{ pb: 1 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', gap: 1, fontWeight: 'bold' }}>
|
||||
<DollarSign size={20} />
|
||||
<TypographyComponent variant="h6" sx={{ display: 'flex', alignItems: 'center', gap: 1, fontWeight: 'bold' }}>
|
||||
<DollarSign size={20} color={terminalTheme ? terminalColors.text : undefined} />
|
||||
Billing Overview
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
<Tooltip title="View your current billing status, usage metrics, and subscription plan details">
|
||||
<Info size={16} color="rgba(255,255,255,0.7)" />
|
||||
<Info size={16} color={terminalTheme ? terminalColors.textSecondary : "rgba(255,255,255,0.7)"} />
|
||||
</Tooltip>
|
||||
<Tooltip title="Refresh data">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onRefresh}
|
||||
sx={{
|
||||
color: 'text.secondary',
|
||||
'&:hover': { color: 'primary.main' }
|
||||
color: terminalTheme ? terminalColors.text : 'text.secondary',
|
||||
'&:hover': { color: terminalTheme ? terminalColors.secondary : 'primary.main' }
|
||||
}}
|
||||
>
|
||||
<RefreshCw size={16} />
|
||||
@@ -112,9 +183,9 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
<Box sx={{ mb: 3 }}>
|
||||
{getStatusChip()}
|
||||
</Box>
|
||||
</CardContent>
|
||||
</CardContentComponent>
|
||||
|
||||
<CardContent sx={{ pt: 0 }}>
|
||||
<CardContentComponent sx={{ pt: 0 }}>
|
||||
{/* Current Cost */}
|
||||
<Box sx={{ mb: 3, textAlign: 'center' }}>
|
||||
<motion.div
|
||||
@@ -122,20 +193,20 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
animate={{ scale: 1 }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
>
|
||||
<Typography
|
||||
<TypographyComponent
|
||||
variant="h3"
|
||||
sx={{
|
||||
fontWeight: 'bold',
|
||||
color: '#ffffff',
|
||||
textShadow: '0 2px 4px rgba(0,0,0,0.3)',
|
||||
color: terminalTheme ? terminalColors.text : '#ffffff',
|
||||
textShadow: terminalTheme ? 'none' : '0 2px 4px rgba(0,0,0,0.3)',
|
||||
mb: 1
|
||||
}}
|
||||
>
|
||||
{formatCurrency(usageStats.total_cost)}
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.8)' }}>
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="body2" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.8)' }}>
|
||||
Total Cost This Month
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</motion.div>
|
||||
</Box>
|
||||
|
||||
@@ -143,34 +214,34 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Tooltip title="Total number of API requests made this billing period">
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
||||
<TypographyComponent variant="body2" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
API Calls
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold', color: '#ffffff' }}>
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="body2" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors.text : '#ffffff' }}>
|
||||
{formatNumber(usageStats.total_calls)}
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Total tokens processed across all API providers (input + output tokens)">
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
||||
<TypographyComponent variant="body2" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
Tokens Used
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold', color: '#ffffff' }}>
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="body2" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors.text : '#ffffff' }}>
|
||||
{formatNumber(usageStats.total_tokens)}
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Average response time for API requests in the last 24 hours">
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="body2" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
||||
<TypographyComponent variant="body2" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
Avg Response Time
|
||||
</Typography>
|
||||
<Typography variant="body2" sx={{ fontWeight: 'bold', color: '#ffffff' }}>
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="body2" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors.text : '#ffffff' }}>
|
||||
{usageStats.avg_response_time.toFixed(0)}ms
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
@@ -179,12 +250,12 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
{usageStats.limits.limits.monthly_cost > 0 && (
|
||||
<Box sx={{ mb: 3 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
<TypographyComponent variant="body2" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
Monthly Cost Limit
|
||||
</Typography>
|
||||
<Typography variant="body2" fontWeight="bold">
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="body2" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors.text : '#ffffff' }}>
|
||||
{formatPercentage(costUsagePercentage)}
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
@@ -192,17 +263,20 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
sx={{
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: 'rgba(255,255,255,0.1)',
|
||||
backgroundColor: terminalTheme ? terminalColors.backgroundLight : 'rgba(255,255,255,0.1)',
|
||||
'& .MuiLinearProgress-bar': {
|
||||
backgroundColor: costUsagePercentage > 80 ? '#ef4444' :
|
||||
costUsagePercentage > 60 ? '#f59e0b' : '#22c55e',
|
||||
backgroundColor: terminalTheme
|
||||
? (costUsagePercentage > 80 ? terminalColors.error :
|
||||
costUsagePercentage > 60 ? terminalColors.warning : terminalColors.success)
|
||||
: (costUsagePercentage > 80 ? '#ef4444' :
|
||||
costUsagePercentage > 60 ? '#f59e0b' : '#22c55e'),
|
||||
borderRadius: 4,
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ mt: 0.5, display: 'block' }}>
|
||||
<TypographyComponent variant="caption" sx={{ mt: 0.5, display: 'block', color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
{formatCurrency(usageStats.total_cost)} of {formatCurrency(usageStats.limits.limits.monthly_cost)} limit
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -210,69 +284,73 @@ const BillingOverview: React.FC<BillingOverviewProps> = ({
|
||||
<Box
|
||||
sx={{
|
||||
p: 2,
|
||||
backgroundColor: 'rgba(255,255,255,0.05)',
|
||||
backgroundColor: terminalTheme ? terminalColors.backgroundLight : 'rgba(255,255,255,0.05)',
|
||||
borderRadius: 2,
|
||||
border: '1px solid rgba(255,255,255,0.1)'
|
||||
border: terminalTheme ? `1px solid ${terminalColors.border}` : '1px solid rgba(255,255,255,0.1)'
|
||||
}}
|
||||
>
|
||||
<Typography variant="body2" sx={{ mb: 1, color: 'rgba(255,255,255,0.8)' }}>
|
||||
<TypographyComponent variant="body2" sx={{ mb: 1, color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.8)' }}>
|
||||
Current Plan
|
||||
</Typography>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold', mb: 1, color: '#ffffff' }}>
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="h6" sx={{ fontWeight: 'bold', mb: 1, color: terminalTheme ? terminalColors.text : '#ffffff' }}>
|
||||
{usageStats.limits.plan_name}
|
||||
</Typography>
|
||||
<Typography variant="caption" sx={{ color: 'rgba(255,255,255,0.7)' }}>
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="caption" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
{usageStats.limits.tier.charAt(0).toUpperCase() + usageStats.limits.tier.slice(1)} Tier
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
|
||||
{/* Quick Stats */}
|
||||
<Box sx={{ mt: 2, display: 'flex', justifyContent: 'space-around' }}>
|
||||
<Box sx={{ textAlign: 'center' }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold', color: 'primary.main' }}>
|
||||
<TypographyComponent variant="h6" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors.text : 'primary.main' }}>
|
||||
{usageStats.usage_percentages.gemini_calls.toFixed(0)}%
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="caption" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
Gemini Usage
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
<Box sx={{ textAlign: 'center' }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 'bold', color: 'secondary.main' }}>
|
||||
<TypographyComponent variant="h6" sx={{ fontWeight: 'bold', color: terminalTheme ? terminalColors.text : 'secondary.main' }}>
|
||||
{usageStats.error_rate.toFixed(1)}%
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
</TypographyComponent>
|
||||
<TypographyComponent variant="caption" sx={{ color: terminalTheme ? terminalColors.textSecondary : 'rgba(255,255,255,0.7)' }}>
|
||||
Error Rate
|
||||
</Typography>
|
||||
</TypographyComponent>
|
||||
</Box>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</CardContentComponent>
|
||||
|
||||
{/* Decorative Elements */}
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: -50,
|
||||
right: -50,
|
||||
width: 100,
|
||||
height: 100,
|
||||
background: 'radial-gradient(circle, rgba(102, 126, 234, 0.1) 0%, transparent 70%)',
|
||||
borderRadius: '50%',
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: -30,
|
||||
left: -30,
|
||||
width: 60,
|
||||
height: 60,
|
||||
background: 'radial-gradient(circle, rgba(118, 75, 162, 0.1) 0%, transparent 70%)',
|
||||
borderRadius: '50%',
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
{/* Decorative Elements - only show in non-terminal theme */}
|
||||
{!terminalTheme && (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: -50,
|
||||
right: -50,
|
||||
width: 100,
|
||||
height: 100,
|
||||
background: 'radial-gradient(circle, rgba(102, 126, 234, 0.1) 0%, transparent 70%)',
|
||||
borderRadius: '50%',
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
bottom: -30,
|
||||
left: -30,
|
||||
width: 60,
|
||||
height: 60,
|
||||
background: 'radial-gradient(circle, rgba(118, 75, 162, 0.1) 0%, transparent 70%)',
|
||||
borderRadius: '50%',
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</CardComponent>
|
||||
</motion.div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user