11import { ReactElement , useMemo } from "react" ;
22
3- import type { GetStaticPaths , GetStaticProps } from "next" ;
43import { useRouter } from "next/router" ;
54
65import { APP_METADATA } from "@/common/constants" ;
@@ -14,25 +13,34 @@ type SeoProps = {
1413 seoImage ?: string ;
1514} ;
1615
17- export default function CampaignPage ( props : SeoProps ) {
16+ export default function CampaignPage ( ) {
1817 const router = useRouter ( ) ;
1918 const { campaignId, tab } = router . query as { campaignId : string ; tab ?: string } ;
2019
21- const parsedCampaignId = parseInt ( campaignId ) ;
20+ const parsedCampaignId = Number . isNaN ( parseInt ( campaignId ) ) ? undefined : parseInt ( campaignId ) ;
21+
22+ const seo : SeoProps = useMemo (
23+ ( ) => ( {
24+ seoTitle : campaignId ? `Campaign ${ campaignId } | Potlock` : `Campaign | Potlock` ,
25+ seoDescription : APP_METADATA . description ,
26+ seoImage : APP_METADATA . openGraph . images . url ,
27+ } ) ,
28+ [ campaignId ] ,
29+ ) ;
2230
2331 // Determine which content to show based on tab param
2432 const content = useMemo ( ( ) => {
2533 switch ( tab ) {
2634 case "settings" :
27- return < CampaignSettings campaignId = { parsedCampaignId } /> ;
35+ return < CampaignSettings campaignId = { parsedCampaignId ?? 0 } /> ;
2836 case "leaderboard" :
2937 default :
30- return < CampaignDonorsTable campaignId = { parsedCampaignId } /> ;
38+ return < CampaignDonorsTable campaignId = { parsedCampaignId ?? 0 } /> ;
3139 }
3240 } , [ tab , parsedCampaignId ] ) ;
3341
3442 return (
35- < RootLayout title = { props . seoTitle } description = { props . seoDescription } image = { props . seoImage } >
43+ < RootLayout title = { seo . seoTitle } description = { seo . seoDescription } image = { seo . seoImage } >
3644 { content }
3745 </ RootLayout >
3846 ) ;
@@ -41,31 +49,3 @@ export default function CampaignPage(props: SeoProps) {
4149CampaignPage . getLayout = function getLayout ( page : ReactElement ) {
4250 return < CampaignLayout > { page } </ CampaignLayout > ;
4351} ;
44-
45- // Only pre-generate paths at build time - no API calls needed for ISR
46- export const getStaticPaths : GetStaticPaths = async ( ) => {
47- // Return empty paths - all campaign pages will be generated on-demand
48- // This avoids slow API calls during build and prevents timeouts
49- return {
50- paths : [ ] ,
51- fallback : "blocking" ,
52- } ;
53- } ;
54-
55- export const getStaticProps : GetStaticProps < SeoProps > = async ( { params } ) => {
56- const campaignId = params ?. campaignId as string ;
57-
58- if ( ! campaignId ) {
59- return { notFound : true } ;
60- }
61-
62- // No server-side fetch to avoid serverless timeouts; client components load data
63- return {
64- props : {
65- seoTitle : `Campaign ${ campaignId } | Potlock` ,
66- seoDescription : APP_METADATA . description ,
67- seoImage : APP_METADATA . openGraph . images . url ,
68- } ,
69- revalidate : 3600 ,
70- } ;
71- } ;
0 commit comments