Skip to content

Commit 13fcce5

Browse files
committed
Add ArticleSearchAndGrid component and refactor article search and display
Introduced the ArticleSearchAndGrid component to unify search and grid rendering logic. Integrated this new component into various pages and removed redundant search and grid code, enhancing code maintainability and readability. Also added enhancements to search results fetching based on URLs and domains.
1 parent 582a0fc commit 13fcce5

File tree

11 files changed

+187
-132
lines changed

11 files changed

+187
-132
lines changed

app/dfda/dfdaActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,5 @@ export async function getMetaAnalysis(treatmentName: string, conditionName: stri
158158
return article;
159159
}
160160

161-
return writeArticle(topic);
161+
return writeArticle(topic, "test-user");
162162
}
Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,7 @@
11
'use client'
22

3-
import { useState, useEffect } from 'react'
43
import { useParams } from 'next/navigation'
5-
import ArticleGrid from '@/components/ArticleGrid'
6-
import ArticleSearchBox from '@/components/ArticleSearchBox'
7-
import {searchArticles} from "@/app/researcher/researcherActions";
8-
9-
type Article = {
10-
id: string;
11-
title: string;
12-
slug: string;
13-
description: string;
14-
featuredImage: string | null;
15-
category: { slug: string; name: string };
16-
tags: { slug: string; name: string }[];
17-
};
4+
import ArticleSearchAndGrid from "@/components/article/ArticleSearchAndGrid";
185

196
type Params = {
207
categorySlug: string
@@ -23,36 +10,11 @@ type Params = {
2310
export default function CategoryArticles() {
2411
const params = useParams<Params>()
2512
const categorySlug = params?.categorySlug ?? ''
26-
const [articles, setArticles] = useState<Article[]>([])
27-
const [isLoading, setIsLoading] = useState(true)
28-
const [searchQuery, setSearchQuery] = useState('')
29-
30-
useEffect(() => {
31-
const fetchArticles = async () => {
32-
setIsLoading(true)
33-
const results = await searchArticles(searchQuery, categorySlug)
34-
setArticles(results)
35-
setIsLoading(false)
36-
}
37-
fetchArticles()
38-
}, [categorySlug, searchQuery])
39-
40-
const handleSearch = (query: string) => {
41-
setSearchQuery(query)
42-
}
4313

4414
return (
4515
<div className="container mx-auto p-4">
4616
<h1 className="text-3xl font-bold mb-6">Articles in {categorySlug}</h1>
47-
<ArticleSearchBox
48-
searchQuery={searchQuery}
49-
setSearchQuery={handleSearch}
50-
isLoading={isLoading}
51-
/>
52-
<ArticleGrid articles={articles} />
53-
{articles.length === 0 && !isLoading && (
54-
<p className="text-center text-muted-foreground mt-6">No articles found in this category.</p>
55-
)}
17+
<ArticleSearchAndGrid categorySlug={categorySlug} />
5618
</div>
5719
)
5820
}

app/researcher/articles/page.tsx

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,12 @@
11
'use client'
22

3-
import { useState, useEffect } from 'react'
4-
import { searchArticles } from '../researcherActions'
5-
import ArticleGrid from '@/components/ArticleGrid'
6-
import ArticleSearchBox from '@/components/ArticleSearchBox'
7-
8-
interface Article {
9-
id: string;
10-
title: string;
11-
slug: string;
12-
description: string;
13-
featuredImage: string | null;
14-
category: { slug: string; name: string };
15-
tags: { slug: string; name: string }[];
16-
}
3+
import ArticleSearchAndGrid from "@/components/article/ArticleSearchAndGrid";
174

185
export default function ArticleList() {
19-
const [articles, setArticles] = useState<Article[]>([])
20-
const [isLoading, setIsLoading] = useState(true)
21-
const [searchQuery, setSearchQuery] = useState('')
22-
23-
useEffect(() => {
24-
const fetchArticles = async () => {
25-
setIsLoading(true)
26-
const results = await searchArticles(searchQuery)
27-
setArticles(results)
28-
setIsLoading(false)
29-
}
30-
fetchArticles()
31-
}, [searchQuery])
32-
33-
const handleSearch = (query: string) => {
34-
setSearchQuery(query)
35-
}
36-
376
return (
387
<div className="container mx-auto p-4">
398
<h1 className="text-3xl font-bold mb-6">Articles</h1>
40-
<ArticleSearchBox
41-
searchQuery={searchQuery}
42-
setSearchQuery={handleSearch}
43-
isLoading={isLoading}
44-
/>
45-
<ArticleGrid articles={articles} />
46-
{articles.length === 0 && !isLoading && (
47-
<p className="text-center text-muted-foreground mt-6">No articles found.</p>
48-
)}
9+
<ArticleSearchAndGrid />
4910
</div>
5011
)
5112
}

app/researcher/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ArticleWithRelations } from '@/lib/agents/researcher/researcher'
1212
import GlobalBrainNetwork from "@/components/landingPage/global-brain-network"
1313
import { findOrCreateArticleByTopic } from "@/app/researcher/researcherActions";
1414
import { UserAuthForm } from '@/components/user/user-auth-form'
15+
import ArticleSearchAndGrid from '@/components/article/ArticleSearchAndGrid';
1516

1617
export default function ResearcherPage() {
1718
const { data: session, status } = useSession()
@@ -88,7 +89,7 @@ export default function ResearcherPage() {
8889
className="flex-grow"
8990
/>
9091
<Button type="submit" disabled={isGenerating}>
91-
{isGenerating ? 'Generating...' : 'Generate Article'}
92+
{isGenerating ? 'Researching...' : 'Start Researching'}
9293
</Button>
9394
</form>
9495
</CardContent>
@@ -104,6 +105,7 @@ export default function ResearcherPage() {
104105
</div>
105106
)}
106107
{!isGenerating && article && <ArticleRenderer article={article} currentUserId={session?.user?.id} />}
108+
<ArticleSearchAndGrid />
107109
</main>
108110
)
109111
}

components/ArticleGrid.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,10 @@ import Link from 'next/link'
22
import Image from 'next/image'
33
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
44
import { Badge } from "@/components/ui/badge"
5-
6-
type Article = {
7-
id: string
8-
title: string
9-
slug: string
10-
description: string
11-
featuredImage: string | null
12-
category: {
13-
name: string
14-
slug: string
15-
}
16-
tags: {
17-
name: string
18-
slug: string
19-
}[]
20-
}
5+
import { ArticleWithRelations } from '@/lib/agents/researcher/researcher'
216

227
type ArticleGridProps = {
23-
articles: Article[]
8+
articles: ArticleWithRelations[]
249
}
2510

2611
export default function ArticleGrid({ articles }: ArticleGridProps) {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { useState, useEffect } from 'react'
2+
import ArticleGrid from '@/components/ArticleGrid'
3+
import ArticleSearchBox from '@/components/ArticleSearchBox'
4+
import { ArticleWithRelations } from '@/lib/agents/researcher/researcher'
5+
import { searchArticles } from '@/app/researcher/researcherActions'
6+
7+
8+
type ArticleSearchAndGridProps = {
9+
categorySlug?: string
10+
}
11+
12+
export default function ArticleSearchAndGrid({ categorySlug = '' }: ArticleSearchAndGridProps) {
13+
const [articles, setArticles] = useState<ArticleWithRelations[]>([])
14+
const [isLoading, setIsLoading] = useState(true)
15+
const [searchQuery, setSearchQuery] = useState('')
16+
17+
useEffect(() => {
18+
const fetchArticles = async () => {
19+
setIsLoading(true)
20+
try {
21+
const results = await searchArticles(searchQuery, categorySlug)
22+
setArticles(results as ArticleWithRelations[])
23+
} catch (error) {
24+
console.error('Error fetching articles:', error)
25+
} finally {
26+
setIsLoading(false)
27+
}
28+
}
29+
fetchArticles()
30+
}, [categorySlug, searchQuery])
31+
32+
const handleSearch = (query: string) => {
33+
setSearchQuery(query)
34+
}
35+
36+
return (
37+
<>
38+
<ArticleSearchBox
39+
searchQuery={searchQuery}
40+
setSearchQuery={handleSearch}
41+
isLoading={isLoading}
42+
/>
43+
<ArticleGrid articles={articles} />
44+
{articles.length === 0 && !isLoading && (
45+
<p className="text-center text-muted-foreground mt-6">No articles found.</p>
46+
)}
47+
</>
48+
)
49+
}

config/links.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export const githubLink: NavItem = {
7777
}
7878

7979
export const researcherLink: NavItem = {
80-
title: "Researcher",
80+
title: "Research Agent",
8181
href: "/researcher",
8282
icon: "pencil",
8383
tooltip: "Your very own AI researcher",
Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,38 @@
1-
import Exa, {SearchResult} from "exa-js";
1+
import Exa, {RegularSearchOptions, SearchResult} from "exa-js";
22
const exa = new Exa(process.env.EXA_API_KEY);
33

4-
export async function getSearchResults(queries: string[], linksPerQuery: number = 5): Promise<SearchResult[]> {
4+
export async function getSearchResults(queries: string[], options?: RegularSearchOptions): Promise<SearchResult[]> {
55
let results: SearchResult[] = [];
66
for (const query of queries) {
77
const searchResponse = await exa.searchAndContents(query, {
8-
numResults: linksPerQuery,
9-
useAutoprompt: false,
8+
numResults: options?.numResults ?? 5,
9+
useAutoprompt: options?.useAutoprompt ?? false,
10+
...options,
1011
});
1112
results.push(...searchResponse.results);
1213
}
1314
return results;
1415
}
16+
17+
export async function getSearchResultsByDomain(domain: string, queries: string[], options?: RegularSearchOptions): Promise<SearchResult[]> {
18+
let results: SearchResult[] = [];
19+
for (const query of queries) {
20+
const searchResponse = await exa.searchAndContents(query, {
21+
numResults: options?.numResults ?? 5,
22+
useAutoprompt: options?.useAutoprompt ?? false,
23+
includeDomains: [domain],
24+
...options,
25+
});
26+
results.push(...searchResponse.results);
27+
}
28+
return results;
29+
}
30+
31+
export async function getSearchResultsByUrl(url: string, linksPerQuery: number = 5): Promise<SearchResult[]> {
32+
let results: SearchResult[] = [];
33+
const searchResponse = await exa.findSimilarAndContents(url, {
34+
numResults: linksPerQuery,
35+
});
36+
results.push(...searchResponse.results);
37+
return results;
38+
}

0 commit comments

Comments
 (0)