@djangocfg/layouts 2.1.10 → 2.1.15

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 (107) hide show
  1. package/README.md +53 -161
  2. package/package.json +6 -6
  3. package/src/components/RedirectPage/RedirectPage.tsx +1 -1
  4. package/src/index.ts +0 -6
  5. package/src/layouts/AppLayout/AppLayout.tsx +1 -1
  6. package/src/layouts/AppLayout/BaseApp.tsx +1 -1
  7. package/src/layouts/AuthLayout/AuthContext.tsx +1 -1
  8. package/src/layouts/AuthLayout/OAuthCallback.tsx +1 -1
  9. package/src/layouts/AuthLayout/OAuthProviders.tsx +1 -1
  10. package/src/layouts/PrivateLayout/PrivateLayout.tsx +1 -1
  11. package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +1 -1
  12. package/src/layouts/ProfileLayout/ProfileLayout.tsx +2 -2
  13. package/src/layouts/ProfileLayout/components/AvatarSection.tsx +2 -2
  14. package/src/layouts/ProfileLayout/components/ProfileForm.tsx +2 -2
  15. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +1 -1
  16. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +1 -1
  17. package/src/layouts/_components/UserMenu.tsx +1 -1
  18. package/src/layouts/index.ts +0 -2
  19. package/src/snippets/Analytics/useAnalytics.ts +1 -1
  20. package/src/snippets/index.ts +0 -3
  21. package/src/auth/README.md +0 -962
  22. package/src/auth/context/AccountsContext.tsx +0 -240
  23. package/src/auth/context/AuthContext.tsx +0 -604
  24. package/src/auth/context/index.ts +0 -4
  25. package/src/auth/context/types.ts +0 -68
  26. package/src/auth/hooks/index.ts +0 -17
  27. package/src/auth/hooks/useAuthForm.ts +0 -332
  28. package/src/auth/hooks/useAuthGuard.ts +0 -25
  29. package/src/auth/hooks/useAuthRedirect.ts +0 -51
  30. package/src/auth/hooks/useAutoAuth.ts +0 -49
  31. package/src/auth/hooks/useGithubAuth.ts +0 -184
  32. package/src/auth/hooks/useLocalStorage.ts +0 -214
  33. package/src/auth/hooks/useProfileCache.ts +0 -146
  34. package/src/auth/hooks/useSessionStorage.ts +0 -189
  35. package/src/auth/index.ts +0 -10
  36. package/src/auth/middlewares/index.ts +0 -1
  37. package/src/auth/middlewares/proxy.ts +0 -32
  38. package/src/auth/server.ts +0 -6
  39. package/src/auth/utils/errors.ts +0 -34
  40. package/src/auth/utils/index.ts +0 -2
  41. package/src/auth/utils/validation.ts +0 -14
  42. package/src/contexts/LeadsContext.tsx +0 -156
  43. package/src/contexts/NewsletterContext.tsx +0 -263
  44. package/src/contexts/SupportContext.tsx +0 -256
  45. package/src/contexts/index.ts +0 -59
  46. package/src/contexts/knowbase/ChatContext.tsx +0 -174
  47. package/src/contexts/knowbase/DocumentsContext.tsx +0 -304
  48. package/src/contexts/knowbase/SessionsContext.tsx +0 -174
  49. package/src/contexts/knowbase/index.ts +0 -61
  50. package/src/contexts/payments/BalancesContext.tsx +0 -65
  51. package/src/contexts/payments/CurrenciesContext.tsx +0 -66
  52. package/src/contexts/payments/OverviewContext.tsx +0 -174
  53. package/src/contexts/payments/PaymentsContext.tsx +0 -132
  54. package/src/contexts/payments/README.md +0 -201
  55. package/src/contexts/payments/RootPaymentsContext.tsx +0 -68
  56. package/src/contexts/payments/index.ts +0 -50
  57. package/src/layouts/PaymentsLayout/PaymentsLayout.tsx +0 -92
  58. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +0 -291
  59. package/src/layouts/PaymentsLayout/components/PaymentDetailsDialog.tsx +0 -290
  60. package/src/layouts/PaymentsLayout/components/index.ts +0 -2
  61. package/src/layouts/PaymentsLayout/events.ts +0 -47
  62. package/src/layouts/PaymentsLayout/index.ts +0 -16
  63. package/src/layouts/PaymentsLayout/types.ts +0 -6
  64. package/src/layouts/PaymentsLayout/views/overview/components/BalanceCard.tsx +0 -128
  65. package/src/layouts/PaymentsLayout/views/overview/components/RecentPayments.tsx +0 -142
  66. package/src/layouts/PaymentsLayout/views/overview/components/index.ts +0 -2
  67. package/src/layouts/PaymentsLayout/views/overview/index.tsx +0 -20
  68. package/src/layouts/PaymentsLayout/views/payments/components/PaymentsList.tsx +0 -276
  69. package/src/layouts/PaymentsLayout/views/payments/components/index.ts +0 -1
  70. package/src/layouts/PaymentsLayout/views/payments/index.tsx +0 -17
  71. package/src/layouts/PaymentsLayout/views/transactions/components/TransactionsList.tsx +0 -273
  72. package/src/layouts/PaymentsLayout/views/transactions/components/index.ts +0 -1
  73. package/src/layouts/PaymentsLayout/views/transactions/index.tsx +0 -17
  74. package/src/layouts/SupportLayout/README.md +0 -91
  75. package/src/layouts/SupportLayout/SupportLayout.tsx +0 -179
  76. package/src/layouts/SupportLayout/components/CreateTicketDialog.tsx +0 -155
  77. package/src/layouts/SupportLayout/components/MessageInput.tsx +0 -92
  78. package/src/layouts/SupportLayout/components/MessageList.tsx +0 -314
  79. package/src/layouts/SupportLayout/components/TicketCard.tsx +0 -96
  80. package/src/layouts/SupportLayout/components/TicketList.tsx +0 -153
  81. package/src/layouts/SupportLayout/components/index.ts +0 -6
  82. package/src/layouts/SupportLayout/context/SupportLayoutContext.tsx +0 -263
  83. package/src/layouts/SupportLayout/context/index.ts +0 -2
  84. package/src/layouts/SupportLayout/events.ts +0 -33
  85. package/src/layouts/SupportLayout/hooks/index.ts +0 -2
  86. package/src/layouts/SupportLayout/hooks/useInfiniteMessages.ts +0 -119
  87. package/src/layouts/SupportLayout/hooks/useInfiniteTickets.ts +0 -92
  88. package/src/layouts/SupportLayout/index.ts +0 -8
  89. package/src/layouts/SupportLayout/types.ts +0 -21
  90. package/src/snippets/Chat/ChatUIContext.tsx +0 -110
  91. package/src/snippets/Chat/ChatWidget.tsx +0 -476
  92. package/src/snippets/Chat/README.md +0 -122
  93. package/src/snippets/Chat/components/MessageInput.tsx +0 -124
  94. package/src/snippets/Chat/components/MessageList.tsx +0 -169
  95. package/src/snippets/Chat/components/SessionList.tsx +0 -192
  96. package/src/snippets/Chat/components/index.ts +0 -9
  97. package/src/snippets/Chat/hooks/index.ts +0 -6
  98. package/src/snippets/Chat/hooks/useInfiniteSessions.ts +0 -82
  99. package/src/snippets/Chat/index.tsx +0 -45
  100. package/src/snippets/Chat/types.ts +0 -80
  101. package/src/snippets/ContactForm/ContactForm.tsx +0 -346
  102. package/src/snippets/ContactForm/ContactFormProvider.tsx +0 -153
  103. package/src/snippets/ContactForm/ContactInfo.tsx +0 -114
  104. package/src/snippets/ContactForm/ContactPage.tsx +0 -131
  105. package/src/snippets/ContactForm/dynamic.tsx +0 -55
  106. package/src/snippets/ContactForm/index.ts +0 -34
  107. package/src/snippets/ContactForm/types.ts +0 -110
@@ -1,962 +0,0 @@
1
- # 🔐 Auth Module Documentation
2
-
3
- **Package**: @djangocfg/ui
4
- **Module**: `/src/auth`
5
- **Version**: 1.0.0
6
-
7
- ---
8
-
9
- ## 📋 Overview
10
-
11
- Full-featured authentication module for Next.js applications with:
12
- - OTP authentication (email/phone)
13
- - React Context for state management
14
- - Pre-built UI components
15
- - Route protection (guards)
16
- - API/media proxy middleware
17
- - Full TypeScript support
18
-
19
- **Architecture**: Context API + React Hooks + UI Components
20
-
21
- ---
22
-
23
- ## 📁 Module Structure
24
-
25
- ```
26
- src/auth/
27
- ├── context/
28
- │ ├── AuthContext.tsx # Main auth context with logic
29
- │ ├── types.ts # TypeScript types
30
- │ └── index.ts # Exports
31
- ├── hooks/
32
- │ ├── useAuthGuard.ts # Route protection
33
- │ ├── useAuthRedirect.ts # Redirect management
34
- │ ├── useAutoAuth.ts # Auto-login
35
- │ ├── useAuthForm.ts # Form state
36
- │ ├── useLocalStorage.ts # localStorage hook
37
- │ ├── useSessionStorage.ts # sessionStorage hook
38
- │ └── index.ts
39
- ├── components/
40
- │ ├── AuthLayout/ # Complete Auth UI
41
- │ │ ├── AuthLayout.tsx # Main layout
42
- │ │ ├── AuthContext.tsx # Local context for form
43
- │ │ ├── IdentifierForm.tsx # Email/Phone input
44
- │ │ ├── OTPForm.tsx # OTP verification
45
- │ │ ├── AuthHelp.tsx # Help component
46
- │ │ ├── types.ts
47
- │ │ └── index.ts
48
- │ ├── AuthDialog.tsx # Modal for auth required
49
- │ └── index.ts
50
- ├── middlewares/
51
- │ ├── proxy.ts # Next.js middleware for /api/* and /media/*
52
- │ └── index.ts
53
- ├── utils/
54
- │ ├── validation.ts # Email/OTP validation
55
- │ ├── errors.ts # Error utilities
56
- │ └── index.ts
57
- └── index.ts # Main export
58
- ```
59
-
60
- ---
61
-
62
- ## 🚀 Quick Start
63
-
64
- ### 1. Setup AuthProvider
65
-
66
- ```tsx
67
- // pages/_app.tsx
68
- import { AuthProvider } from '@djangocfg/layouts/auth';
69
-
70
- export default function App({ Component, pageProps }) {
71
- return (
72
- <AuthProvider
73
- config={{
74
- apiUrl: process.env.NEXT_PUBLIC_API_URL,
75
- routes: {
76
- auth: '/auth',
77
- defaultCallback: '/dashboard',
78
- defaultAuthCallback: '/auth',
79
- },
80
- }}
81
- >
82
- <Component {...pageProps} />
83
- </AuthProvider>
84
- );
85
- }
86
- ```
87
-
88
- ### 2. Create Auth Page
89
-
90
- ```tsx
91
- // pages/auth.tsx
92
- import { AuthLayout } from '@djangocfg/layouts/auth';
93
-
94
- export default function AuthPage() {
95
- return (
96
- <AuthLayout
97
- title="Welcome to Unrealon"
98
- subtitle="Sign in to continue"
99
- supportEmail="support@djangocfg.com"
100
- supportPhone="+1 (555) 123-4567"
101
- >
102
- {/* Optional: Custom header/footer */}
103
- </AuthLayout>
104
- );
105
- }
106
- ```
107
-
108
- ### 3. Protect Routes
109
-
110
- ```tsx
111
- // pages/dashboard.tsx
112
- import { useAuthGuard } from '@djangocfg/layouts/auth';
113
-
114
- export default function Dashboard() {
115
- const { isAuthenticated, isLoading } = useAuthGuard({
116
- redirectTo: '/auth',
117
- requireAuth: true,
118
- });
119
-
120
- if (isLoading) return <div>Loading...</div>;
121
-
122
- return <div>Protected Dashboard</div>;
123
- }
124
- ```
125
-
126
- ---
127
-
128
- ## 🧩 Core Components
129
-
130
- ### 1. AuthProvider %%PRIORITY:HIGH%%
131
-
132
- **Purpose**: Main authentication context provider.
133
-
134
- ```tsx
135
- import { AuthProvider } from '@djangocfg/layouts/auth';
136
-
137
- <AuthProvider config={authConfig}>
138
- {children}
139
- </AuthProvider>
140
- ```
141
-
142
- **Config Options**:
143
-
144
- ```typescript
145
- interface AuthConfig {
146
- apiUrl?: string; // API base URL
147
- routes?: {
148
- auth?: string; // Auth page path (default: /auth)
149
- defaultCallback?: string; // After login redirect (default: /dashboard)
150
- defaultAuthCallback?: string; // After logout redirect (default: /auth)
151
- };
152
- onLogout?: () => void; // Custom logout handler
153
- onConfirm?: (options) => Promise<{ confirmed: boolean }>; // Custom confirm dialog
154
- }
155
- ```
156
-
157
- **Context Value**:
158
-
159
- ```typescript
160
- interface AuthContextType {
161
- // State
162
- user: UserProfile | null;
163
- isLoading: boolean;
164
- isAuthenticated: boolean;
165
-
166
- // Profile
167
- loadCurrentProfile: () => Promise<void>;
168
- checkAuthAndRedirect: () => Promise<void>;
169
-
170
- // Email Methods
171
- getSavedEmail: () => string | null;
172
- saveEmail: (email: string) => void;
173
- clearSavedEmail: () => void;
174
-
175
- // Phone Methods
176
- getSavedPhone: () => string | null;
177
- savePhone: (phone: string) => void;
178
- clearSavedPhone: () => void;
179
-
180
- // OTP Methods
181
- requestOTP: (identifier: string, channel?: 'email' | 'phone', sourceUrl?: string) => Promise<{
182
- success: boolean;
183
- message: string;
184
- }>;
185
- verifyOTP: (identifier: string, otpCode: string, channel?: 'email' | 'phone', sourceUrl?: string) => Promise<{
186
- success: boolean;
187
- message: string;
188
- user?: UserProfile;
189
- }>;
190
- refreshToken: () => Promise<{ success: boolean; message: string }>;
191
- logout: () => Promise<void>;
192
-
193
- // Redirect Methods
194
- getSavedRedirectUrl: () => string | null;
195
- saveRedirectUrl: (url: string) => void;
196
- clearSavedRedirectUrl: () => void;
197
- getFinalRedirectUrl: () => string;
198
- useAndClearRedirectUrl: () => string;
199
- saveCurrentUrlForRedirect: () => void;
200
- }
201
- ```
202
-
203
- ---
204
-
205
- ### 2. AuthLayout %%PRIORITY:HIGH%%
206
-
207
- **Purpose**: Pre-built UI for auth page with two-step flow.
208
-
209
- ```tsx
210
- import { AuthLayout } from '@djangocfg/layouts/auth';
211
-
212
- <AuthLayout
213
- title="Welcome Back"
214
- subtitle="Sign in to your account"
215
- supportEmail="support@example.com"
216
- supportPhone="+1 234 567 8900"
217
- className="custom-class"
218
- >
219
- {/* Optional custom content above forms */}
220
- </AuthLayout>
221
- ```
222
-
223
- **Props**:
224
-
225
- ```typescript
226
- interface AuthProps {
227
- title?: string; // Main title
228
- subtitle?: string; // Subtitle text
229
- supportEmail?: string; // Support email (shows help)
230
- supportPhone?: string; // Support phone (shows help)
231
- className?: string; // Custom CSS class
232
- children?: React.ReactNode; // Custom content above forms
233
- }
234
- ```
235
-
236
- **Features**:
237
- - ✅ Step 1: Email/Phone input with validation
238
- - ✅ Step 2: OTP verification (6-digit code)
239
- - ✅ Auto-redirect after successful auth
240
- - ✅ Error handling with user-friendly messages
241
- - ✅ Saved identifier (remembers email/phone)
242
- - ✅ Support info display
243
- - ✅ Fully styled with Tailwind CSS
244
-
245
- **Flow**:
246
-
247
- ```
248
- 1. User enters email/phone
249
- → Validation
250
- → Save to localStorage
251
- → Call AuthContext.requestOTP()
252
- → Show success message
253
-
254
- 2. User enters OTP code
255
- → Validation (6 digits)
256
- → Call AuthContext.verifyOTP()
257
- → Save tokens (LocalStorage via @djangocfg/api)
258
- → Load user profile
259
- → Redirect to dashboard
260
- ```
261
-
262
- ---
263
-
264
- ### 3. AuthDialog %%PRIORITY:MEDIUM%%
265
-
266
- **Purpose**: Modal dialog for "auth required" scenarios.
267
-
268
- ```tsx
269
- import { AuthDialog, DIALOG_EVENTS } from '@djangocfg/layouts/auth';
270
-
271
- // In your app
272
- <AuthDialog
273
- authPath="/auth"
274
- onAuthRequired={() => {
275
- // Custom handler
276
- }}
277
- />
278
-
279
- // Trigger from anywhere
280
- window.dispatchEvent(new CustomEvent(DIALOG_EVENTS.OPEN_AUTH_DIALOG, {
281
- detail: { message: 'Please sign in to access this feature' }
282
- }));
283
- ```
284
-
285
- **Events**:
286
-
287
- ```typescript
288
- const DIALOG_EVENTS = {
289
- OPEN_AUTH_DIALOG: 'OPEN_AUTH_DIALOG', // Open dialog
290
- CLOSE_AUTH_DIALOG: 'CLOSE_AUTH_DIALOG', // Close dialog
291
- AUTH_SUCCESS: 'AUTH_SUCCESS', // Auth successful
292
- AUTH_FAILURE: 'AUTH_FAILURE', // Auth failed
293
- };
294
- ```
295
-
296
- **Usage Example**:
297
-
298
- ```tsx
299
- // In a protected action
300
- function handleProtectedAction() {
301
- if (!isAuthenticated) {
302
- window.dispatchEvent(new CustomEvent(DIALOG_EVENTS.OPEN_AUTH_DIALOG, {
303
- detail: { message: 'Sign in to save your work' }
304
- }));
305
- return;
306
- }
307
-
308
- // Continue with action
309
- }
310
- ```
311
-
312
- ---
313
-
314
- ## 🪝 Hooks
315
-
316
- ### 1. useAuth() %%PRIORITY:HIGH%%
317
-
318
- **Purpose**: Access AuthContext from any component.
319
-
320
- ```tsx
321
- import { useAuth } from '@djangocfg/layouts/auth';
322
-
323
- function MyComponent() {
324
- const {
325
- user,
326
- isAuthenticated,
327
- isLoading,
328
- requestOTP,
329
- verifyOTP,
330
- logout
331
- } = useAuth();
332
-
333
- if (isLoading) return <div>Loading...</div>;
334
-
335
- if (!isAuthenticated) {
336
- return <button onClick={() => requestOTP(email)}>Sign In</button>;
337
- }
338
-
339
- return (
340
- <div>
341
- Welcome, {user?.email}
342
- <button onClick={logout}>Logout</button>
343
- </div>
344
- );
345
- }
346
- ```
347
-
348
- ---
349
-
350
- ### 2. useAuthGuard() %%PRIORITY:HIGH%%
351
-
352
- **Purpose**: Protect routes, auto-redirect unauthorized users.
353
-
354
- ```tsx
355
- import { useAuthGuard } from '@djangocfg/layouts/auth';
356
-
357
- function ProtectedPage() {
358
- const { isAuthenticated, isLoading } = useAuthGuard({
359
- redirectTo: '/auth', // Where to redirect if not authenticated
360
- requireAuth: true, // Require authentication (default: true)
361
- });
362
-
363
- if (isLoading) return <div>Checking authentication...</div>;
364
-
365
- return <div>Protected content</div>;
366
- }
367
- ```
368
-
369
- **Options**:
370
-
371
- ```typescript
372
- interface UseAuthGuardOptions {
373
- redirectTo?: string; // Redirect path (default: '/auth')
374
- requireAuth?: boolean; // Require auth (default: true)
375
- }
376
- ```
377
-
378
- ---
379
-
380
- ### 3. useAuthRedirectManager() %%PRIORITY:MEDIUM%%
381
-
382
- **Purpose**: Manage redirect URL after authentication.
383
-
384
- ```tsx
385
- import { useAuthRedirectManager } from '@djangocfg/layouts/auth';
386
-
387
- function ProtectedRoute() {
388
- const {
389
- setRedirect,
390
- getFinalRedirectUrl,
391
- useAndClearRedirect
392
- } = useAuthRedirectManager({
393
- fallbackUrl: '/dashboard',
394
- clearOnUse: true
395
- });
396
-
397
- // Save current URL before redirect to auth
398
- useEffect(() => {
399
- if (!isAuthenticated) {
400
- setRedirect(window.location.pathname);
401
- router.push('/auth');
402
- }
403
- }, [isAuthenticated]);
404
-
405
- // After successful auth
406
- const handleLoginSuccess = () => {
407
- const redirectUrl = useAndClearRedirect();
408
- router.push(redirectUrl); // Goes back to saved URL or fallback
409
- };
410
- }
411
- ```
412
-
413
- **Methods**:
414
-
415
- ```typescript
416
- interface AuthRedirectManager {
417
- redirectUrl: string;
418
- setRedirect: (url: string) => void;
419
- getRedirect: () => string;
420
- clearRedirect: () => void;
421
- hasRedirect: () => boolean;
422
- getFinalRedirectUrl: () => string; // Returns redirect or fallback
423
- useAndClearRedirect: () => string; // Gets and clears redirect
424
- }
425
- ```
426
-
427
- ---
428
-
429
- ### 4. useAutoAuth() %%PRIORITY:LOW%%
430
-
431
- **Purpose**: Automatic authentication when tokens exist.
432
-
433
- ```tsx
434
- import { useAutoAuth } from '@djangocfg/layouts/auth';
435
-
436
- function App() {
437
- useAutoAuth({
438
- enabled: true, // Enable auto-auth
439
- redirectTo: '/dashboard', // Where to redirect after auto-auth
440
- onSuccess: (user) => {
441
- console.log('Auto-auth successful:', user);
442
- },
443
- onFailure: () => {
444
- console.log('Auto-auth failed');
445
- }
446
- });
447
-
448
- return <div>App</div>;
449
- }
450
- ```
451
-
452
- ---
453
-
454
- ### 5. useLocalStorage() & useSessionStorage() %%PRIORITY:LOW%%
455
-
456
- **Purpose**: Type-safe storage hooks.
457
-
458
- ```tsx
459
- import { useLocalStorage, useSessionStorage } from '@djangocfg/layouts/auth';
460
-
461
- function Component() {
462
- const [email, setEmail, removeEmail] = useLocalStorage<string>('saved_email', '');
463
- const [tempData, setTempData] = useSessionStorage<object>('temp_data', {});
464
-
465
- return (
466
- <div>
467
- <input value={email} onChange={(e) => setEmail(e.target.value)} />
468
- <button onClick={removeEmail}>Clear</button>
469
- </div>
470
- );
471
- }
472
- ```
473
-
474
- ---
475
-
476
- ## 🛡️ Middleware
477
-
478
- ### Next.js Proxy Middleware %%PRIORITY:HIGH%%
479
-
480
- **Purpose**: Proxy `/api/*` and `/media/*` to Django backend.
481
-
482
- **Setup**:
483
-
484
- ```typescript
485
- // middleware.ts (in your Next.js app root)
486
- export { middleware, config } from '@djangocfg/layouts/auth/middlewares';
487
- ```
488
-
489
- **What it does**:
490
-
491
- ```typescript
492
- // Proxies these patterns:
493
- /api/* → NEXT_PUBLIC_API_URL/api/*
494
- /media/* → NEXT_PUBLIC_API_URL/media/*
495
-
496
- // Example:
497
- // Request: http://localhost:3000/api/auth/profile
498
- // Proxies: http://localhost:8000/api/auth/profile
499
- ```
500
-
501
- **Why needed**:
502
- - CORS bypass in development
503
- - Unified URL structure
504
- - Transparent access to Django API and media files
505
-
506
- ---
507
-
508
- ## 🔧 Utilities
509
-
510
- ### 1. Validation
511
-
512
- ```typescript
513
- import { validateEmail, validateOTP } from '@djangocfg/layouts/auth';
514
-
515
- const isValidEmail = validateEmail('user@example.com'); // true
516
- const isValidOTP = validateOTP('123456'); // true
517
- const isInvalidOTP = validateOTP('12345'); // false (not 6 digits)
518
- ```
519
-
520
- ### 2. Error Utilities
521
-
522
- ```typescript
523
- import { formatAuthError, isNetworkError } from '@djangocfg/layouts/auth/utils';
524
-
525
- try {
526
- await authService.login();
527
- } catch (error) {
528
- if (isNetworkError(error)) {
529
- alert('Network error, please try again');
530
- } else {
531
- alert(formatAuthError(error));
532
- }
533
- }
534
- ```
535
-
536
- ---
537
-
538
- ## 📖 Usage Patterns
539
-
540
- ### Pattern 1: Simple Auth Page
541
-
542
- ```tsx
543
- // pages/auth.tsx
544
- import { AuthLayout } from '@djangocfg/layouts/auth';
545
-
546
- export default function AuthPage() {
547
- return <AuthLayout />;
548
- }
549
- ```
550
-
551
- **That's it!** You get a fully functional auth flow:
552
- - Email/Phone input
553
- - OTP verification
554
- - Auto-redirect
555
- - Error handling
556
- - Saved identifier
557
-
558
- ---
559
-
560
- ### Pattern 2: Custom Auth Flow
561
-
562
- ```tsx
563
- import { useAuth } from '@djangocfg/layouts/auth';
564
- import { useState } from 'react';
565
-
566
- export default function CustomAuth() {
567
- const { requestOTP, verifyOTP } = useAuth();
568
- const [step, setStep] = useState<'email' | 'otp'>('email');
569
- const [email, setEmail] = useState('');
570
- const [otp, setOTP] = useState('');
571
-
572
- const handleRequestOTP = async () => {
573
- const result = await requestOTP(email);
574
- if (result.success) {
575
- setStep('otp');
576
- } else {
577
- alert(result.message);
578
- }
579
- };
580
-
581
- const handleVerifyOTP = async () => {
582
- const result = await verifyOTP(email, otp);
583
- if (result.success) {
584
- // User logged in, tokens saved, will auto-redirect
585
- } else {
586
- alert(result.message);
587
- }
588
- };
589
-
590
- if (step === 'email') {
591
- return (
592
- <div>
593
- <input value={email} onChange={(e) => setEmail(e.target.value)} />
594
- <button onClick={handleRequestOTP}>Send OTP</button>
595
- </div>
596
- );
597
- }
598
-
599
- return (
600
- <div>
601
- <input value={otp} onChange={(e) => setOTP(e.target.value)} />
602
- <button onClick={handleVerifyOTP}>Verify</button>
603
- </div>
604
- );
605
- }
606
- ```
607
-
608
- ---
609
-
610
- ### Pattern 3: Protected Route
611
-
612
- ```tsx
613
- // pages/dashboard.tsx
614
- import { useAuthGuard } from '@djangocfg/layouts/auth';
615
-
616
- export default function Dashboard() {
617
- const { isLoading } = useAuthGuard();
618
-
619
- if (isLoading) {
620
- return <div>Loading...</div>;
621
- }
622
-
623
- // If not authenticated, already redirected to /auth
624
- return <div>Welcome to Dashboard</div>;
625
- }
626
- ```
627
-
628
- ---
629
-
630
- ### Pattern 4: Conditional UI
631
-
632
- ```tsx
633
- import { useAuth } from '@djangocfg/layouts/auth';
634
-
635
- function Navigation() {
636
- const { isAuthenticated, user, logout } = useAuth();
637
-
638
- if (!isAuthenticated) {
639
- return <a href="/auth">Sign In</a>;
640
- }
641
-
642
- return (
643
- <div>
644
- <span>Welcome, {user?.email}</span>
645
- <button onClick={logout}>Logout</button>
646
- </div>
647
- );
648
- }
649
- ```
650
-
651
- ---
652
-
653
- ### Pattern 5: Auth Required Dialog
654
-
655
- ```tsx
656
- // app.tsx
657
- import { AuthDialog } from '@djangocfg/layouts/auth';
658
-
659
- function App() {
660
- return (
661
- <>
662
- <AuthDialog authPath="/auth" />
663
- {/* Rest of app */}
664
- </>
665
- );
666
- }
667
-
668
- // anywhere.tsx
669
- import { DIALOG_EVENTS } from '@djangocfg/layouts/auth';
670
-
671
- function ProtectedAction() {
672
- const handleAction = () => {
673
- if (!isAuthenticated) {
674
- window.dispatchEvent(new CustomEvent(DIALOG_EVENTS.OPEN_AUTH_DIALOG, {
675
- detail: { message: 'Sign in to continue' }
676
- }));
677
- return;
678
- }
679
-
680
- // Perform action
681
- };
682
- }
683
- ```
684
-
685
- ---
686
-
687
- ## 🔐 Security Features
688
-
689
- ### 1. Token Management
690
-
691
- - ✅ Tokens stored in LocalStorage (via @djangocfg/api)
692
- - ✅ Automatic injection in API requests
693
- - ✅ Auto-refresh tokens
694
- - ✅ Secure logout (tokens cleared)
695
-
696
- ### 2. Input Validation
697
-
698
- - ✅ Email format validation
699
- - ✅ Phone format validation (libphonenumber-js)
700
- - ✅ OTP format validation (6 digits)
701
- - ✅ XSS protection (React automatic)
702
-
703
- ### 3. CSRF Protection
704
-
705
- - ✅ Django CSRF tokens via cookies
706
- - ✅ credentials: 'include' in fetch requests
707
- - ✅ Same-origin policy enforcement
708
-
709
- ### 4. Route Protection
710
-
711
- - ✅ Server-side middleware (Next.js)
712
- - ✅ Client-side guards (useAuthGuard)
713
- - ✅ Auto-redirect unauthorized users
714
-
715
- ---
716
-
717
- ## 🎨 Styling
718
-
719
- ### Tailwind CSS Classes
720
-
721
- All components use Tailwind CSS:
722
-
723
- ```tsx
724
- // AuthLayout - Customizable
725
- <AuthLayout className="bg-gradient-to-br from-blue-500 to-purple-600">
726
- {/* Custom content */}
727
- </AuthLayout>
728
-
729
- // Forms use these classes:
730
- - bg-background
731
- - text-foreground
732
- - border-input
733
- - text-destructive (errors)
734
- - text-muted-foreground (help text)
735
- ```
736
-
737
- ### Dark Mode Support
738
-
739
- ```tsx
740
- // Automatically respects next-themes
741
- import { ThemeProvider } from 'next-themes';
742
-
743
- <ThemeProvider attribute="class">
744
- <AuthProvider>
745
- <AuthLayout />
746
- </AuthProvider>
747
- </ThemeProvider>
748
- ```
749
-
750
- ---
751
-
752
- ## 🧪 Testing
753
-
754
- ### Example: Test Auth Flow
755
-
756
- ```typescript
757
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
758
- import { AuthProvider, AuthLayout } from '@djangocfg/layouts/auth';
759
-
760
- test('auth flow works', async () => {
761
- const { getByPlaceholderText, getByText } = render(
762
- <AuthProvider>
763
- <AuthLayout />
764
- </AuthProvider>
765
- );
766
-
767
- // Step 1: Enter email
768
- const emailInput = getByPlaceholderText('Email or phone');
769
- fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
770
- fireEvent.click(getByText('Continue'));
771
-
772
- // Step 2: Enter OTP
773
- await waitFor(() => {
774
- expect(getByText('Enter verification code')).toBeInTheDocument();
775
- });
776
-
777
- const otpInput = getByPlaceholderText('000000');
778
- fireEvent.change(otpInput, { target: { value: '123456' } });
779
- fireEvent.click(getByText('Verify'));
780
-
781
- // Expect redirect or success
782
- await waitFor(() => {
783
- expect(window.location.pathname).toBe('/dashboard');
784
- });
785
- });
786
- ```
787
-
788
- ---
789
-
790
- ## 🐛 Common Issues
791
-
792
- ### Issue 1: "Module not found" error
793
-
794
- ```bash
795
- # Make sure @djangocfg/api is installed
796
- pnpm add @djangocfg/api@workspace:*
797
- ```
798
-
799
- ### Issue 2: Infinite redirect loop
800
-
801
- ```typescript
802
- // Check your routes config
803
- <AuthProvider config={{
804
- routes: {
805
- auth: '/auth', // Auth page path
806
- defaultCallback: '/dashboard', // After login
807
- defaultAuthCallback: '/auth' // After logout
808
- }
809
- }} />
810
- ```
811
-
812
- ### Issue 3: Tokens not persisting
813
-
814
- ```typescript
815
- // Check if LocalStorageAdapter is configured in @djangocfg/api
816
- import { api } from '@djangocfg/api';
817
- console.log(api.isAuthenticated()); // Should return true after login
818
- ```
819
-
820
- ### Issue 4: CORS errors
821
-
822
- ```typescript
823
- // Add middleware to proxy /api/*
824
- // middleware.ts
825
- export { middleware, config } from '@djangocfg/layouts/auth/middlewares';
826
- ```
827
-
828
- ---
829
-
830
- ## 📊 Architecture Diagram
831
-
832
- ```
833
- ┌─────────────────────────────────────────────────────────────┐
834
- │ User Browser │
835
- │ │
836
- │ ┌──────────────────────────────────────────────────────┐ │
837
- │ │ Next.js App (Frontend) │ │
838
- │ │ │ │
839
- │ │ ┌────────────┐ ┌──────────────┐ ┌─────────────┐ │ │
840
- │ │ │ AuthLayout │→ │ AuthContext │→ │ @djangocfg/ │ │ │
841
- │ │ │ (UI) │ │ (State) │ │ api │ │ │
842
- │ │ └────────────┘ └──────────────┘ └─────────────┘ │ │
843
- │ │ ↓ ↓ ↓ │ │
844
- │ │ ┌────────────────────────────────────────────────┐ │ │
845
- │ │ │ LocalStorage (Tokens) │ │ │
846
- │ │ └────────────────────────────────────────────────┘ │ │
847
- │ └──────────────────────────────────────────────────────┘ │
848
- │ ↓ HTTP │
849
- └───────────────────────────┼─────────────────────────────────┘
850
-
851
- ┌───────────────┐
852
- │ Next.js │
853
- │ Middleware │
854
- │ (Proxy) │
855
- └───────┬───────┘
856
- ↓ /api/*, /media/*
857
- ┌───────────────┐
858
- │ Django API │
859
- │ Backend │
860
- └───────────────┘
861
- ```
862
-
863
- ---
864
-
865
- ## 🔗 Related Modules
866
-
867
- - **@djangocfg/api** - API client with auth services
868
- - **@djangocfg/ui-nextjs/components** - UI components (Button, Dialog, etc)
869
- - **@djangocfg/ui-nextjs/hooks** - Utility hooks
870
- - **next-themes** - Theme support
871
- - **libphonenumber-js** - Phone validation
872
-
873
- ---
874
-
875
- ## 📝 TODO / Future Improvements
876
-
877
- - [ ] Add biometric authentication support
878
- - [ ] Social auth (Google, GitHub, etc)
879
- - [ ] 2FA/MFA support
880
- - [ ] Remember device functionality
881
- - [ ] Session timeout warnings
882
- - [ ] Magic link authentication
883
- - [ ] SSR-compatible cookie auth
884
- - [ ] Rate limiting for OTP requests
885
-
886
- ---
887
-
888
- ## 🎓 Best Practices
889
-
890
- ### 1. Always wrap app in AuthProvider
891
-
892
- ```tsx
893
- // ✅ Good
894
- <AuthProvider>
895
- <App />
896
- </AuthProvider>
897
-
898
- // ❌ Bad - hooks won't work
899
- <App />
900
- ```
901
-
902
- ### 2. Use useAuthGuard for protected routes
903
-
904
- ```tsx
905
- // ✅ Good - automatic redirect
906
- function ProtectedPage() {
907
- useAuthGuard();
908
- return <div>Content</div>;
909
- }
910
-
911
- // ❌ Bad - manual checks everywhere
912
- function ProtectedPage() {
913
- const { isAuthenticated } = useAuth();
914
- useEffect(() => {
915
- if (!isAuthenticated) router.push('/auth');
916
- }, [isAuthenticated]);
917
- // ...
918
- }
919
- ```
920
-
921
- ### 3. Handle loading states
922
-
923
- ```tsx
924
- // ✅ Good
925
- function Dashboard() {
926
- const { isLoading, user } = useAuth();
927
- if (isLoading) return <Spinner />;
928
- return <div>Welcome {user?.email}</div>;
929
- }
930
-
931
- // ❌ Bad - might show undefined
932
- function Dashboard() {
933
- const { user } = useAuth();
934
- return <div>Welcome {user.email}</div>; // Error if user is null
935
- }
936
- ```
937
-
938
- ### 4. Save redirect URL before auth
939
-
940
- ```tsx
941
- // ✅ Good - user returns to intended page
942
- function ProtectedRoute() {
943
- const { setRedirect } = useAuthRedirectManager();
944
-
945
- useEffect(() => {
946
- if (!isAuthenticated) {
947
- setRedirect(window.location.pathname);
948
- router.push('/auth');
949
- }
950
- }, []);
951
- }
952
- ```
953
-
954
- ---
955
-
956
- **Version**: 1.0.0
957
- **Last Updated**: 2025-10-08
958
- **Maintainer**: Reforms AI
959
-
960
- ---
961
-
962
- **Tags**: `auth, authentication, otp, react, next.js, context, hooks, ui, middleware`