/** * @file Profile page component displaying a player's public profile. * @copyright nhcarrigan * @license Naomi's Public License * @author Naomi Carrigan */ /* eslint-disable max-lines-per-function -- Complex component with many render paths */ /* eslint-disable complexity -- Many conditional stat visibility checks */ import { useEffect, useState, type JSX } from "react"; import { formatNumber } from "../../utils/format.js"; import { logError } from "../../utils/logError.js"; import type { PublicProfileResponse } from "@elysium/types"; interface ProfilePageProperties { readonly discordId: string; } interface StatEntry { icon: string; value: string; label: string; date: boolean; } /** * Renders the public profile page for a given player. * @param props - The profile page properties. * @param props.discordId - The Discord ID of the player to display. * @returns The JSX element. */ const ProfilePage = ({ discordId }: ProfilePageProperties): JSX.Element => { const [ profile, setProfile ] = useState(null); const [ error, setError ] = useState(null); const [ copied, setCopied ] = useState(false); useEffect(() => { fetch(`/api/profile/${discordId}`). then(async(response) => { if (!response.ok) { throw new Error("Player not found"); } // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- API response cast return await (response.json() as Promise); }). then(setProfile). catch((error_: unknown) => { setError( error_ instanceof Error ? error_.message : "Failed to load profile", ); }); }, [ discordId ]); function handleCopy(): void { void navigator.clipboard.writeText(window.location.href). then(() => { setCopied(true); setTimeout(() => { setCopied(false); }, 2000); }). catch((error_: unknown) => { logError("clipboard_copy", error_); }); } if (error !== null) { return (

{"⚠️ "} {error}

{"← Play Elysium"}
); } if (profile === null) { return (
{"Loading profile…"}
); } const settings = profile.profileSettings; function fmt(value: number): string { return formatNumber(value, settings.numberFormat); } const avatarUrl = profile.avatar === null ? `https://cdn.discordapp.com/embed/avatars/${String(Number.parseInt(discordId, 10) % 5)}.png` : `https://cdn.discordapp.com/avatars/${discordId}/${profile.avatar}.png?size=128`; const memberSince = new Date(profile.createdAt).toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric", }); const currentRunStatsRaw: Array = [ settings.showCurrentGold && { date: false, icon: "πŸͺ™", label: "Gold Earned", value: fmt(profile.currentRunGold), }, settings.showCurrentClicks && { date: false, icon: "πŸ‘†", label: "Clicks", value: fmt(profile.currentRunClicks), }, settings.showBossesDefeated && { date: false, icon: "πŸ’€", label: "Bosses Defeated", value: String(profile.bossesDefeated), }, settings.showQuestsCompleted && { date: false, icon: "πŸ“œ", label: "Quests Completed", value: String(profile.questsCompleted), }, settings.showAdventurersRecruited && { date: false, icon: "βš”οΈ", label: "Adventurers Recruited", value: fmt(profile.adventurersRecruited), }, settings.showAchievementsUnlocked && { date: false, icon: "πŸ†", label: "Achievements Unlocked", value: String(profile.achievementsUnlocked), }, ]; const currentRunStats = currentRunStatsRaw.filter( (entry): entry is StatEntry => { return entry !== false; }, ); const allTimeStatsRaw: Array = [ settings.showTotalGold && { date: false, icon: "πŸͺ™", label: "Total Gold Earned", value: fmt(profile.totalGoldEarned), }, settings.showTotalClicks && { date: false, icon: "πŸ‘†", label: "Total Clicks", value: fmt(profile.totalClicks), }, settings.showLifetimeBossesDefeated && { date: false, icon: "πŸ’€", label: "Bosses Defeated", value: String(profile.lifetimeBossesDefeated), }, settings.showLifetimeQuestsCompleted && { date: false, icon: "πŸ“œ", label: "Quests Completed", value: String(profile.lifetimeQuestsCompleted), }, settings.showLifetimeAdventurersRecruited && { date: false, icon: "βš”οΈ", label: "Adventurers Recruited", value: fmt(profile.lifetimeAdventurersRecruited), }, settings.showLifetimeAchievementsUnlocked && { date: false, icon: "πŸ†", label: "Achievements Unlocked", value: String(profile.lifetimeAchievementsUnlocked), }, settings.showGuildFounded && { date: true, icon: "πŸ“…", label: "Guild Founded", value: memberSince, }, ]; const allTimeStats = allTimeStatsRaw.filter((entry): entry is StatEntry => { return entry !== false; }); function renderStats(stats: Array): JSX.Element { return (
{stats.map((stat) => { return (
{stat.icon} {stat.value} {stat.label}
); })}
); } return (
{`${profile.username}'s

{profile.characterName}

{"@"} {profile.username}

{settings.showApotheosis && profile.apotheosisCount > 0 ? {"✨ Apotheosis "} {profile.apotheosisCount} : null} {settings.showTranscendence && profile.transcendenceCount > 0 ? {"🌌 Transcendence "} {profile.transcendenceCount} : null} {settings.showPrestige && profile.prestigeCount > 0 ? {"⭐ Prestige "} {profile.prestigeCount} : null}
{profile.bio === "" ? null :

{profile.bio}

} {currentRunStats.length > 0 &&

{"Current Run"}

{renderStats(currentRunStats)}
} {allTimeStats.length > 0 &&

{"All Time"}

{renderStats(allTimeStats)}
}
{"βš”οΈ Play Elysium"}
); }; export { ProfilePage };