From fd7b7567fe1b648c00f78302ef457669c17c7647 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Mon, 9 Sep 2024 15:56:51 -0500 Subject: [PATCH] Added search to feeds --- src/components/feeds/DiscordFeed.js | 13 +++++++++---- src/components/feeds/GlobalFeed.js | 23 +++++++++++++++++++---- src/components/feeds/NostrFeed.js | 15 +++++++++++---- src/components/feeds/StackerNewsFeed.js | 13 +++++++++---- src/pages/feed.js | 10 +++++----- src/utils/text.js | 9 +++++++++ 6 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 src/utils/text.js diff --git a/src/components/feeds/DiscordFeed.js b/src/components/feeds/DiscordFeed.js index 404bd18..74e3cf1 100644 --- a/src/components/feeds/DiscordFeed.js +++ b/src/components/feeds/DiscordFeed.js @@ -6,8 +6,9 @@ import { Button } from 'primereact/button'; import { ProgressSpinner } from 'primereact/progressspinner'; import { useDiscordQuery } from '@/hooks/communityQueries/useDiscordQuery'; import { useRouter } from 'next/router'; +import { highlightText } from '@/utils/text'; -const DiscordFeed = () => { +const DiscordFeed = ({ searchQuery }) => { const router = useRouter(); const { data, error, isLoading } = useDiscordQuery({page: router.query.page}); @@ -54,18 +55,22 @@ const DiscordFeed = () => { ); + const filteredData = data.filter(message => + message.content.toLowerCase().includes(searchQuery.toLowerCase()) + ); + return (
- {data && data.length > 0 ? ( - data.map(message => ( + {filteredData && filteredData.length > 0 ? ( + filteredData.map(message => ( header(message)} footer={() => footer(message)} className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4" > -

{message.content}

+

{highlightText(message.content, searchQuery)}

)) ) : ( diff --git a/src/components/feeds/GlobalFeed.js b/src/components/feeds/GlobalFeed.js index c4ac17f..73ae5d5 100644 --- a/src/components/feeds/GlobalFeed.js +++ b/src/components/feeds/GlobalFeed.js @@ -14,6 +14,7 @@ import { findKind0Fields } from '@/utils/nostr'; import NostrIcon from '../../../public/images/nostr.png'; import Image from 'next/image'; import { useImageProxy } from '@/hooks/useImageProxy'; +import { highlightText } from '@/utils/text'; import { nip19 } from 'nostr-tools'; const StackerNewsIconComponent = () => ( @@ -28,7 +29,7 @@ const fetchStackerNews = async () => { return response.data.data.items.items; }; -const GlobalFeed = () => { +const GlobalFeed = ({searchQuery}) => { const router = useRouter(); const { data: discordData, error: discordError, isLoading: discordLoading } = useDiscordQuery({page: router.query.page}); const { data: stackerNewsData, error: stackerNewsError, isLoading: stackerNewsLoading } = useQuery({queryKey: ['stackerNews'], queryFn: fetchStackerNews}); @@ -109,6 +110,14 @@ const GlobalFeed = () => { const dateA = a.type === 'nostr' ? a.created_at * 1000 : new Date(a.timestamp || a.createdAt); const dateB = b.type === 'nostr' ? b.created_at * 1000 : new Date(b.timestamp || b.createdAt); return dateB - dateA; + }).filter(item => { + const searchLower = searchQuery.toLowerCase(); + if (item.type === 'discord' || item.type === 'nostr') { + return item.content.toLowerCase().includes(searchLower); + } else if (item.type === 'stackernews') { + return item.title.toLowerCase().includes(searchLower); + } + return false; }); const header = (item) => ( @@ -192,10 +201,14 @@ const GlobalFeed = () => { className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4" > {item.type === 'discord' || item.type === 'nostr' ? ( -

{item.content}

+

+ {highlightText(item.content, searchQuery)} +

) : ( <> -

{item.title}

+

+ {highlightText(item.title, searchQuery)} +

Comments: {item.comments.length} | Sats: {item.sats}

@@ -204,7 +217,9 @@ const GlobalFeed = () => { )) ) : ( -
No items available.
+
+ {searchQuery ? "No matching items found." : "No items available."} +
)}
diff --git a/src/components/feeds/NostrFeed.js b/src/components/feeds/NostrFeed.js index 15f43cf..46cc026 100644 --- a/src/components/feeds/NostrFeed.js +++ b/src/components/feeds/NostrFeed.js @@ -12,9 +12,10 @@ import Image from 'next/image'; import { useImageProxy } from '@/hooks/useImageProxy'; import { nip19 } from 'nostr-tools'; import { useCommunityNotes } from '@/hooks/nostr/useCommunityNotes'; +import { highlightText } from '@/utils/text'; import ZapThreadsWrapper from '@/components/ZapThreadsWrapper'; -const NostrFeed = () => { +const NostrFeed = ({ searchQuery }) => { const { communityNotes, isLoading, error } = useCommunityNotes(); const { ndk } = useNDKContext(); const { returnImageProxy } = useImageProxy(); @@ -134,18 +135,24 @@ const NostrFeed = () => { return
Failed to load messages. Please try again later.
; } + const filteredNotes = communityNotes.filter(message => + message.content.toLowerCase().includes(searchQuery.toLowerCase()) + ); + return (
- {communityNotes.length > 0 ? ( - communityNotes.map(message => ( + {filteredNotes.length > 0 ? ( + filteredNotes.map(message => ( footer(message)} className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4" > -

{message.content}

+

+ {highlightText(message.content, searchQuery)} +

)) ) : ( diff --git a/src/components/feeds/StackerNewsFeed.js b/src/components/feeds/StackerNewsFeed.js index 94bc0e7..95648e7 100644 --- a/src/components/feeds/StackerNewsFeed.js +++ b/src/components/feeds/StackerNewsFeed.js @@ -5,6 +5,7 @@ import { Tag } from 'primereact/tag'; import { Button } from 'primereact/button'; import { ProgressSpinner } from 'primereact/progressspinner'; import { useQuery } from '@tanstack/react-query'; +import { highlightText } from '@/utils/text'; import axios from 'axios'; const StackerNewsIconComponent = () => ( @@ -19,7 +20,7 @@ const fetchStackerNews = async () => { return response.data.data.items.items; // Note the change here }; -const StackerNewsFeed = () => { +const StackerNewsFeed = ({ searchQuery }) => { const { data: items, isLoading, error } = useQuery({queryKey: ['stackerNews'], queryFn: fetchStackerNews}); useEffect(() => { @@ -71,18 +72,22 @@ const StackerNewsFeed = () => {
); + const filteredItems = items.filter(item => + item.title.toLowerCase().includes(searchQuery.toLowerCase()) + ); + return (
- {items && items.length > 0 ? ( - items.map(item => ( + {filteredItems && filteredItems.length > 0 ? ( + filteredItems.map(item => ( header(item)} footer={() => footer(item)} className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4" > -

{item.title}

+

{highlightText(item.title, searchQuery)}

Comments: {item.comments.length} | Sats: {item.sats}

diff --git a/src/pages/feed.js b/src/pages/feed.js index f4cb9a2..eddbd72 100644 --- a/src/pages/feed.js +++ b/src/pages/feed.js @@ -15,9 +15,9 @@ import { Divider } from 'primereact/divider'; const Feed = () => { const [selectedTopic, setSelectedTopic] = useState('global'); - const [searchQuery, setSearchQuery] = useState(''); const [title, setTitle] = useState('Community'); const allTopics = ['global', 'nostr', 'discord', 'stackernews']; + const [searchQuery, setSearchQuery] = useState(''); const router = useRouter(); @@ -96,16 +96,16 @@ const Feed = () => { />
{ - selectedTopic === 'global' && + selectedTopic === 'global' && } { - selectedTopic === 'nostr' && + selectedTopic === 'nostr' && } { - selectedTopic === 'discord' && + selectedTopic === 'discord' && } { - selectedTopic === 'stackernews' && + selectedTopic === 'stackernews' && }
); diff --git a/src/utils/text.js b/src/utils/text.js new file mode 100644 index 0000000..60caaa3 --- /dev/null +++ b/src/utils/text.js @@ -0,0 +1,9 @@ +export const highlightText = (text, query) => { + if (!query) return text; + const parts = text.split(new RegExp(`(${query})`, 'gi')); + return parts.map((part, index) => + part.toLowerCase() === query.toLowerCase() + ? {part} + : part + ); +}; \ No newline at end of file