refactor note component
This commit is contained in:
@@ -1,74 +1,66 @@
|
||||
import { NDKEvent, NDKFilter } from '@nostr-dev-kit/ndk';
|
||||
import * as Tooltip from '@radix-ui/react-tooltip';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { decode } from 'light-bolt11-decoder';
|
||||
|
||||
import { useNDK } from '@libs/ndk/provider';
|
||||
import { createBlock, createReplyNote } from '@libs/storage';
|
||||
|
||||
import { LoaderIcon, ReplyIcon, RepostIcon, ZapIcon } from '@shared/icons';
|
||||
import { ThreadIcon } from '@shared/icons/thread';
|
||||
import { NoteReply } from '@shared/notes/metadata/reply';
|
||||
import { NoteRepost } from '@shared/notes/metadata/repost';
|
||||
import { NoteZap } from '@shared/notes/metadata/zap';
|
||||
import { LoaderIcon } from '@shared/icons';
|
||||
import { MiniUser } from '@shared/notes/users/mini';
|
||||
|
||||
export function NoteMetadata({
|
||||
id,
|
||||
rootID,
|
||||
eventPubkey,
|
||||
}: {
|
||||
id: string;
|
||||
rootID?: string;
|
||||
eventPubkey: string;
|
||||
}) {
|
||||
import { compactNumber } from '@utils/number';
|
||||
|
||||
export function NoteMetadata({ id }: { id: string }) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { ndk } = useNDK();
|
||||
const { status, data } = useQuery(['note-metadata', id], async () => {
|
||||
let replies = 0;
|
||||
let reposts = 0;
|
||||
let zap = 0;
|
||||
const { status, data } = useQuery(
|
||||
['note-metadata', id],
|
||||
async () => {
|
||||
let replies = 0;
|
||||
let zap = 0;
|
||||
const users = [];
|
||||
|
||||
const filter: NDKFilter = {
|
||||
'#e': [id],
|
||||
kinds: [1, 6, 9735],
|
||||
};
|
||||
const filter: NDKFilter = {
|
||||
'#e': [id],
|
||||
kinds: [1, 9735],
|
||||
};
|
||||
|
||||
const events = await ndk.fetchEvents(filter);
|
||||
events.forEach((event: NDKEvent) => {
|
||||
switch (event.kind) {
|
||||
case 1:
|
||||
replies += 1;
|
||||
createReplyNote(
|
||||
id,
|
||||
event.id,
|
||||
event.pubkey,
|
||||
event.kind,
|
||||
event.tags,
|
||||
event.content,
|
||||
event.created_at
|
||||
);
|
||||
break;
|
||||
case 6:
|
||||
reposts += 1;
|
||||
break;
|
||||
case 9735: {
|
||||
const bolt11 = event.tags.find((tag) => tag[0] === 'bolt11')[1];
|
||||
if (bolt11) {
|
||||
const decoded = decode(bolt11);
|
||||
const amount = decoded.sections.find((item) => item.name === 'amount');
|
||||
const sats = amount.value / 1000;
|
||||
zap += sats;
|
||||
const events = await ndk.fetchEvents(filter);
|
||||
events.forEach((event: NDKEvent) => {
|
||||
switch (event.kind) {
|
||||
case 1:
|
||||
replies += 1;
|
||||
if (users.length < 3) users.push(event.pubkey);
|
||||
createReplyNote(
|
||||
id,
|
||||
event.id,
|
||||
event.pubkey,
|
||||
event.kind,
|
||||
event.tags,
|
||||
event.content,
|
||||
event.created_at
|
||||
);
|
||||
break;
|
||||
case 9735: {
|
||||
const bolt11 = event.tags.find((tag) => tag[0] === 'bolt11')[1];
|
||||
if (bolt11) {
|
||||
const decoded = decode(bolt11);
|
||||
const amount = decoded.sections.find((item) => item.name === 'amount');
|
||||
const sats = amount.value / 1000;
|
||||
zap += sats;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return { replies, reposts, zap };
|
||||
});
|
||||
return { replies, users, zap };
|
||||
},
|
||||
{ refetchOnWindowFocus: false, refetchOnReconnect: false }
|
||||
);
|
||||
|
||||
const block = useMutation({
|
||||
mutationFn: (data: any) => {
|
||||
@@ -85,81 +77,50 @@ export function NoteMetadata({
|
||||
|
||||
if (status === 'loading') {
|
||||
return (
|
||||
<div className="mt-2 inline-flex h-12 w-full items-center">
|
||||
<div className="group inline-flex w-20 items-center gap-1.5">
|
||||
<ReplyIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-green-400"
|
||||
/>
|
||||
<LoaderIcon
|
||||
width={12}
|
||||
height={12}
|
||||
className="animate-spin text-black dark:text-zinc-100"
|
||||
/>
|
||||
</div>
|
||||
<div className="group inline-flex w-20 items-center gap-1.5">
|
||||
<RepostIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-green-400"
|
||||
/>
|
||||
<LoaderIcon
|
||||
width={12}
|
||||
height={12}
|
||||
className="animate-spin text-black dark:text-zinc-100"
|
||||
/>
|
||||
</div>
|
||||
<div className="group inline-flex w-20 items-center gap-1.5">
|
||||
<ZapIcon
|
||||
width={16}
|
||||
height={16}
|
||||
className="text-zinc-400 group-hover:text-green-400"
|
||||
/>
|
||||
<LoaderIcon
|
||||
width={12}
|
||||
height={12}
|
||||
className="animate-spin text-black dark:text-zinc-100"
|
||||
/>
|
||||
<div className="mb-3 flex items-center gap-3">
|
||||
<div className="mt-2h-6 w-11 shrink-0"></div>
|
||||
<div className="mt-2 inline-flex h-6 items-center">
|
||||
<LoaderIcon className="h-4 w-4 animate-spin text-zinc-100" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip.Provider>
|
||||
<div className="mt-2 inline-flex h-12 w-full items-center justify-between">
|
||||
<div className="inline-flex items-center justify-between">
|
||||
<NoteReply
|
||||
id={id}
|
||||
rootID={rootID}
|
||||
pubkey={eventPubkey}
|
||||
replies={data.replies}
|
||||
/>
|
||||
<NoteRepost id={id} pubkey={eventPubkey} reposts={data.reposts} />
|
||||
<NoteZap zaps={data.zap} />
|
||||
</div>
|
||||
<Tooltip.Root delayDuration={150}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openThread(id)}
|
||||
className="inline-flex h-6 w-6 items-center justify-center rounded border-t border-zinc-700/50 bg-zinc-800 hover:bg-zinc-700"
|
||||
>
|
||||
<ThreadIcon className="h-4 w-4 text-zinc-400" />
|
||||
</button>
|
||||
</Tooltip.Trigger>
|
||||
<Tooltip.Portal>
|
||||
<Tooltip.Content
|
||||
className="-left-10 select-none rounded-md bg-zinc-800/80 px-3.5 py-1.5 text-sm leading-none text-zinc-100 backdrop-blur-lg will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"
|
||||
sideOffset={5}
|
||||
>
|
||||
Open thread
|
||||
<Tooltip.Arrow className="fill-zinc-800/80 backdrop-blur-lg" />
|
||||
</Tooltip.Content>
|
||||
</Tooltip.Portal>
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
</Tooltip.Provider>
|
||||
<div>
|
||||
{data.replies > 0 ? (
|
||||
<>
|
||||
<div className="absolute bottom-0 left-[18px] h-[calc(100%-3.4rem)] w-0.5 bg-gradient-to-t from-zinc-800 to-zinc-600" />
|
||||
<div className="relative z-10 flex items-center gap-3 bg-zinc-900 pb-3">
|
||||
<div className="mt-2 inline-flex h-6 w-11 shrink-0 items-center justify-center">
|
||||
<div className="isolate flex -space-x-1 overflow-hidden">
|
||||
{data.users?.map((user, index) => (
|
||||
<MiniUser key={user + index} pubkey={user} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 inline-flex h-6 items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openThread(id)}
|
||||
className="text-zinc-500"
|
||||
>
|
||||
<span className="font-semibold text-zinc-300">{data.replies}</span>{' '}
|
||||
replies
|
||||
</button>
|
||||
<span className="text-zinc-500">·</span>
|
||||
<p className="text-zinc-500">
|
||||
<span className="font-semibold text-zinc-300">
|
||||
{compactNumber.format(data.zap)}
|
||||
</span>{' '}
|
||||
zaps
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="pb-3" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user