import { useEffect, useMemo, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import Layout from "@/components/Layout"; import LoadingScreen from "@/components/LoadingScreen"; import { useAuth } from "@/contexts/AuthContext"; import { aethexAchievementService, type AethexAchievement, } from "@/lib/aethex-database-adapter"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { CalendarClock, Compass, Edit, MapPin, Rocket, Shield, Trophy, UserCircle, Briefcase, Code2, Globe, Award, } from "lucide-react"; interface ProfileStat { label: string; value: string; helper?: string; Icon: typeof UserCircle; } const safeRelativeDate = (value?: string | null) => { if (!value) return null; const date = new Date(value); if (Number.isNaN(date.getTime())) return null; const diff = Date.now() - date.getTime(); const minutes = Math.round(diff / (1000 * 60)); if (minutes < 1) return "just now"; if (minutes < 60) return `${minutes} min ago`; const hours = Math.round(minutes / 60); if (hours < 24) return `${hours} hr ago`; const days = Math.round(hours / 24); if (days < 7) return `${days} day${days === 1 ? "" : "s"} ago`; const weeks = Math.round(days / 7); if (weeks < 5) return `${weeks} wk${weeks === 1 ? "" : "s"} ago`; const months = Math.round(days / 30.4375); if (months < 12) return `${months} mo${months === 1 ? "" : "s"} ago`; const years = Math.round(days / 365.25); return `${years} yr${years === 1 ? "" : "s"} ago`; }; const Profile = () => { const navigate = useNavigate(); const { user, profile, loading: authLoading } = useAuth(); const [achievements, setAchievements] = useState([]); const [loadingAchievements, setLoadingAchievements] = useState(false); const username = profile?.username || user?.email?.split("@")[0] || "creator"; const passportHref = `/passport/${encodeURIComponent(username)}`; const dashboardSettingsHref = "/dashboard?tab=profile#settings"; useEffect(() => { if (!authLoading && !user) { navigate("/login", { replace: true }); } }, [authLoading, user, navigate]); useEffect(() => { const loadAchievements = async () => { if (!user?.id) return; setLoadingAchievements(true); try { const data = await aethexAchievementService.getUserAchievements( user.id, ); setAchievements(data.slice(0, 6)); } catch (error) { console.warn("Failed to load achievements for profile overview", error); setAchievements([]); } finally { setLoadingAchievements(false); } }; loadAchievements().catch(() => undefined); }, [user?.id]); const stats = useMemo(() => { const level = Math.max(1, Number(profile?.level ?? 1)); const totalXp = Math.max(0, Number(profile?.total_xp ?? 0)); const loyalty = Math.max(0, Number((profile as any)?.loyalty_points ?? 0)); const streak = Math.max(0, Number(profile?.current_streak ?? 0)); return [ { label: "Level", value: `Lv ${level}`, helper: "Progress toward next milestone", Icon: Shield, }, { label: "Total XP", value: `${totalXp.toLocaleString()} XP`, helper: "Earned across AeThex activities", Icon: Rocket, }, { label: "Loyalty", value: loyalty.toLocaleString(), helper: "Reward points available", Icon: Trophy, }, { label: "Streak", value: `${streak} day${streak === 1 ? "" : "s"}`, helper: "Keep shipping to extend your streak", Icon: CalendarClock, }, ]; }, [profile]); const socialLinks = useMemo(() => { const entries: { label: string; url: string; domain: string }[] = []; const maybePush = (label: string, value?: string | null) => { if (!value) return; const trimmed = value.trim(); if (!trimmed) return; const url = /^https?:/i.test(trimmed) ? trimmed : `https://${trimmed}`; try { const u = new URL(url); entries.push({ label, url: u.toString(), domain: u.host }); } catch (error) { console.warn(`Skipping invalid ${label} link`, value, error); } }; maybePush("Website", (profile as any)?.website_url); maybePush("GitHub", profile?.github_url); maybePush("LinkedIn", profile?.linkedin_url); maybePush("Twitter", profile?.twitter_url); return entries; }, [profile]); if (authLoading || !user || !profile) { return ; } const lastUpdated = safeRelativeDate(profile.updated_at); const memberSince = safeRelativeDate(profile.created_at); return (
{(profile.full_name || username) .split(" ") .map((name) => name[0]) .join("") .toUpperCase() .slice(0, 2)}
{profile.full_name || username} {profile.user_type ? ( {profile.user_type.replace(/_/g, " ")} ) : null} {profile.experience_level ? ( {profile.experience_level} ) : null} {profile.location ? ( {profile.location} ) : null}
{profile.bio ? (

{profile.bio}

) : (

Share your story by updating your profile bio.

)}
{memberSince ? (

Joined {memberSince}

) : null} {lastUpdated ? (

Updated {lastUpdated}

) : null}
Progress snapshot Where you stand across AeThex programs.
{stats.map(({ label, value, helper, Icon }) => (

{label}

{value}

{helper ? (

{helper}

) : null}
))}
About {profile.full_name || username} Community presence, specialties, and how to collaborate with you.

Role focus

{profile.user_type ? profile.user_type.replace(/_/g, " ") : "Tell the community what you love building."}

Experience level

{profile.experience_level || "Let collaborators know your seniority."}

Links & presence

{socialLinks.length ? (
{socialLinks.map((link) => ( {link.label} {link.domain} ))}
) : (

Add your links to help collaborators discover your work.

)}
{/* SKILLS & LANGUAGES */} {(profile.skills_detailed && profile.skills_detailed.length > 0) || (profile.languages && profile.languages.length > 0) ? ( Skills & Languages Technical expertise and languages you speak. {profile.skills_detailed && profile.skills_detailed.length > 0 ? (

Technical Skills

{(profile.skills_detailed as any[]).map( (skill: any, idx: number) => ( {skill.name}{" "} • {skill.level} ), )}
) : null} {profile.languages && profile.languages.length > 0 ? (

Languages

{(profile.languages as string[]).map( (lang: string, idx: number) => ( {lang} ), )}
) : null}
) : null} {/* WORK EXPERIENCE */} {profile.work_experience && profile.work_experience.length > 0 ? ( Work Experience Professional background and experience. {(profile.work_experience as any[]).map( (exp: any, idx: number) => (

{exp.title}

{exp.duration}

{exp.company}

{exp.description && (

{exp.description}

)}
), )}
) : null} {/* PORTFOLIO ITEMS */} {profile.portfolio_items && profile.portfolio_items.length > 0 ? ( Portfolio Featured projects and work samples. {(profile.portfolio_items as any[]).map( (item: any, idx: number) => (

{item.title}

{item.description && (

{item.description}

)}

{item.url}

), )}
) : null} {/* ARM AFFILIATIONS */} {profile.arm_affiliations && profile.arm_affiliations.length > 0 ? ( Arm Affiliations Part of these AeThex arms and initiatives.
{(profile.arm_affiliations as string[]).map( (arm: string) => { const armConfig: Record< string, { label: string; color: string } > = { foundation: { label: "Foundation", color: "bg-red-500/20 text-red-200 border-red-500/40", }, gameforge: { label: "GameForge", color: "bg-green-500/20 text-green-200 border-green-500/40", }, labs: { label: "Labs", color: "bg-yellow-500/20 text-yellow-200 border-yellow-500/40", }, corp: { label: "Corp", color: "bg-blue-500/20 text-blue-200 border-blue-500/40", }, devlink: { label: "Dev-Link", color: "bg-cyan-500/20 text-cyan-200 border-cyan-500/40", }, }; const config = armConfig[arm] || { label: arm, color: "bg-slate-500/20 text-slate-200 border-slate-500/40", }; return ( {config.label} ); }, )}
) : null} Recent achievements Milestones you've unlocked across AeThex games and programs. {loadingAchievements ? (
Syncing achievements…
) : achievements.length ? (
{achievements.map((achievement) => (

{achievement.name}

+{achievement.xp_reward} XP

{achievement.description}

))}
) : (

Start contributing to unlock your first AeThex achievement.

)}
); }; export default Profile;