/* 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) =>

)
:
{me.nick.slice(0, 2)}
}
{me.nick}
{window.roleLabel(me)}
login · {store.user.username}
{pfps.length > 1 &&
{pfps.length} PFPs · managed by admin
}
{/* account */}
{/* password */}
{/* 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;