feat: nip-89
This commit is contained in:
@ -24,6 +24,7 @@ import { NoteProps } from "../EventComponent";
|
||||
import HiddenNote from "../HiddenNote";
|
||||
import Poll from "../Poll";
|
||||
import NoteFooter from "./NoteFooter/NoteFooter";
|
||||
import NoteAppHandler from "./NoteAppHandler";
|
||||
|
||||
const defaultOptions = {
|
||||
showHeader: true,
|
||||
@ -169,22 +170,9 @@ function Reaction({ ev }: { ev: TaggedNostrEvent }) {
|
||||
}
|
||||
|
||||
function handleNonTextNote(ev: TaggedNostrEvent) {
|
||||
const alt = findTag(ev, "alt");
|
||||
if (alt) {
|
||||
return (
|
||||
<div className="note-quote">
|
||||
<Text id={ev.id} content={alt} tags={[]} creator={ev.pubkey} />
|
||||
</div>
|
||||
);
|
||||
} else if (ev.kind === EventKind.Reaction) {
|
||||
if (ev.kind === EventKind.Reaction) {
|
||||
return <Reaction ev={ev} />;
|
||||
} else {
|
||||
return (
|
||||
<div className="card">
|
||||
<CollapsedSection title={<FormattedMessage {...messages.UnknownEventKind} values={{ kind: ev.kind }} />}>
|
||||
<pre className="text-xs">{JSON.stringify(ev, undefined, " ")}</pre>
|
||||
</CollapsedSection>
|
||||
</div>
|
||||
);
|
||||
return <NoteAppHandler ev={ev} />;
|
||||
}
|
||||
}
|
||||
|
44
packages/app/src/Components/Event/Note/NoteAppHandler.tsx
Normal file
44
packages/app/src/Components/Event/Note/NoteAppHandler.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { mapEventToProfile, NostrLink, TaggedNostrEvent } from "@snort/system";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import Icon from "@/Components/Icons/Icon";
|
||||
import Avatar from "@/Components/User/Avatar";
|
||||
import DisplayName from "@/Components/User/DisplayName";
|
||||
import useAppHandler from "@/Hooks/useAppHandler";
|
||||
|
||||
export default function NoteAppHandler({ ev }: { ev: TaggedNostrEvent }) {
|
||||
const handlers = useAppHandler(ev.kind);
|
||||
const link = NostrLink.fromEvent(ev);
|
||||
|
||||
const profiles = handlers.apps
|
||||
.map(a => ({ profile: mapEventToProfile(a), event: a }))
|
||||
.filter(a => a.profile)
|
||||
.slice(0, 5);
|
||||
|
||||
return (
|
||||
<div className="card flex flex-col gap-2">
|
||||
<small>
|
||||
<FormattedMessage defaultMessage="Sorry, we dont understand this event kind, please try one of the following apps instead!" />
|
||||
</small>
|
||||
{profiles.map(a => (
|
||||
<div className="flex justify-between items-center" key={a.event.id}>
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar size={40} pubkey={a.event.pubkey} user={a.profile} />
|
||||
<div>
|
||||
<DisplayName pubkey={a.event.pubkey} user={a.profile} />
|
||||
</div>
|
||||
</div>
|
||||
<Icon
|
||||
name="link"
|
||||
onClick={() => {
|
||||
const webHandler = a.event.tags.find(a => a[0] === "web" && a[2] === "nevent")?.[1];
|
||||
if (webHandler) {
|
||||
window.open(webHandler.replace("<bech32>", link.encode()), "_blank");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -12,9 +12,9 @@ interface DisplayNameProps {
|
||||
user?: UserMetadata | undefined;
|
||||
}
|
||||
|
||||
const DisplayName = ({ pubkey }: DisplayNameProps) => {
|
||||
const profile = useUserProfile(pubkey);
|
||||
const [name, isPlaceHolder] = useMemo(() => getDisplayNameOrPlaceHolder(profile, pubkey), [profile, pubkey]);
|
||||
const DisplayName = ({ pubkey, user }: DisplayNameProps) => {
|
||||
const profile = useUserProfile(user ? undefined : pubkey);
|
||||
const [name, isPlaceHolder] = useMemo(() => getDisplayNameOrPlaceHolder(profile ?? user, pubkey), [profile, pubkey]);
|
||||
|
||||
return <span className={classNames({ placeholder: isPlaceHolder })}>{name}</span>;
|
||||
};
|
||||
|
31
packages/app/src/Hooks/useAppHandler.ts
Normal file
31
packages/app/src/Hooks/useAppHandler.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { EventKind, NostrLink, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
|
||||
import useFollowsControls from "./useFollowControls";
|
||||
|
||||
export default function useAppHandler(kind: EventKind) {
|
||||
const { followList } = useFollowsControls();
|
||||
|
||||
const sub = new RequestBuilder(`app-handler:${kind}`);
|
||||
sub
|
||||
.withFilter()
|
||||
.kinds([31990 as EventKind])
|
||||
.tag("k", [kind.toString()]);
|
||||
|
||||
const dataApps = useRequestBuilder(sub);
|
||||
|
||||
const reccomendsSub = new RequestBuilder(`app-handler:${kind}:recommends`);
|
||||
if (dataApps.length > 0 && followList.length > 0) {
|
||||
reccomendsSub
|
||||
.withFilter()
|
||||
.kinds([31989 as EventKind])
|
||||
.replyToLink(dataApps.map(a => NostrLink.fromEvent(a)))
|
||||
.authors(followList);
|
||||
}
|
||||
|
||||
const dataRecommends = useRequestBuilder(reccomendsSub);
|
||||
return {
|
||||
reccomends: dataRecommends,
|
||||
apps: dataApps,
|
||||
};
|
||||
}
|
@ -1106,6 +1106,9 @@
|
||||
"TwyMau": {
|
||||
"defaultMessage": "Account"
|
||||
},
|
||||
"TzeMlV": {
|
||||
"defaultMessage": "Sorry, we dont understand this event kind, please try one of the following apps instead!"
|
||||
},
|
||||
"U1aPPi": {
|
||||
"defaultMessage": "Stop listening"
|
||||
},
|
||||
|
@ -366,6 +366,7 @@
|
||||
"Tpy00S": "People",
|
||||
"TvKqBp": "liked",
|
||||
"TwyMau": "Account",
|
||||
"TzeMlV": "Sorry, we dont understand this event kind, please try one of the following apps instead!",
|
||||
"U1aPPi": "Stop listening",
|
||||
"UJTWqI": "Remove from my relays",
|
||||
"ULXFfP": "Receive",
|
||||
|
Reference in New Issue
Block a user