feat: add useEventReactions to system-react

This commit is contained in:
Kieran 2023-10-16 21:24:54 +01:00
parent 3b427338f4
commit 5e42c5e70c
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
7 changed files with 83 additions and 76 deletions

View File

@ -1,49 +0,0 @@
import { EventKind, NostrLink, parseZap, TaggedNostrEvent } from "@snort/system";
import { UserCache } from "Cache";
import { useMemo } from "react";
import { dedupeByPubkey, getLinkReactions, normalizeReaction, Reaction } from "SnortUtils";
export function useEventReactions(ev: TaggedNostrEvent, related: ReadonlyArray<TaggedNostrEvent>) {
return useMemo(() => {
const link = NostrLink.fromEvent(ev);
const deletions = getLinkReactions(related, link, EventKind.Deletion);
const reactions = getLinkReactions(related, link, EventKind.Reaction);
const reposts = getLinkReactions(related, link, EventKind.Repost);
const groupReactions = (() => {
const result = reactions?.reduce(
(acc, reaction) => {
const kind = normalizeReaction(reaction.content);
const rs = acc[kind] || [];
return { ...acc, [kind]: [...rs, reaction] };
},
{
[Reaction.Positive]: [] as TaggedNostrEvent[],
[Reaction.Negative]: [] as TaggedNostrEvent[],
},
);
return {
[Reaction.Positive]: dedupeByPubkey(result[Reaction.Positive]),
[Reaction.Negative]: dedupeByPubkey(result[Reaction.Negative]),
};
})();
const positive = groupReactions[Reaction.Positive];
const negative = groupReactions[Reaction.Negative];
const zaps = getLinkReactions(related, link, EventKind.ZapReceipt)
.map(a => parseZap(a, UserCache, ev))
.filter(a => a.valid)
.sort((a, b) => b.amount - a.amount);
return {
deletions,
reactions: {
all: reactions,
positive,
negative,
},
reposts,
zaps,
};
}, [ev, related]);
}

View File

@ -140,29 +140,6 @@ export function hexToBech32(hrp: string, hex?: string) {
return ""; return "";
} }
} }
/**
* Reaction types
*/
export const Reaction = {
Positive: "+",
Negative: "-",
};
/**
* Return normalized reaction content
*/
export function normalizeReaction(content: string) {
switch (content) {
case "-":
return Reaction.Negative;
case "👎":
return Reaction.Negative;
default:
return Reaction.Positive;
}
}
export function getLinkReactions( export function getLinkReactions(
notes: ReadonlyArray<TaggedNostrEvent> | undefined, notes: ReadonlyArray<TaggedNostrEvent> | undefined,
link: NostrLink, link: NostrLink,

View File

@ -1,6 +1,6 @@
{ {
"name": "@snort/shared", "name": "@snort/shared",
"version": "1.0.7", "version": "1.0.8",
"description": "Shared components for Snort", "description": "Shared components for Snort",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",

View File

@ -193,3 +193,25 @@ export async function fetchNip05Pubkey(name: string, domain: string, timeout = 2
export function removeUndefined<T>(v: Array<T | undefined>) { export function removeUndefined<T>(v: Array<T | undefined>) {
return v.filter(a => a != undefined).map(a => unwrap(a)); return v.filter(a => a != undefined).map(a => unwrap(a));
} }
/**
* Reaction types
*/
export const enum Reaction {
Positive = "+",
Negative = "-",
}
/**
* Return normalized reaction content
*/
export function normalizeReaction(content: string) {
switch (content) {
case "-":
return Reaction.Negative;
case "👎":
return Reaction.Negative;
default:
return Reaction.Positive;
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "@snort/system-react", "name": "@snort/system-react",
"version": "1.0.16", "version": "1.0.17",
"description": "React hooks for @snort/system", "description": "React hooks for @snort/system",
"main": "dist/index.js", "main": "dist/index.js",
"types": "dist/index.d.ts", "types": "dist/index.d.ts",
@ -15,7 +15,7 @@
"dist" "dist"
], ],
"dependencies": { "dependencies": {
"@snort/shared": "^1.0.7", "@snort/shared": "^1.0.8",
"@snort/system": "^1.0.22", "@snort/system": "^1.0.22",
"react": "^18.2.0" "react": "^18.2.0"
}, },

View File

@ -1,5 +1,7 @@
export * from "./context";
export * from "./useRequestBuilder"; export * from "./useRequestBuilder";
export * from "./useSystemState"; export * from "./useSystemState";
export * from "./useUserProfile"; export * from "./useUserProfile";
export * from "./context";
export * from "./useUserSearch"; export * from "./useUserSearch";
export * from "./useEventReactions";

View File

@ -0,0 +1,55 @@
import { useContext, useMemo } from "react";
import { normalizeReaction, Reaction } from "@snort/shared";
import { EventKind, NostrLink, parseZap, TaggedNostrEvent } from "@snort/system";
import { SnortContext } from "./context";
/**
* Parse reactions to a given event from a set of related events
* @param ev
* @param related
* @returns
*/
export function useEventReactions(ev: TaggedNostrEvent, related: ReadonlyArray<TaggedNostrEvent>) {
const system = useContext(SnortContext);
return useMemo(() => {
const link = NostrLink.fromEvent(ev);
const reactionKinds = related.reduce((acc, v) => {
if (link.isReplyToThis(v)) {
acc[v.kind.toString()] ??= [];
acc[v.kind.toString()].push(v);
}
return acc;
}, {} as Record<string, Array<TaggedNostrEvent>>);
const deletions = reactionKinds[EventKind.Deletion.toString()] ?? [];
const reactions = reactionKinds[EventKind.Reaction.toString()] ?? [];
const reposts = reactionKinds[EventKind.Repost.toString()] ?? [];
const groupReactions = reactions?.reduce((acc, reaction) => {
const kind = normalizeReaction(reaction.content);
acc[kind] ??= [];
acc[kind].push(reaction);
return acc;
}, {} as Record<Reaction, Array<TaggedNostrEvent>>);
const zaps = (reactionKinds[EventKind.ZapReceipt] ?? [])
.map(a => parseZap(a, system.ProfileLoader.Cache, ev))
.filter(a => a.valid)
.sort((a, b) => b.amount - a.amount);
return {
deletions,
reactions: {
positive: groupReactions[Reaction.Positive],
negative: groupReactions[Reaction.Negative],
},
reposts,
zaps,
others: Object.fromEntries(
Object.entries(reactionKinds)
.filter(([k]) => ![EventKind.Deletion, EventKind.Reaction, EventKind.Repost, EventKind.ZapReceipt].includes(Number(k))))
};
}, [ev, related]);
}