@djangocfg/layouts 1.2.31 → 1.2.33

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 (28) hide show
  1. package/package.json +5 -5
  2. package/src/auth/context/AccountsContext.tsx +40 -9
  3. package/src/auth/context/AuthContext.tsx +43 -13
  4. package/src/auth/context/types.ts +1 -1
  5. package/src/auth/hooks/useAuthForm.ts +2 -1
  6. package/src/auth/hooks/useAutoAuth.ts +2 -1
  7. package/src/auth/hooks/useLocalStorage.ts +19 -18
  8. package/src/auth/hooks/useProfileCache.ts +4 -1
  9. package/src/auth/hooks/useSessionStorage.ts +19 -18
  10. package/src/index.ts +4 -1
  11. package/src/layouts/AppLayout/AppLayout.tsx +9 -2
  12. package/src/layouts/AppLayout/components/ErrorBoundary.tsx +3 -2
  13. package/src/layouts/AppLayout/components/PackageVersions/packageVersions.config.ts +8 -8
  14. package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +56 -19
  15. package/src/layouts/AppLayout/layouts/AdminLayout/components/ParentSync.tsx +29 -18
  16. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/useApp.ts +65 -19
  17. package/src/layouts/AppLayout/providers/CoreProviders.tsx +12 -2
  18. package/src/layouts/PaymentsLayout/components/CreatePaymentDialog.tsx +2 -1
  19. package/src/layouts/ProfileLayout/components/AvatarSection.tsx +2 -1
  20. package/src/layouts/UILayout/components/layout/Header/Header.tsx +11 -4
  21. package/src/layouts/UILayout/components/layout/Header/HeaderDesktop.tsx +14 -7
  22. package/src/layouts/UILayout/components/layout/Header/TestValidationButton.tsx +265 -0
  23. package/src/layouts/UILayout/components/layout/Header/index.ts +2 -0
  24. package/src/utils/logger.ts +3 -1
  25. package/src/validation/README.md +507 -0
  26. package/src/validation/ValidationErrorContext.tsx +333 -0
  27. package/src/validation/ValidationErrorToast.tsx +251 -0
  28. package/src/validation/index.ts +25 -0
@@ -0,0 +1,507 @@
1
+ # Validation Error System
2
+
3
+ Automatic Zod validation error tracking with toast notifications and copy-to-clipboard functionality.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ ✅ **Auto-capture validation errors** from API client via CustomEvent
10
+ ✅ **Toast notifications** with destructive styling
11
+ ✅ **Copy button** - One-click copy full error details to clipboard
12
+ ✅ **Error history** - Store and manage validation errors
13
+ ✅ **Configurable** - Customize display and behavior
14
+ ✅ **Type-safe** - Full TypeScript support
15
+
16
+ ---
17
+
18
+ ## Quick Start
19
+
20
+ ### 1. Setup Provider
21
+
22
+ Wrap your app with `ValidationErrorProvider`:
23
+
24
+ ```tsx
25
+ // apps/admin/src/layouts/RootLayout.tsx
26
+ import { ValidationErrorProvider } from '@djangocfg/layouts/validation';
27
+
28
+ export default function RootLayout({ children }) {
29
+ return (
30
+ <ValidationErrorProvider>
31
+ {children}
32
+ </ValidationErrorProvider>
33
+ );
34
+ }
35
+ ```
36
+
37
+ ### 2. Trigger Validation Error
38
+
39
+ Use the test button in UILayout header:
40
+
41
+ ```tsx
42
+ // In UILayout header, click "Test Validation" button
43
+ // Select any error type (Simple, Multiple, Nested, Array)
44
+ ```
45
+
46
+ Or dispatch manually:
47
+
48
+ ```typescript
49
+ import type { ValidationErrorDetail } from '@djangocfg/layouts/validation';
50
+
51
+ const errorDetail: ValidationErrorDetail = {
52
+ operation: 'createUser',
53
+ path: '/api/users',
54
+ method: 'POST',
55
+ error: zodError, // ZodError instance
56
+ response: responseData,
57
+ timestamp: new Date(),
58
+ };
59
+
60
+ window.dispatchEvent(new CustomEvent('zod-validation-error', {
61
+ detail: errorDetail,
62
+ bubbles: true,
63
+ cancelable: false,
64
+ }));
65
+ ```
66
+
67
+ ### 3. See Results
68
+
69
+ You'll see a toast with:
70
+ - **Title**: "❌ Validation Error in operation_name"
71
+ - **Description**: Endpoint, error count, first 3 errors
72
+ - **Copy Button**: "📋 Copy" - Copies full error JSON to clipboard
73
+
74
+ ---
75
+
76
+ ## Toast with Copy Button
77
+
78
+ The system automatically shows toasts with a copy button for all validation errors.
79
+
80
+ ### What Gets Copied
81
+
82
+ When you click "📋 Copy", the following JSON is copied to clipboard:
83
+
84
+ ```json
85
+ {
86
+ "timestamp": "2025-11-11T00:39:22.123Z",
87
+ "operation": "createUser",
88
+ "endpoint": {
89
+ "method": "POST",
90
+ "path": "/api/users"
91
+ },
92
+ "validation_errors": [
93
+ {
94
+ "path": "email",
95
+ "message": "Invalid email format",
96
+ "code": "invalid_string",
97
+ "expected": "email",
98
+ "received": "string"
99
+ },
100
+ {
101
+ "path": "age",
102
+ "message": "Number must be greater than 0",
103
+ "code": "too_small",
104
+ "minimum": 0
105
+ }
106
+ ],
107
+ "response": {
108
+ "email": "not-an-email",
109
+ "age": -5
110
+ },
111
+ "total_errors": 2
112
+ }
113
+ ```
114
+
115
+ ### Copy Success/Error Feedback
116
+
117
+ - **Success**: Shows "✅ Copied! Error details copied to clipboard" for 2 seconds
118
+ - **Error**: Shows "❌ Copy failed - Could not copy error details" for 2 seconds
119
+
120
+ ---
121
+
122
+ ## Configuration
123
+
124
+ ### Provider Config
125
+
126
+ ```tsx
127
+ <ValidationErrorProvider
128
+ config={{
129
+ enableToast: true, // Show toast notifications
130
+ maxErrors: 50, // Max errors to store in history
131
+ toastSettings: {
132
+ duration: 5000, // Toast duration in ms
133
+ showOperation: true, // Show operation name in title
134
+ showPath: true, // Show endpoint path in description
135
+ showErrorCount: true, // Show error count in description
136
+ },
137
+ onError: (detail) => {
138
+ // Custom error handler
139
+ console.error('Validation error:', detail);
140
+ // Return false to prevent toast
141
+ return true;
142
+ },
143
+ }}
144
+ >
145
+ {children}
146
+ </ValidationErrorProvider>
147
+ ```
148
+
149
+ ### Custom Toast Config
150
+
151
+ Create custom toast programmatically:
152
+
153
+ ```typescript
154
+ import { useToast } from '@djangocfg/ui';
155
+ import { createValidationErrorToast } from '@djangocfg/layouts/validation';
156
+
157
+ function MyComponent() {
158
+ const { toast } = useToast();
159
+
160
+ const handleError = (errorDetail: ValidationErrorDetail) => {
161
+ const toastOptions = createValidationErrorToast(errorDetail, {
162
+ config: {
163
+ showOperation: true,
164
+ showPath: true,
165
+ showErrorCount: true,
166
+ maxIssuesInDescription: 5, // Show up to 5 errors
167
+ titlePrefix: '🚨 API Error', // Custom prefix
168
+ },
169
+ duration: 10000, // 10 seconds
170
+ onCopySuccess: () => {
171
+ toast({ title: 'Copied!', duration: 1000 });
172
+ },
173
+ onCopyError: (error) => {
174
+ console.error('Copy failed:', error);
175
+ },
176
+ });
177
+
178
+ toast(toastOptions);
179
+ };
180
+
181
+ return <button onClick={() => handleError(errorDetail)}>Trigger Error</button>;
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ## API Reference
188
+
189
+ ### `ValidationErrorProvider`
190
+
191
+ Main provider component for validation error tracking.
192
+
193
+ **Props:**
194
+ ```typescript
195
+ interface ValidationErrorProviderProps {
196
+ children: ReactNode;
197
+ config?: Partial<ValidationErrorConfig>;
198
+ }
199
+
200
+ interface ValidationErrorConfig {
201
+ enableToast: boolean; // Default: true
202
+ maxErrors: number; // Default: 50
203
+ toastSettings: {
204
+ duration: number; // Default: 5000ms
205
+ showOperation: boolean; // Default: true
206
+ showPath: boolean; // Default: true
207
+ showErrorCount: boolean; // Default: true
208
+ };
209
+ onError?: (detail: ValidationErrorDetail) => boolean | void;
210
+ }
211
+ ```
212
+
213
+ ---
214
+
215
+ ### `useValidationErrors()`
216
+
217
+ Hook to access validation error state.
218
+
219
+ **Returns:**
220
+ ```typescript
221
+ interface ValidationErrorContextValue {
222
+ errors: StoredValidationError[]; // All errors in history
223
+ clearErrors: () => void; // Clear all errors
224
+ clearError: (id: string) => void; // Clear specific error
225
+ }
226
+ ```
227
+
228
+ **Usage:**
229
+ ```typescript
230
+ import { useValidationErrors } from '@djangocfg/layouts/validation';
231
+
232
+ function ErrorList() {
233
+ const { errors, clearErrors, clearError } = useValidationErrors();
234
+
235
+ return (
236
+ <div>
237
+ <button onClick={clearErrors}>Clear All</button>
238
+ {errors.map((error) => (
239
+ <div key={error.id}>
240
+ <p>{error.operation}: {error.error.issues.length} errors</p>
241
+ <button onClick={() => clearError(error.id)}>Clear</button>
242
+ </div>
243
+ ))}
244
+ </div>
245
+ );
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ### `createValidationErrorToast()`
252
+
253
+ Create custom toast options with copy button.
254
+
255
+ **Signature:**
256
+ ```typescript
257
+ function createValidationErrorToast(
258
+ detail: ValidationErrorDetail,
259
+ options?: {
260
+ config?: Partial<ValidationErrorToastConfig>;
261
+ duration?: number;
262
+ onCopySuccess?: () => void;
263
+ onCopyError?: (error: Error) => void;
264
+ }
265
+ ): ToastOptions
266
+ ```
267
+
268
+ **Returns:** Object with `title`, `description`, `variant`, `duration`, `action` (copy button)
269
+
270
+ ---
271
+
272
+ ### `formatErrorForClipboard()`
273
+
274
+ Format error details as JSON for clipboard.
275
+
276
+ **Signature:**
277
+ ```typescript
278
+ function formatErrorForClipboard(detail: ValidationErrorDetail): string
279
+ ```
280
+
281
+ **Returns:** Formatted JSON string with all error details
282
+
283
+ ---
284
+
285
+ ### `createCopyAction()`
286
+
287
+ Create standalone copy button for toast.
288
+
289
+ **Signature:**
290
+ ```typescript
291
+ function createCopyAction(
292
+ detail: ValidationErrorDetail,
293
+ onCopySuccess?: () => void,
294
+ onCopyError?: (error: Error) => void
295
+ ): React.ReactElement
296
+ ```
297
+
298
+ **Returns:** `<ToastAction>` component with copy functionality
299
+
300
+ ---
301
+
302
+ ## Testing
303
+
304
+ ### Test Button in UILayout
305
+
306
+ The `TestValidationButton` in UILayout header provides 4 test scenarios:
307
+
308
+ 1. **Simple Error** - Single field validation (email)
309
+ 2. **Multiple Errors** - 3 validation errors (email, age, username)
310
+ 3. **Nested Object** - Nested property errors (address.street, address.zipCode)
311
+ 4. **Array Validation** - Array item errors (items[0].quantity, items[1].price)
312
+
313
+ Each test:
314
+ - Dispatches CustomEvent
315
+ - Triggers toast with copy button
316
+ - Logs to console
317
+
318
+ ---
319
+
320
+ ## Browser Compatibility
321
+
322
+ ### Clipboard API
323
+
324
+ **Modern browsers** (Chrome 66+, Firefox 63+, Safari 13.1+):
325
+ - Uses `navigator.clipboard.writeText()` (async)
326
+
327
+ **Older browsers**:
328
+ - Fallback to `document.execCommand('copy')`
329
+
330
+ ---
331
+
332
+ ## Examples
333
+
334
+ ### Example 1: Basic Setup
335
+
336
+ ```tsx
337
+ import { ValidationErrorProvider } from '@djangocfg/layouts/validation';
338
+
339
+ function App() {
340
+ return (
341
+ <ValidationErrorProvider>
342
+ <YourApp />
343
+ </ValidationErrorProvider>
344
+ );
345
+ }
346
+ ```
347
+
348
+ ### Example 2: Custom Error Handler
349
+
350
+ ```tsx
351
+ <ValidationErrorProvider
352
+ config={{
353
+ onError: (detail) => {
354
+ // Log to external service
355
+ logToSentry(detail);
356
+
357
+ // Only show toast for POST/PUT/PATCH errors
358
+ return ['POST', 'PUT', 'PATCH'].includes(detail.method);
359
+ },
360
+ }}
361
+ >
362
+ {children}
363
+ </ValidationErrorProvider>
364
+ ```
365
+
366
+ ### Example 3: Manual Toast Trigger
367
+
368
+ ```typescript
369
+ import { useToast } from '@djangocfg/ui';
370
+ import { createValidationErrorToast } from '@djangocfg/layouts/validation';
371
+
372
+ function MyForm() {
373
+ const { toast } = useToast();
374
+
375
+ const handleSubmit = async (data) => {
376
+ try {
377
+ await api.createUser(data);
378
+ } catch (error) {
379
+ if (error instanceof ZodError) {
380
+ const toastOptions = createValidationErrorToast({
381
+ operation: 'createUser',
382
+ path: '/api/users',
383
+ method: 'POST',
384
+ error: error,
385
+ response: data,
386
+ timestamp: new Date(),
387
+ }, {
388
+ onCopySuccess: () => console.log('Copied!'),
389
+ });
390
+
391
+ toast(toastOptions);
392
+ }
393
+ }
394
+ };
395
+
396
+ return <form onSubmit={handleSubmit}>...</form>;
397
+ }
398
+ ```
399
+
400
+ ### Example 4: Error History Display
401
+
402
+ ```tsx
403
+ import { useValidationErrors } from '@djangocfg/layouts/validation';
404
+
405
+ function ErrorHistory() {
406
+ const { errors, clearErrors } = useValidationErrors();
407
+
408
+ return (
409
+ <div className="space-y-4">
410
+ <div className="flex justify-between items-center">
411
+ <h2>Validation Error History ({errors.length})</h2>
412
+ <Button onClick={clearErrors} variant="outline" size="sm">
413
+ Clear All
414
+ </Button>
415
+ </div>
416
+
417
+ {errors.map((error) => (
418
+ <div key={error.id} className="border p-4 rounded">
419
+ <div className="flex justify-between">
420
+ <div>
421
+ <p className="font-semibold">{error.operation}</p>
422
+ <p className="text-sm text-muted-foreground">
423
+ {error.method} {error.path}
424
+ </p>
425
+ </div>
426
+ <p className="text-xs text-muted-foreground">
427
+ {error.timestamp.toLocaleString()}
428
+ </p>
429
+ </div>
430
+ <div className="mt-2">
431
+ <p className="text-sm">
432
+ {error.error.issues.length} validation errors
433
+ </p>
434
+ </div>
435
+ </div>
436
+ ))}
437
+ </div>
438
+ );
439
+ }
440
+ ```
441
+
442
+ ---
443
+
444
+ ## Troubleshooting
445
+
446
+ ### Toast not showing
447
+
448
+ 1. **Check Toaster is rendered**:
449
+ ```tsx
450
+ import { Toaster } from '@djangocfg/ui';
451
+ // In your root layout
452
+ <Toaster />
453
+ ```
454
+
455
+ 2. **Check ValidationErrorProvider is wrapping your app**
456
+
457
+ 3. **Check config.enableToast is true**
458
+
459
+ ### Copy button not working
460
+
461
+ 1. **Check HTTPS**: Clipboard API requires secure context (HTTPS or localhost)
462
+ 2. **Check browser permissions**: Some browsers may block clipboard access
463
+ 3. **Check console**: Look for clipboard errors
464
+
465
+ ### Test button not visible
466
+
467
+ 1. **Check NODE_ENV**: Button only shows in development by default
468
+ 2. **Override in production**: Pass `showInProduction={true}` to TestValidationButton
469
+
470
+ ---
471
+
472
+ ## File Structure
473
+
474
+ ```
475
+ validation/
476
+ ├── index.ts # Public exports
477
+ ├── ValidationErrorContext.tsx # Provider & hook
478
+ ├── ValidationErrorToast.tsx # Toast utilities & copy button
479
+ └── README.md # This file
480
+ ```
481
+
482
+ ---
483
+
484
+ ## Related Components
485
+
486
+ - **TestValidationButton** - Test button in UILayout header
487
+ - **UILayout** - Layout with validation test button
488
+ - **Toaster** - Toast notification container (@djangocfg/ui)
489
+ - **useToast** - Toast hook (@djangocfg/ui)
490
+
491
+ ---
492
+
493
+ ## Changelog
494
+
495
+ ### 2025-11-11 - v2.0.0
496
+ - ✨ Added copy-to-clipboard button in toast
497
+ - ✨ Added `ValidationErrorToast` utilities
498
+ - ✨ Added `formatErrorForClipboard()` function
499
+ - ✨ Added success/error feedback for copy action
500
+ - 📝 Added comprehensive documentation
501
+
502
+ ### 2025-11-10 - v1.0.0
503
+ - 🎉 Initial release
504
+ - ✨ ValidationErrorProvider component
505
+ - ✨ useValidationErrors hook
506
+ - ✨ CustomEvent-based error capture
507
+ - ✨ Toast notifications