import { useState, useEffect, useMemo } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import Layout from "@/components/Layout"; import { Button } from "@/components/ui/button"; import { useAuth } from "@/contexts/AuthContext"; import { aethexToast } from "@/lib/aethex-toast"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import LoadingScreen from "@/components/LoadingScreen"; import { Link } from "react-router-dom"; import OAuthConnections, { type ProviderDescriptor, type ProviderKey, } from "@/components/settings/OAuthConnections"; import RealmSwitcher, { RealmKey } from "@/components/settings/RealmSwitcher"; import { User, Settings, TrendingUp, Users, Bell, Star, Trophy, Rocket, Code, Database, Shield, ChevronRight, Activity, LogOut, Sparkles, CheckCircle, ArrowRight, Copy, CheckCircle2, Github, Mail, Loader2, Unlink, Link as LinkIcon, } from "lucide-react"; const DiscordIcon = () => ( ); const ARMS = [ { id: "staff", label: "Staff", color: "#7c3aed", href: "/staff/dashboard", icon: Shield, description: "Operations & Administration", bgGradient: "from-purple-500/20 to-purple-900/20", borderColor: "border-purple-500/30 hover:border-purple-500/60", }, { id: "labs", label: "Labs", color: "#FBBF24", href: "/dashboard/labs", icon: Code, description: "Research & Development", bgGradient: "from-amber-500/20 to-amber-900/20", borderColor: "border-amber-500/30 hover:border-amber-500/60", }, { id: "gameforge", label: "GameForge", color: "#22C55E", href: "/dashboard/gameforge", icon: Rocket, description: "Game Development", bgGradient: "from-green-500/20 to-green-900/20", borderColor: "border-green-500/30 hover:border-green-500/60", }, { id: "corp", label: "Corp", color: "#3B82F6", href: "/hub/client", icon: Users, description: "Business & Consulting", bgGradient: "from-blue-500/20 to-blue-900/20", borderColor: "border-blue-500/30 hover:border-blue-500/60", }, { id: "foundation", label: "Foundation", color: "#EF4444", href: "https://aethex.foundation", icon: Trophy, description: "Education & Mentorship", bgGradient: "from-red-500/20 to-red-900/20", borderColor: "border-red-500/30 hover:border-red-500/60", external: true, }, { id: "nexus", label: "Nexus", color: "#A855F7", href: "/dashboard/nexus", icon: Sparkles, description: "Talent Marketplace", bgGradient: "from-purple-500/20 to-fuchsia-900/20", borderColor: "border-purple-500/30 hover:border-purple-500/60", }, ]; const OAUTH_PROVIDERS: readonly ProviderDescriptor[] = [ { provider: "github", name: "GitHub", description: "Connect your GitHub account for project collaboration", Icon: Github, gradient: "from-gray-700 to-black", }, { provider: "google", name: "Google", description: "Sign in with your Google account", Icon: Mail, gradient: "from-red-500 to-orange-500", }, { provider: "discord", name: "Discord", description: "Link your Discord account for community chat", Icon: DiscordIcon, gradient: "from-indigo-600 to-purple-600", }, ]; const API_BASE = import.meta.env.VITE_API_BASE || window.location.origin; function AeThexIDConnection({ user }: { user: any }) { const isLinked = !!user?.user_metadata?.authentik_linked; const sub = user?.user_metadata?.authentik_sub as string | undefined; const [unlinking, setUnlinking] = useState(false); const handleLink = () => { window.location.href = `${API_BASE}/api/auth/authentik/start?redirectTo=/dashboard?tab=connections`; }; const handleUnlink = async () => { setUnlinking(true); try { const res = await fetch(`${API_BASE}/api/auth/authentik/unlink`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${(await import("@/lib/supabase")).supabase.auth.getSession().then(s => s.data.session?.access_token || "")}` }, }); if (res.ok) { aethexToast.success({ title: "AeThex ID unlinked", description: "You can re-link at any time." }); setTimeout(() => window.location.reload(), 800); } else { aethexToast.error({ title: "Unlink failed", description: "Try again." }); } } catch { aethexToast.error({ title: "Unlink failed", description: "Try again." }); } finally { setUnlinking(false); } }; return (
Æ

AeThex ID

{isLinked ? ( Linked ) : ( Not linked )} AeThex Staff

Single sign-on via auth.aethex.tech — for AeThex employees and internal team members.

{isLinked && sub && (

Identity: {sub.slice(0, 16)}…

)}
{isLinked ? ( ) : ( )}
); } export default function Dashboard() { const navigate = useNavigate(); const { user, profile, session, loading: authLoading, signOut, profileComplete, linkedProviders, linkProvider, unlinkProvider, } = useAuth(); const [searchParams] = useSearchParams(); const [activeTab, setActiveTab] = useState( () => searchParams.get("tab") ?? "realms", ); const [displayName, setDisplayName] = useState(""); const [bio, setBio] = useState(""); const [website, setWebsite] = useState(""); const [linkedin, setLinkedin] = useState(""); const [github, setGithub] = useState(""); const [twitter, setTwitter] = useState(""); const [savingProfile, setSavingProfile] = useState(false); const [profileLinkCopied, setProfileLinkCopied] = useState(false); const [selectedRealm, setSelectedRealm] = useState(null); const [selectedExperience, setSelectedExperience] = useState("intermediate"); const [realmHasChanges, setRealmHasChanges] = useState(false); const [savingRealm, setSavingRealm] = useState(false); useEffect(() => { if (profile) { setDisplayName(profile.full_name || ""); setBio(profile.bio || ""); setWebsite(profile.website_url || ""); setLinkedin(profile.linkedin_url || ""); setGithub(profile.github_url || ""); setTwitter(profile.twitter_url || ""); setSelectedRealm((profile as any).primary_realm || null); setSelectedExperience((profile as any).experience_level || "intermediate"); } }, [profile]); const handleRealmChange = (realm: RealmKey) => { setSelectedRealm(realm); setRealmHasChanges(true); }; const handleExperienceChange = (value: string) => { setSelectedExperience(value); setRealmHasChanges(true); }; const handleSaveRealm = async () => { if (!user || !selectedRealm || !session?.access_token) return; setSavingRealm(true); try { const response = await fetch("/api/profile/update", { method: "PATCH", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session.access_token}`, }, body: JSON.stringify({ user_id: user.id, primary_realm: selectedRealm, experience_level: selectedExperience, }), }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Failed to save realm preference"); } aethexToast.success({ description: "Realm preference saved!", }); setRealmHasChanges(false); } catch (error: any) { aethexToast.error({ description: error?.message || "Failed to save realm preference", }); } finally { setSavingRealm(false); } }; const handleSaveProfile = async () => { if (!user || !session?.access_token) return; setSavingProfile(true); try { const response = await fetch("/api/profile/update", { method: "PATCH", headers: { "Content-Type": "application/json", Authorization: `Bearer ${session.access_token}`, }, body: JSON.stringify({ user_id: user.id, full_name: displayName, bio: bio, website_url: website, linkedin_url: linkedin, github_url: github, twitter_url: twitter, }), }); if (!response.ok) { const data = await response.json(); throw new Error(data.error || "Failed to update profile"); } aethexToast.success({ description: "Profile updated successfully!", }); } catch (error: any) { console.error("Failed to update profile", error); aethexToast.error({ description: error?.message || "Failed to update profile", }); } finally { setSavingProfile(false); } }; const profileUrl = profile?.username ? `https://${profile.username}.aethex.me` : ""; const copyProfileLink = () => { if (profileUrl) { navigator.clipboard.writeText(profileUrl); setProfileLinkCopied(true); setTimeout(() => setProfileLinkCopied(false), 2000); } }; if (authLoading) { return ; } if (!user) { return (

Welcome to AeThex

Sign in to access your personalized dashboard

); } const showProfileSetup = !profileComplete; return (
{/* Header Section */}

Dashboard

Welcome back,{" "} {profile?.full_name || user.email?.split("@")[0]}

{profileComplete && ( Profile Complete )} {profile?.level && ( Level {profile.level} )}
{/* Setup Banner */} {showProfileSetup && (

Complete Your Profile

Set up your profile to unlock all AeThex features and join the community

)}
{/* Tabs Section */} Realms Arms Profile Connections Settings {/* Realms Tab */} {/* Developer CTA Card */} {user && (

Building with AeThex?

Get API keys, access comprehensive documentation, and explore developer tools to integrate AeThex into your applications.

)}
{ARMS.map((arm) => { const IconComponent = arm.icon; return ( ); })}
{/* Profile Tab */}
{/* Profile Card */}
Profile

{profile?.full_name || "User"}

{user.email}

Level {profile?.level || 1}
{/* Edit Profile Form */} Edit Profile Update your public profile information
setDisplayName(e.target.value)} placeholder="Your full name" className="bg-purple-950/30 border-purple-500/20" />