2022-12-27 23:46:13 +00:00
|
|
|
import "./ProfilePage.css";
|
2023-01-09 11:00:23 +00:00
|
|
|
|
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";
|
|
|
|
import { useNavigate, useParams } from "react-router-dom";
|
2022-12-29 22:23:41 +00:00
|
|
|
|
2023-01-25 18:08:53 +00:00
|
|
|
import Link from "Icons/Link";
|
|
|
|
import Zap from "Icons/Zap";
|
2023-01-20 11:11:50 +00:00
|
|
|
import useProfile from "Feed/ProfileFeed";
|
|
|
|
import FollowButton from "Element/FollowButton";
|
|
|
|
import { extractLnAddress, parseId, hexToBech32 } from "Util";
|
|
|
|
import Avatar from "Element/Avatar";
|
2023-01-26 11:34:18 +00:00
|
|
|
import LogoutButton from "Element/LogoutButton";
|
2023-01-20 11:11:50 +00:00
|
|
|
import Timeline from "Element/Timeline";
|
|
|
|
import Text from 'Element/Text'
|
|
|
|
import LNURLTip from "Element/LNURLTip";
|
|
|
|
import Nip05 from "Element/Nip05";
|
|
|
|
import Copy from "Element/Copy";
|
|
|
|
import ProfilePreview from "Element/ProfilePreview";
|
|
|
|
import FollowersList from "Element/FollowersList";
|
2023-01-27 21:10:14 +00:00
|
|
|
import BlockList from "Element/BlockList";
|
2023-01-26 11:34:18 +00:00
|
|
|
import MutedList from "Element/MutedList";
|
2023-01-20 11:11:50 +00:00
|
|
|
import FollowsList from "Element/FollowsList";
|
|
|
|
import { RootState } from "State/Store";
|
|
|
|
import { HexKey } from "Nostr";
|
|
|
|
import FollowsYou from "Element/FollowsYou"
|
2023-01-10 10:30:33 +00:00
|
|
|
|
2023-01-16 17:48:25 +00:00
|
|
|
enum ProfileTab {
|
|
|
|
Notes = "Notes",
|
|
|
|
Reactions = "Reactions",
|
|
|
|
Followers = "Followers",
|
2023-01-26 11:34:18 +00:00
|
|
|
Follows = "Follows",
|
2023-01-28 18:30:39 +00:00
|
|
|
Muted = "Muted",
|
|
|
|
Blocked = "Blocked"
|
2023-01-10 10:30:33 +00:00
|
|
|
};
|
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-16 17:48:25 +00:00
|
|
|
const id = useMemo(() => parseId(params.id!), [params]);
|
|
|
|
const user = useProfile(id)?.get(id);
|
2023-01-26 06:51:38 +00:00
|
|
|
const loggedOut = useSelector<RootState, boolean | undefined>(s => s.login.loggedOut);
|
2023-01-16 17:48:25 +00:00
|
|
|
const loginPubKey = useSelector<RootState, HexKey | undefined>(s => s.login.publicKey);
|
|
|
|
const follows = useSelector<RootState, HexKey[]>(s => s.login.follows);
|
2022-12-27 23:46:13 +00:00
|
|
|
const isMe = loginPubKey === id;
|
2023-01-16 17:48:25 +00:00
|
|
|
const [showLnQr, setShowLnQr] = useState<boolean>(false);
|
2023-01-10 10:30:33 +00:00
|
|
|
const [tab, setTab] = useState(ProfileTab.Notes);
|
2023-01-25 18:08:53 +00:00
|
|
|
const aboutText = user?.about || ''
|
2023-01-16 17:39:30 +00:00
|
|
|
const about = Text({ content: user?.about || '', tags: [], users: new Map() })
|
2023-01-25 18:08:53 +00:00
|
|
|
const lnurl = extractLnAddress(user?.lud16 || user?.lud06 || "");
|
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() {
|
2023-01-16 17:48:25 +00:00
|
|
|
return (
|
|
|
|
<div className="name">
|
2023-01-18 23:31:34 +00:00
|
|
|
<h2>
|
2023-01-19 18:00:56 +00:00
|
|
|
{user?.display_name || user?.name || 'Nostrich'}
|
|
|
|
<FollowsYou pubkey={id} />
|
2023-01-18 23:31:34 +00:00
|
|
|
</h2>
|
2023-01-16 17:48:25 +00:00
|
|
|
{user?.nip05 && <Nip05 nip05={user.nip05} pubkey={user.pubkey} />}
|
2023-01-25 18:08:53 +00:00
|
|
|
<Copy text={params.id || ""} />
|
|
|
|
{links()}
|
2023-01-18 03:26:42 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2023-01-19 18:00:56 +00:00
|
|
|
|
2023-01-25 18:08:53 +00:00
|
|
|
function links() {
|
|
|
|
return (
|
|
|
|
<div className="links">
|
|
|
|
{user?.website && (
|
|
|
|
<div className="website f-ellipsis">
|
|
|
|
<span className="link-icon">
|
|
|
|
<Link />
|
|
|
|
</span>
|
|
|
|
<a href={user.website} target="_blank" rel="noreferrer">{user.website}</a>
|
|
|
|
</div>
|
|
|
|
)}
|
2023-01-10 07:09:09 +00:00
|
|
|
|
2023-01-25 18:08:53 +00:00
|
|
|
{lnurl && (
|
|
|
|
<div className="ln-address" onClick={(e) => setShowLnQr(true)}>
|
|
|
|
<span className="link-icon">
|
|
|
|
<Zap />
|
|
|
|
</span>
|
|
|
|
<span className="lnurl f-ellipsis" >
|
|
|
|
{lnurl}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
<LNURLTip svc={lnurl} show={showLnQr} onClose={() => setShowLnQr(false)} />
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
2023-01-01 20:31:09 +00:00
|
|
|
|
2023-01-25 18:08:53 +00:00
|
|
|
function bio() {
|
|
|
|
return aboutText.length > 0 && (
|
|
|
|
<>
|
|
|
|
<h3>Bio</h3>
|
|
|
|
<div className="details">
|
|
|
|
{about}
|
|
|
|
</div>
|
|
|
|
</>
|
2022-12-28 23:28:28 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-01-10 10:30:33 +00:00
|
|
|
function tabContent() {
|
|
|
|
switch (tab) {
|
2023-01-17 00:54:08 +00:00
|
|
|
case ProfileTab.Notes:
|
2023-01-19 18:00:56 +00:00
|
|
|
return <Timeline key={id} subject={{ type: "pubkey", items: [id] }} postsOnly={false} method={"LIMIT_UNTIL"} />;
|
2023-01-10 10:30:33 +00:00
|
|
|
case ProfileTab.Follows: {
|
|
|
|
if (isMe) {
|
2023-01-10 14:36:23 +00:00
|
|
|
return (
|
2023-01-25 21:41:01 +00:00
|
|
|
<div className="main-content">
|
2023-01-10 14:36:23 +00:00
|
|
|
<h4>Following {follows.length}</h4>
|
|
|
|
{follows.map(a => <ProfilePreview key={a} pubkey={a.toLowerCase()} options={{ about: false }} />)}
|
2023-01-25 21:41:01 +00:00
|
|
|
</div>
|
2023-01-10 14:36:23 +00:00
|
|
|
);
|
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} />
|
|
|
|
}
|
2023-01-26 11:34:18 +00:00
|
|
|
case ProfileTab.Muted: {
|
2023-01-28 18:30:39 +00:00
|
|
|
return isMe ? <BlockList variant="muted" /> : <MutedList pubkey={id} />
|
|
|
|
}
|
|
|
|
case ProfileTab.Blocked: {
|
|
|
|
return isMe ? <BlockList variant="blocked" /> : null
|
2023-01-26 11:34:18 +00:00
|
|
|
}
|
2023-01-10 10:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-14 13:28:22 +00:00
|
|
|
function avatar() {
|
2023-01-15 19:40:47 +00:00
|
|
|
return (
|
|
|
|
<div className="avatar-wrapper">
|
2023-01-18 16:13:38 +00:00
|
|
|
<Avatar user={user} />
|
2023-01-15 19:40:47 +00:00
|
|
|
</div>
|
|
|
|
)
|
2023-01-14 13:28:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function userDetails() {
|
2023-01-15 19:40:47 +00:00
|
|
|
return (
|
|
|
|
<div className="details-wrapper">
|
|
|
|
{username()}
|
2023-01-25 18:08:53 +00:00
|
|
|
<div className="profile-actions">
|
|
|
|
{isMe ? (
|
2023-01-26 11:34:18 +00:00
|
|
|
<>
|
|
|
|
<LogoutButton />
|
2023-01-25 18:08:53 +00:00
|
|
|
<button type="button" onClick={() => navigate("/settings")}>
|
|
|
|
Settings
|
|
|
|
</button>
|
2023-01-26 11:34:18 +00:00
|
|
|
</>
|
2023-01-25 18:08:53 +00:00
|
|
|
) : (
|
2023-01-26 06:51:38 +00:00
|
|
|
!loggedOut && (
|
|
|
|
<>
|
|
|
|
<button type="button" onClick={() => navigate(`/messages/${hexToBech32("npub", id)}`)}>
|
|
|
|
Message
|
|
|
|
</button>
|
|
|
|
<FollowButton pubkey={id} />
|
|
|
|
</>
|
|
|
|
)
|
2023-01-25 18:08:53 +00:00
|
|
|
)}
|
|
|
|
</div>
|
2023-01-15 19:40:47 +00:00
|
|
|
{bio()}
|
|
|
|
</div>
|
|
|
|
)
|
2023-01-14 13:28:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-28 18:30:39 +00:00
|
|
|
function renderTab(v: ProfileTab) {
|
|
|
|
return <div className={`tab f-1${tab === v ? " active" : ""}`} key={v} onClick={() => setTab(v)}>{v}</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">
|
2023-01-25 18:08:53 +00:00
|
|
|
{user?.banner && <img alt="banner" className="banner" src={user.banner} />}
|
|
|
|
<div className="profile-wrapper flex">
|
|
|
|
{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-28 18:30:39 +00:00
|
|
|
{[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows, ProfileTab.Muted].map(renderTab)}
|
|
|
|
{isMe && renderTab(ProfileTab.Blocked)}
|
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
|
|
|
)
|
2023-01-10 09:18:46 +00:00
|
|
|
}
|