Added search to feeds

This commit is contained in:
austinkelsay 2024-09-09 15:56:51 -05:00
parent 185c96bf9b
commit fd7b7567fe
6 changed files with 62 additions and 21 deletions

@ -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 = () => {
</div>
);
const filteredData = data.filter(message =>
message.content.toLowerCase().includes(searchQuery.toLowerCase())
);
return (
<div className="bg-gray-900 h-full w-full min-bottom-bar:w-[86vw]">
<div className="mx-4 mt-4">
{data && data.length > 0 ? (
data.map(message => (
{filteredData && filteredData.length > 0 ? (
filteredData.map(message => (
<Card
key={message.id}
header={() => header(message)}
footer={() => footer(message)}
className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4"
>
<p className="m-0 text-lg text-gray-200">{message.content}</p>
<p className="m-0 text-lg text-gray-200">{highlightText(message.content, searchQuery)}</p>
</Card>
))
) : (

@ -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' ? (
<p className="m-0 text-lg text-gray-200 overflow-hidden break-words">{item.content}</p>
<p className="m-0 text-lg text-gray-200 overflow-hidden break-words">
{highlightText(item.content, searchQuery)}
</p>
) : (
<>
<h3 className="m-0 text-lg text-gray-200">{item.title}</h3>
<h3 className="m-0 text-lg text-gray-200">
{highlightText(item.title, searchQuery)}
</h3>
<p className="text-sm text-gray-400">
Comments: {item.comments.length} | Sats: {item.sats}
</p>
@ -204,7 +217,9 @@ const GlobalFeed = () => {
</Card>
))
) : (
<div className="text-gray-400 text-center p-4">No items available.</div>
<div className="text-gray-400 text-center p-4">
{searchQuery ? "No matching items found." : "No items available."}
</div>
)}
</div>
</div>

@ -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 <div className="text-red-500 text-center p-4">Failed to load messages. Please try again later.</div>;
}
const filteredNotes = communityNotes.filter(message =>
message.content.toLowerCase().includes(searchQuery.toLowerCase())
);
return (
<div className="bg-gray-900 h-full w-full min-bottom-bar:w-[86vw]">
<div className="mx-4 mt-4">
{communityNotes.length > 0 ? (
communityNotes.map(message => (
{filteredNotes.length > 0 ? (
filteredNotes.map(message => (
<Card
key={message.id}
header={renderHeader(message)}
footer={() => footer(message)}
className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4"
>
<p className="m-0 text-lg text-gray-200 overflow-hidden break-words">{message.content}</p>
<p className="m-0 text-lg text-gray-200 overflow-hidden break-words">
{highlightText(message.content, searchQuery)}
</p>
</Card>
))
) : (

@ -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 = () => {
</div>
);
const filteredItems = items.filter(item =>
item.title.toLowerCase().includes(searchQuery.toLowerCase())
);
return (
<div className="bg-gray-900 h-full w-full min-bottom-bar:w-[86vw]">
<div className="mx-4 mt-4">
{items && items.length > 0 ? (
items.map(item => (
{filteredItems && filteredItems.length > 0 ? (
filteredItems.map(item => (
<Card
key={item.id}
header={() => header(item)}
footer={() => footer(item)}
className="w-full bg-gray-700 shadow-lg hover:shadow-xl transition-shadow duration-300 mb-4"
>
<h3 className="m-0 text-lg text-gray-200">{item.title}</h3>
<h3 className="m-0 text-lg text-gray-200">{highlightText(item.title, searchQuery)}</h3>
<p className="text-sm text-gray-400">
Comments: {item.comments.length} | Sats: {item.sats}
</p>

@ -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 = () => {
/>
</div>
{
selectedTopic === 'global' && <GlobalFeed />
selectedTopic === 'global' && <GlobalFeed searchQuery={searchQuery} />
}
{
selectedTopic === 'nostr' && <NostrFeed />
selectedTopic === 'nostr' && <NostrFeed searchQuery={searchQuery} />
}
{
selectedTopic === 'discord' && <DiscordFeed />
selectedTopic === 'discord' && <DiscordFeed searchQuery={searchQuery} />
}
{
selectedTopic === 'stackernews' && <StackerNewsFeed />
selectedTopic === 'stackernews' && <StackerNewsFeed searchQuery={searchQuery} />
}
</div>
);

9
src/utils/text.js Normal file

@ -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()
? <span key={index} className="bg-yellow-300 text-black">{part}</span>
: part
);
};