-
Notifications
You must be signed in to change notification settings - Fork 1
Citation prototyping experiments #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { notFound } from "next/navigation"; | ||
| import ActionButtons from "@/components/ActionButtons"; | ||
| import Breadcrumbs from "@/components/Breadcrumbs"; | ||
| import { fetchEntity } from "@/data/fetch"; | ||
|
|
||
| export default async function Layout({ | ||
| children, | ||
| }: LayoutProps<"/citations/[...doi]">) { | ||
|
|
||
| return ( | ||
| <> | ||
| {children} | ||
| </> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import { redirect } from "next/navigation"; | ||
| import * as Cards from "@/components/cards/Cards"; | ||
| import OverviewCard from "@/components/cards/OverviewCard"; | ||
| import { SectionHeader } from "@/components/datacite/Headings"; | ||
| import { | ||
| fetchDoiRecord, | ||
| fetchEvents, | ||
| fetchDoisRecords, | ||
| fetchDois, | ||
| } from "@/data/fetch"; | ||
| import DoiRegistrationsChart from "@/components/DoiRegistrationsChart"; | ||
| import ResourceTypesChart from "@/components/ResourceTypesChart"; | ||
| import EventFeed from "@/components/EventFeed"; | ||
| import { Filter } from "lucide-react"; | ||
| import { DoiRecordList } from "@/components/DoiRecordList"; | ||
| import { H2 } from "@/components/datacite/Headings"; | ||
|
|
||
| interface PageProps { | ||
| params: { doi: string }; | ||
| } | ||
|
|
||
| export default async function Page({ params }: PageProps) { | ||
| const { doi } = await params; | ||
| const doi_id = Array.isArray(doi) ? doi.join("/") : doi; | ||
|
|
||
| // Fetch the DOI record and events | ||
| const [record, eventsResult, doisRecords] = await Promise.all([ | ||
| fetchDoiRecord(doi_id), | ||
| fetchEvents(doi_id), | ||
| fetchDoisRecords("reference_ids:" + doi_id), | ||
| ]); | ||
| const citationsOverTime = record?.data?.attributes?.citationsOverTime || []; | ||
| let chartData: { year: string; count: number }[] = []; | ||
| if (citationsOverTime.length > 0) { | ||
| const yearNums = citationsOverTime.map((item: { year: string }) => | ||
| parseInt(item.year, 10), | ||
| ); | ||
| const minYear = Math.min(...yearNums); | ||
| const maxYear = new Date().getFullYear(); | ||
| const yearToCount: Record<string, number> = {}; | ||
| citationsOverTime.forEach((item: { year: string; total: number }) => { | ||
| yearToCount[item.year] = item.total; | ||
| }); | ||
| for (let y = minYear; y <= maxYear; y++) { | ||
| chartData.push({ | ||
| year: y.toString(), | ||
| count: yearToCount[y.toString()] ?? 0, | ||
| }); | ||
| } | ||
| } | ||
| const events = eventsResult?.data || []; | ||
|
|
||
| return ( | ||
| <> | ||
| <div className="mt-8 mb-0"> | ||
| <H2 > | ||
| {record.data.attributes.titles[0].title} | ||
| </H2> | ||
| <div className="text-gray-500 font-semibold"> | ||
| {record.data.attributes.doi} | ||
| </div> | ||
| </div> | ||
| <main className="w-full mx-auto flex flex-row items-start gap-8"> | ||
| <div className="w-1/2"> | ||
| <div className="bg-card text-card-foreground border p-8 shadow-sm"> | ||
| <h3 className="text-xl font-bold mb-4">Citations Over Time</h3> | ||
| {record.data.attributes.citationCount > 0 && ( | ||
| <div className="max-w-300"> | ||
| <DoiRegistrationsChart data={chartData} /> | ||
| </div> | ||
| ) || ( | ||
| <p>No citation data available.</p> | ||
| )} | ||
| </div> | ||
| <div className="bg-card text-card-foreground border p-8 shadow-sm mt-8"> | ||
| <h3 className="text-xl font-bold">Event Feed</h3> | ||
| <EventFeed events={events} doi={doi_id} /> | ||
| </div> | ||
| </div> | ||
| <div className="w-1/2"> | ||
| <div className="bg-card text-card-foreground border p-8 shadow-sm"> | ||
| <h3 className="text-xl font-bold mb-4"> | ||
| Available Citation Records | ||
| </h3> | ||
| {doisRecords.meta.resourceTypes && <ResourceTypesChart data={doisRecords.meta.resourceTypes} />} | ||
| <DoiRecordList records={doisRecords.data} /> | ||
| </div> | ||
| </div> | ||
| </main> | ||
| </> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { H2 } from "@/components/datacite/Headings"; | ||
| import type { Entity } from "@/types"; | ||
|
|
||
| export default function Header(props: { entity: Entity }) { | ||
| return ( | ||
| <div className="gap-0 mt-8"> | ||
| <H2 className={`text-4xl w-full`}>{props.entity.name}</H2> | ||
| <div className="text-gray-500 font-semibold"> | ||
| {props.entity.id} | ||
| </div> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import { notFound } from "next/navigation"; | ||
| import ActionButtons from "@/components/ActionButtons"; | ||
| import Breadcrumbs from "@/components/Breadcrumbs"; | ||
| import { fetchEntity } from "@/data/fetch"; | ||
| import Header from "./Header"; | ||
|
|
||
| export default async function Layout({ | ||
| params, | ||
| children, | ||
| }: LayoutProps<"/[id]">) { | ||
| const { id } = await params; | ||
|
|
||
| // Check if entity exists | ||
| const entity = await fetchEntity(id); | ||
| if (!entity) notFound(); | ||
|
|
||
| return ( | ||
| <> | ||
| <Header entity={entity} /> | ||
| {children} | ||
| </> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,82 @@ | ||||||||||||||||||||||||||||
| import { redirect } from "next/navigation"; | ||||||||||||||||||||||||||||
| import * as Cards from "@/components/cards/Cards"; | ||||||||||||||||||||||||||||
| import OverviewCard from "@/components/cards/OverviewCard"; | ||||||||||||||||||||||||||||
| import { SectionHeader } from "@/components/datacite/Headings"; | ||||||||||||||||||||||||||||
| import { fetchDoisRecords, fetchEntity } from "@/data/fetch"; | ||||||||||||||||||||||||||||
| import { fetchEntityCitations } from "@/data/fetch"; | ||||||||||||||||||||||||||||
| import DoiRegistrationsChart from "@/components/DoiRegistrationsChart"; | ||||||||||||||||||||||||||||
| import { DoiRecordList } from "@/components/DoiRecordList"; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export default async function Page({ | ||||||||||||||||||||||||||||
| params, | ||||||||||||||||||||||||||||
| searchParams, | ||||||||||||||||||||||||||||
| }: PageProps<"/[id]">) { | ||||||||||||||||||||||||||||
| const { id } = await params; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const [doisRecords] = await Promise.all([ | ||||||||||||||||||||||||||||
| fetchEntityCitations("provider.id:" + id + " OR client_id:" + id), | ||||||||||||||||||||||||||||
| ]); | ||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normalize before fetching, and redirect back into the same route tree. The redirect target drops the ↪️ Suggested fix- redirect(`/${id.toLowerCase()}?${urlSearchParams.toString()}`);
+ const query = urlSearchParams.toString();
+ redirect(
+ `/citationsByEntity/${id.toLowerCase()}${query ? `?${query}` : ""}`,
+ );Also applies to: 43-55 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const citationsOverTime = doisRecords?.meta?.citations || []; | ||||||||||||||||||||||||||||
| let chartData: { year: string; count: number }[] = []; | ||||||||||||||||||||||||||||
| if (citationsOverTime.length > 0) { | ||||||||||||||||||||||||||||
| // Map citations to { year, count } | ||||||||||||||||||||||||||||
| const mapped = citationsOverTime.map((item: { id: string; count: number }) => ({ | ||||||||||||||||||||||||||||
| year: item.id, | ||||||||||||||||||||||||||||
| count: item.count, | ||||||||||||||||||||||||||||
| })); | ||||||||||||||||||||||||||||
| const yearNums = mapped.map((item: { year: string; count: number }) => parseInt(item.year, 10)); | ||||||||||||||||||||||||||||
| const minYear = Math.min(...yearNums); | ||||||||||||||||||||||||||||
| const maxYear = new Date().getFullYear(); | ||||||||||||||||||||||||||||
|
Comment on lines
+28
to
+30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against invalid year values that produce If the API returns a non-numeric year string, Proposed fix- const yearNums = mapped.map((item: { year: string; count: number }) => parseInt(item.year, 10));
- const minYear = Math.min(...yearNums);
- const maxYear = new Date().getFullYear();
+ const yearNums = mapped
+ .map((item: { year: string; count: number }) => parseInt(item.year, 10))
+ .filter((y) => !Number.isNaN(y));
+ if (yearNums.length === 0) {
+ // No valid years, leave chartData empty
+ } else {
+ const minYear = Math.min(...yearNums);
+ const maxYear = new Date().getFullYear();
+ const yearToCount: Record<string, number> = {};
+ mapped.forEach((item: { year: string; count: number }) => {
+ yearToCount[item.year] = item.count;
+ });
+ for (let y = minYear; y <= maxYear; y++) {
+ chartData.push({
+ year: y.toString(),
+ count: yearToCount[y.toString()] ?? 0,
+ });
+ }
+ }🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| const yearToCount: Record<string, number> = {}; | ||||||||||||||||||||||||||||
| mapped.forEach((item: { year: string; count: number }) => { | ||||||||||||||||||||||||||||
| yearToCount[item.year] = item.count; | ||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||
| for (let y = minYear; y <= maxYear; y++) { | ||||||||||||||||||||||||||||
| chartData.push({ | ||||||||||||||||||||||||||||
| year: y.toString(), | ||||||||||||||||||||||||||||
| count: yearToCount[y.toString()] ?? 0, | ||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| // Redirect to lowercased id if it contains uppercase letters | ||||||||||||||||||||||||||||
| if (id !== id.toLowerCase()) { | ||||||||||||||||||||||||||||
| const urlSearchParams = new URLSearchParams(); | ||||||||||||||||||||||||||||
| Object.entries(await searchParams).forEach(([key, value]) => { | ||||||||||||||||||||||||||||
| if (!value) return; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| if (Array.isArray(value)) | ||||||||||||||||||||||||||||
| for (const v of value) urlSearchParams.append(key, v); | ||||||||||||||||||||||||||||
| else urlSearchParams.append(key, value); | ||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| redirect(`/${id.toLowerCase()}?${urlSearchParams.toString()}`); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| const entity = await fetchEntity(id); | ||||||||||||||||||||||||||||
| if (!entity) return null; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||
| <main className=""> | ||||||||||||||||||||||||||||
| <main className="w-full mx-auto flex flex-row items-start gap-8"> | ||||||||||||||||||||||||||||
|
Comment on lines
+60
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid nested Nested Proposed fix return (
- <main className="">
- <main className="w-full mx-auto flex flex-row items-start gap-8">
+ <main className="w-full mx-auto flex flex-row items-start gap-8">
<div className="w-1/2">
...
</div>
<div className="w-1/2">
...
</div>
- </main>
</main>
);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| <div className="w-1/2"> | ||||||||||||||||||||||||||||
| <div className="bg-card text-card-foreground border p-8 shadow-sm"> | ||||||||||||||||||||||||||||
| <h3 className="text-xl font-bold mb-4">Citations By Record Publication Year</h3> | ||||||||||||||||||||||||||||
| <div className="max-w-300"> | ||||||||||||||||||||||||||||
| <DoiRegistrationsChart data={chartData} /> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| <div className="w-1/2"> | ||||||||||||||||||||||||||||
| <div className="bg-card text-card-foreground border p-8 shadow-sm"> | ||||||||||||||||||||||||||||
| <h3 className="text-xl font-bold mb-4">Most Cited Records</h3> | ||||||||||||||||||||||||||||
| <div className="max-w-300"> | ||||||||||||||||||||||||||||
| <DoiRecordList records={doisRecords.data} /> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </main> | ||||||||||||||||||||||||||||
| </main> | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,85 @@ | ||||||||||||||||||||||||||||
| import React from "react"; | ||||||||||||||||||||||||||||
| import Link from "next/link"; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export type DoiRecord = { | ||||||||||||||||||||||||||||
| id: string; | ||||||||||||||||||||||||||||
| attributes: { | ||||||||||||||||||||||||||||
| titles: { title: string }[]; | ||||||||||||||||||||||||||||
| doi: string; | ||||||||||||||||||||||||||||
| descriptions?: { description: string }[]; | ||||||||||||||||||||||||||||
| types: { resourceTypeGeneral?: string }; | ||||||||||||||||||||||||||||
| citationCount?: number; | ||||||||||||||||||||||||||||
| viewCount?: number; | ||||||||||||||||||||||||||||
| downloadCount?: number; | ||||||||||||||||||||||||||||
| publicationYear?: string; | ||||||||||||||||||||||||||||
| publisher?: string; | ||||||||||||||||||||||||||||
| agency?: string; | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| type DoiRecordListProps = { | ||||||||||||||||||||||||||||
| records: DoiRecord[]; | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export function DoiRecordList({ records }: DoiRecordListProps) { | ||||||||||||||||||||||||||||
| if (!records || records.length === 0) { | ||||||||||||||||||||||||||||
| return <p>No citations found.</p>; | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||
| <div className="flex flex-col py-4"> | ||||||||||||||||||||||||||||
| {records.map((record, idx) => ( | ||||||||||||||||||||||||||||
| <div key={record.id} className="flex flex-col"> | ||||||||||||||||||||||||||||
| <DoiRecordItem record={record} /> | ||||||||||||||||||||||||||||
| {idx < records.length - 1 && ( | ||||||||||||||||||||||||||||
| <div className="w-full flex justify-center"> | ||||||||||||||||||||||||||||
| <div className="h-px w-5/6 bg-gray-300 my-2" /> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| type DoiRecordItemProps = { | ||||||||||||||||||||||||||||
| record: DoiRecord; | ||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| export function DoiRecordItem({ record }: DoiRecordItemProps) { | ||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||
| <Link | ||||||||||||||||||||||||||||
| href={`/citations/${record.attributes.doi}`} | ||||||||||||||||||||||||||||
| className="cursor-pointer" | ||||||||||||||||||||||||||||
| scroll={false} | ||||||||||||||||||||||||||||
| shallow | ||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||
|
Comment on lines
+50
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: No, the Next.js 16 Link component does not support the shallow prop in the App Router (the default and recommended router). The shallow prop was specific to the Pages Router, where it enabled changing the URL without re-running data fetching methods like getStaticProps or getServerSideProps. In Next.js 16, official App Router Link documentation lists props like href, replace, scroll, prefetch, and onNavigate, but not shallow. GitHub discussions confirm shallow routing is unavailable in the App Router since Next.js 13, with no restoration in version 16 release notes. The Pages Router documentation still mentions shallow, but Next.js 16 emphasizes the App Router, and Pages Router is legacy. Citations:
🏁 Script executed: # Check Next.js version in package.json
cat package.json | grep -A 2 '"next"'Repository: datacite/puli Length of output: 128 🏁 Script executed: # Check directory structure to determine routing system
git ls-files | head -20
find . -type d -name "app" -o -type d -name "pages" | head -10Repository: datacite/puli Length of output: 515 🏁 Script executed: # Check the actual file to see routing context
cat -n src/components/DoiRecordList.tsx | head -60Repository: datacite/puli Length of output: 1987 Remove the The Proposed fix <Link
href={`/citations/${record.attributes.doi}`}
className="cursor-pointer"
scroll={false}
- shallow
>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| <div className="py-2"> | ||||||||||||||||||||||||||||
| <div className="font-bold text-[#243B54]"> | ||||||||||||||||||||||||||||
| {record.attributes.titles[0].title} | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against empty
Proposed fix <div className="font-bold text-[`#243B54`]">
- {record.attributes.titles[0].title}
+ {record.attributes.titles[0]?.title ?? "Untitled"}
</div>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| <div className="text-gray-500 font-semibold text-sm"> | ||||||||||||||||||||||||||||
| https://doi.org/{record.attributes.doi} | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| <div className="text-gray-500 text-sm mt-2"> | ||||||||||||||||||||||||||||
| {record.attributes.publicationYear} · {record.attributes.publisher} · via {record.attributes.agency && record.attributes.agency.charAt(0).toUpperCase() + record.attributes.agency.slice(1)} | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
|
Comment on lines
+63
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle missing metadata fields to avoid rendering artifacts like When Proposed fix- <div className="text-gray-500 text-sm mt-2">
- {record.attributes.publicationYear} · {record.attributes.publisher} · via {record.attributes.agency && record.attributes.agency.charAt(0).toUpperCase() + record.attributes.agency.slice(1)}
- </div>
+ <div className="text-gray-500 text-sm mt-2">
+ {[
+ record.attributes.publicationYear,
+ record.attributes.publisher,
+ record.attributes.agency &&
+ `via ${record.attributes.agency.charAt(0).toUpperCase() + record.attributes.agency.slice(1)}`,
+ ]
+ .filter(Boolean)
+ .join(" · ")}
+ </div>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| <div className="text-gray-500 line-clamp-3 text-sm mt-2"> | ||||||||||||||||||||||||||||
| {record.attributes.descriptions?.[0]?.description} | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| <div className="text-gray-500 text-sm mt-2"> | ||||||||||||||||||||||||||||
| {record.attributes.types.resourceTypeGeneral ? ( | ||||||||||||||||||||||||||||
| <span className="font-semibold mr-2 bg-[#e6f0fa] text-[#003366] rounded-full px-3 py-1 text-xs inline-block"> | ||||||||||||||||||||||||||||
| {record.attributes.types.resourceTypeGeneral} | ||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||
| ) : null} | ||||||||||||||||||||||||||||
| <span className="align-right font-semibold mt-2 bg-gray-100 text-[#003366] rounded-sm px-3 py-1 text-xs inline-block"> | ||||||||||||||||||||||||||||
| Citations: <span className="font-bold mr-2">{record.attributes.citationCount} </span> | ||||||||||||||||||||||||||||
| Views: <span className="font-bold mr-2">{record.attributes.viewCount} </span> | ||||||||||||||||||||||||||||
| Downloads: <span className="font-bold mr-2">{record.attributes.downloadCount} </span> | ||||||||||||||||||||||||||||
|
Comment on lines
+76
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default missing metrics before rendering the badge. These fields are optional in the local type, so records without metrics will render 🪄 Suggested fix- Citations: <span className="font-bold mr-2">{record.attributes.citationCount} </span>
- Views: <span className="font-bold mr-2">{record.attributes.viewCount} </span>
- Downloads: <span className="font-bold mr-2">{record.attributes.downloadCount} </span>
+ Citations: <span className="font-bold mr-2">{record.attributes.citationCount ?? 0} </span>
+ Views: <span className="font-bold mr-2">{record.attributes.viewCount ?? 0} </span>
+ Downloads: <span className="font-bold mr-2">{record.attributes.downloadCount ?? 0} </span>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| </span> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </Link> | ||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Map facet data into the chart's expected shape first.
ResourceTypesChartexpects{ type, count }[], butdoisRecords.meta.resourceTypescomes through asFacet[]with{ id, title, count }. Passing it straight through leaves the chart without the field it renders against.📊 Suggested fix
Also applies to: 85-85
🤖 Prompt for AI Agents