import { useState, useEffect } from 'react'; import PageMeta from '../../components/common/PageMeta'; import { useToast } from '../../components/ui/toast/ToastContainer'; import { fetchCreditUsage, CreditUsageLog, fetchUsageLimits, LimitCard } from '../../services/api'; import { Card } from '../../components/ui/card'; import Badge from '../../components/ui/badge/Badge'; // Credit costs per operation (Phase 0: Credit-only system) const CREDIT_COSTS: Record = { clustering: { cost: 10, description: 'Per clustering request' }, idea_generation: { cost: 15, description: 'Per cluster → ideas request' }, content_generation: { cost: '1 per 100 words', description: 'Per 100 words generated' }, image_prompt_extraction: { cost: 2, description: 'Per content piece' }, image_generation: { cost: 5, description: 'Per image generated' }, linking: { cost: 8, description: 'Per content piece' }, optimization: { cost: '1 per 200 words', description: 'Per 200 words optimized' }, site_structure_generation: { cost: 50, description: 'Per site blueprint' }, site_page_generation: { cost: 20, description: 'Per page generated' }, }; export default function Usage() { const toast = useToast(); const [usageLogs, setUsageLogs] = useState([]); const [limits, setLimits] = useState([]); const [loading, setLoading] = useState(true); const [limitsLoading, setLimitsLoading] = useState(true); useEffect(() => { loadUsage(); loadLimits(); }, []); const loadUsage = async () => { try { setLoading(true); const response = await fetchCreditUsage({ page: 1 }); setUsageLogs(response.results || []); } catch (error: any) { toast.error(`Failed to load usage logs: ${error.message}`); } finally { setLoading(false); } }; const loadLimits = async () => { try { setLimitsLoading(true); const response = await fetchUsageLimits(); setLimits(response.limits || []); } catch (error: any) { toast.error(`Failed to load usage limits: ${error.message}`); setLimits([]); } finally { setLimitsLoading(false); } }; // Filter limits to show only credits and account management (Phase 0: Credit-only system) const creditLimits = limits.filter(l => l.category === 'credits'); const accountLimits = limits.filter(l => l.category === 'account'); return (

Credit Usage & Limits

Monitor your credit usage and account management limits

{/* Credit Costs Reference */}

Credit Costs per Operation

{Object.entries(CREDIT_COSTS).map(([operation, info]) => (
{operation.replace(/_/g, ' ')}
{info.description}
{typeof info.cost === 'number' ? `${info.cost} credits` : info.cost}
))}
{/* Credit Limits */} {limitsLoading ? (
Loading limits...
) : (
{/* Credit Usage Limits */} {creditLimits.length > 0 && (

Credit Usage

{creditLimits.map((limit, idx) => ( ))}
)} {/* Account Management Limits */} {accountLimits.length > 0 && (

Account Management

{accountLimits.map((limit, idx) => ( ))}
)} {creditLimits.length === 0 && accountLimits.length === 0 && (

No limits data available.

Your account may not have a plan configured.

)}
)} {/* Usage Logs Table */}

Usage Logs

{loading ? (
Loading...
) : (
{usageLogs.map((log) => ( ))}
Date Operation Credits Used Model Cost (USD)
{new Date(log.created_at).toLocaleString()} {log.operation_type_display} {log.credits_used} {log.model_used || 'N/A'} {log.cost_usd ? `$${parseFloat(log.cost_usd).toFixed(4)}` : 'N/A'}
)}
); } // Limit Card Component function LimitCardComponent({ limit }: { limit: LimitCard }) { const getCategoryColor = (category: string) => { switch (category) { case 'credits': return 'primary'; case 'account': return 'gray'; default: return 'gray'; } }; const getUsageStatus = (percentage: number | null) => { if (percentage === null) return 'info'; if (percentage >= 90) return 'danger'; if (percentage >= 75) return 'warning'; return 'success'; }; const percentage = limit.percentage !== null && limit.percentage !== undefined ? Math.min(limit.percentage, 100) : null; const status = getUsageStatus(percentage); const color = getCategoryColor(limit.category); const statusColorClass = status === 'danger' ? 'bg-red-500' : status === 'warning' ? 'bg-yellow-500' : status === 'info' ? 'bg-blue-500' : 'bg-green-500'; const statusTextColor = status === 'danger' ? 'text-red-600 dark:text-red-400' : status === 'warning' ? 'text-yellow-600 dark:text-yellow-400' : status === 'info' ? 'text-blue-600 dark:text-blue-400' : 'text-green-600 dark:text-green-400'; return (

{limit.title}

{limit.category}
{limit.limit !== null && limit.limit !== undefined ? ( <> {limit.used.toLocaleString()} / {limit.limit.toLocaleString()} ) : ( {limit.available !== null && limit.available !== undefined ? limit.available.toLocaleString() : limit.used.toLocaleString()} )} {limit.unit && ( {limit.unit} )}
{percentage !== null && (
)}
{limit.available !== null && limit.available !== undefined ? ( {limit.available.toLocaleString()} available ) : ( Current value )} {percentage !== null && ( {percentage.toFixed(1)}% used )}
); }