@djangocfg/nextjs 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -115
- package/package.json +26 -34
- package/src/config/base-next-config.ts +68 -0
- package/src/contact/submit.ts +26 -13
- package/src/index.ts +0 -9
- package/src/scripts/check-links.ts +477 -0
- package/src/scripts/index.ts +6 -0
- package/src/components/HomePage.tsx +0 -73
- package/src/components/index.ts +0 -7
- package/src/errors/ErrorLayout.tsx +0 -228
- package/src/errors/errorConfig.ts +0 -118
- package/src/errors/index.ts +0 -10
- package/src/legal/LegalPage.tsx +0 -85
- package/src/legal/configs.ts +0 -131
- package/src/legal/index.ts +0 -24
- package/src/legal/pages.tsx +0 -58
- package/src/legal/types.ts +0 -15
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @djangocfg/nextjs
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Server-side Next.js utilities: sitemap generation, health checks, OG images, contact forms, navigation, and config
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@djangocfg/nextjs)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
## Overview
|
|
13
13
|
|
|
14
|
-
`@djangocfg/nextjs` provides
|
|
14
|
+
`@djangocfg/nextjs` provides server-side utilities for Next.js applications. This package focuses on server-only functionality: SEO optimization with sitemaps, health monitoring, dynamic OG images, contact form handling, navigation utilities, and configuration management.
|
|
15
|
+
|
|
16
|
+
> **Note:** Client components (legal pages, error pages, redirect components) have been moved to `@djangocfg/layouts` to keep this package server-only.
|
|
15
17
|
|
|
16
18
|
## Features
|
|
17
19
|
|
|
@@ -19,12 +21,10 @@
|
|
|
19
21
|
- **Sitemap Generation** - Dynamic XML sitemap generation for SEO
|
|
20
22
|
- **Health Checks** - Production-ready health monitoring endpoints
|
|
21
23
|
- **OG Images** - Dynamic Open Graph image generation with templates
|
|
24
|
+
- **Contact Forms** - Server-side contact form submission handlers
|
|
22
25
|
- **Navigation Utilities** - Route definitions, menu generation, and navigation helpers
|
|
23
|
-
- **Legal Pages** - Pre-built privacy, terms, cookies, and security pages
|
|
24
|
-
- **Error Pages** - Reusable 404 and 500 error layouts
|
|
25
|
-
- **HomePage Component** - Smart authentication redirect component
|
|
26
26
|
- **TypeScript** - Full type safety throughout
|
|
27
|
-
- **
|
|
27
|
+
- **Server-Only** - No client-side code, pure server utilities
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
@@ -147,77 +147,55 @@ Automatically add OG images to page metadata:
|
|
|
147
147
|
|
|
148
148
|
```tsx
|
|
149
149
|
// app/page.tsx
|
|
150
|
-
import {
|
|
150
|
+
import { generateOgImageMetadata } from '@djangocfg/nextjs/og-image/utils';
|
|
151
151
|
|
|
152
|
-
export const metadata =
|
|
152
|
+
export const metadata = generateOgImageMetadata({
|
|
153
153
|
title: 'My Page',
|
|
154
154
|
description: 'Page description',
|
|
155
155
|
});
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
###
|
|
158
|
+
### Contact Form
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
Create a contact form API route:
|
|
161
161
|
|
|
162
162
|
```tsx
|
|
163
|
-
// app/
|
|
164
|
-
import {
|
|
163
|
+
// app/api/contact/route.ts
|
|
164
|
+
import { createContactRoute } from '@djangocfg/nextjs/contact';
|
|
165
165
|
|
|
166
|
-
export
|
|
166
|
+
export const POST = createContactRoute();
|
|
167
167
|
```
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
- `PrivacyPage` - Privacy policy
|
|
171
|
-
- `TermsPage` - Terms of service
|
|
172
|
-
- `CookiesPage` - Cookie policy
|
|
173
|
-
- `SecurityPage` - Security policy
|
|
174
|
-
|
|
175
|
-
### Error Pages
|
|
176
|
-
|
|
177
|
-
Use reusable error layouts:
|
|
169
|
+
The route handler accepts form data and submits it to your API endpoint. The `apiUrl` can be passed in the request body or configured via environment variables.
|
|
178
170
|
|
|
179
|
-
|
|
180
|
-
// app/not-found.tsx
|
|
181
|
-
import { ErrorLayout } from '@djangocfg/nextjs/errors';
|
|
171
|
+
### Navigation Utilities
|
|
182
172
|
|
|
183
|
-
|
|
184
|
-
return <ErrorLayout code={404} supportEmail="support@example.com" />;
|
|
185
|
-
}
|
|
186
|
-
```
|
|
173
|
+
Define routes and generate navigation menus:
|
|
187
174
|
|
|
188
175
|
```tsx
|
|
189
|
-
|
|
190
|
-
'use client';
|
|
176
|
+
import { defineRoute, routesToMenuItems } from '@djangocfg/nextjs/navigation';
|
|
191
177
|
|
|
192
|
-
|
|
193
|
-
|
|
178
|
+
const routes = [
|
|
179
|
+
defineRoute('/dashboard', { title: 'Dashboard' }),
|
|
180
|
+
defineRoute('/settings', { title: 'Settings' }),
|
|
181
|
+
];
|
|
194
182
|
|
|
195
|
-
|
|
196
|
-
useEffect(() => {
|
|
197
|
-
console.error('Error:', error);
|
|
198
|
-
}, [error]);
|
|
199
|
-
|
|
200
|
-
return <ErrorLayout code={500} supportEmail="support@example.com" />;
|
|
201
|
-
}
|
|
183
|
+
const menuItems = routesToMenuItems(routes);
|
|
202
184
|
```
|
|
203
185
|
|
|
204
|
-
###
|
|
186
|
+
### Client Components
|
|
205
187
|
|
|
206
|
-
|
|
188
|
+
Client-side components (legal pages, error pages, redirect components) are available in `@djangocfg/layouts`:
|
|
207
189
|
|
|
208
190
|
```tsx
|
|
209
|
-
//
|
|
210
|
-
import {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
loadingText="Loading..."
|
|
218
|
-
/>
|
|
219
|
-
);
|
|
220
|
-
}
|
|
191
|
+
// Legal pages
|
|
192
|
+
import { PrivacyPage, TermsPage } from '@djangocfg/layouts/pages/legal';
|
|
193
|
+
|
|
194
|
+
// Error pages
|
|
195
|
+
import { ErrorLayout } from '@djangocfg/layouts/components/errors';
|
|
196
|
+
|
|
197
|
+
// Redirect component
|
|
198
|
+
import { RedirectPage } from '@djangocfg/layouts/components/RedirectPage';
|
|
221
199
|
```
|
|
222
200
|
|
|
223
201
|
## Exports
|
|
@@ -230,10 +208,10 @@ export default function Page() {
|
|
|
230
208
|
| `@djangocfg/nextjs/health` | Health check handlers |
|
|
231
209
|
| `@djangocfg/nextjs/og-image` | OG image generation |
|
|
232
210
|
| `@djangocfg/nextjs/og-image/utils` | OG image URL and metadata utilities |
|
|
211
|
+
| `@djangocfg/nextjs/og-image/components` | OG image template components |
|
|
212
|
+
| `@djangocfg/nextjs/contact` | Contact form route handlers |
|
|
233
213
|
| `@djangocfg/nextjs/navigation` | Route definitions, menu generation, navigation helpers |
|
|
234
|
-
| `@djangocfg/nextjs/
|
|
235
|
-
| `@djangocfg/nextjs/errors` | Error page layouts |
|
|
236
|
-
| `@djangocfg/nextjs/components` | Reusable components |
|
|
214
|
+
| `@djangocfg/nextjs/scripts` | Utility scripts (e.g., link checking) |
|
|
237
215
|
|
|
238
216
|
## API Reference
|
|
239
217
|
|
|
@@ -326,17 +304,35 @@ generateOgImageMetadata(
|
|
|
326
304
|
|
|
327
305
|
#### `generateOgImageUrl(baseUrl, params, useBase64?)`
|
|
328
306
|
|
|
329
|
-
|
|
307
|
+
> **Note:** This utility has been moved to `@djangocfg/layouts/utils/og-image` for client-side usage.
|
|
308
|
+
|
|
309
|
+
For server-side usage, you can still use it from `@djangocfg/nextjs/og-image/utils`, but for client components, import from layouts:
|
|
330
310
|
|
|
331
311
|
```tsx
|
|
332
|
-
|
|
312
|
+
// Client component
|
|
313
|
+
import { generateOgImageUrl } from '@djangocfg/layouts/utils/og-image';
|
|
314
|
+
|
|
315
|
+
const url = generateOgImageUrl('/api/og', {
|
|
333
316
|
title: 'My Page',
|
|
334
317
|
description: 'Page description',
|
|
335
318
|
siteName: 'My Site',
|
|
336
|
-
|
|
337
|
-
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Contact Form
|
|
323
|
+
|
|
324
|
+
#### `createContactRoute(options?)`
|
|
325
|
+
|
|
326
|
+
Creates a Next.js API route handler for contact form submissions.
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
createContactRoute({
|
|
330
|
+
// Options are handled via request body or environment variables
|
|
331
|
+
})
|
|
338
332
|
```
|
|
339
333
|
|
|
334
|
+
The route accepts POST requests with form data and submits to the API endpoint specified in the request body (`_apiUrl` field) or environment variables.
|
|
335
|
+
|
|
340
336
|
### Navigation
|
|
341
337
|
|
|
342
338
|
#### `defineRoute(path, metadata, config?)`
|
|
@@ -371,57 +367,6 @@ Converts route definitions to menu items.
|
|
|
371
367
|
const menuItems = routesToMenuItems(allRoutes);
|
|
372
368
|
```
|
|
373
369
|
|
|
374
|
-
### Legal Pages
|
|
375
|
-
|
|
376
|
-
#### `PrivacyPage`, `TermsPage`, `CookiesPage`, `SecurityPage`
|
|
377
|
-
|
|
378
|
-
Pre-built legal page components with default content. Can be customized:
|
|
379
|
-
|
|
380
|
-
```tsx
|
|
381
|
-
import { PrivacyPage, privacyConfig } from '@djangocfg/nextjs/legal';
|
|
382
|
-
|
|
383
|
-
// Use default
|
|
384
|
-
export default PrivacyPage;
|
|
385
|
-
|
|
386
|
-
// Or customize
|
|
387
|
-
export default function CustomPrivacy() {
|
|
388
|
-
return <PrivacyPage config={{
|
|
389
|
-
...privacyConfig,
|
|
390
|
-
lastUpdated: '2024-01-01',
|
|
391
|
-
}} />;
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
### Error Pages
|
|
396
|
-
|
|
397
|
-
#### `ErrorLayout`
|
|
398
|
-
|
|
399
|
-
Reusable error page layout component.
|
|
400
|
-
|
|
401
|
-
```tsx
|
|
402
|
-
<ErrorLayout
|
|
403
|
-
code={404 | 500 | string | number}
|
|
404
|
-
title?: string
|
|
405
|
-
description?: string
|
|
406
|
-
supportEmail?: string
|
|
407
|
-
actions?: React.ReactNode
|
|
408
|
-
showDefaultActions?: boolean
|
|
409
|
-
/>
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
### Components
|
|
413
|
-
|
|
414
|
-
#### `HomePage`
|
|
415
|
-
|
|
416
|
-
Authentication redirect component.
|
|
417
|
-
|
|
418
|
-
```tsx
|
|
419
|
-
<HomePage
|
|
420
|
-
authenticatedPath?: string // Default: '/private'
|
|
421
|
-
unauthenticatedPath?: string // Default: '/auth'
|
|
422
|
-
loadingText?: string // Default: 'Loading...'
|
|
423
|
-
/>
|
|
424
|
-
```
|
|
425
370
|
|
|
426
371
|
## Requirements
|
|
427
372
|
|
|
@@ -431,9 +376,8 @@ Authentication redirect component.
|
|
|
431
376
|
|
|
432
377
|
## Peer Dependencies
|
|
433
378
|
|
|
434
|
-
- `@djangocfg/
|
|
435
|
-
-
|
|
436
|
-
- `lucide-react` - For icons
|
|
379
|
+
- `@djangocfg/api` - For API client functionality
|
|
380
|
+
- `next` - Next.js framework (^15.4.4)
|
|
437
381
|
|
|
438
382
|
## Documentation
|
|
439
383
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/nextjs",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Next.js utilities
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"description": "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
7
7
|
"sitemap",
|
|
8
8
|
"health",
|
|
9
9
|
"og-image",
|
|
10
|
-
"
|
|
11
|
-
"
|
|
10
|
+
"contact",
|
|
11
|
+
"navigation",
|
|
12
|
+
"config",
|
|
12
13
|
"react",
|
|
13
14
|
"typescript"
|
|
14
15
|
],
|
|
@@ -59,21 +60,6 @@
|
|
|
59
60
|
"import": "./src/og-image/components/index.ts",
|
|
60
61
|
"default": "./src/og-image/components/index.ts"
|
|
61
62
|
},
|
|
62
|
-
"./legal": {
|
|
63
|
-
"types": "./src/legal/index.ts",
|
|
64
|
-
"import": "./src/legal/index.ts",
|
|
65
|
-
"default": "./src/legal/index.ts"
|
|
66
|
-
},
|
|
67
|
-
"./errors": {
|
|
68
|
-
"types": "./src/errors/index.ts",
|
|
69
|
-
"import": "./src/errors/index.ts",
|
|
70
|
-
"default": "./src/errors/index.ts"
|
|
71
|
-
},
|
|
72
|
-
"./components": {
|
|
73
|
-
"types": "./src/components/index.ts",
|
|
74
|
-
"import": "./src/components/index.ts",
|
|
75
|
-
"default": "./src/components/index.ts"
|
|
76
|
-
},
|
|
77
63
|
"./contact": {
|
|
78
64
|
"types": "./src/contact/index.ts",
|
|
79
65
|
"import": "./src/contact/index.ts",
|
|
@@ -88,6 +74,11 @@
|
|
|
88
74
|
"types": "./src/config/index.ts",
|
|
89
75
|
"import": "./src/config/index.ts",
|
|
90
76
|
"default": "./src/config/index.ts"
|
|
77
|
+
},
|
|
78
|
+
"./scripts": {
|
|
79
|
+
"types": "./src/scripts/index.ts",
|
|
80
|
+
"import": "./src/scripts/index.ts",
|
|
81
|
+
"default": "./src/scripts/index.ts"
|
|
91
82
|
}
|
|
92
83
|
},
|
|
93
84
|
"files": [
|
|
@@ -100,34 +91,35 @@
|
|
|
100
91
|
"dev": "tsup --watch",
|
|
101
92
|
"clean": "rm -rf dist",
|
|
102
93
|
"lint": "eslint .",
|
|
103
|
-
"check": "tsc --noEmit"
|
|
104
|
-
|
|
105
|
-
"dependencies": {
|
|
106
|
-
"@vercel/og": "^0.8.5"
|
|
94
|
+
"check": "tsc --noEmit",
|
|
95
|
+
"check-links": "tsx src/scripts/check-links.ts"
|
|
107
96
|
},
|
|
108
97
|
"peerDependencies": {
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"react-dom": "^19.1.0",
|
|
112
|
-
"@djangocfg/ui": "^1.4.34",
|
|
113
|
-
"@djangocfg/layouts": "^2.0.4",
|
|
114
|
-
"@djangocfg/api": "^1.4.34",
|
|
115
|
-
"lucide-react": "^0.469.0"
|
|
98
|
+
"@djangocfg/api": "^1.4.36",
|
|
99
|
+
"next": "^15.4.4"
|
|
116
100
|
},
|
|
117
101
|
"devDependencies": {
|
|
118
|
-
"@djangocfg/
|
|
119
|
-
"@djangocfg/layouts": "^2.0.
|
|
102
|
+
"@djangocfg/imgai": "^1.0.22",
|
|
103
|
+
"@djangocfg/layouts": "^2.0.6",
|
|
104
|
+
"@djangocfg/typescript-config": "^1.4.36",
|
|
120
105
|
"@types/node": "^24.7.2",
|
|
121
106
|
"@types/react": "19.2.2",
|
|
122
107
|
"@types/react-dom": "19.2.1",
|
|
123
108
|
"@types/webpack": "^5.28.5",
|
|
109
|
+
"@vercel/og": "^0.8.5",
|
|
124
110
|
"eslint": "^9.37.0",
|
|
111
|
+
"linkinator": "^7.5.0",
|
|
125
112
|
"lucide-react": "^0.469.0",
|
|
113
|
+
"picocolors": "^1.1.1",
|
|
114
|
+
"prompts": "^2.4.2",
|
|
126
115
|
"tsup": "^8.0.1",
|
|
116
|
+
"tsx": "^4.19.2",
|
|
127
117
|
"typescript": "^5.9.3"
|
|
128
118
|
},
|
|
129
119
|
"publishConfig": {
|
|
130
120
|
"access": "public"
|
|
121
|
+
},
|
|
122
|
+
"dependencies": {
|
|
123
|
+
"chalk": "^5.3.0"
|
|
131
124
|
}
|
|
132
|
-
}
|
|
133
|
-
|
|
125
|
+
}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
import type { NextConfig } from 'next';
|
|
25
25
|
import type { Configuration as WebpackConfig } from 'webpack';
|
|
26
|
+
import chalk from 'chalk';
|
|
26
27
|
import { deepMerge } from './deepMerge';
|
|
27
28
|
|
|
28
29
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -32,6 +33,25 @@ import { deepMerge } from './deepMerge';
|
|
|
32
33
|
const isStaticBuild = process.env.NEXT_PUBLIC_STATIC_BUILD === 'true';
|
|
33
34
|
const isDev = process.env.NODE_ENV === 'development';
|
|
34
35
|
|
|
36
|
+
// Global flag to track if browser was already opened (persists across hot reloads)
|
|
37
|
+
let browserOpened = false;
|
|
38
|
+
let bannerPrinted = false;
|
|
39
|
+
|
|
40
|
+
// ASCII Art Banner for Django CFG
|
|
41
|
+
const DJANGO_CFG_BANNER = `
|
|
42
|
+
888 d8b .d888
|
|
43
|
+
888 Y8P d88P"
|
|
44
|
+
888 888
|
|
45
|
+
.d88888 8888 8888b. 88888b. .d88b. .d88b. .d8888b 888888 .d88b.
|
|
46
|
+
d88" 888 "888 "88b 888 "88b d88P"88b d88""88b d88P" 888 d88P"88b
|
|
47
|
+
888 888 888 .d888888 888 888 888 888 888 888 888 888 888 888
|
|
48
|
+
Y88b 888 888 888 888 888 888 Y88b 888 Y88..88P Y88b. 888 Y88b 888
|
|
49
|
+
"Y88888 888 "Y888888 888 888 "Y88888 "Y88P" "Y8888P 888 "Y88888
|
|
50
|
+
888 888 888
|
|
51
|
+
d88P Y8b d88P Y8b d88P
|
|
52
|
+
888P" "Y88P" "Y88P"
|
|
53
|
+
`;
|
|
54
|
+
|
|
35
55
|
// ─────────────────────────────────────────────────────────────────────────
|
|
36
56
|
// Configuration Options
|
|
37
57
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -43,6 +63,8 @@ export interface BaseNextConfigOptions {
|
|
|
43
63
|
transpilePackages?: string[];
|
|
44
64
|
/** Additional optimize package imports (merged with defaults) */
|
|
45
65
|
optimizePackageImports?: string[];
|
|
66
|
+
/** Automatically open browser in dev mode (default: false) */
|
|
67
|
+
openBrowser?: boolean;
|
|
46
68
|
/** Custom webpack configuration function (called after base webpack logic) */
|
|
47
69
|
webpack?: (
|
|
48
70
|
config: WebpackConfig,
|
|
@@ -153,6 +175,50 @@ export function createBaseNextConfig(
|
|
|
153
175
|
webpack: (config: WebpackConfig, webpackOptions: { isServer: boolean; dev: boolean;[key: string]: any }) => {
|
|
154
176
|
const { isServer, dev } = webpackOptions;
|
|
155
177
|
|
|
178
|
+
// Print banner and auto-open browser in dev mode (client-side only)
|
|
179
|
+
if (dev && !isServer) {
|
|
180
|
+
// Create a simple plugin to print banner and open browser after first compilation
|
|
181
|
+
const DevStartupPlugin = class {
|
|
182
|
+
apply(compiler: any) {
|
|
183
|
+
compiler.hooks.done.tap('DevStartupPlugin', () => {
|
|
184
|
+
// Print banner only once
|
|
185
|
+
if (!bannerPrinted) {
|
|
186
|
+
bannerPrinted = true;
|
|
187
|
+
console.log('\n' + chalk.yellowBright.bold(DJANGO_CFG_BANNER) + '\n');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Auto-open browser if enabled
|
|
191
|
+
if (options.openBrowser && !browserOpened) {
|
|
192
|
+
browserOpened = true;
|
|
193
|
+
// Delay to ensure server is ready
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
const { exec } = require('child_process');
|
|
196
|
+
const port = process.env.PORT || '3000';
|
|
197
|
+
const url = `http://localhost:${port}`;
|
|
198
|
+
|
|
199
|
+
const command = process.platform === 'darwin'
|
|
200
|
+
? 'open'
|
|
201
|
+
: process.platform === 'win32'
|
|
202
|
+
? 'start'
|
|
203
|
+
: 'xdg-open';
|
|
204
|
+
|
|
205
|
+
exec(`${command} ${url}`, (error: Error | null) => {
|
|
206
|
+
if (error) {
|
|
207
|
+
console.warn(`Failed to open browser: ${error.message}`);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}, 2000); // Wait 2 seconds for server to be ready
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
if (!config.plugins) {
|
|
217
|
+
config.plugins = [];
|
|
218
|
+
}
|
|
219
|
+
config.plugins.push(new DevStartupPlugin());
|
|
220
|
+
}
|
|
221
|
+
|
|
156
222
|
// Dev mode optimizations
|
|
157
223
|
if (dev) {
|
|
158
224
|
config.optimization = {
|
|
@@ -226,6 +292,8 @@ export function createBaseNextConfig(
|
|
|
226
292
|
// Cleanup: Remove our custom options that are not part of NextConfig
|
|
227
293
|
// These are internal to BaseNextConfigOptions and should not be in the final config
|
|
228
294
|
delete (finalConfig as any).optimizePackageImports;
|
|
295
|
+
delete (finalConfig as any).isDefaultCfgAdmin;
|
|
296
|
+
delete (finalConfig as any).openBrowser;
|
|
229
297
|
// Note: We don't delete transpilePackages, experimental, env, webpack
|
|
230
298
|
// as they are valid NextConfig keys and may have been overridden by user
|
|
231
299
|
|
package/src/contact/submit.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Server-side function to submit contact form data to backend API.
|
|
5
5
|
* Can be used in Next.js API routes to avoid CORS issues.
|
|
6
6
|
*
|
|
7
|
+
* Uses Fetchers with server-side API instance for type safety and Zod validation.
|
|
8
|
+
*
|
|
7
9
|
* @example
|
|
8
10
|
* ```ts
|
|
9
11
|
* import { submitContactForm } from '@djangocfg/nextjs/contact';
|
|
@@ -17,8 +19,9 @@
|
|
|
17
19
|
* ```
|
|
18
20
|
*/
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
import
|
|
22
|
+
// Use server-only exports to avoid loading React hooks (useSWRConfig)
|
|
23
|
+
import { API, MemoryStorageAdapter, Fetchers } from '@djangocfg/api/server';
|
|
24
|
+
import type { Schemas } from '@djangocfg/api/server';
|
|
22
25
|
|
|
23
26
|
export interface SubmitContactFormOptions {
|
|
24
27
|
/** Lead submission data */
|
|
@@ -38,8 +41,8 @@ export interface SubmitContactFormResult {
|
|
|
38
41
|
/**
|
|
39
42
|
* Submit contact form data to backend API
|
|
40
43
|
*
|
|
41
|
-
* Server-side function that uses
|
|
42
|
-
*
|
|
44
|
+
* Server-side function that uses Fetchers with server-side API instance.
|
|
45
|
+
* This provides type safety, Zod validation, and proper error handling.
|
|
43
46
|
*/
|
|
44
47
|
export async function submitContactForm({
|
|
45
48
|
data,
|
|
@@ -56,7 +59,7 @@ export async function submitContactForm({
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
// Create server-side API instance with MemoryStorageAdapter
|
|
59
|
-
// This works on
|
|
62
|
+
// This works on server-side and doesn't require browser APIs
|
|
60
63
|
const serverApi = new API(apiUrl, {
|
|
61
64
|
storage: new MemoryStorageAdapter(),
|
|
62
65
|
});
|
|
@@ -67,14 +70,24 @@ export async function submitContactForm({
|
|
|
67
70
|
site_url: data.site_url || siteUrl,
|
|
68
71
|
};
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
try {
|
|
74
|
+
// Use typed fetcher with server API instance
|
|
75
|
+
// This provides type safety and runtime validation via Zod
|
|
76
|
+
// Using Fetchers namespace to avoid loading hooks
|
|
77
|
+
const result = await Fetchers.createLeadsSubmitCreate(submissionData, serverApi);
|
|
73
78
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
// Return formatted result
|
|
80
|
+
return {
|
|
81
|
+
success: result.success ?? true,
|
|
82
|
+
message: result.message || 'Contact form submitted successfully',
|
|
83
|
+
lead_id: result.lead_id,
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
// Handle API errors (including validation errors from Zod)
|
|
87
|
+
if (error instanceof Error) {
|
|
88
|
+
throw new Error(`Failed to submit contact form: ${error.message}`);
|
|
89
|
+
}
|
|
90
|
+
throw new Error('An unexpected error occurred while submitting the contact form');
|
|
91
|
+
}
|
|
79
92
|
}
|
|
80
93
|
|
package/src/index.ts
CHANGED
|
@@ -13,15 +13,6 @@ export * from './health';
|
|
|
13
13
|
// OG Image
|
|
14
14
|
export * from './og-image';
|
|
15
15
|
|
|
16
|
-
// Legal pages
|
|
17
|
-
export * from './legal';
|
|
18
|
-
|
|
19
|
-
// Error pages
|
|
20
|
-
export * from './errors';
|
|
21
|
-
|
|
22
|
-
// Components
|
|
23
|
-
export * from './components';
|
|
24
|
-
|
|
25
16
|
// Contact form
|
|
26
17
|
export * from './contact';
|
|
27
18
|
|