feat: nip5 in profile path
This commit is contained in:
parent
688c5cf4f8
commit
45c4c3bce1
@ -4,7 +4,7 @@ import { RootState } from "State/Store";
|
||||
import { HexKey, Lists } from "@snort/nostr";
|
||||
import useNotelistSubscription from "Feed/useNotelistSubscription";
|
||||
|
||||
export default function useBookmarkFeed(pubkey: HexKey) {
|
||||
export default function useBookmarkFeed(pubkey?: HexKey) {
|
||||
const { bookmarked } = useSelector((s: RootState) => s.login);
|
||||
return useNotelistSubscription(pubkey, Lists.Bookmarked, bookmarked);
|
||||
}
|
||||
|
@ -3,8 +3,9 @@ import { HexKey } from "@snort/nostr";
|
||||
import { EventKind, Subscriptions } from "@snort/nostr";
|
||||
import useSubscription from "Feed/Subscription";
|
||||
|
||||
export default function useFollowersFeed(pubkey: HexKey) {
|
||||
export default function useFollowersFeed(pubkey?: HexKey) {
|
||||
const sub = useMemo(() => {
|
||||
if (!pubkey) return null;
|
||||
const x = new Subscriptions();
|
||||
x.Id = `followers:${pubkey.slice(0, 12)}`;
|
||||
x.Kinds = new Set([EventKind.ContactList]);
|
||||
|
@ -5,12 +5,12 @@ import { HexKey, TaggedRawEvent, EventKind, Subscriptions } from "@snort/nostr";
|
||||
import useSubscription from "Feed/Subscription";
|
||||
import { RootState } from "State/Store";
|
||||
|
||||
export default function useFollowsFeed(pubkey: HexKey) {
|
||||
export default function useFollowsFeed(pubkey?: HexKey) {
|
||||
const { publicKey, follows } = useSelector((s: RootState) => s.login);
|
||||
const isMe = publicKey === pubkey;
|
||||
|
||||
const sub = useMemo(() => {
|
||||
if (isMe) return null;
|
||||
if (isMe || !pubkey) return null;
|
||||
const x = new Subscriptions();
|
||||
x.Id = `follows:${pubkey.slice(0, 12)}`;
|
||||
x.Kinds = new Set([EventKind.ContactList]);
|
||||
@ -23,11 +23,12 @@ export default function useFollowsFeed(pubkey: HexKey) {
|
||||
if (isMe) {
|
||||
return follows;
|
||||
}
|
||||
|
||||
return getFollowing(contactFeed.store.notes ?? [], pubkey);
|
||||
}, [contactFeed.store, follows]);
|
||||
}, [contactFeed.store, follows, pubkey]);
|
||||
}
|
||||
|
||||
export function getFollowing(notes: TaggedRawEvent[], pubkey: HexKey) {
|
||||
export function getFollowing(notes: TaggedRawEvent[], pubkey?: HexKey) {
|
||||
const contactLists = notes.filter(a => a.kind === EventKind.ContactList && a.pubkey === pubkey);
|
||||
const pTags = contactLists?.map(a => a.tags.filter(b => b[0] === "p").map(c => c[1]));
|
||||
return [...new Set(pTags?.flat())];
|
||||
|
@ -7,12 +7,12 @@ import { EventKind, Subscriptions } from "@snort/nostr";
|
||||
import useSubscription, { NoteStore } from "Feed/Subscription";
|
||||
import { RootState } from "State/Store";
|
||||
|
||||
export default function useMutedFeed(pubkey: HexKey) {
|
||||
export default function useMutedFeed(pubkey?: HexKey) {
|
||||
const { publicKey, muted } = useSelector((s: RootState) => s.login);
|
||||
const isMe = publicKey === pubkey;
|
||||
|
||||
const sub = useMemo(() => {
|
||||
if (isMe) return null;
|
||||
if (isMe || !pubkey) return null;
|
||||
const sub = new Subscriptions();
|
||||
sub.Id = `muted:${pubkey.slice(0, 12)}`;
|
||||
sub.Kinds = new Set([EventKind.PubkeyLists]);
|
||||
@ -25,8 +25,11 @@ export default function useMutedFeed(pubkey: HexKey) {
|
||||
const mutedFeed = useSubscription(sub, { leaveOpen: false, cache: true });
|
||||
|
||||
const mutedList = useMemo(() => {
|
||||
return getMuted(mutedFeed.store, pubkey);
|
||||
}, [mutedFeed.store]);
|
||||
if (pubkey) {
|
||||
return getMuted(mutedFeed.store, pubkey);
|
||||
}
|
||||
return [];
|
||||
}, [mutedFeed.store, pubkey]);
|
||||
|
||||
return isMe ? muted : mutedList;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { RootState } from "State/Store";
|
||||
import { HexKey, Lists } from "@snort/nostr";
|
||||
import useNotelistSubscription from "Feed/useNotelistSubscription";
|
||||
|
||||
export default function usePinnedFeed(pubkey: HexKey) {
|
||||
export default function usePinnedFeed(pubkey?: HexKey) {
|
||||
const { pinned } = useSelector((s: RootState) => s.login);
|
||||
return useNotelistSubscription(pubkey, Lists.Pinned, pinned);
|
||||
}
|
||||
|
@ -3,8 +3,9 @@ import { HexKey, FullRelaySettings } from "@snort/nostr";
|
||||
import { EventKind, Subscriptions } from "@snort/nostr";
|
||||
import useSubscription from "./Subscription";
|
||||
|
||||
export default function useRelaysFeed(pubkey: HexKey) {
|
||||
export default function useRelaysFeed(pubkey?: HexKey) {
|
||||
const sub = useMemo(() => {
|
||||
if (!pubkey) return null;
|
||||
const x = new Subscriptions();
|
||||
x.Id = `relays:${pubkey.slice(0, 12)}`;
|
||||
x.Kinds = new Set([EventKind.ContactList]);
|
||||
|
@ -3,8 +3,9 @@ import { HexKey, EventKind, Subscriptions } from "@snort/nostr";
|
||||
import { parseZap } from "Element/Zap";
|
||||
import useSubscription from "./Subscription";
|
||||
|
||||
export default function useZapsFeed(pubkey: HexKey) {
|
||||
export default function useZapsFeed(pubkey?: HexKey) {
|
||||
const sub = useMemo(() => {
|
||||
if (!pubkey) return null;
|
||||
const x = new Subscriptions();
|
||||
x.Id = `zaps:${pubkey.slice(0, 12)}`;
|
||||
x.Kinds = new Set([EventKind.ZapReceipt]);
|
||||
|
@ -6,12 +6,12 @@ import { HexKey, Lists, EventKind, Subscriptions } from "@snort/nostr";
|
||||
import useSubscription from "Feed/Subscription";
|
||||
import { RootState } from "State/Store";
|
||||
|
||||
export default function useNotelistSubscription(pubkey: HexKey, l: Lists, defaultIds: HexKey[]) {
|
||||
export default function useNotelistSubscription(pubkey: HexKey | undefined, l: Lists, defaultIds: HexKey[]) {
|
||||
const { preferences, publicKey } = useSelector((s: RootState) => s.login);
|
||||
const isMe = publicKey === pubkey;
|
||||
|
||||
const sub = useMemo(() => {
|
||||
if (isMe) return null;
|
||||
if (isMe || !pubkey) return null;
|
||||
const sub = new Subscriptions();
|
||||
sub.Id = `note-list-${l}:${pubkey.slice(0, 12)}`;
|
||||
sub.Kinds = new Set([EventKind.NoteLists]);
|
||||
@ -33,12 +33,13 @@ export default function useNotelistSubscription(pubkey: HexKey, l: Lists, defaul
|
||||
}, [store.notes, isMe, defaultIds]);
|
||||
|
||||
const esub = useMemo(() => {
|
||||
if (!pubkey) return null;
|
||||
const s = new Subscriptions();
|
||||
s.Id = `${l}-notes:${pubkey.slice(0, 12)}`;
|
||||
s.Kinds = new Set([EventKind.TextNote]);
|
||||
s.Ids = new Set(etags);
|
||||
return s;
|
||||
}, [etags]);
|
||||
}, [etags, pubkey]);
|
||||
|
||||
const subRelated = useMemo(() => {
|
||||
let sub: Subscriptions | undefined;
|
||||
|
@ -46,6 +46,19 @@ const Artwork: Array<ArtworkEntry> = [
|
||||
},
|
||||
];
|
||||
|
||||
export async function getNip05PubKey(addr: string): Promise<string> {
|
||||
const [username, domain] = addr.split("@");
|
||||
const rsp = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username)}`);
|
||||
if (rsp.ok) {
|
||||
const data = await rsp.json();
|
||||
const pKey = data.names[username];
|
||||
if (pKey) {
|
||||
return pKey;
|
||||
}
|
||||
}
|
||||
throw new Error("User key not found");
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
@ -69,19 +82,6 @@ export default function LoginPage() {
|
||||
setArt(ret);
|
||||
}, []);
|
||||
|
||||
async function getNip05PubKey(addr: string) {
|
||||
const [username, domain] = addr.split("@");
|
||||
const rsp = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(username)}`);
|
||||
if (rsp.ok) {
|
||||
const data = await rsp.json();
|
||||
const pKey = data.names[username];
|
||||
if (pKey) {
|
||||
return pKey;
|
||||
}
|
||||
}
|
||||
throw new Error("User key not found");
|
||||
}
|
||||
|
||||
async function doLogin() {
|
||||
try {
|
||||
if (key.startsWith("nsec")) {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import "./ProfilePage.css";
|
||||
import { useEffect, useMemo, useState, CSSProperties } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useIntl, FormattedMessage } from "react-intl";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { NostrPrefix } from "@snort/nostr";
|
||||
|
||||
import { unwrap } from "Util";
|
||||
import { formatShort } from "Number";
|
||||
@ -32,20 +33,20 @@ import Text from "Element/Text";
|
||||
import SendSats from "Element/SendSats";
|
||||
import Nip05 from "Element/Nip05";
|
||||
import Copy from "Element/Copy";
|
||||
import ProfilePreview from "Element/ProfilePreview";
|
||||
import ProfileImage from "Element/ProfileImage";
|
||||
import BlockList from "Element/BlockList";
|
||||
import MutedList from "Element/MutedList";
|
||||
import FollowsList from "Element/FollowListBase";
|
||||
import IconButton from "Element/IconButton";
|
||||
import { RootState } from "State/Store";
|
||||
import { HexKey, NostrPrefix } from "@snort/nostr";
|
||||
import FollowsYou from "Element/FollowsYou";
|
||||
import QrCode from "Element/QrCode";
|
||||
import Modal from "Element/Modal";
|
||||
import { ProxyImg } from "Element/ProxyImg";
|
||||
import useHorizontalScroll from "Hooks/useHorizontalScroll";
|
||||
import messages from "./messages";
|
||||
import { EmailRegex } from "Const";
|
||||
import { getNip05PubKey } from "./Login";
|
||||
|
||||
const NOTES = 0;
|
||||
const REACTIONS = 1;
|
||||
@ -61,10 +62,9 @@ export default function ProfilePage() {
|
||||
const { formatMessage } = useIntl();
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
const id = useMemo(() => parseId(params.id ?? ""), [params]);
|
||||
const [id, setId] = useState<string>();
|
||||
const user = useUserProfile(id);
|
||||
const loggedOut = useSelector<RootState, boolean | undefined>(s => s.login.loggedOut);
|
||||
const loginPubKey = useSelector<RootState, HexKey | undefined>(s => s.login.publicKey);
|
||||
const loginPubKey = useSelector((s: RootState) => s.login.publicKey);
|
||||
const isMe = loginPubKey === id;
|
||||
const [showLnQr, setShowLnQr] = useState<boolean>(false);
|
||||
const [showProfileQr, setShowProfileQr] = useState<boolean>(false);
|
||||
@ -75,7 +75,7 @@ export default function ProfilePage() {
|
||||
users: new Map(),
|
||||
creator: "",
|
||||
});
|
||||
const npub = !id.startsWith("npub") ? hexToBech32("npub", id || undefined) : id;
|
||||
const npub = !id?.startsWith("npub") ? hexToBech32("npub", id || undefined) : id;
|
||||
|
||||
const lnurl = extractLnAddress(user?.lud16 || user?.lud06 || "");
|
||||
const website_url =
|
||||
@ -112,6 +112,13 @@ export default function ProfilePage() {
|
||||
const horizontalScroll = useHorizontalScroll();
|
||||
|
||||
useEffect(() => {
|
||||
if (params.id?.match(EmailRegex)) {
|
||||
getNip05PubKey(params.id).then(a => {
|
||||
setId(a);
|
||||
});
|
||||
} else {
|
||||
setId(parseId(params.id ?? ""));
|
||||
}
|
||||
setTab(ProfileTab.Notes);
|
||||
}, [params]);
|
||||
|
||||
@ -174,6 +181,8 @@ export default function ProfilePage() {
|
||||
}
|
||||
|
||||
function tabContent() {
|
||||
if (!id) return null;
|
||||
|
||||
switch (tab.value) {
|
||||
case NOTES:
|
||||
return (
|
||||
@ -254,7 +263,7 @@ export default function ProfilePage() {
|
||||
</IconButton>
|
||||
{showProfileQr && (
|
||||
<Modal className="qr-modal" onClose={() => setShowProfileQr(false)}>
|
||||
<ProfileImage pubkey={id} />
|
||||
<ProfileImage pubkey={id ?? ""} />
|
||||
<QrCode
|
||||
data={`nostr:${hexToBech32(NostrPrefix.PublicKey, id)}`}
|
||||
link={undefined}
|
||||
@ -275,7 +284,7 @@ export default function ProfilePage() {
|
||||
<Zap width={14} height={16} />
|
||||
</IconButton>
|
||||
)}
|
||||
{!loggedOut && (
|
||||
{loginPubKey && (
|
||||
<>
|
||||
<IconButton onClick={() => navigate(`/messages/${hexToBech32(NostrPrefix.PublicKey, id)}`)}>
|
||||
<Envelope width={16} height={13} />
|
||||
@ -294,7 +303,7 @@ export default function ProfilePage() {
|
||||
{username()}
|
||||
<div className="profile-actions">
|
||||
{renderIcons()}
|
||||
{!isMe && <FollowButton pubkey={id} />}
|
||||
{!isMe && <FollowButton pubkey={id ?? ""} />}
|
||||
</div>
|
||||
{bio()}
|
||||
</div>
|
||||
@ -306,7 +315,6 @@ export default function ProfilePage() {
|
||||
}
|
||||
|
||||
const w = window.document.querySelector(".page")?.clientWidth;
|
||||
const bannerStyle = user?.banner ? ({ "--img-url": `url(${user.banner})` } as CSSProperties) : {};
|
||||
return (
|
||||
<>
|
||||
<div className="profile flex">
|
||||
|
Loading…
x
Reference in New Issue
Block a user