import { NDKEvent } from '@nostr-dev-kit/ndk'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { useCallback, useEffect, useRef } from 'react'; import { useParams } from 'react-router-dom'; import { VList, VListHandle } from 'virtua'; import { ChatForm } from '@app/chats/components/chatForm'; import { ChatMessage } from '@app/chats/components/message'; import { useArk } from '@libs/ark'; import { LoaderIcon } from '@shared/icons'; import { User } from '@shared/user'; import { useNostr } from '@utils/hooks/useNostr'; export function ChatScreen() { const { ark } = useArk(); const { pubkey } = useParams(); const { fetchNIP04Messages } = useNostr(); const { status, data } = useQuery({ queryKey: ['nip04-dm', pubkey], queryFn: async () => { return await fetchNIP04Messages(pubkey); }, refetchOnWindowFocus: false, }); const queryClient = useQueryClient(); const listRef = useRef(null); const newMessage = useMutation({ mutationFn: async (event: NDKEvent) => { // Cancel any outgoing refetches await queryClient.cancelQueries({ queryKey: ['nip04-dm', pubkey] }); // Snapshot the previous value const prevMessages = queryClient.getQueryData(['nip04-dm', pubkey]); // Optimistically update to the new value queryClient.setQueryData(['nip04-dm', pubkey], (prev: NDKEvent[]) => [ ...prev, event, ]); // Return a context object with the snapshotted value return { prevMessages }; }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ['nip04-dm', pubkey] }); }, }); const renderItem = useCallback( (message: NDKEvent) => { return ( ); }, [data] ); useEffect(() => { if (data && data.length > 0) listRef.current?.scrollToIndex(data.length); }, [data]); useEffect(() => { const sub = ark.subscribe({ filter: { kinds: [4], authors: [ark.account.pubkey], '#p': [pubkey], since: Math.floor(Date.now() / 1000), }, closeOnEose: false, cb: (event) => newMessage.mutate(event), }); return () => { sub.stop(); }; }, [pubkey]); return (
{status === 'pending' ? (

Loading messages

) : data.length === 0 ? (

🙌

You two didn't talk yet, let's send first message

) : ( {data.map((message) => renderItem(message))} )}
); }