/* P.E.S.T Web App — Profile (username/password + up to 3 referral links) */ function Profile({ onOpenMember }) { const store = useStore(); const me = store.member; const [username, setUsername] = useState(store.user.username); const [pw, setPw] = useState({ cur: "", next: "", conf: "" }); const [refModal, setRefModal] = useState(false); const [pfpIdx, setPfpIdx] = useState(0); const pfps = (me.pfps || []).filter((p) => p.img); useEffect(() => { if (pfps.length < 2) return; const t = setInterval(() => setPfpIdx((x) => (x + 1) % pfps.length), 4200); return () => clearInterval(t); }, [pfps.length]); const myRefs = store.referralsByMember[store.user.nick] || []; const saveUsername = async () => { if (!username.trim()) { toast("Username can't be empty", "err"); return; } await store.setUsername(username.trim()); }; const savePassword = async () => { if (!pw.cur || !pw.next || !pw.conf) { toast("Fill in all password fields", "err"); return; } if (pw.next !== pw.conf) { toast("New passwords don't match", "err"); return; } if (pw.next.length < 6) { toast("Use at least 6 characters", "err"); return; } const ok = await store.changePassword(pw.cur, pw.next); if (ok) setPw({ cur: "", next: "", conf: "" }); }; return (
Profile

Your node

Manage your access and the referral links you share with the hive.

{pfps.length > 0 ? pfps.map((p, k) => {p.name}) :
{me.nick.slice(0, 2)}
}
{me.nick}
{window.roleLabel(me)}
login · {store.user.username}
{pfps.length > 1 &&
{pfps.length} PFPs · managed by admin
}
{/* account */}
Account

Username

setUsername(e.target.value)} />
{/* password */}
Security

Change password

setPw({ ...pw, cur: e.target.value })} placeholder="••••••••" />
setPw({ ...pw, next: e.target.value })} placeholder="••••••••" />
setPw({ ...pw, conf: e.target.value })} placeholder="••••••••" />
{/* referrals */}
Referrals

Your referral links

{myRefs.length}/{window.PEST_APP.MAX_REFS}

Share up to {window.PEST_APP.MAX_REFS} referral links. They appear as badges on your member card so the hive can support you.

{myRefs.length === 0 &&
No referral links yet.
} {myRefs.length > 0 && (
{myRefs.map((r, i) => { const proj = store.projects.find((p) => p.id === r.projectId); if (!proj) return null; return (
{proj.name} {r.url}
); })}
)}
{refModal && setRefModal(false)} />}
); } function AddReferralModal({ onClose }) { const store = useStore(); const myRefs = store.referralsByMember[store.user.nick] || []; const usedIds = new Set(myRefs.map((r) => r.projectId)); const avail = store.projects.filter((p) => !usedIds.has(p.id)); const [pid, setPid] = useState(avail[0] ? avail[0].id : ""); const [url, setUrl] = useState(""); const proj = store.projects.find((p) => p.id === pid); useEffect(() => { const k = (e) => e.key === "Escape" && onClose(); window.addEventListener("keydown", k); return () => window.removeEventListener("keydown", k); }, []); const save = async () => { if (!pid) { toast("Pick a project", "err"); return; } if (!url.trim() || !/^https?:\/\//i.test(url.trim())) { toast("Enter a valid URL (https://…)", "err"); return; } const ok = await store.addReferral(pid, url.trim()); if (ok) onClose(); }; return (
e.stopPropagation()}>

Add referral link

{proj && (
{proj.name}
{(proj.categories && proj.categories.join(" · ")) || proj.category || ""}
)}
setUrl(e.target.value)} placeholder="https://…/ref?code=YOU" />
); } window.Profile = Profile;