Skip to content

Commit e0a345b

Browse files
authored
[refactor] Updated to Next15, react-notion-x 'lm' support, and fixed /[slug] to /[notionId] route (#226)
* [refactor] Updated to Next15, react-notion-x 'lm' support, and fixed /[slug] to /[notionId] route * [refactor] Fix 'standalone' warning * [bug] Deal with sub-pages not handled well by getPageTitle * [refactor] Prettier fix * [feat] dynamicParams=false for External
1 parent 07ed645 commit e0a345b

File tree

26 files changed

+2103
-1992
lines changed

26 files changed

+2103
-1992
lines changed

next.config.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const nextConfig = {
1010
},
1111
],
1212
},
13-
output: 'standalone',
13+
// output: 'standalone', // NOTE: Check the Dockerfile for why we might need this
1414
};
1515

1616
export default nextConfig;

package-lock.json

+1,919-1,783
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"quality": "npm run format-check && npm run lint",
1010
"dev": "next dev",
1111
"build": "npm run quality && next build",
12+
"test-build": "rm -rf .next && build && start",
1213
"start": "next start"
1314
},
1415
"dependencies": {
@@ -25,7 +26,7 @@
2526
"date-fns": "^3.6.0",
2627
"embla-carousel-react": "^8.1.3",
2728
"lucide-react": "^0.363.0",
28-
"next": "^14.2.23",
29+
"next": "^15.2.4",
2930
"notion-client": "^7.1.6",
3031
"notion-utils": "^6.16.0",
3132
"react": "^18",

src/app/(pages)/[notionId]/page.tsx

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import NotionPage from '@/components/NotionPage';
2+
import { getAllPageIds, getRecordMap, getTitleByPageId } from '@/lib/notion/utils';
3+
4+
export async function generateStaticParams() {
5+
const pageIds = await getAllPageIds();
6+
return pageIds.map(pageId => ({ notionId: pageId.replace(/-/g, '') }));
7+
}
8+
9+
export default async function ArbitraryNotionPage({ params }: { params: Promise<{ notionId: string }> }) {
10+
const { notionId } = await params;
11+
12+
const recordMap = await getRecordMap(notionId);
13+
const title = await getTitleByPageId(notionId);
14+
15+
return <NotionPage recordMap={recordMap} title={title} />;
16+
}
17+
18+
export const dynamicParams = false;

src/app/(pages)/[slug]/page.tsx

-37
This file was deleted.
+6-17
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,21 @@
1-
import NotionPage, { EventDetailsType } from '@/components/NotionPage';
1+
import NotionPage from '@/components/NotionPage';
22
import { getEventPageBySlug, getEvents } from '@/lib/notion/events';
33
import { getRecordMap } from '@/lib/notion/utils';
44
import { notFound } from 'next/navigation';
55

66
export async function generateStaticParams() {
77
const events = await getEvents();
8-
return events.map(event => ({
9-
slug: event.slug,
10-
}));
8+
return events.map(event => ({ slug: event.slug }));
119
}
1210

13-
type PropsType = {
14-
params: { slug: string };
15-
};
16-
17-
export default async function EventPage({ params }: PropsType) {
18-
const event = await getEventPageBySlug(params.slug);
11+
export default async function EventPage({ params }: { params: Promise<{ slug: string }> }) {
12+
const { slug } = await params;
13+
const event = await getEventPageBySlug(slug);
1914

2015
if (!event) notFound();
2116

22-
const eventDetails: EventDetailsType = {
23-
date: event.date,
24-
venue: event.venue,
25-
status: event.status,
26-
};
27-
2817
const recordMap = await getRecordMap(event.eventPageId);
2918
const title = event.eventName;
3019

31-
return <NotionPage recordMap={recordMap} title={title} eventDetails={eventDetails} />;
20+
return <NotionPage recordMap={recordMap} title={title} eventDetails={event} />;
3221
}

src/app/(pages)/events/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import EventCard from './_components/EventCard';
33
import { getEvents } from '@/lib/notion/events';
44
import BlockContainer from '@/components/BlockContainer';
55

6-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
6+
export const revalidate = 3600;
77

88
const EventsPage: React.FC = async () => {
99
const res = await getEvents();
+10-14
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import NotionPage from '@/components/NotionPage';
2-
import { getExternalPageIdBySlug, getExternalPageSlugs } from '@/lib/notion/external';
3-
import { getRecordMap, getTitleByPageId } from '@/lib/notion/utils';
2+
import { getExternalPages } from '@/lib/notion/external';
3+
import { notFound } from 'next/navigation';
44

55
export async function generateStaticParams() {
6-
const slugs = await getExternalPageSlugs();
7-
return slugs.map((slug: string) => ({ slug }));
6+
const externalPages = await getExternalPages();
7+
return externalPages.map(externalPage => ({ slug: externalPage.slug }));
88
}
99

10-
type PropsType = {
11-
params: { slug: string };
12-
};
10+
export default async function ExternalPage({ params }: { params: Promise<{ slug: string }> }) {
11+
const { slug } = await params;
1312

14-
export default async function ArbitraryNotionPage({ params }: PropsType) {
15-
const slug = params.slug;
13+
const externalPages = await getExternalPages();
14+
const data = externalPages.find(page => page.slug === slug);
15+
if (data === undefined) return notFound();
1616

17-
const pageId = await getExternalPageIdBySlug(slug);
18-
const title = await getTitleByPageId(pageId);
19-
const recordMap = await getRecordMap(pageId);
20-
21-
return <NotionPage recordMap={recordMap} title={title} />;
17+
return <NotionPage recordMap={data.recordMap} title={data.title} />;
2218
}

src/app/(pages)/home/_components/EventsBlock.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getFeaturedEvents } from '@/lib/notion/events';
44
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel';
55
import { getFeaturedAnnouncements } from '@/lib/notion/announcements';
66

7-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
7+
export const revalidate = 3600;
88

99
export default async function HomeEvents() {
1010
const res = await getFeaturedEvents();

src/app/(pages)/home/_components/HeroBlock.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import button from '../_assets/button.svg';
77
import { getLatestCallout } from '@/lib/notion/announcements';
88
import CallOutWrapper from './CallOutWrapper';
99

10-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
10+
export const revalidate = 3600;
1111

1212
export default async function HeroBlock() {
1313
const text = await getLatestCallout();

src/app/(pages)/home/_components/ProjectsBlock.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { MdDoubleArrow } from 'react-icons/md';
55
import { getFeaturedProjects } from '@/lib/notion/projects';
66
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from '@/components/ui/carousel';
77

8-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
8+
export const revalidate = 3600;
99

1010
export default async function ProjectsBlock() {
1111
const featuredProjects = await getFeaturedProjects();

src/app/(pages)/home/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ProjectsBlock from './_components/ProjectsBlock';
55
import EventsBlock from './_components/EventsBlock';
66
import SponsorsBlock from './_components/SponsorsBlock';
77

8-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
8+
export const revalidate = 3600;
99

1010
export default async function Home() {
1111
return (

src/app/(pages)/news/[slug]/page.tsx

+3-6
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ export async function generateStaticParams() {
1010
}));
1111
}
1212

13-
type PropsType = {
14-
params: { slug: string };
15-
};
16-
17-
export default async function EventPage({ params }: PropsType) {
18-
const newsPage = await getNewsPageBySlug(params.slug);
13+
export default async function EventPage({ params }: { params: Promise<{ slug: string }> }) {
14+
const { slug } = await params;
15+
const newsPage = await getNewsPageBySlug(slug);
1916

2017
if (!newsPage) notFound();
2118

src/app/(pages)/projects/[slug]/page.tsx

+4-9
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@ import { notFound } from 'next/navigation';
55

66
export async function generateStaticParams() {
77
const projects = await getProjects();
8-
return projects.map(project => ({
9-
slug: project.slug,
10-
}));
8+
return projects.map(project => ({ slug: project.slug }));
119
}
1210

13-
type PropsType = {
14-
params: { slug: string };
15-
};
16-
17-
export default async function ProjectPage({ params }: PropsType) {
18-
const project = await getProjectPageBySlug(params.slug);
11+
export default async function ProjectPage({ params }: { params: Promise<{ slug: string }> }) {
12+
const { slug } = await params;
13+
const project = await getProjectPageBySlug(slug);
1914

2015
if (!project) notFound();
2116

src/app/(pages)/projects/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import CurrentProjects from './_components/CurrentProjects';
33
import PastProjects from './_components/PastProjects';
44
import { getProjects, isCurrentProject } from '@/lib/notion/projects';
55

6-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
6+
export const revalidate = 3600;
77

88
export default async function Projects() {
99
const res = await getProjects();

src/app/(pages)/students/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { v4 as uuidv4 } from 'uuid';
44
import bluePeople from './_assets/blue_people.svg';
55
import Image from 'next/image';
66

7-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
7+
export const revalidate = 3600;
88

99
export default async function Students() {
1010
const students = await getStudents();

src/app/page.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Home from './(pages)/home/page';
22

3-
export const revalidate = Number(process.env.REVALIDATION_INTERVAL) || 3600;
3+
export const revalidate = 3600;
44

55
export default function App() {
66
return <Home />;

src/components/NotionPage.tsx

-72
This file was deleted.
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { EventDataType } from '@/lib/notion/events';
2+
import { BsCalendar3 } from 'react-icons/bs';
3+
import { MdOutlineLocationCity } from 'react-icons/md';
4+
import { MdOutlineUpcoming } from 'react-icons/md';
5+
6+
export type EventDetailsDataType = Pick<EventDataType, 'date' | 'venue' | 'status'>;
7+
8+
export default function EventDetails({ data }: { data: EventDetailsDataType }) {
9+
const { date, venue, status } = data;
10+
return (
11+
<div className="w-full md:px-[96px]">
12+
<div className="mb-10">
13+
<h1 className="mb-5 text-3xl font-semibold text-gray-800">Event Details</h1>
14+
<div className="grid grid-cols-2 items-center gap-2 md:w-[500px]">
15+
<p className="text-md flex items-center gap-1 text-gray-800">
16+
<BsCalendar3 /> Date
17+
</p>
18+
<p className="text-md text-gray-800">{date}</p>
19+
<p className="text-md flex items-center gap-1 text-gray-800">
20+
<MdOutlineLocationCity /> Venue
21+
</p>
22+
<p className="text-md text-gray-800">{venue}</p>
23+
<p className="text-md flex items-center gap-1 text-gray-800">
24+
<MdOutlineUpcoming /> Status
25+
</p>
26+
{status === 'Scheduled' ? (
27+
<span className="w-fit rounded-full bg-green-500 px-3 py-1 text-xs font-bold text-white">Upcoming</span>
28+
) : (
29+
<span className="w-fit rounded-full bg-gray-400 px-3 py-1 text-xs font-bold text-white">Passed</span>
30+
)}
31+
</div>
32+
</div>
33+
</div>
34+
);
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use client'; // TODO: removing this throws an error. why?
2+
3+
import { ExtendedRecordMap } from 'notion-types';
4+
import { NotionRenderer } from 'react-notion-x';
5+
import Link from 'next/link';
6+
import Image from 'next/image';
7+
8+
export default function NotionRendererClient({ recordMap }: { recordMap: ExtendedRecordMap }) {
9+
return (
10+
<NotionRenderer
11+
recordMap={recordMap}
12+
// fullPage={true}
13+
// darkMode={false}
14+
components={{
15+
nextImage: Image,
16+
nextLink: Link,
17+
Collection: () => <></>,
18+
}}
19+
/>
20+
);
21+
}

0 commit comments

Comments
 (0)