Skip to content

Commit c55b14e

Browse files
committed
Fix up build
1 parent 4033b64 commit c55b14e

19 files changed

+223
-120
lines changed

next.config.mjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,24 @@ const nextConfig = {
2525
],
2626
experimental: {
2727
optimizeCss: true, // Inlines critical CSS
28+
typedRoutes: true,
2829
},
30+
// These were moved from experimental to top level
31+
skipTrailingSlashRedirect: true,
32+
skipMiddlewareUrlNormalize: true,
33+
onDemandEntries: {
34+
// Don't dispose of pages in development
35+
maxInactiveAge: 1000 * 60 * 60,
36+
},
37+
// Ignore errors during static export
38+
typescript: {
39+
ignoreBuildErrors: process.env.SKIP_FAILING_PAGES === 'true',
40+
},
41+
eslint: {
42+
ignoreDuringBuilds: process.env.SKIP_FAILING_PAGES === 'true',
43+
},
44+
// Skip certain pages on build failure
45+
distDir: process.env.SKIP_FAILING_PAGES === 'true' ? '.next-skip-errors' : '.next',
2946
async redirects() {
3047
return [
3148
{

scripts/create-ai-assisted-dev-tools-comparison-pages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const generateComparisonPageContent = (tool1, tool2, existingDate) => {
1919
const proseParagraphs = generateComparison(tool1, tool2, categories);
2020

2121
return `
22-
import ComparisonPageLayout from '@/components/ComparisonPageLayout'
22+
import { ComparisonPageLayout } from '@/components/ComparisonPageLayout'
2323
import { createMetadata } from '@/utils/createMetadata'
2424
import aiAssistedDevTools from '@/images/ai-assisted-dev-tools.webp'
2525

src/app/admin/layout.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,17 @@ export default function AdminLayout({ children }: AdminLayoutProps) {
4343
const navItems = [
4444
{
4545
title: "Dashboard",
46-
href: "/admin",
46+
href: "/admin" as any,
4747
icon: LayoutDashboard
4848
},
4949
{
5050
title: "Tools",
51-
href: "/admin/tools",
51+
href: "/admin/tools" as any,
5252
icon: Wrench
5353
},
5454
{
5555
title: "Categories",
56-
href: "/admin/categories",
56+
href: "/admin/categories" as any,
5757
icon: Tags
5858
}
5959
]

src/app/admin/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ export default function AdminDashboard() {
1414
title: "Tools Management",
1515
description: "Add, edit, and remove developer tools from the database",
1616
icon: Wrench,
17-
href: "/admin/tools",
17+
href: "/admin/tools" as any,
1818
color: "from-violet-600 to-purple-600"
1919
},
2020
{
2121
title: "Categories",
2222
description: "Manage tool categories and classifications",
2323
icon: Tags,
24-
href: "/admin/categories",
24+
href: "/admin/categories" as any,
2525
color: "from-blue-600 to-cyan-600"
2626
}
2727
]

src/app/checkout/result/page.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function CheckoutResultContent() {
6969

7070
if (authStatus === 'authenticated') {
7171
const contentUrl = getContentUrlFromObject(data.content, true);
72-
setTimeout(() => router.push(contentUrl), 1000);
72+
setTimeout(() => router.push(contentUrl as any), 1000);
7373
}
7474
} catch (err) {
7575
setError(err instanceof Error ? err.message : 'An error occurred');
@@ -129,7 +129,7 @@ function CheckoutResultContent() {
129129
</p>
130130
<div className="mt-4 flex space-x-4">
131131
<button
132-
onClick={() => router.push('/login')}
132+
onClick={() => router.push('/login' as any)}
133133
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
134134
>
135135
Log in
@@ -195,7 +195,7 @@ function CheckoutResultContent() {
195195
<div className="mt-4">
196196
{authStatus === 'authenticated' ? (
197197
<Link
198-
href={contentUrl}
198+
href={contentUrl as any}
199199
className="inline-block px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
200200
>
201201
Read Now
@@ -224,7 +224,7 @@ function CheckoutResultContent() {
224224
</p>
225225
{authStatus === 'authenticated' ? (
226226
<Link
227-
href={contentUrl}
227+
href={contentUrl as any}
228228
className="inline-block px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors"
229229
>
230230
Start Learning

src/app/learn/waitinglist/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export default async function LearningHome() {
5252
className="mt-4"
5353
variant="solid"
5454
color="green"
55-
href={`/learn/about`}
55+
href={`/learn/about` as any}
5656
>
5757
Learn more
5858
</Button>

src/components/ArticleLayout.tsx

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,29 @@ export function ArticleLayout({
3636
const { data: session } = useSession()
3737
const [hasPurchased, setHasPurchased] = useState(serverHasPurchased)
3838

39+
// Ensure we have string values for required fields with proper defaults
40+
const safeSlug = metadata?.slug || '';
41+
const safeTitle = metadata?.title as string || 'Untitled';
42+
const safeType = typeof metadata?.type === 'string' ? metadata.type : 'blog';
43+
const safeDescription = metadata?.description as string || '';
44+
3945
// Add a debug log to help identify which articles are missing slugs
40-
if (!metadata.slug || metadata.slug === '') {
46+
if (!safeSlug) {
4147
// Instead of just logging an error, log more details to help debug
4248
logger.warn('ArticleLayout: metadata missing slug', {
43-
title: metadata.title,
44-
type: metadata.type,
45-
date: metadata.date
49+
title: safeTitle,
50+
type: safeType,
51+
date: metadata?.date
4652
});
4753
}
48-
49-
// Ensure we have string values for required fields
50-
const safeSlug = metadata.slug || '';
51-
const safeTitle = metadata.title as string || 'Untitled';
52-
const safeType = metadata.type || 'blog';
5354

54-
// Extract the base slug to help with matching
55-
const baseSlug = safeSlug.split('/').pop() || safeSlug;
56-
57-
// Only log debug info if DEBUG_METADATA environment variable is set
58-
// const isDebugMode = process.env.NODE_ENV === 'development' && process.env.DEBUG_METADATA === 'true';
59-
// const debugLog = (message: string) => {
60-
// if (isDebugMode) {
61-
// console.log(`[ArticleLayout] ${message}`);
62-
// }
63-
// };
55+
// Extract the base slug to help with matching - handle empty strings gracefully
56+
const baseSlug = safeSlug ? safeSlug.split('/').pop() || safeSlug : '';
6457

6558
logger.debug(`Rendering for slug: ${safeSlug}, baseSlug: ${baseSlug}`);
6659

6760
// Add more debug information about the image
68-
if (metadata.image) {
61+
if (metadata?.image) {
6962
logger.debug(`Image type: ${typeof metadata.image}`);
7063
if (typeof metadata.image === 'object' && metadata.image !== null) {
7164
logger.debug(`Image keys: ${Object.keys(metadata.image).join(',')}`);
@@ -82,8 +75,8 @@ export function ArticleLayout({
8275
// Generate the OG URL with proper slug parameter
8376
const ogUrl = generateOgUrl({
8477
title: safeTitle,
85-
description: typeof metadata.description === 'string' ? metadata.description : undefined,
86-
image: metadata.image,
78+
description: safeDescription || undefined,
79+
image: metadata?.image,
8780
slug: baseSlug as any // Force type to match expected parameter type
8881
});
8982

@@ -100,7 +93,8 @@ export function ArticleLayout({
10093
}
10194

10295
const checkPurchaseStatus = async () => {
103-
if (!metadata.commerce?.isPaid || !safeSlug) return;
96+
// Make sure both conditions are checked with null/undefined safety
97+
if (!metadata?.commerce?.isPaid || !safeSlug) return;
10498

10599
try {
106100
// If user is signed in, use their email
@@ -127,51 +121,55 @@ export function ArticleLayout({
127121
};
128122

129123
checkPurchaseStatus();
130-
}, [session, safeSlug, metadata.commerce?.isPaid, serverHasPurchased]);
124+
}, [session, safeSlug, metadata?.commerce?.isPaid, serverHasPurchased]);
131125

132-
// Determine if we should show the mini paywall
126+
// Determine if we should show the mini paywall - add null checks for all properties
133127
const shouldShowMiniPaywall =
134-
metadata.commerce?.isPaid &&
135-
!metadata.hideMiniPaywall &&
128+
metadata?.commerce?.isPaid &&
129+
!metadata?.hideMiniPaywall &&
136130
!hasPurchased &&
137-
(metadata.miniPaywallTitle || metadata.commerce.miniPaywallTitle) &&
138-
(metadata.miniPaywallDescription || metadata.commerce?.miniPaywallDescription);
131+
(metadata?.miniPaywallTitle || metadata?.commerce?.miniPaywallTitle) &&
132+
(metadata?.miniPaywallDescription || metadata?.commerce?.miniPaywallDescription);
139133

140134
// Build the full URL for og:url and twitter:url
141135
let rootPath = '/blog/';
136+
137+
// Use a more flexible approach to determine the root path
142138
if (safeType === 'video') {
143139
rootPath = '/videos/';
144140
} else if (safeType === 'course') {
145141
rootPath = '/learn/courses/';
142+
} else if (typeof safeType === 'string' && safeType.includes('comparison') || safeSlug.includes('comparisons/')) {
143+
rootPath = '/comparisons/';
146144
}
147145

148-
const fullUrl = `${process.env.NEXT_PUBLIC_SITE_URL}${rootPath}${safeSlug}`;
146+
const fullUrl = `${process.env.NEXT_PUBLIC_SITE_URL || ''}${rootPath}${safeSlug}`;
149147

150148
return (
151149
<>
152150
<Head>
153151
<title>{`${safeTitle} - Zachary Proser`}</title>
154-
<meta name="description" content={metadata.description as string} />
152+
<meta name="description" content={safeDescription} />
155153

156154
{/* Open Graph tags */}
157155
<meta property="og:title" content={safeTitle} />
158-
<meta property="og:description" content={metadata.description as string} />
156+
<meta property="og:description" content={safeDescription} />
159157
<meta property="og:url" content={fullUrl} />
160158
<meta property="og:type" content="article" />
161159
<meta property="og:image" content={ogUrl} />
162160

163161
{/* Twitter card tags */}
164162
<meta name="twitter:card" content="summary_large_image" />
165163
<meta name="twitter:title" content={safeTitle} />
166-
<meta name="twitter:description" content={metadata.description as string} />
164+
<meta name="twitter:description" content={safeDescription} />
167165
<meta name="twitter:image" content={ogUrl} />
168166
<meta name="twitter:domain" content="zackproser.com" />
169167
</Head>
170168

171169
<Container className="mt-16 lg:mt-32">
172170
<div className="xl:relative">
173171
<div className="mx-auto max-w-2xl">
174-
{shouldShowMiniPaywall && (
172+
{shouldShowMiniPaywall && metadata && (
175173
<MiniPaywall
176174
content={metadata as Content}
177175
/>
@@ -182,11 +180,11 @@ export function ArticleLayout({
182180
{safeTitle}
183181
</h1>
184182
<time
185-
dateTime={metadata.date}
183+
dateTime={metadata?.date}
186184
className="order-first flex items-center text-base text-gray-500 dark:text-gray-400"
187185
>
188186
<span className="h-4 w-0.5 rounded-full bg-blue-200 dark:bg-blue-700" />
189-
<span className="ml-3">{metadata.date}</span>
187+
<span className="ml-3">{metadata?.date}</span>
190188
</time>
191189
</header>
192190

0 commit comments

Comments
 (0)