88 lines
3.0 KiB
TypeScript
88 lines
3.0 KiB
TypeScript
import { NDKEvent } from '@nostr-dev-kit/ndk';
|
|
import * as Avatar from '@radix-ui/react-avatar';
|
|
import { minidenticon } from 'minidenticons';
|
|
import { memo } from 'react';
|
|
import { NavLink } from 'react-router-dom';
|
|
import { twMerge } from 'tailwind-merge';
|
|
|
|
import { useDecryptMessage } from '@app/chats/hooks/useDecryptMessage';
|
|
|
|
import { useStorage } from '@libs/storage/provider';
|
|
|
|
import { useStronghold } from '@stores/stronghold';
|
|
|
|
import { formatCreatedAt } from '@utils/createdAt';
|
|
import { useProfile } from '@utils/hooks/useProfile';
|
|
import { displayNpub } from '@utils/shortenKey';
|
|
|
|
export const ChatListItem = memo(function ChatListItem({ event }: { event: NDKEvent }) {
|
|
const { db } = useStorage();
|
|
const { status, user } = useProfile(event.pubkey);
|
|
|
|
const privkey = useStronghold((state) => state.privkey);
|
|
const decryptedContent = useDecryptMessage(event, db.account.pubkey, privkey);
|
|
|
|
const createdAt = formatCreatedAt(event.created_at, true);
|
|
const svgURI =
|
|
'data:image/svg+xml;utf8,' + encodeURIComponent(minidenticon(event.pubkey, 90, 50));
|
|
|
|
if (status === 'loading') {
|
|
return (
|
|
<div className="flex items-center gap-2.5 rounded-md px-3">
|
|
<div className="h-9 w-9 shrink-0 animate-pulse rounded-lg bg-white/10 backdrop-blur-xl" />
|
|
<div className="flex w-full flex-col">
|
|
<div className="h-2.5 w-1/2 animate-pulse rounded bg-white/10 backdrop-blur-xl" />
|
|
<div className="h-2.5 w-full animate-pulse rounded bg-white/10 backdrop-blur-xl" />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<NavLink
|
|
to={`/chats/chat/${event.pubkey}`}
|
|
preventScrollReset={true}
|
|
className={({ isActive }) =>
|
|
twMerge(
|
|
'flex items-center gap-2.5 px-3 py-1.5 hover:bg-white/10',
|
|
isActive
|
|
? 'border-fuchsia-500 bg-white/5 text-white'
|
|
: 'border-transparent text-white/70'
|
|
)
|
|
}
|
|
>
|
|
<Avatar.Root className="shrink-0">
|
|
<Avatar.Image
|
|
src={user?.picture || user?.image}
|
|
alt={event.pubkey}
|
|
loading="lazy"
|
|
decoding="async"
|
|
style={{ contentVisibility: 'auto' }}
|
|
className="h-10 w-10 rounded-lg"
|
|
/>
|
|
<Avatar.Fallback delayMs={300}>
|
|
<img
|
|
src={svgURI}
|
|
alt={event.pubkey}
|
|
className="h-10 w-10 rounded-lg bg-white"
|
|
/>
|
|
</Avatar.Fallback>
|
|
</Avatar.Root>
|
|
<div className="flex w-full flex-col">
|
|
<div className="max-w-[10rem] truncate font-semibold text-white">
|
|
{user?.name ||
|
|
user?.display_name ||
|
|
user?.displayName ||
|
|
displayNpub(event.pubkey, 16)}
|
|
</div>
|
|
<div className="flex w-full items-center justify-between">
|
|
<div className="max-w-[10rem] truncate text-sm text-white/70">
|
|
{decryptedContent}
|
|
</div>
|
|
<div className="text-sm text-white/70">{createdAt}</div>
|
|
</div>
|
|
</div>
|
|
</NavLink>
|
|
);
|
|
});
|