@djangocfg/layouts 1.4.30 → 2.0.1

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.
Files changed (119) hide show
  1. package/README.md +277 -18
  2. package/package.json +15 -24
  3. package/src/auth/context/AuthContext.tsx +5 -5
  4. package/src/auth/hooks/useAuthGuard.ts +1 -1
  5. package/src/auth/hooks/useAutoAuth.ts +8 -7
  6. package/src/components/ErrorBoundary.tsx +78 -0
  7. package/src/components/JsonLd.tsx +31 -0
  8. package/src/components/LucideIcon.tsx +91 -0
  9. package/src/components/PageProgress.tsx +127 -0
  10. package/src/components/Suspense.tsx +29 -0
  11. package/src/{layouts/AppLayout/components → components}/UpdateNotifier/UpdateNotifier.tsx +56 -49
  12. package/src/components/index.ts +10 -0
  13. package/src/index.ts +25 -7
  14. package/src/layouts/AdminLayout/AdminLayout.tsx +46 -0
  15. package/src/layouts/AdminLayout/index.ts +7 -0
  16. package/src/layouts/AppLayout/AppLayout.tsx +278 -326
  17. package/src/layouts/AppLayout/index.ts +2 -39
  18. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthContext.tsx +3 -2
  19. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthHelp.tsx +1 -0
  20. package/src/layouts/AuthLayout/AuthLayout.tsx +61 -0
  21. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/IdentifierForm.tsx +47 -34
  22. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/OTPForm.tsx +2 -3
  23. package/src/layouts/AuthLayout/index.ts +24 -0
  24. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/types.ts +1 -0
  25. package/src/layouts/PrivateLayout/PrivateLayout.tsx +144 -0
  26. package/src/layouts/PrivateLayout/components/PrivateContent.tsx +32 -0
  27. package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +57 -0
  28. package/src/layouts/PrivateLayout/components/PrivateSidebar.tsx +141 -0
  29. package/src/layouts/PrivateLayout/components/index.ts +8 -0
  30. package/src/layouts/PrivateLayout/index.ts +7 -0
  31. package/src/layouts/ProfileLayout/ProfileLayout.tsx +15 -7
  32. package/src/layouts/PublicLayout/PublicLayout.tsx +121 -0
  33. package/src/layouts/PublicLayout/components/PublicFooter.tsx +190 -0
  34. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +117 -0
  35. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +101 -0
  36. package/src/layouts/PublicLayout/components/index.ts +8 -0
  37. package/src/layouts/PublicLayout/index.ts +7 -0
  38. package/src/layouts/_components/UserMenu.tsx +160 -0
  39. package/src/layouts/_components/index.ts +7 -0
  40. package/src/layouts/index.ts +15 -8
  41. package/src/snippets/Analytics/AnalyticsProvider.tsx +8 -4
  42. package/src/snippets/Analytics/useAnalytics.ts +11 -21
  43. package/src/snippets/Chat/ChatWidget.tsx +4 -4
  44. package/src/snippets/ContactForm/ContactFormProvider.tsx +32 -19
  45. package/src/snippets/ContactForm/ContactPage.tsx +2 -4
  46. package/src/snippets/ContactForm/types.ts +3 -2
  47. package/src/snippets/index.ts +0 -1
  48. package/src/layouts/AppLayout/README.md +0 -204
  49. package/src/layouts/AppLayout/SUMMARY.md +0 -240
  50. package/src/layouts/AppLayout/USAGE.md +0 -312
  51. package/src/layouts/AppLayout/components/ErrorBoundary.tsx +0 -112
  52. package/src/layouts/AppLayout/components/PageProgress.tsx +0 -123
  53. package/src/layouts/AppLayout/components/Seo.tsx +0 -171
  54. package/src/layouts/AppLayout/components/UserMenu.tsx +0 -385
  55. package/src/layouts/AppLayout/components/index.ts +0 -11
  56. package/src/layouts/AppLayout/context/AppContext.tsx +0 -151
  57. package/src/layouts/AppLayout/context/index.ts +0 -5
  58. package/src/layouts/AppLayout/hooks/index.ts +0 -8
  59. package/src/layouts/AppLayout/hooks/useLayoutMode.ts +0 -26
  60. package/src/layouts/AppLayout/hooks/useNavigation.ts +0 -51
  61. package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +0 -224
  62. package/src/layouts/AppLayout/layouts/AdminLayout/README.md +0 -409
  63. package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.example.tsx +0 -98
  64. package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.tsx +0 -149
  65. package/src/layouts/AppLayout/layouts/AdminLayout/components/ParentSync.tsx +0 -146
  66. package/src/layouts/AppLayout/layouts/AdminLayout/components/index.ts +0 -3
  67. package/src/layouts/AppLayout/layouts/AdminLayout/context/CfgAppContext.tsx +0 -48
  68. package/src/layouts/AppLayout/layouts/AdminLayout/context/index.ts +0 -2
  69. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/index.ts +0 -6
  70. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/useApp.ts +0 -279
  71. package/src/layouts/AppLayout/layouts/AdminLayout/index.ts +0 -24
  72. package/src/layouts/AppLayout/layouts/AdminLayout/lottie/energizing.json +0 -1
  73. package/src/layouts/AppLayout/layouts/AdminLayout/types/index.ts +0 -45
  74. package/src/layouts/AppLayout/layouts/AuthLayout/AuthLayout.tsx +0 -41
  75. package/src/layouts/AppLayout/layouts/AuthLayout/index.ts +0 -15
  76. package/src/layouts/AppLayout/layouts/PrivateLayout/PrivateLayout.tsx +0 -82
  77. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardContent.tsx +0 -62
  78. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardHeader.tsx +0 -89
  79. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +0 -181
  80. package/src/layouts/AppLayout/layouts/PrivateLayout/components/index.ts +0 -9
  81. package/src/layouts/AppLayout/layouts/PrivateLayout/index.ts +0 -5
  82. package/src/layouts/AppLayout/layouts/PublicLayout/PublicLayout.tsx +0 -44
  83. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +0 -242
  84. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileDrawer.tsx +0 -150
  85. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +0 -169
  86. package/src/layouts/AppLayout/layouts/PublicLayout/index.ts +0 -5
  87. package/src/layouts/AppLayout/layouts/index.ts +0 -7
  88. package/src/layouts/AppLayout/providers/CoreProviders.tsx +0 -80
  89. package/src/layouts/AppLayout/providers/index.ts +0 -5
  90. package/src/layouts/AppLayout/types/config.ts +0 -79
  91. package/src/layouts/AppLayout/types/index.ts +0 -11
  92. package/src/layouts/AppLayout/types/layout.ts +0 -54
  93. package/src/layouts/AppLayout/types/navigation.ts +0 -43
  94. package/src/layouts/AppLayout/types/page.ts +0 -80
  95. package/src/layouts/AppLayout/types/routes.ts +0 -43
  96. package/src/layouts/AppLayout/utils/index.ts +0 -5
  97. package/src/layouts/AppLayout/utils/routeDetection.ts +0 -31
  98. package/src/layouts/ErrorLayout/ErrorLayout.tsx +0 -173
  99. package/src/layouts/ErrorLayout/errorConfig.tsx +0 -152
  100. package/src/layouts/ErrorLayout/index.ts +0 -8
  101. package/src/layouts/SimpleLayout/SimpleLayout.tsx +0 -72
  102. package/src/layouts/SimpleLayout/index.ts +0 -3
  103. package/src/snippets/VideoPlayer/README.md +0 -238
  104. package/src/snippets/VideoPlayer/VideoControls.tsx +0 -137
  105. package/src/snippets/VideoPlayer/VideoPlayer.tsx +0 -248
  106. package/src/snippets/VideoPlayer/index.ts +0 -8
  107. package/src/snippets/VideoPlayer/types.ts +0 -61
  108. package/src/types/index.ts +0 -2
  109. package/src/types/pageConfig.ts +0 -100
  110. /package/src/{validation → components/ErrorsTracker}/README.md +0 -0
  111. /package/src/{validation → components/ErrorsTracker}/components/ErrorButtons.tsx +0 -0
  112. /package/src/{validation → components/ErrorsTracker}/components/ErrorToast.tsx +0 -0
  113. /package/src/{validation → components/ErrorsTracker}/hooks.ts +0 -0
  114. /package/src/{validation → components/ErrorsTracker}/index.ts +0 -0
  115. /package/src/{validation → components/ErrorsTracker}/providers/ErrorTrackingProvider.tsx +0 -0
  116. /package/src/{validation → components/ErrorsTracker}/types.ts +0 -0
  117. /package/src/{validation → components/ErrorsTracker}/utils/curl-generator.ts +0 -0
  118. /package/src/{validation → components/ErrorsTracker}/utils/formatters.ts +0 -0
  119. /package/src/{layouts/AppLayout/components → components}/UpdateNotifier/index.ts +0 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @djangocfg/layouts
2
2
 
3
- Pre-built layouts, auth, analytics, and snippets for Next.js + Tailwind CSS.
3
+ Simple, straightforward layout components for Next.js - import and use with props.
4
4
 
5
5
  **Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
6
6
 
@@ -12,23 +12,67 @@ pnpm add @djangocfg/layouts
12
12
 
13
13
  ## Layouts
14
14
 
15
- ```tsx
16
- import { AppLayout } from '@djangocfg/layouts/layouts';
15
+ Simple, props-based layout components. No complex configs needed!
16
+
17
+ ### Basic Layouts
17
18
 
18
- <AppLayout config={config}>{children}</AppLayout>
19
+ ```tsx
20
+ import { PublicLayout, PrivateLayout, AuthLayout } from '@djangocfg/layouts';
21
+
22
+ // Public page
23
+ <PublicLayout
24
+ logo="/logo.svg"
25
+ siteName="My App"
26
+ navigation={navItems}
27
+ >
28
+ {children}
29
+ </PublicLayout>
30
+
31
+ // Private page
32
+ <PrivateLayout
33
+ sidebar={{ items: menuItems }}
34
+ header={{ title: 'Dashboard' }}
35
+ >
36
+ {children}
37
+ </PrivateLayout>
38
+
39
+ // Auth page
40
+ <AuthLayout
41
+ logo="/logo.svg"
42
+ title="Sign In"
43
+ subtitle="Welcome back"
44
+ >
45
+ <LoginForm />
46
+ </AuthLayout>
19
47
  ```
20
48
 
21
49
  | Layout | Description |
22
50
  |--------|-------------|
23
- | `AppLayout` | Main app shell with sidebar, header, footer |
51
+ | `PublicLayout` | Public pages (home, docs, contact, legal) |
52
+ | `PrivateLayout` | Authenticated user pages (dashboard, profile) |
53
+ | `AuthLayout` | Authentication pages (login, signup, password reset) |
54
+ | `AdminLayout` | Admin panel layout |
55
+ | `AppLayout` | Smart layout router with config-based setup |
24
56
  | `ProfileLayout` | User profile pages |
25
- | `SupportLayout` | Support/help pages |
26
- | `PaymentsLayout` | Payment flows |
27
- | `UILayout` | UI showcase |
28
- | `ErrorLayout` | Error pages (404, 500) |
57
+ | `SupportLayout` | Support/help pages with ticket system |
58
+ | `PaymentsLayout` | Payment flows and billing |
59
+
60
+ ### AppLayout
61
+
62
+ Smart layout component that automatically selects the right layout based on config:
63
+
64
+ ```tsx
65
+ import { AppLayout } from '@djangocfg/layouts';
66
+
67
+ <AppLayout config={appLayoutConfig}>
68
+ {children}
69
+ </AppLayout>
70
+ ```
29
71
 
30
72
  ## Auth
31
73
 
74
+ Complete authentication system with context, hooks, and middleware.
75
+
32
76
  ```tsx
33
77
  import { AuthProvider, useAuth } from '@djangocfg/layouts/auth';
34
78
  import { AuthDialog } from '@djangocfg/layouts/snippets';
@@ -43,8 +87,28 @@ import { AuthDialog } from '@djangocfg/layouts/snippets';
43
87
  | `AuthProvider` | Auth context provider |
44
88
  | `useAuth` | Auth hook (user, login, logout) |
45
89
  | `useAuthGuard` | Route protection hook |
90
+ | `useAuthRedirect` | Redirect hook for auth flows |
91
+ | `useAutoAuth` | Auto-authentication hook |
46
92
  | `authMiddleware` | Next.js middleware |
47
93
 
94
+ ### Auth Context
95
+
96
+ ```tsx
97
+ import { AccountsProvider, useAccountsContext } from '@djangocfg/layouts/auth/context';
98
+ ```
99
+
100
+ ### Auth Hooks
101
+
102
+ ```tsx
103
+ import {
104
+ useAuthForm,
105
+ useAuthGuard,
106
+ useAuthRedirect,
107
+ useAutoAuth,
108
+ useProfileCache
109
+ } from '@djangocfg/layouts/auth/hooks';
110
+ ```
111
+
48
112
  ## Analytics
49
113
 
50
114
  Google Analytics integration via `react-ga4`. Auto-tracks pageviews and user sessions.
@@ -102,24 +166,52 @@ Built-in tracking for:
102
166
 
103
167
  ## Snippets
104
168
 
169
+ Reusable UI components ready to use.
170
+
105
171
  ```tsx
106
- import { ContactPage, VideoPlayer, Breadcrumbs } from '@djangocfg/layouts/snippets';
172
+ import {
173
+ Breadcrumbs,
174
+ AuthDialog,
175
+ ContactForm,
176
+ ContactPage,
177
+ KnowledgeChat,
178
+ ChatWidget
179
+ } from '@djangocfg/layouts/snippets';
107
180
  ```
108
181
 
109
182
  | Snippet | Description |
110
183
  |---------|-------------|
111
- | `ContactPage` | Ready-to-use contact page with form |
112
- | `ContactForm` | Contact form with API integration |
113
- | `ContactInfo` | Contact details card |
114
- | `AuthDialog` | Auth modal (login/register) |
115
- | `VideoPlayer` | Vidstack video player |
116
- | `Breadcrumbs` | Navigation breadcrumbs |
117
- | `Chat` | Chat widget |
184
+ | `Breadcrumbs` | Navigation breadcrumbs with automatic path generation |
185
+ | `AuthDialog` | Auth modal (login/register) with event-based triggers |
186
+ | `ContactForm` | Contact form with API integration and validation |
187
+ | `ContactPage` | Complete contact page with form and info cards |
188
+ | `ContactInfo` | Contact details card component |
189
+ | `KnowledgeChat` | AI-powered chat widget with knowledge base |
190
+ | `ChatWidget` | Chat widget component |
118
191
  | `AnalyticsProvider` | Analytics wrapper component |
119
192
 
193
+ ### Breadcrumbs
194
+
195
+ ```tsx
196
+ import Breadcrumbs from '@djangocfg/layouts/snippets';
197
+
198
+ // Auto-generate from current path
199
+ <Breadcrumbs />
200
+
201
+ // Or provide custom items
202
+ <Breadcrumbs
203
+ items={[
204
+ { path: '/', label: 'Home', isActive: false },
205
+ { path: '/products', label: 'Products', isActive: true },
206
+ ]}
207
+ />
208
+ ```
209
+
120
210
  ### ContactPage
121
211
 
122
212
  ```tsx
213
+ import { ContactPage } from '@djangocfg/layouts/snippets';
214
+
123
215
  // Minimal - all defaults configured
124
216
  <ContactPage />
125
217
 
@@ -135,13 +227,75 @@ import { ContactPage, VideoPlayer, Breadcrumbs } from '@djangocfg/layouts/snippe
135
227
  - localStorage draft saving
136
228
  - Success state with icon
137
229
  - Zod validation from `@djangocfg/api`
230
+ - Contact info cards (Email, WhatsApp, Location)
231
+ - Optional Calendly integration
232
+
233
+ ### AuthDialog
234
+
235
+ ```tsx
236
+ import { AuthDialog, openAuthDialog } from '@djangocfg/layouts/snippets';
237
+
238
+ // Add to layout
239
+ <AuthDialog authPath="/auth" />
240
+
241
+ // Trigger from anywhere
242
+ openAuthDialog({ message: 'Sign in to continue' });
243
+ ```
244
+
245
+ ### Chat Widget
246
+
247
+ ```tsx
248
+ import { ChatWidget, ChatUIProvider, useChatUI } from '@djangocfg/layouts/snippets';
249
+
250
+ <ChatUIProvider>
251
+ <ChatWidget />
252
+ </ChatUIProvider>
253
+ ```
254
+
255
+ ## Components
256
+
257
+ Utility components for common use cases.
258
+
259
+ ```tsx
260
+ import {
261
+ ErrorBoundary,
262
+ PageProgress,
263
+ JsonLd,
264
+ LucideIcon
265
+ } from '@djangocfg/layouts/components';
266
+ ```
267
+
268
+ | Component | Description |
269
+ |-----------|-------------|
270
+ | `ErrorBoundary` | React error boundary component |
271
+ | `PageProgress` | Page loading progress indicator |
272
+ | `JsonLd` | JSON-LD structured data component |
273
+ | `LucideIcon` | Lucide icon wrapper component |
138
274
 
139
275
  ## Validation
140
276
 
141
277
  Error tracking and validation utilities.
142
278
 
143
279
  ```tsx
144
- import { ValidationErrorConfig, CORSErrorConfig, NetworkErrorConfig } from '@djangocfg/layouts';
280
+ import {
281
+ ErrorTrackingProvider,
282
+ useErrors,
283
+ ErrorButtons,
284
+ ErrorToast
285
+ } from '@djangocfg/layouts/validation';
286
+ ```
287
+
288
+ ### Error Tracking
289
+
290
+ ```tsx
291
+ import { ErrorTrackingProvider, useErrors } from '@djangocfg/layouts/validation';
292
+
293
+ <ErrorTrackingProvider>
294
+ <YourApp />
295
+ </ErrorTrackingProvider>
296
+
297
+ // In components
298
+ const { addError, clearErrors, errors } = useErrors();
145
299
  ```
146
300
 
147
301
  ## Exports
@@ -151,10 +305,15 @@ import { ValidationErrorConfig, CORSErrorConfig, NetworkErrorConfig } from '@dja
151
305
  | `@djangocfg/layouts` | Main exports (all modules) |
152
306
  | `@djangocfg/layouts/layouts` | Layout components |
153
307
  | `@djangocfg/layouts/auth` | Auth context & hooks |
308
+ | `@djangocfg/layouts/auth/context` | Auth context only |
309
+ | `@djangocfg/layouts/auth/hooks` | Auth hooks only |
154
310
  | `@djangocfg/layouts/snippets` | Reusable components + Analytics |
311
+ | `@djangocfg/layouts/components` | Utility components |
312
+ | `@djangocfg/layouts/validation` | Validation & error tracking |
155
313
  | `@djangocfg/layouts/utils` | Utilities |
156
314
  | `@djangocfg/layouts/types` | TypeScript types |
157
315
  | `@djangocfg/layouts/styles` | CSS |
316
+ | `@djangocfg/layouts/styles/dashboard` | Dashboard-specific CSS |
158
317
 
159
318
  ## Requirements
160
319
 
@@ -162,3 +321,103 @@ import { ValidationErrorConfig, CORSErrorConfig, NetworkErrorConfig } from '@dja
162
321
  - React >= 19
163
322
  - Tailwind CSS >= 4
164
323
  - react-ga4 (bundled)
324
+ - @djangocfg/ui (peer dependency)
325
+ - @djangocfg/api (peer dependency)
326
+
327
+ ## Philosophy
328
+
329
+ This package follows a **simple, props-based approach**:
330
+
331
+ - ✅ **No complex configs** - just pass props
332
+ - ✅ **Type-safe** - full TypeScript support
333
+ - ✅ **Flexible** - compose layouts as needed
334
+ - ✅ **Production-ready** - built for real apps
335
+
336
+ ## Examples
337
+
338
+ ### Complete App Setup
339
+
340
+ ```tsx
341
+ // app/layout.tsx
342
+ import { AppLayout } from '@djangocfg/layouts';
343
+ import { appLayoutConfig } from './_config/appLayoutConfig';
344
+
345
+ export default function RootLayout({ children }) {
346
+ return (
347
+ <AppLayout config={appLayoutConfig}>
348
+ {children}
349
+ </AppLayout>
350
+ );
351
+ }
352
+ ```
353
+
354
+ ### Public Page
355
+
356
+ ```tsx
357
+ // app/page.tsx
358
+ import { PublicLayout } from '@djangocfg/layouts';
359
+
360
+ export default function HomePage() {
361
+ return (
362
+ <PublicLayout
363
+ logo="/logo.svg"
364
+ siteName="My App"
365
+ navigation={[
366
+ { label: 'Home', href: '/' },
367
+ { label: 'Docs', href: '/docs' },
368
+ { label: 'Contact', href: '/contact' }
369
+ ]}
370
+ >
371
+ <h1>Welcome</h1>
372
+ </PublicLayout>
373
+ );
374
+ }
375
+ ```
376
+
377
+ ### Private Dashboard
378
+
379
+ ```tsx
380
+ // app/dashboard/page.tsx
381
+ import { PrivateLayout } from '@djangocfg/layouts';
382
+
383
+ export default function DashboardPage() {
384
+ return (
385
+ <PrivateLayout
386
+ sidebar={{
387
+ items: [
388
+ { label: 'Dashboard', href: '/dashboard', icon: 'LayoutDashboard' },
389
+ { label: 'Settings', href: '/settings', icon: 'Settings' }
390
+ ]
391
+ }}
392
+ header={{
393
+ title: 'Dashboard',
394
+ userMenu: { name: 'John Doe', email: 'john@example.com' }
395
+ }}
396
+ >
397
+ <h1>Dashboard</h1>
398
+ </PrivateLayout>
399
+ );
400
+ }
401
+ ```
402
+
403
+ ### Auth Page
404
+
405
+ ```tsx
406
+ // app/auth/login/page.tsx
407
+ import { AuthLayout } from '@djangocfg/layouts';
408
+ import { LoginForm } from './_components/LoginForm';
409
+
410
+ export default function LoginPage() {
411
+ return (
412
+ <AuthLayout
413
+ logo="/logo.svg"
414
+ siteName="My App"
415
+ title="Sign In"
416
+ subtitle="Welcome back! Please sign in to continue."
417
+ >
418
+ <LoginForm />
419
+ </AuthLayout>
420
+ );
421
+ }
422
+ ```
423
+
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@djangocfg/layouts",
3
- "version": "1.4.30",
4
- "description": "Pre-built dashboard layouts, authentication pages, and admin templates for Next.js applications with Tailwind CSS",
3
+ "version": "2.0.1",
4
+ "description": "Simple, straightforward layout components for Next.js - import and use with props",
5
5
  "keywords": [
6
6
  "layouts",
7
7
  "dashboard",
@@ -10,10 +10,7 @@
10
10
  "nextjs",
11
11
  "react",
12
12
  "tailwindcss",
13
- "typescript",
14
- "django",
15
- "templates",
16
- "ui-kit"
13
+ "typescript"
17
14
  ],
18
15
  "author": {
19
16
  "name": "DjangoCFG",
@@ -37,6 +34,11 @@
37
34
  "import": "./src/index.ts",
38
35
  "default": "./src/index.ts"
39
36
  },
37
+ "./layouts": {
38
+ "types": "./src/layouts/index.ts",
39
+ "import": "./src/layouts/index.ts",
40
+ "default": "./src/layouts/index.ts"
41
+ },
40
42
  "./auth": {
41
43
  "types": "./src/auth/index.ts",
42
44
  "import": "./src/auth/index.ts",
@@ -52,21 +54,11 @@
52
54
  "import": "./src/auth/hooks/index.ts",
53
55
  "default": "./src/auth/hooks/index.ts"
54
56
  },
55
- "./layouts": {
56
- "types": "./src/layouts/index.ts",
57
- "import": "./src/layouts/index.ts",
58
- "default": "./src/layouts/index.ts"
59
- },
60
57
  "./snippets": {
61
58
  "types": "./src/snippets/index.ts",
62
59
  "import": "./src/snippets/index.ts",
63
60
  "default": "./src/snippets/index.ts"
64
61
  },
65
- "./types": {
66
- "types": "./src/types/index.ts",
67
- "import": "./src/types/index.ts",
68
- "default": "./src/types/index.ts"
69
- },
70
62
  "./utils": {
71
63
  "types": "./src/utils/index.ts",
72
64
  "import": "./src/utils/index.ts",
@@ -85,9 +77,9 @@
85
77
  "check": "tsc --noEmit"
86
78
  },
87
79
  "peerDependencies": {
88
- "@djangocfg/api": "^1.4.30",
89
- "@djangocfg/og-image": "^1.4.30",
90
- "@djangocfg/ui": "^1.4.30",
80
+ "@djangocfg/api": "^1.4.31",
81
+ "@djangocfg/centrifugo": "^1.4.31",
82
+ "@djangocfg/ui": "^1.4.31",
91
83
  "@hookform/resolvers": "^5.2.0",
92
84
  "consola": "^3.4.2",
93
85
  "lucide-react": "^0.468.0",
@@ -103,13 +95,11 @@
103
95
  "zod": "^4.0.10"
104
96
  },
105
97
  "dependencies": {
106
- "@vidstack/react": "next",
107
- "media-icons": "next",
108
- "react-ga4": "^2.1.0",
109
- "vidstack": "next"
98
+ "react-ga4": "^2.1.0"
110
99
  },
111
100
  "devDependencies": {
112
- "@djangocfg/typescript-config": "^1.4.30",
101
+ "@djangocfg/centrifugo": "^1.4.31",
102
+ "@djangocfg/typescript-config": "^1.4.31",
113
103
  "@types/node": "^24.7.2",
114
104
  "@types/react": "19.2.2",
115
105
  "@types/react-dom": "19.2.1",
@@ -120,3 +110,4 @@
120
110
  "access": "public"
121
111
  }
122
112
  }
113
+
@@ -1,14 +1,14 @@
1
1
  // @ts-nocheck
2
2
  'use client';
3
3
 
4
- import { useRouter, usePathname, useSearchParams } from 'next/navigation';
4
+ import { useRouter, usePathname } from 'next/navigation';
5
5
  import React, {
6
6
  createContext, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState
7
7
  } from 'react';
8
8
 
9
9
  import { api, Enums } from '@djangocfg/api';
10
10
  import { useAccountsContext, AccountsProvider } from './AccountsContext';
11
- import { useLocalStorage } from '@djangocfg/ui/hooks';
11
+ import { useLocalStorage, useQueryParams } from '@djangocfg/ui/hooks';
12
12
  import { getCachedProfile, clearProfileCache } from '../hooks/useProfileCache';
13
13
 
14
14
  import { authLogger } from '../../utils/logger';
@@ -52,7 +52,7 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
52
52
  const [initialized, setInitialized] = useState(false);
53
53
  const router = useRouter();
54
54
  const pathname = usePathname();
55
- const searchParams = useSearchParams();
55
+ const queryParams = useQueryParams();
56
56
 
57
57
  // Use localStorage hooks for email, phone, and redirect
58
58
  const [storedEmail, setStoredEmail, clearStoredEmail] = useLocalStorage<string | null>(EMAIL_STORAGE_KEY, null);
@@ -232,7 +232,7 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
232
232
  const isAuthenticated = api.isAuthenticated();
233
233
  const authRoute = config?.routes?.auth || defaultRoutes.auth;
234
234
  const isAuthPage = pathname === authRoute;
235
- const flowParam = searchParams?.get('flow');
235
+ const flowParam = queryParams.get('flow');
236
236
 
237
237
  // Only redirect authenticated users away from auth page if they're not in a flow
238
238
  // This prevents interference with OTP verification flow
@@ -240,7 +240,7 @@ const AuthProviderInternal: React.FC<AuthProviderProps> = ({ children, config })
240
240
  const callbackUrl = config?.routes?.defaultCallback || defaultRoutes.defaultCallback;
241
241
  window.location.href = callbackUrl;
242
242
  }
243
- }, [initialized, pathname, searchParams, config?.routes]);
243
+ }, [initialized, pathname, queryParams, config?.routes]);
244
244
 
245
245
  const pushToDefaultCallbackUrl = useCallback(() => {
246
246
  const callbackUrl = config?.routes?.defaultCallback || defaultRoutes.defaultCallback;
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
 
3
- import { useRouter } from 'next/router';
3
+ import { useRouter } from 'next/navigation';
4
4
  import { useEffect } from 'react';
5
5
 
6
6
  import { useAuth } from '../context';
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { useEffect } from 'react';
4
- import { usePathname, useRouter, useSearchParams } from 'next/navigation';
4
+ import { usePathname, useRouter } from 'next/navigation';
5
+ import { useQueryParams } from '@djangocfg/ui/hooks';
5
6
  import { authLogger } from '../../utils/logger';
6
7
 
7
8
  export interface UseAutoAuthOptions {
@@ -15,17 +16,17 @@ export interface UseAutoAuthOptions {
15
16
  */
16
17
  export const useAutoAuth = (options: UseAutoAuthOptions = {}) => {
17
18
  const { onOTPDetected, cleanupUrl = true } = options;
18
- const searchParams = useSearchParams();
19
+ const queryParams = useQueryParams();
19
20
  const pathname = usePathname();
20
21
  const router = useRouter();
21
22
 
22
- const isReady = !!pathname && !!searchParams.get('otp');
23
- const hasOTP = !!(searchParams.get('otp'));
23
+ const isReady = !!pathname && !!queryParams.get('otp');
24
+ const hasOTP = !!(queryParams.get('otp'));
24
25
 
25
26
  useEffect(() => {
26
27
  if (!isReady) return;
27
28
 
28
- const queryOtp = searchParams.get('otp') as string;
29
+ const queryOtp = queryParams.get('otp') as string;
29
30
 
30
31
  // Handle OTP detection
31
32
  if (queryOtp && typeof queryOtp === 'string' && queryOtp.length === 6) {
@@ -35,11 +36,11 @@ export const useAutoAuth = (options: UseAutoAuthOptions = {}) => {
35
36
 
36
37
  // Clean up URL to remove sensitive params for security
37
38
  if (cleanupUrl && queryOtp) {
38
- const cleanQuery = Object.fromEntries(searchParams.entries());
39
+ const cleanQuery = Object.fromEntries(queryParams.entries());
39
40
  delete cleanQuery.otp;
40
41
  router.push(`${pathname}?${new URLSearchParams(cleanQuery).toString()}`);
41
42
  }
42
- }, [pathname, searchParams, onOTPDetected, cleanupUrl]);
43
+ }, [pathname, queryParams, onOTPDetected, cleanupUrl, router]);
43
44
 
44
45
  return {
45
46
  isReady,
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Simple ErrorBoundary Component
3
+ *
4
+ * Catches React errors and displays a fallback UI
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import React, { Component, ReactNode, ErrorInfo } from 'react';
10
+
11
+ interface ErrorBoundaryProps {
12
+ children: ReactNode;
13
+ supportEmail?: string;
14
+ onError?: (error: Error, errorInfo: ErrorInfo) => void;
15
+ }
16
+
17
+ interface ErrorBoundaryState {
18
+ hasError: boolean;
19
+ error: Error | null;
20
+ }
21
+
22
+ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
23
+ constructor(props: ErrorBoundaryProps) {
24
+ super(props);
25
+ this.state = { hasError: false, error: null };
26
+ }
27
+
28
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
29
+ return { hasError: true, error };
30
+ }
31
+
32
+ componentDidCatch(error: Error, errorInfo: ErrorInfo) {
33
+ // Call custom error handler if provided
34
+ if (this.props.onError) {
35
+ this.props.onError(error, errorInfo);
36
+ }
37
+
38
+ // Log to console in development
39
+ if (process.env.NODE_ENV === 'development') {
40
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
41
+ }
42
+ }
43
+
44
+ render() {
45
+ if (this.state.hasError) {
46
+ return (
47
+ <div className="flex min-h-screen items-center justify-center bg-background p-4">
48
+ <div className="max-w-md w-full space-y-4 text-center">
49
+ <h1 className="text-2xl font-bold text-foreground">Something went wrong</h1>
50
+ <p className="text-muted-foreground">
51
+ We're sorry, but something unexpected happened. Please try refreshing the page.
52
+ </p>
53
+ {this.props.supportEmail && (
54
+ <p className="text-sm text-muted-foreground">
55
+ If the problem persists, please contact{' '}
56
+ <a
57
+ href={`mailto:${this.props.supportEmail}`}
58
+ className="text-primary hover:underline"
59
+ >
60
+ {this.props.supportEmail}
61
+ </a>
62
+ </p>
63
+ )}
64
+ <button
65
+ onClick={() => window.location.reload()}
66
+ className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90"
67
+ >
68
+ Refresh Page
69
+ </button>
70
+ </div>
71
+ </div>
72
+ );
73
+ }
74
+
75
+ return this.props.children;
76
+ }
77
+ }
78
+
@@ -0,0 +1,31 @@
1
+ import React from 'react';
2
+
3
+ interface JsonLdProps {
4
+ data: Record<string, any> | Record<string, any>[];
5
+ }
6
+
7
+ /**
8
+ * JsonLd Component
9
+ *
10
+ * Renders JSON-LD structured data for SEO.
11
+ * Use this for schema.org markup (Organization, WebSite, FAQPage, etc.)
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * <JsonLd data={{
16
+ * "@context": "https://schema.org",
17
+ * "@type": "Organization",
18
+ * "name": "My Company"
19
+ * }} />
20
+ * ```
21
+ */
22
+ export function JsonLd({ data }: JsonLdProps) {
23
+ return (
24
+ <script
25
+ type="application/ld+json"
26
+ dangerouslySetInnerHTML={{
27
+ __html: JSON.stringify(data, null, 0),
28
+ }}
29
+ />
30
+ );
31
+ }