import { useState, useEffect } from "react"; import { useAuth } from "@/contexts/AuthContext"; import { useNavigate } from "react-router-dom"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { aethexToast } from "@/lib/aethex-toast"; import { Bot, Server, Terminal, Users, MessageSquare, RefreshCw, CheckCircle, XCircle, Clock, Zap, ArrowLeftRight, Hash, Activity, } from "lucide-react"; interface BotStatus { status: string; bot: { tag: string; id: string; avatar: string; }; guilds: Array<{ id: string; name: string; memberCount: number; icon: string; }>; guildCount: number; commands: string[]; commandCount: number; uptime: number; feedBridge: { enabled: boolean; channelId: string; }; timestamp: string; } interface LinkedUser { discord_id: string; user_id: string; primary_arm: string; created_at: string; profile: { username: string; full_name: string; avatar_url: string; } | null; } interface FeedStats { totalPosts: number; discordPosts: number; websitePosts: number; recentPosts: Array<{ id: string; content: string; source: string; created_at: string; discord_author_name: string; }>; } interface CommandInfo { name: string; description: string; options: number; } const API_BASE = "/api/discord"; export default function BotPanel() { const { user, loading: authLoading } = useAuth(); const navigate = useNavigate(); const [botStatus, setBotStatus] = useState(null); const [linkedUsers, setLinkedUsers] = useState([]); const [feedStats, setFeedStats] = useState(null); const [commands, setCommands] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); useEffect(() => { if (!authLoading && !user) { navigate("/"); return; } fetchAllData(); }, [user, authLoading, navigate]); const fetchAllData = async () => { setLoading(true); await Promise.all([ fetchBotStatus(), fetchLinkedUsers(), fetchFeedStats(), fetchCommands(), ]); setLoading(false); }; const handleRefresh = async () => { setRefreshing(true); await fetchAllData(); setRefreshing(false); aethexToast.success({ description: "Data refreshed successfully" }); }; const fetchBotStatus = async () => { try { const res = await fetch(`${API_BASE}/bot-status`); if (res.ok) { const data = await res.json(); setBotStatus(data); } } catch (error) { console.error("Failed to fetch bot status:", error); } }; const fetchLinkedUsers = async () => { try { const res = await fetch(`${API_BASE}/linked-users`); if (res.ok) { const data = await res.json(); if (data.success) { setLinkedUsers(data.links || []); } } } catch (error) { console.error("Failed to fetch linked users:", error); } }; const fetchFeedStats = async () => { try { const res = await fetch(`${API_BASE}/feed-stats`); if (res.ok) { const data = await res.json(); if (data.success) { setFeedStats(data.stats); } } } catch (error) { console.error("Failed to fetch feed stats:", error); } }; const fetchCommands = async () => { try { const res = await fetch(`${API_BASE}/command-stats`); if (res.ok) { const data = await res.json(); if (data.success) { setCommands(data.stats.commands || []); } } } catch (error) { console.error("Failed to fetch commands:", error); } }; const registerCommands = async () => { try { const res = await fetch(`${API_BASE}/bot-register-commands`, { method: "POST", headers: { "Content-Type": "application/json" }, }); const data = await res.json(); if (data.success) { aethexToast.success({ title: "Commands Registered", description: `Successfully registered ${data.count} commands`, }); await fetchCommands(); } else { throw new Error(data.error); } } catch (error: any) { aethexToast.error({ description: error?.message || "Failed to register commands", }); } }; const formatUptime = (seconds: number) => { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days > 0) return `${days}d ${hours}h ${minutes}m`; if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", }); }; if (authLoading || loading) { return (

Loading Bot Panel...

); } return (

Bot Panel

Manage your AeThex Discord bot

Status

{botStatus?.status === "online" ? ( <> Online ) : ( <> Offline )}

Servers

{botStatus?.guildCount || 0}

Uptime

{botStatus ? formatUptime(botStatus.uptime) : "--"}

Linked Users

{linkedUsers.length}

Overview Servers Commands Linked Users Feed Bridge
Bot Information {botStatus?.bot && (
{botStatus.bot.avatar && ( Bot Avatar )}

{botStatus.bot.tag}

ID: {botStatus.bot.id}

)}

Commands

{botStatus?.commandCount || 0}

Feed Bridge

{botStatus?.feedBridge?.enabled ? "Enabled" : "Disabled"}
Feed Bridge Stats

{feedStats?.totalPosts || 0}

Total Posts

{feedStats?.discordPosts || 0}

From Discord

{feedStats?.websitePosts || 0}

From Website

Connected Servers ({botStatus?.guildCount || 0}) All Discord servers where the bot is installed
{botStatus?.guilds?.map((guild) => (
{guild.icon ? ( {guild.name} ) : (
)}

{guild.name}

ID: {guild.id}

{guild.memberCount} members
))} {(!botStatus?.guilds || botStatus.guilds.length === 0) && (
No servers connected yet
)}
Slash Commands ({commands.length}) All available Discord slash commands
{commands.map((cmd) => (
/{cmd.name} {cmd.options > 0 && ( {cmd.options} options )}

{cmd.description}

))}
Linked Users ({linkedUsers.length}) Discord accounts linked to AeThex profiles
{linkedUsers.map((link) => (
{link.profile?.avatar_url ? ( Avatar ) : (
)}

{link.profile?.full_name || link.profile?.username || "Unknown"}

Discord ID: {link.discord_id}

{link.primary_arm && ( {link.primary_arm} )} {formatDate(link.created_at)}
))} {linkedUsers.length === 0 && (
No linked users yet
)}
Recent Feed Activity Latest posts synced between Discord and AeThex
{feedStats?.recentPosts?.map((post) => (
{post.source === "discord" ? "Discord" : "Website"} {post.discord_author_name && ( by {post.discord_author_name} )} {formatDate(post.created_at)}

{post.content?.slice(0, 200)} {post.content?.length > 200 ? "..." : ""}

))} {(!feedStats?.recentPosts || feedStats.recentPosts.length === 0) && (
No recent feed activity
)}
); }