show zap list on profile
This commit is contained in:
parent
6fa02bd0df
commit
e7430edb06
@ -1,11 +1,10 @@
|
|||||||
import "./Zap.css";
|
import "./Zap.css";
|
||||||
import { useMemo } from "react";
|
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
import { decode as invoiceDecode } from "light-bolt11-decoder";
|
import { decode as invoiceDecode } from "light-bolt11-decoder";
|
||||||
import { bytesToHex } from "@noble/hashes/utils";
|
import { bytesToHex } from "@noble/hashes/utils";
|
||||||
|
|
||||||
import { sha256 } from "Util";
|
//import { sha256 } from "Util";
|
||||||
import { formatShort } from "Number";
|
import { formatShort } from "Number";
|
||||||
import { HexKey, TaggedRawEvent } from "Nostr";
|
import { HexKey, TaggedRawEvent } from "Nostr";
|
||||||
import Event from "Nostr/Event";
|
import Event from "Nostr/Event";
|
||||||
@ -20,16 +19,6 @@ function findTag(e: TaggedRawEvent, tag: string) {
|
|||||||
return maybeTag && maybeTag[1]
|
return maybeTag && maybeTag[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Section = {
|
|
||||||
name: string
|
|
||||||
value?: any
|
|
||||||
letters?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSection(sections: Section[], name: string) {
|
|
||||||
return sections.find((s) => s.name === name)
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInvoice(zap: TaggedRawEvent) {
|
function getInvoice(zap: TaggedRawEvent) {
|
||||||
const bolt11 = findTag(zap, 'bolt11')
|
const bolt11 = findTag(zap, 'bolt11')
|
||||||
const decoded = invoiceDecode(bolt11)
|
const decoded = invoiceDecode(bolt11)
|
||||||
@ -83,7 +72,7 @@ export function parseZap(zap: TaggedRawEvent): ParsedZap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Zap = ({ zap }: { zap: ParsedZap }) => {
|
const Zap = ({ zap, showZapped = true }: { zap: ParsedZap, showZapped?: boolean }) => {
|
||||||
const { amount, content, zapper, valid, p } = zap
|
const { amount, content, zapper, valid, p } = zap
|
||||||
const pubKey = useSelector((s: RootState) => s.login.publicKey)
|
const pubKey = useSelector((s: RootState) => s.login.publicKey)
|
||||||
|
|
||||||
@ -91,7 +80,7 @@ const Zap = ({ zap }: { zap: ParsedZap }) => {
|
|||||||
<div className="zap note card">
|
<div className="zap note card">
|
||||||
<div className="header">
|
<div className="header">
|
||||||
{zapper && <ProfileImage pubkey={zapper} />}
|
{zapper && <ProfileImage pubkey={zapper} />}
|
||||||
{p !== pubKey && <ProfileImage pubkey={p} />}
|
{p !== pubKey && showZapped && <ProfileImage pubkey={p} />}
|
||||||
<div className="amount">
|
<div className="amount">
|
||||||
<span className="amount-number">{formatShort(amount)}</span> sats
|
<span className="amount-number">{formatShort(amount)}</span> sats
|
||||||
</div>
|
</div>
|
||||||
@ -111,18 +100,11 @@ const Zap = ({ zap }: { zap: ParsedZap }) => {
|
|||||||
interface ZapsSummaryProps { zaps: ParsedZap[] }
|
interface ZapsSummaryProps { zaps: ParsedZap[] }
|
||||||
|
|
||||||
export const ZapsSummary = ({ zaps }: ZapsSummaryProps) => {
|
export const ZapsSummary = ({ zaps }: ZapsSummaryProps) => {
|
||||||
const zapTotal = zaps.reduce((acc, z) => acc + z.amount, 0)
|
|
||||||
|
|
||||||
const topZap = zaps.length > 0 && zaps.reduce((acc, z) => {
|
const topZap = zaps.length > 0 && zaps.reduce((acc, z) => {
|
||||||
return z.amount > acc.amount ? z : acc
|
return z.amount > acc.amount ? z : acc
|
||||||
})
|
})
|
||||||
const restZaps = zaps.filter(z => topZap && z.id !== topZap.id)
|
const restZaps = zaps.filter(z => topZap && z.id !== topZap.id)
|
||||||
const restZapsTotal = restZaps.reduce((acc, z) => acc + z.amount, 0)
|
const restZapsTotal = restZaps.reduce((acc, z) => acc + z.amount, 0)
|
||||||
const sortedZaps = useMemo(() => {
|
|
||||||
const s = [...restZaps]
|
|
||||||
s.sort((a, b) => b.amount - a.amount)
|
|
||||||
return s
|
|
||||||
}, [restZaps])
|
|
||||||
const { zapper, amount, content, valid } = topZap || {}
|
const { zapper, amount, content, valid } = topZap || {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -11,7 +11,7 @@ import Zap from "Icons/Zap";
|
|||||||
import Envelope from "Icons/Envelope";
|
import Envelope from "Icons/Envelope";
|
||||||
import { useUserProfile } from "Feed/ProfileFeed";
|
import { useUserProfile } from "Feed/ProfileFeed";
|
||||||
import useZapsFeed from "Feed/ZapsFeed";
|
import useZapsFeed from "Feed/ZapsFeed";
|
||||||
import { parseZap } from "Element/Zap";
|
import { default as ZapElement, parseZap } from "Element/Zap";
|
||||||
import FollowButton from "Element/FollowButton";
|
import FollowButton from "Element/FollowButton";
|
||||||
import { extractLnAddress, parseId, hexToBech32 } from "Util";
|
import { extractLnAddress, parseId, hexToBech32 } from "Util";
|
||||||
import Avatar from "Element/Avatar";
|
import Avatar from "Element/Avatar";
|
||||||
@ -39,6 +39,7 @@ enum ProfileTab {
|
|||||||
Reactions = "Reactions",
|
Reactions = "Reactions",
|
||||||
Followers = "Followers",
|
Followers = "Followers",
|
||||||
Follows = "Follows",
|
Follows = "Follows",
|
||||||
|
Zaps = "Zaps",
|
||||||
Muted = "Muted",
|
Muted = "Muted",
|
||||||
Blocked = "Blocked"
|
Blocked = "Blocked"
|
||||||
};
|
};
|
||||||
@ -63,7 +64,9 @@ export default function ProfilePage() {
|
|||||||
: user?.website || "";
|
: user?.website || "";
|
||||||
const zapFeed = useZapsFeed(id)
|
const zapFeed = useZapsFeed(id)
|
||||||
const zaps = useMemo(() => {
|
const zaps = useMemo(() => {
|
||||||
return zapFeed.store.notes.map(parseZap).filter(z => z.valid && z.p === id && !z.e)
|
const profileZaps = zapFeed.store.notes.map(parseZap).filter(z => z.valid && z.p === id && !z.e)
|
||||||
|
profileZaps.sort((a, b) => b.amount - a.amount)
|
||||||
|
return profileZaps
|
||||||
}, [zapFeed.store.notes, id])
|
}, [zapFeed.store.notes, id])
|
||||||
const zapsTotal = zaps.reduce((acc, z) => acc + z.amount, 0)
|
const zapsTotal = zaps.reduce((acc, z) => acc + z.amount, 0)
|
||||||
|
|
||||||
@ -117,6 +120,14 @@ export default function ProfilePage() {
|
|||||||
switch (tab) {
|
switch (tab) {
|
||||||
case ProfileTab.Notes:
|
case ProfileTab.Notes:
|
||||||
return <Timeline key={id} subject={{ type: "pubkey", items: [id], discriminator: id.slice(0, 12) }} postsOnly={false} method={"LIMIT_UNTIL"} ignoreModeration={true} />;
|
return <Timeline key={id} subject={{ type: "pubkey", items: [id], discriminator: id.slice(0, 12) }} postsOnly={false} method={"LIMIT_UNTIL"} ignoreModeration={true} />;
|
||||||
|
case ProfileTab.Zaps: {
|
||||||
|
return (
|
||||||
|
<div className="main-content">
|
||||||
|
{zaps.map(z => <ZapElement showZapped={false} zap={z} />)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
case ProfileTab.Follows: {
|
case ProfileTab.Follows: {
|
||||||
if (isMe) {
|
if (isMe) {
|
||||||
return (
|
return (
|
||||||
@ -216,7 +227,7 @@ export default function ProfilePage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="tabs">
|
<div className="tabs">
|
||||||
{[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows, ProfileTab.Muted].map(renderTab)}
|
{[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows, ProfileTab.Zaps, ProfileTab.Muted].map(renderTab)}
|
||||||
{isMe && renderTab(ProfileTab.Blocked)}
|
{isMe && renderTab(ProfileTab.Blocked)}
|
||||||
</div>
|
</div>
|
||||||
{tabContent()}
|
{tabContent()}
|
||||||
|
Loading…
Reference in New Issue
Block a user