snort/src/pages/ProfilePage.js

160 lines
5.5 KiB
JavaScript
Raw Normal View History

2022-12-27 23:46:13 +00:00
import "./ProfilePage.css";
2023-01-09 11:00:23 +00:00
import Nostrich from "../nostrich.jpg";
2023-01-10 10:30:33 +00:00
import { useEffect, useMemo, useState } from "react";
2023-01-09 11:00:23 +00:00
import { useSelector } from "react-redux";
2022-12-29 22:23:41 +00:00
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
2023-01-14 12:25:08 +00:00
import { faQrcode, faGear, faEnvelope } from "@fortawesome/free-solid-svg-icons";
2023-01-09 11:00:23 +00:00
import { useNavigate, useParams } from "react-router-dom";
2022-12-29 22:23:41 +00:00
import useProfile from "../feed/ProfileFeed";
2023-01-01 20:31:09 +00:00
import FollowButton from "../element/FollowButton";
2023-01-14 12:25:08 +00:00
import { extractLnAddress, parseId, hexToBech32 } from "../Util";
import Timeline from "../element/Timeline";
2023-01-14 14:37:31 +00:00
import Text from '../element/Text'
2023-01-07 20:54:12 +00:00
import LNURLTip from "../element/LNURLTip";
2023-01-13 15:25:58 +00:00
import Nip05, { useIsVerified } from "../element/Nip05";
2023-01-09 11:00:23 +00:00
import Copy from "../element/Copy";
2023-01-10 10:30:33 +00:00
import ProfilePreview from "../element/ProfilePreview";
import FollowersList from "../element/FollowersList";
2023-01-10 12:05:36 +00:00
import FollowsList from "../element/FollowsList";
2023-01-10 10:30:33 +00:00
const ProfileTab = {
Notes: 0,
2023-01-10 12:05:36 +00:00
//Reactions: 1,
2023-01-10 10:30:33 +00:00
Followers: 2,
Follows: 3
};
2022-12-18 14:51:32 +00:00
export default function ProfilePage() {
const params = useParams();
2023-01-09 11:00:23 +00:00
const navigate = useNavigate();
2023-01-10 10:30:33 +00:00
const id = useMemo(() => parseId(params.id), [params]);
2022-12-27 23:46:13 +00:00
const user = useProfile(id);
const loginPubKey = useSelector(s => s.login.publicKey);
2023-01-10 10:30:33 +00:00
const follows = useSelector(s => s.login.follows);
2022-12-27 23:46:13 +00:00
const isMe = loginPubKey === id;
2022-12-29 22:23:41 +00:00
const [showLnQr, setShowLnQr] = useState(false);
2023-01-10 10:30:33 +00:00
const [tab, setTab] = useState(ProfileTab.Notes);
2023-01-14 01:39:20 +00:00
const about = Text({ content: user?.about })
2023-01-13 15:25:58 +00:00
const { name, domain, isVerified, couldNotVerify } = useIsVerified(user?.nip05, user?.pubkey)
const avatarUrl = (user?.picture?.length ?? 0) === 0 ? Nostrich : user?.picture
const backgroundImage = `url(${avatarUrl})`
2023-01-10 10:30:33 +00:00
useEffect(() => {
setTab(ProfileTab.Notes);
}, [params]);
2022-12-28 14:51:33 +00:00
2023-01-13 22:48:24 +00:00
function username() {
return (
<div className="name">
<h2>{user?.display_name || user?.name || 'Nostrich'}</h2>
2023-01-13 22:48:24 +00:00
<Copy text={params.id} />
{user?.nip05 && <Nip05 name={name} domain={domain} isVerified={isVerified} couldNotVerify={couldNotVerify} />}
</div>
)
}
function bio() {
2023-01-09 11:00:23 +00:00
const lnurl = extractLnAddress(user?.lud16 || user?.lud06 || "");
2022-12-28 23:28:28 +00:00
return (
2023-01-13 22:48:24 +00:00
<div className="details">
2023-01-15 10:41:34 +00:00
<div>{about}</div>
2023-01-10 07:09:09 +00:00
{user?.website && (
2023-01-10 14:36:23 +00:00
<div className="website f-ellipsis">
<a href={user.website} target="_blank" rel="noreferrer">{user.website}</a>
</div>
2023-01-10 07:09:09 +00:00
)}
2023-01-01 20:31:09 +00:00
{lnurl ? <div className="lnurl f-ellipsis">
{lnurl}
<div className="btn btn-icon" onClick={(e) => setShowLnQr(true)}>
2023-01-10 14:36:23 +00:00
<FontAwesomeIcon icon={faQrcode} size="lg" />
2022-12-28 23:28:28 +00:00
</div>
2022-12-29 22:23:41 +00:00
</div> : null}
2023-01-09 11:00:23 +00:00
<LNURLTip svc={lnurl} show={showLnQr} onClose={() => setShowLnQr(false)} />
2023-01-13 22:48:24 +00:00
</div>
2022-12-28 23:28:28 +00:00
)
}
2023-01-10 10:30:33 +00:00
function tabContent() {
switch (tab) {
case ProfileTab.Notes: return <Timeline pubkeys={id} />;
case ProfileTab.Follows: {
if (isMe) {
2023-01-10 14:36:23 +00:00
return (
<>
<h4>Following {follows.length}</h4>
{follows.map(a => <ProfilePreview key={a} pubkey={a.toLowerCase()} options={{ about: false }} />)}
</>
);
2023-01-10 12:05:36 +00:00
} else {
return <FollowsList pubkey={id} />;
2023-01-10 10:30:33 +00:00
}
}
case ProfileTab.Followers: {
return <FollowersList pubkey={id} />
}
}
return null;
}
function avatar() {
return (
<div className="avatar-wrapper">
<div style={{ '--img-url': backgroundImage }} className="avatar" data-domain={isVerified ? domain : ''}>
</div>
</div>
)
}
function userDetails() {
return (
<div className="details-wrapper">
{username()}
{isMe ? (
<div className="btn btn-icon follow-button" onClick={() => navigate("/settings")}>
<FontAwesomeIcon icon={faGear} size="lg" />
</div>
) : <>
<div className="btn message-button" onClick={() => navigate(`/messages/${hexToBech32("npub", id)}`)}>
<FontAwesomeIcon icon={faEnvelope} size="lg" />
</div>
<FollowButton pubkey={id} />
</>
}
{bio()}
</div>
)
}
2022-12-18 14:51:32 +00:00
return (
2022-12-28 23:28:28 +00:00
<>
2023-01-03 16:55:51 +00:00
<div className="profile flex">
{user?.banner && <img alt="banner" className="banner" src={user.banner} /> }
{user?.banner ? (
<>
{avatar()}
{userDetails()}
</>
) : (
<div className="no-banner">
{avatar()}
{userDetails()}
</div>
)}
2022-12-27 23:46:13 +00:00
</div>
2022-12-30 14:01:51 +00:00
<div className="tabs">
2023-01-10 10:30:33 +00:00
{
Object.entries(ProfileTab).map(([k, v]) => {
return <div className={`tab f-1${tab === v ? " active" : ""}`} key={k} onClick={() => setTab(v)}>{k}</div>
}
)
}
2022-12-30 14:01:51 +00:00
</div>
2023-01-10 10:30:33 +00:00
{tabContent()}
2022-12-28 23:28:28 +00:00
</>
2022-12-18 14:51:32 +00:00
)
}