Skip to content

Commit

Permalink
Nostr bookmark hook (#68)
Browse files Browse the repository at this point in the history
* Feat: Implement repost hook (useRepost)

* Chore: Implement repost hook

* fix: useRepost

* feat: Implement useBookmark hook

* feat: Complete Implementation of useBookmark hook

* chore: commit hooks/index.ts

* Feat: Implement Bookmark hook

* fix: conflict in hooks/index.ts
  • Loading branch information
Benjtalkshow authored Aug 28, 2024
1 parent 439422b commit aee9172
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 9 deletions.
1 change: 1 addition & 0 deletions apps/mobile/src/assets/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ export const RepostIcon: React.FC<SvgProps> = (props) => {
);
};


export const LikeIcon: React.FC<SvgProps> = (props) => {
return (
<Svg width="26" height="26" viewBox="0 0 20 20" fill="none" {...props}>
Expand Down
22 changes: 13 additions & 9 deletions apps/mobile/src/modules/Post/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {NDKEvent, NDKKind} from '@nostr-dev-kit/ndk';
import {useNavigation} from '@react-navigation/native';
import {useQueryClient} from '@tanstack/react-query';
import {useProfile, useReact, useReactions, useReplyNotes, useRepost} from 'afk_nostr_sdk';
import {useProfile, useReact, useReactions, useReplyNotes, useRepost, useBookmark} from 'afk_nostr_sdk';
// import { useAuth } from '../../store/auth';
import {useAuth} from 'afk_nostr_sdk';
import {useMemo, useState} from 'react';
Expand Down Expand Up @@ -31,7 +31,6 @@ export type PostProps = {
isRepost?:boolean
};


export const Post: React.FC<PostProps> = ({asComment, event, repostedEventProps, isRepost}) => {
const repostedEvent = repostedEventProps ?? undefined;

Expand All @@ -51,6 +50,7 @@ export const Post: React.FC<PostProps> = ({asComment, event, repostedEventProps,
const react = useReact();
const queryClient = useQueryClient();
const repostMutation = useRepost({ event });
const { bookmarkNote } = useBookmark(publicKey);

const [menuOpen, setMenuOpen] = useState(false);

Expand Down Expand Up @@ -134,8 +134,15 @@ export const Post: React.FC<PostProps> = ({asComment, event, repostedEventProps,
}
};

const handleBookmarkList = async () => {
showToast({title: 'Bookmark and List coming soon', type: 'info'});
const handleBookmark = async () => {
if (!event) return;
try {
await bookmarkNote({ event });
showToast({title: 'Post bookmarked successfully', type: 'success'});
} catch (error) {
console.error('Bookmark error:', error);
showToast({title: 'Failed to bookmark', type: 'error'});
}
};

const content = event?.content || '';
Expand Down Expand Up @@ -287,10 +294,7 @@ export const Post: React.FC<PostProps> = ({asComment, event, repostedEventProps,

<Pressable
style={{marginHorizontal: 3}}
onPress={() => {
if (!event) return;
handleBookmarkList();
}}
onPress={handleBookmark}
>
<Icon name="BookmarkIcon" size={20} title="Bookmark" />
</Pressable>
Expand Down Expand Up @@ -319,4 +323,4 @@ export const Post: React.FC<PostProps> = ({asComment, event, repostedEventProps,
)}
</View>
);
};
};
1 change: 1 addition & 0 deletions packages/afk_nostr_sdk/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ export {useRepost} from './useRepost';
export {useSendPrivateMessage} from './messages/useSendPrivateMessage';
export {useMyGiftWrapMessages} from './messages/useMyGiftWrapMessages';
export {useMyMessagesSent} from './messages/useMyMessagesSent';
export {useBookmark} from './useBookmark';

106 changes: 106 additions & 0 deletions packages/afk_nostr_sdk/src/hooks/useBookmark.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useNostrContext } from '../context/NostrContext';

interface BookmarkParams {
event: NDKEvent;
category?: string;
}

interface RemoveBookmarkParams {
eventId: string;
category?: string;
}

export const useBookmark = (userPublicKey: string) => {
const { ndk } = useNostrContext();
const queryClient = useQueryClient();

const bookmarkNote = useMutation({
mutationKey: ["bookmark", ndk],
mutationFn: async ({ event, category }: BookmarkParams) => {
if (!event) {
throw new Error('No event provided for bookmark');
}

const bookmarkEvent = new NDKEvent(ndk);

if (category) {
bookmarkEvent.kind = NDKKind.BookmarkSet;
bookmarkEvent.tags = [
['d', category],
['e', event.id, event.relay?.url || ''],
['p', event.pubkey],
];
} else {
bookmarkEvent.kind = 10003;
bookmarkEvent.tags = [
['e', event.id, event.relay?.url || ''],
['p', event.pubkey],
];
}

await bookmarkEvent.publish();
return bookmarkEvent;
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['bookmarks'] });
},
onError: (error) => {
console.error('Failed to bookmark note:', error);
},
});

const getBookmarks = useQuery({
queryKey: ['bookmarks', userPublicKey],
queryFn: async () => {
if (!ndk.signer) {
throw new Error('No signer available');
}
const filter = { kinds: [10003, 30003], authors: [userPublicKey] };
const events = await ndk.fetchEvents(filter);
return Array.from(events);
},
});

const removeBookmark = useMutation({
mutationKey: ["bookmark", ndk],
mutationFn: async ({ eventId, category }: RemoveBookmarkParams) => {
const existingBookmarks = getBookmarks.data;

if (!existingBookmarks) {
throw new Error('No existing bookmarks found');
}

const bookmarkEvent = existingBookmarks.find((event) => {
const isMatchingCategory = category
? event.tags.some(tag => tag[0] === 'd' && tag[1] === category)
: true;

return isMatchingCategory && event.tags.some(tag => tag[0] === 'e' && tag[1] === eventId);
});

if (bookmarkEvent) {
bookmarkEvent.tags = bookmarkEvent.tags.filter(tag => !(tag[0] === 'e' && tag[1] === eventId));
if (bookmarkEvent.tags.length > 0) {
await bookmarkEvent.publish();
}
} else {
throw new Error('Bookmark not found');
}
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['bookmarks', userPublicKey] });
},
onError: (error) => {
console.error('Failed to remove bookmark:', error);
},
});

return {
bookmarkNote: bookmarkNote.mutateAsync,
removeBookmark: removeBookmark.mutateAsync,
getBookmarks: getBookmarks.data,
isFetchingBookmarks: getBookmarks.isFetching,
};
};

0 comments on commit aee9172

Please sign in to comment.