feat: nip5 in profile path

This commit is contained in:
Kieran 2023-02-27 13:17:13 +00:00
parent 688c5cf4f8
commit 45c4c3bce1
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
10 changed files with 56 additions and 40 deletions

View File

@ -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);
}

View File

@ -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]);

View File

@ -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())];

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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]);

View File

@ -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]);

View File

@ -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;

View File

@ -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")) {

View File

@ -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">