feat(frontend): connect Next.js server components to Go backend REST API with resilient fallback
- Implement typed REST API client in refer_landing_page/lib/api.ts - Support API_BASE_URL environment variable with graceful fallback to static content - Connect Home page (projects, areas, stats), Members page (active, alumni), Publications (highlights, list, patents), Lectures, and Standardization pages to backend endpoints - Pass all 12 SSG build, TypeScript, ESLint, and E2E quality gates
This commit is contained in:
@@ -2,7 +2,8 @@ import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { notFound } from "next/navigation";
|
||||
import { CategoryNav } from "../_components/CategoryNav";
|
||||
import { publications, patents } from "../../../content/publications";
|
||||
import { publications as staticPubs, patents as staticPatents } from "../../../content/publications";
|
||||
import { getPublications, getPatents } from "../../../lib/api";
|
||||
import { PUB_CATEGORIES } from "../../../content/categories";
|
||||
import { PubCategory } from "../../../content/types";
|
||||
|
||||
@@ -30,7 +31,7 @@ export function generateStaticParams() {
|
||||
}));
|
||||
}
|
||||
|
||||
export default function PublicationCategoryPage({ params }: PageProps) {
|
||||
export default async function PublicationCategoryPage({ params }: PageProps) {
|
||||
const { category } = params;
|
||||
const currentCat = PUB_CATEGORIES.find((c) => c.slug === category);
|
||||
|
||||
@@ -40,6 +41,15 @@ export default function PublicationCategoryPage({ params }: PageProps) {
|
||||
|
||||
const slug = category as PubCategory;
|
||||
|
||||
const publications = (await getPublications()) ?? staticPubs;
|
||||
const patents = (await getPatents()) ?? staticPatents;
|
||||
|
||||
const counts = {
|
||||
"intl-journal-conf": publications.filter((p) => p.category === "intl-journal-conf").length,
|
||||
"domestic-journal-conf": publications.filter((p) => p.category === "domestic-journal-conf").length,
|
||||
patent: patents.length,
|
||||
};
|
||||
|
||||
let records: any[] = [];
|
||||
if (slug === "patent") {
|
||||
records = patents.map((p) => ({
|
||||
@@ -82,7 +92,7 @@ export default function PublicationCategoryPage({ params }: PageProps) {
|
||||
|
||||
{/* Category Nav Cards */}
|
||||
<section className="pt-6 md:pt-8 border-t border-line">
|
||||
<CategoryNav currentCategory={slug} />
|
||||
<CategoryNav currentCategory={slug} counts={counts} />
|
||||
</section>
|
||||
|
||||
{/* Record List Section */}
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
import { PUB_CATEGORIES } from "../../../content/categories";
|
||||
import { publications, patents } from "../../../content/publications";
|
||||
import { publications as staticPubs, patents as staticPatents } from "../../../content/publications";
|
||||
import { PubCategory } from "../../../content/types";
|
||||
|
||||
export interface CategoryCounts {
|
||||
"intl-journal-conf"?: number;
|
||||
"domestic-journal-conf"?: number;
|
||||
patent?: number;
|
||||
}
|
||||
|
||||
interface CategoryNavProps {
|
||||
currentCategory?: PubCategory;
|
||||
counts?: CategoryCounts;
|
||||
}
|
||||
|
||||
export function CategoryNav({ currentCategory }: CategoryNavProps) {
|
||||
export function CategoryNav({ currentCategory, counts }: CategoryNavProps) {
|
||||
const getCount = (slug: string) => {
|
||||
if (slug === "patent") return patents.length;
|
||||
return publications.filter((p) => p.category === slug).length;
|
||||
if (counts?.[slug as keyof CategoryCounts] !== undefined) {
|
||||
return counts[slug as keyof CategoryCounts]!;
|
||||
}
|
||||
if (slug === "patent") return staticPatents.length;
|
||||
return staticPubs.filter((p) => p.category === slug).length;
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
import type { Metadata } from "next";
|
||||
import { CategoryNav } from "./_components/CategoryNav";
|
||||
import { publications } from "../../content/publications";
|
||||
import { publications as staticPubs, patents as staticPatents } from "../../content/publications";
|
||||
import { getPublications, getPatents } from "../../lib/api";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Publications",
|
||||
description: "AI Agent Networking Lab (ANL) research publications and patents overview",
|
||||
};
|
||||
|
||||
export default function PublicationsIndexPage() {
|
||||
export default async function PublicationsIndexPage() {
|
||||
const publications = (await getPublications()) ?? staticPubs;
|
||||
const patents = (await getPatents()) ?? staticPatents;
|
||||
|
||||
const counts = {
|
||||
"intl-journal-conf": publications.filter((p) => p.category === "intl-journal-conf").length,
|
||||
"domestic-journal-conf": publications.filter((p) => p.category === "domestic-journal-conf").length,
|
||||
patent: patents.length,
|
||||
};
|
||||
|
||||
// Selected representative publications (curated via database isHighlight flag)
|
||||
const highlights = publications.filter((p) => p.isHighlight);
|
||||
|
||||
@@ -22,7 +32,7 @@ export default function PublicationsIndexPage() {
|
||||
|
||||
{/* Category Summary Cards */}
|
||||
<section className="pt-6 md:pt-8 border-t border-line">
|
||||
<CategoryNav />
|
||||
<CategoryNav counts={counts} />
|
||||
</section>
|
||||
|
||||
{/* Highlights Section */}
|
||||
|
||||
Reference in New Issue
Block a user