import { ArrowLeft, BadgeCheck, CircleAlert, ImagePlus, MonitorSmartphone, ScrollText, Settings2, Sparkles, Star, UserRound } from "lucide-react"; import { useEffect, useState, type ReactNode } from "react"; import { api, errorMessage } from "../api"; import { AccountAvatarModal } from "../components/AccountAvatarModal"; import { ActionButton } from "../components/ActionButton"; import { Avatar } from "../components/Avatar"; import { AuthorizationTable } from "../components/AuthorizationTable"; import { Alert, AuditTable, Badge, LoadingSurface, PageFrame, SectionHead, Summary, UsernameCell } from "../components/ui"; import { ScamFakeActions, ScamFakeBadges } from "../components/flags"; import { ColorAction, EmojiStatusAction, LoginEmailAction, PhoneAction, ProfileNameAction, SupportAction, UsernameAction } from "../components/attributes"; import { displayName, displayPhone, displayUsername, formatDate, formatUnix, toInt } from "../lib/format"; import type { Navigate } from "../routing"; import type { AccountDetail } from "../types"; type Tab = "profile" | "devices" | "actions"; export function AccountDetailPage({ id, navigate }: { id: number; navigate: Navigate }) { const [detail, setDetail] = useState(null); const [error, setError] = useState(""); const [busy, setBusy] = useState(false); const [tab, setTab] = useState("profile"); const [months, setMonths] = useState("1"); const [starsAmount, setStarsAmount] = useState("1000"); const [freezeUntil, setFreezeUntil] = useState(() => toDateTimeLocal(new Date(Date.now() + 7 * 86400_000))); const [freezeAppealURL, setFreezeAppealURL] = useState(""); const [avatarModalOpen, setAvatarModalOpen] = useState(false); const [avatarVersion, setAvatarVersion] = useState(0); async function load() { setBusy(true); setError(""); try { const next = await api.account(id); setDetail(next); if (next.Restriction.Frozen) { if (next.Restriction.Until) { setFreezeUntil(toDateTimeLocal(new Date(next.Restriction.Until))); } setFreezeAppealURL(next.Restriction.AppealURL || ""); } } catch (err) { setError(errorMessage(err)); } finally { setBusy(false); } } useEffect(() => { void load(); setTab("profile"); // eslint-disable-next-line react-hooks/exhaustive-deps }, [id]); if (error) { return {error}; } if (!detail) { return ; } const account = detail.Account; const tabs: Array<{ key: Tab; label: string; icon: ReactNode }> = [ { key: "profile", label: "Profile & Status", icon: }, { key: "devices", label: "Authorized Devices", icon: }, { key: "actions", label: "Actions & Management", icon: } ]; return ( navigate("/accounts")}> {"Back to list"}} >
{displayName(account)}
{displayUsername(account.Username) || "No username"} ยท {displayPhone(account.Phone) || "No phone"}
{account.Collectibles?.length > 0 && (
)}
{account.PremiumUntil > 0 ? {"Premium"} : {"Not premium"}} {detail.Verified ? {"Verified"} : {"Not verified"}} {account.Frozen ? {"Account frozen"} : {"Account active"}}
{tabs.map((item) => ( ))}
{tab === "profile" && (
0 ? formatUnix(account.PremiumUntil) : "None"} />
{detail.About &&

{detail.About}

}
)} {tab === "devices" && (
)} {tab === "actions" && (
} tone="danger" path="/api/actions/set-frozen" payload={() => ({ user_id: account.ID, frozen: true, freeze_until: new Date(freezeUntil).toISOString(), freeze_appeal_url: freezeAppealURL.trim() })} onDone={load} /> {account.Frozen && ( } path="/api/actions/set-frozen" payload={() => ({ user_id: account.ID, frozen: false })} onDone={load} /> )}
} tone="warn" path="/api/actions/grant-premium" payload={() => ({ user_id: account.ID, months: toInt(months) })} onDone={load} /> } tone="warn" path="/api/actions/grant-premium" payload={() => ({ user_id: account.ID, months: 0 })} onDone={load} />
} tone="warn" path="/api/actions/grant-stars" payload={() => ({ user_id: account.ID, amount: toInt(starsAmount) })} onDone={load} />
} tone="warn" path="/api/actions/set-verified" payload={() => ({ user_id: account.ID, verified: !detail.Verified })} onDone={load} />
} />
)} {avatarModalOpen && ( setAvatarModalOpen(false)} onDone={() => { setAvatarVersion((v) => v + 1); void load(); }} /> )}
); } function toDateTimeLocal(date: Date): string { const local = new Date(date.getTime() - date.getTimezoneOffset() * 60_000); return local.toISOString().slice(0, 16); }