/ src / hooks / usePostComment.ts
usePostComment.ts
 1  import { useMutation, useQueryClient } from '@tanstack/react-query';
 2  import { useNostrPublish } from '@/hooks/useNostrPublish';
 3  import { NKinds, type NostrEvent } from '@nostrify/nostrify';
 4  
 5  interface PostCommentParams {
 6    root: NostrEvent | URL; // The root event to comment on
 7    reply?: NostrEvent | URL; // Optional reply to another comment
 8    content: string;
 9  }
10  
11  /** Post a NIP-22 (kind 1111) comment on an event. */
12  export function usePostComment() {
13    const { mutateAsync: publishEvent } = useNostrPublish();
14    const queryClient = useQueryClient();
15  
16    return useMutation({
17      mutationFn: async ({ root, reply, content }: PostCommentParams) => {
18        const tags: string[][] = [];
19  
20        // d-tag identifiers
21        const dRoot = root instanceof URL ? '' : root.tags.find(([name]) => name === 'd')?.[1] ?? '';
22        const dReply = reply instanceof URL ? '' : reply?.tags.find(([name]) => name === 'd')?.[1] ?? '';
23  
24        // Root event tags
25        if (root instanceof URL) {
26          tags.push(['I', root.toString()]);
27        } else if (NKinds.addressable(root.kind)) {
28          tags.push(['A', `${root.kind}:${root.pubkey}:${dRoot}`]);
29        } else if (NKinds.replaceable(root.kind)) {
30          tags.push(['A', `${root.kind}:${root.pubkey}:`]);
31        } else {
32          tags.push(['E', root.id]);
33        }
34        if (root instanceof URL) {
35          tags.push(['K', root.hostname]);
36        } else {
37          tags.push(['K', root.kind.toString()]);
38          tags.push(['P', root.pubkey]);
39        }
40  
41        // Reply event tags
42        if (reply) {
43          if (reply instanceof URL) {
44            tags.push(['i', reply.toString()]);
45          } else if (NKinds.addressable(reply.kind)) {
46            tags.push(['a', `${reply.kind}:${reply.pubkey}:${dReply}`]);
47          } else if (NKinds.replaceable(reply.kind)) {
48            tags.push(['a', `${reply.kind}:${reply.pubkey}:`]);
49          } else {
50            tags.push(['e', reply.id]);
51          }
52          if (reply instanceof URL) {
53            tags.push(['k', reply.hostname]);
54          } else {
55            tags.push(['k', reply.kind.toString()]);
56            tags.push(['p', reply.pubkey]);
57          }
58        } else {
59          // If this is a top-level comment, use the root event's tags
60          if (root instanceof URL) {
61            tags.push(['i', root.toString()]);
62          } else if (NKinds.addressable(root.kind)) {
63            tags.push(['a', `${root.kind}:${root.pubkey}:${dRoot}`]);
64          } else if (NKinds.replaceable(root.kind)) {
65            tags.push(['a', `${root.kind}:${root.pubkey}:`]);
66          } else {
67            tags.push(['e', root.id]);
68          }
69          if (root instanceof URL) {
70            tags.push(['k', root.hostname]);
71          } else {
72            tags.push(['k', root.kind.toString()]);
73            tags.push(['p', root.pubkey]);
74          }
75        }
76  
77        const event = await publishEvent({
78          kind: 1111,
79          content,
80          tags,
81        });
82  
83        return event;
84      },
85      onSuccess: (_, { root }) => {
86        // Invalidate and refetch comments
87        queryClient.invalidateQueries({
88          queryKey: ['nostr', 'comments', root instanceof URL ? root.toString() : root.id]
89        });
90      },
91    });
92  }