import { useState, useEffect } from "react"; import Layout from "@/components/Layout"; import SEO from "@/components/SEO"; import { Breadcrumbs } from "@/components/dev-platform/Breadcrumbs"; import { StatCard } from "@/components/dev-platform/ui/StatCard"; import { ApiKeyCard } from "@/components/dev-platform/ApiKeyCard"; import { CreateApiKeyDialog } from "@/components/dev-platform/CreateApiKeyDialog"; import { UsageChart } from "@/components/dev-platform/UsageChart"; import { Button } from "@/components/ui/button"; import { Callout } from "@/components/dev-platform/ui/Callout"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Key, Plus, Activity, TrendingUp, Clock, AlertTriangle, Loader2, } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; interface ApiKey { id: string; name: string; key_prefix: string; scopes: string[]; last_used_at?: string | null; usage_count: number; is_active: boolean; created_at: string; expires_at?: string | null; } interface DeveloperProfile { user_id: string; company_name?: string; website_url?: string; github_username?: string; is_verified: boolean; plan_tier: string; max_api_keys: number; } export default function DeveloperDashboard() { const [keys, setKeys] = useState([]); const [profile, setProfile] = useState(null); const [stats, setStats] = useState(null); const [isLoading, setIsLoading] = useState(true); const [createDialogOpen, setCreateDialogOpen] = useState(false); const { toast } = useToast(); useEffect(() => { loadDashboardData(); }, []); const loadDashboardData = async () => { setIsLoading(true); try { // Load API keys const keysRes = await fetch("/api/developer/keys"); if (keysRes.ok) { const keysData = await keysRes.json(); setKeys(keysData.keys || []); } // Load developer profile const profileRes = await fetch("/api/developer/profile"); if (profileRes.ok) { const profileData = await profileRes.json(); setProfile(profileData.profile); } // Calculate overall stats const totalRequests = keys.reduce((sum, key) => sum + key.usage_count, 0); const activeKeys = keys.filter((k) => k.is_active).length; const recentlyUsed = keys.filter( (k) => k.last_used_at && Date.now() - new Date(k.last_used_at).getTime() < 24 * 60 * 60 * 1000 ).length; setStats({ totalRequests, activeKeys, recentlyUsed, totalKeys: keys.length, }); } catch (error) { console.error("Error loading dashboard data:", error); toast({ title: "Error", description: "Failed to load dashboard data", variant: "destructive", }); } finally { setIsLoading(false); } }; const handleCreateKey = async (data: { name: string; scopes: string[]; expiresInDays?: number; }) => { try { const res = await fetch("/api/developer/keys", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); const result = await res.json(); if (!res.ok) { return { error: result.error || "Failed to create API key" }; } toast({ title: "API Key Created", description: "Your new API key has been generated successfully", }); await loadDashboardData(); return { full_key: result.key.full_key }; } catch (error) { console.error("Error creating API key:", error); return { error: "Network error. Please try again." }; } }; const handleDeleteKey = async (id: string) => { if (!confirm("Are you sure you want to delete this API key? This action cannot be undone.")) { return; } try { const res = await fetch(`/api/developer/keys/${id}`, { method: "DELETE", }); if (!res.ok) { throw new Error("Failed to delete key"); } toast({ title: "API Key Deleted", description: "The API key has been permanently deleted", }); await loadDashboardData(); } catch (error) { console.error("Error deleting API key:", error); toast({ title: "Error", description: "Failed to delete API key", variant: "destructive", }); } }; const handleToggleActive = async (id: string, isActive: boolean) => { try { const res = await fetch(`/api/developer/keys/${id}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ is_active: isActive }), }); if (!res.ok) { throw new Error("Failed to update key"); } toast({ title: isActive ? "API Key Activated" : "API Key Deactivated", description: `The API key has been ${isActive ? "activated" : "deactivated"}`, }); await loadDashboardData(); } catch (error) { console.error("Error toggling key:", error); toast({ title: "Error", description: "Failed to update API key", variant: "destructive", }); } }; const handleViewStats = (id: string) => { // TODO: Navigate to detailed stats page or open modal console.log("View stats for key:", id); toast({ title: "Coming Soon", description: "Detailed statistics view is under development", }); }; if (isLoading) { return (
); } const expiringSoon = keys.filter((k) => { if (!k.expires_at) return false; const daysUntilExpiry = Math.ceil( (new Date(k.expires_at).getTime() - Date.now()) / (1000 * 60 * 60 * 24) ); return daysUntilExpiry > 0 && daysUntilExpiry < 30; }); return (
{/* Warning for expiring keys */} {expiringSoon.length > 0 && (

{expiringSoon.length} API key{expiringSoon.length > 1 ? "s" : ""} expiring soon

Review your keys and regenerate them before they expire to avoid service interruptions.

)} {/* Overview Stats */}
0 ? { value: 12.5, label: "vs last week" } : undefined } />
{/* Main Content Tabs */} API Keys Analytics {/* API Keys Tab */}

Your API Keys

Manage access to the AeThex platform

{keys.length === 0 ? (

No API keys yet

Create your first API key to start building with AeThex. You can create up to {profile?.max_api_keys || 3} keys on your current plan.

) : (
{keys.map((key) => ( ))}
)} {keys.length >= (profile?.max_api_keys || 3) && (

API Key Limit Reached

You've reached the maximum number of API keys for your plan. Delete an existing key to create a new one, or upgrade your plan for more keys.

)}
{/* Analytics Tab */}

Usage Analytics

Monitor your API usage over time

{stats?.totalRequests > 0 ? (

Note: Real-time analytics are coming soon. This preview shows sample data.

) : (

No usage data yet

Start making API requests to see your usage analytics here.

)}
{/* Create API Key Dialog */}
); }