diff --git a/app/paper/[id]/[slug]/bounties/page.tsx b/app/paper/[id]/[slug]/bounties/page.tsx index 873f8bab4..b63cc472f 100644 --- a/app/paper/[id]/[slug]/bounties/page.tsx +++ b/app/paper/[id]/[slug]/bounties/page.tsx @@ -1,11 +1,10 @@ -import { PaperService } from '@/services/paper.service'; -import { MetadataService } from '@/services/metadata.service'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { WorkDocument } from '@/components/work/WorkDocument'; import { SearchHistoryTracker } from '@/components/work/SearchHistoryTracker'; import { WorkDocumentTracker } from '@/components/WorkDocumentTracker'; import { getWorkMetadata } from '@/lib/metadata-helpers'; +import { getPaper, getDocumentMetadata } from '../data'; interface Props { params: Promise<{ @@ -20,7 +19,7 @@ async function getWork(id: string) { } try { - return await PaperService.get(id); + return await getPaper(id); } catch (error) { notFound(); } @@ -38,7 +37,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function WorkBountiesPage({ params }: Props) { const resolvedParams = await params; const work = await getWork(resolvedParams.id); - const metadata = await MetadataService.get(work.unifiedDocumentId?.toString() || ''); + const metadata = await getDocumentMetadata(work.unifiedDocumentId); if (!work) { notFound(); diff --git a/app/paper/[id]/[slug]/conversation/page.tsx b/app/paper/[id]/[slug]/conversation/page.tsx index 20d0771fc..c3983ca2c 100644 --- a/app/paper/[id]/[slug]/conversation/page.tsx +++ b/app/paper/[id]/[slug]/conversation/page.tsx @@ -1,11 +1,10 @@ -import { PaperService } from '@/services/paper.service'; -import { MetadataService } from '@/services/metadata.service'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { WorkDocument } from '@/components/work/WorkDocument'; import { SearchHistoryTracker } from '@/components/work/SearchHistoryTracker'; import { WorkDocumentTracker } from '@/components/WorkDocumentTracker'; import { getWorkMetadata } from '@/lib/metadata-helpers'; +import { getPaper, getDocumentMetadata } from '../data'; interface Props { params: Promise<{ @@ -20,7 +19,7 @@ async function getWork(id: string) { } try { - return await PaperService.get(id); + return await getPaper(id); } catch (error) { notFound(); } @@ -38,7 +37,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function WorkConversationPage({ params }: Props) { const resolvedParams = await params; const work = await getWork(resolvedParams.id); - const metadata = await MetadataService.get(work.unifiedDocumentId?.toString() || ''); + const metadata = await getDocumentMetadata(work.unifiedDocumentId); if (!work) { notFound(); diff --git a/app/paper/[id]/[slug]/data.ts b/app/paper/[id]/[slug]/data.ts new file mode 100644 index 000000000..5f3ffcb45 --- /dev/null +++ b/app/paper/[id]/[slug]/data.ts @@ -0,0 +1,19 @@ +import 'server-only'; + +import { cache } from 'react'; +import { MetadataService } from '@/services/metadata.service'; +import { PaperService } from '@/services/paper.service'; + +/** + * Deduplicates paper detail requests within a single server render. + */ +export const getPaper = cache(async (id: string) => { + return PaperService.get(id); +}); + +/** + * Deduplicates document metadata requests within a single server render. + */ +export const getDocumentMetadata = cache(async (unifiedDocumentId: number | null | undefined) => { + return MetadataService.get(unifiedDocumentId?.toString() || ''); +}); diff --git a/app/paper/[id]/[slug]/history/page.tsx b/app/paper/[id]/[slug]/history/page.tsx index 0da1befa3..f55e8bc7f 100644 --- a/app/paper/[id]/[slug]/history/page.tsx +++ b/app/paper/[id]/[slug]/history/page.tsx @@ -1,11 +1,10 @@ -import { PaperService } from '@/services/paper.service'; -import { MetadataService } from '@/services/metadata.service'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { WorkDocument } from '@/components/work/WorkDocument'; import { SearchHistoryTracker } from '@/components/work/SearchHistoryTracker'; import { WorkDocumentTracker } from '@/components/WorkDocumentTracker'; import { getWorkMetadata } from '@/lib/metadata-helpers'; +import { getPaper, getDocumentMetadata } from '../data'; interface Props { params: Promise<{ @@ -20,7 +19,7 @@ async function getWork(id: string) { } try { - return await PaperService.get(id); + return await getPaper(id); } catch (error) { notFound(); } @@ -38,7 +37,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function WorkHistoryPage({ params }: Props) { const resolvedParams = await params; const work = await getWork(resolvedParams.id); - const metadata = await MetadataService.get(work.unifiedDocumentId?.toString() || ''); + const metadata = await getDocumentMetadata(work.unifiedDocumentId); if (!work) { notFound(); diff --git a/app/paper/[id]/[slug]/layout.tsx b/app/paper/[id]/[slug]/layout.tsx index a8db9006e..7f7f95f50 100644 --- a/app/paper/[id]/[slug]/layout.tsx +++ b/app/paper/[id]/[slug]/layout.tsx @@ -1,13 +1,12 @@ import { Suspense } from 'react'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; -import { PaperService } from '@/services/paper.service'; -import { MetadataService } from '@/services/metadata.service'; import { buildArticleMetadata } from '@/lib/metadata'; import { stripHtml } from '@/utils/stringUtils'; import { PageLayout } from '@/app/layouts/PageLayout'; import { WorkHeader, WorkTabProvider } from '@/components/work/WorkHeader/index'; import { WorkRightSidebar } from '@/components/work/WorkRightSidebar'; +import { getPaper, getDocumentMetadata } from './data'; interface Props { params: Promise<{ @@ -20,7 +19,7 @@ interface Props { export async function generateMetadata({ params }: Props): Promise { const { id, slug } = await params; try { - const work = await PaperService.get(id); + const work = await getPaper(id); const previewText = stripHtml(work.previewContent || '').substring(0, 155); const description = work.abstract || previewText || 'Read this research paper on ResearchHub.'; return buildArticleMetadata({ @@ -48,11 +47,11 @@ export default async function PaperSlugLayout({ params, children }: Props) { let work; try { - work = await PaperService.get(id); + work = await getPaper(id); } catch { notFound(); } - const metadata = await MetadataService.get(work.unifiedDocumentId?.toString() || ''); + const metadata = await getDocumentMetadata(work.unifiedDocumentId); return ( diff --git a/app/paper/[id]/[slug]/page.tsx b/app/paper/[id]/[slug]/page.tsx index 8bcc4844a..ff68f0002 100644 --- a/app/paper/[id]/[slug]/page.tsx +++ b/app/paper/[id]/[slug]/page.tsx @@ -1,11 +1,10 @@ -import { PaperService } from '@/services/paper.service'; -import { MetadataService } from '@/services/metadata.service'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { WorkDocument } from '@/components/work/WorkDocument'; import { SearchHistoryTracker } from '@/components/work/SearchHistoryTracker'; import { WorkDocumentTracker } from '@/components/WorkDocumentTracker'; import { getWorkMetadata } from '@/lib/metadata-helpers'; +import { getPaper, getDocumentMetadata } from './data'; interface Props { params: Promise<{ @@ -20,7 +19,7 @@ async function getWork(id: string) { } try { - return await PaperService.get(id); + return await getPaper(id); } catch (error) { notFound(); } @@ -39,7 +38,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function WorkPage({ params }: Props) { const resolvedParams = await params; const work = await getWork(resolvedParams.id); - const metadata = await MetadataService.get(work.unifiedDocumentId?.toString() || ''); + const metadata = await getDocumentMetadata(work.unifiedDocumentId); if (!work) { notFound(); diff --git a/app/paper/[id]/[slug]/reviews/page.tsx b/app/paper/[id]/[slug]/reviews/page.tsx index 395ffbe95..3aaba21d4 100644 --- a/app/paper/[id]/[slug]/reviews/page.tsx +++ b/app/paper/[id]/[slug]/reviews/page.tsx @@ -1,11 +1,10 @@ -import { PaperService } from '@/services/paper.service'; -import { MetadataService } from '@/services/metadata.service'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; import { WorkDocument } from '@/components/work/WorkDocument'; import { SearchHistoryTracker } from '@/components/work/SearchHistoryTracker'; import { WorkDocumentTracker } from '@/components/WorkDocumentTracker'; import { getWorkMetadata } from '@/lib/metadata-helpers'; +import { getPaper, getDocumentMetadata } from '../data'; interface Props { params: Promise<{ @@ -20,7 +19,7 @@ async function getWork(id: string) { } try { - return await PaperService.get(id); + return await getPaper(id); } catch (error) { notFound(); } @@ -38,7 +37,7 @@ export async function generateMetadata({ params }: Props): Promise { export default async function WorkReviewsPage({ params }: Props) { const resolvedParams = await params; const work = await getWork(resolvedParams.id); - const metadata = await MetadataService.get(work.unifiedDocumentId?.toString() || ''); + const metadata = await getDocumentMetadata(work.unifiedDocumentId); if (!work) { notFound();