@jmruthers/pace-core 0.5.121 → 0.5.123

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 (254) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
  11. package/dist/chunk-DHMFMXFV.js.map +1 -0
  12. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  13. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  23. package/dist/chunk-XN6GWKMV.js.map +1 -0
  24. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  25. package/dist/chunk-ZBLK676C.js.map +1 -0
  26. package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
  27. package/dist/chunk-ZPJMYGEP.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +66 -136
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  175. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  176. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  177. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  178. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  179. package/src/components/Dialog/Dialog.tsx +1 -1
  180. package/src/components/Dialog/README.md +24 -24
  181. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  182. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  183. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  184. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  185. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  186. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  187. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  188. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  189. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  190. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  191. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  192. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  193. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  194. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  195. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  196. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  197. package/src/examples/PublicEventPage.tsx +41 -41
  198. package/src/examples/PublicPageApp.tsx +33 -33
  199. package/src/examples/PublicPageUsageExample.tsx +30 -30
  200. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  201. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  202. package/src/hooks/index.ts +1 -1
  203. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  204. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  205. package/src/hooks/useEventTheme.test.ts +119 -43
  206. package/src/hooks/useEventTheme.ts +84 -55
  207. package/src/index.ts +3 -1
  208. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  209. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  210. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  211. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  213. package/src/rbac/secureClient.ts +4 -2
  214. package/src/services/EventService.ts +0 -66
  215. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  216. package/src/styles/index.ts +1 -1
  217. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  218. package/src/theming/parseEventColours.ts +123 -0
  219. package/src/theming/runtime.ts +3 -0
  220. package/src/types/__tests__/file-reference.test.ts +447 -0
  221. package/src/utils/formatDate.test.ts +11 -11
  222. package/src/utils/formatting.ts +3 -2
  223. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  224. package/dist/chunk-BHWIUEYH.js.map +0 -1
  225. package/dist/chunk-CGURJ27Z.js.map +0 -1
  226. package/dist/chunk-FKFHZUGF.js.map +0 -1
  227. package/dist/chunk-GKHF54DI 2.js +0 -619
  228. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  229. package/dist/chunk-GZRXOUBE.js.map +0 -1
  230. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  231. package/dist/chunk-NZ32EONV.js.map +0 -1
  232. package/dist/chunk-O3NWNXDY 2.js +0 -76
  233. package/dist/chunk-QPI2CCBA.js.map +0 -1
  234. package/dist/chunk-SMJZMKYN.js.map +0 -1
  235. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  237. package/dist/chunk-VKOCWWVY.js.map +0 -1
  238. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  239. package/dist/index 3.js +0 -856
  240. package/dist/providers 3.js +0 -38
  241. package/dist/providers.js 3.map +0 -1
  242. package/dist/types 3.js +0 -128
  243. package/dist/types.js 3.map +0 -1
  244. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  245. package/dist/utils.js 3.map +0 -1
  246. package/dist/validation 3.js +0 -479
  247. package/src/styles/semantic.css +0 -24
  248. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
  249. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  250. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  251. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  252. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  253. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  254. /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
@@ -0,0 +1,1117 @@
1
+ # Debugging Guide
2
+
3
+ Effective debugging is essential for maintaining and troubleshooting `@jmruthers/pace-core` applications. This guide provides comprehensive debugging techniques and tools.
4
+
5
+ ## Overview
6
+
7
+ Debugging in `@jmruthers/pace-core` covers multiple areas:
8
+
9
+ - **Component Debugging**: React component issues and rendering problems
10
+ - **Hook Debugging**: Custom hook behavior and state management
11
+ - **Authentication Debugging**: User authentication and session issues
12
+ - **Permission Debugging**: RBAC and access control problems
13
+ - **API Debugging**: Supabase and external API issues
14
+ - **Performance Debugging**: Performance bottlenecks and memory leaks
15
+
16
+ ## Debugging Tools
17
+
18
+ ### 1. React Developer Tools
19
+
20
+ ```typescript
21
+ // Enable React DevTools in development
22
+ if (process.env.NODE_ENV === 'development') {
23
+ // React DevTools will automatically connect
24
+ console.log('React DevTools enabled');
25
+ }
26
+
27
+ // Custom hook for debugging component renders
28
+ function useDebugRender(componentName: string, props?: any) {
29
+ useEffect(() => {
30
+ console.log(`${componentName} rendered with props:`, props);
31
+ });
32
+
33
+ useEffect(() => {
34
+ console.log(`${componentName} mounted`);
35
+ return () => console.log(`${componentName} unmounted`);
36
+ }, []);
37
+ }
38
+
39
+ // Usage in components
40
+ function MyComponent({ data, loading }) {
41
+ useDebugRender('MyComponent', { data, loading });
42
+
43
+ if (loading) return <div>Loading...</div>;
44
+ return <div>{data}</div>;
45
+ }
46
+ ```
47
+
48
+ ### 2. Custom Debug Hooks
49
+
50
+ ```typescript
51
+ // hooks/useDebug.ts
52
+ import { useEffect, useRef } from 'react';
53
+
54
+ export function useDebugValue<T>(value: T, label: string) {
55
+ const prevValue = useRef<T>();
56
+
57
+ useEffect(() => {
58
+ if (prevValue.current !== value) {
59
+ console.log(`${label} changed:`, {
60
+ previous: prevValue.current,
61
+ current: value,
62
+ });
63
+ prevValue.current = value;
64
+ }
65
+ }, [value, label]);
66
+ }
67
+
68
+ export function useDebugEffect(effect: () => void, deps: any[], label: string) {
69
+ useEffect(() => {
70
+ console.log(`${label} effect triggered with deps:`, deps);
71
+ effect();
72
+ }, deps);
73
+ }
74
+
75
+ export function useDebugCallback<T extends (...args: any[]) => any>(
76
+ callback: T,
77
+ deps: any[],
78
+ label: string
79
+ ): T {
80
+ const prevDeps = useRef<any[]>();
81
+
82
+ useEffect(() => {
83
+ if (JSON.stringify(prevDeps.current) !== JSON.stringify(deps)) {
84
+ console.log(`${label} callback dependencies changed:`, deps);
85
+ prevDeps.current = deps;
86
+ }
87
+ }, [deps, label]);
88
+
89
+ return callback;
90
+ }
91
+
92
+ // Usage
93
+ function MyComponent({ userId }) {
94
+ useDebugValue(userId, 'userId');
95
+
96
+ const handleClick = useDebugCallback(() => {
97
+ console.log('Button clicked');
98
+ }, [userId], 'handleClick');
99
+
100
+ return <button onClick={handleClick}>Click me</button>;
101
+ }
102
+ ```
103
+
104
+ ### 3. Error Boundary with Debugging
105
+
106
+ ```typescript
107
+ // components/DebugErrorBoundary.tsx
108
+ import React from 'react';
109
+ import { ErrorBoundary } from '@jmruthers/pace-core';
110
+
111
+ interface DebugErrorBoundaryProps {
112
+ children: React.ReactNode;
113
+ fallback?: React.ComponentType<{ error: Error; resetError: () => void }>;
114
+ }
115
+
116
+ export function DebugErrorBoundary({ children, fallback }: DebugErrorBoundaryProps) {
117
+ const handleError = (error: Error, errorInfo: React.ErrorInfo) => {
118
+ console.error('Error caught by boundary:', error);
119
+ console.error('Error info:', errorInfo);
120
+
121
+ // Send to error tracking service
122
+ if (typeof Sentry !== 'undefined') {
123
+ Sentry.captureException(error, {
124
+ extra: {
125
+ componentStack: errorInfo.componentStack,
126
+ },
127
+ });
128
+ }
129
+ };
130
+
131
+ const FallbackComponent = fallback || DefaultFallback;
132
+
133
+ return (
134
+ <ErrorBoundary onError={handleError} fallback={FallbackComponent}>
135
+ {children}
136
+ </ErrorBoundary>
137
+ );
138
+ }
139
+
140
+ function DefaultFallback({ error, resetError }: { error: Error; resetError: () => void }) {
141
+ return (
142
+ <div className="error-boundary">
143
+ <h2>Something went wrong</h2>
144
+ <details>
145
+ <summary>Error details</summary>
146
+ <pre>{error.message}</pre>
147
+ <pre>{error.stack}</pre>
148
+ </details>
149
+ <button onClick={resetError}>Try again</button>
150
+ </div>
151
+ );
152
+ }
153
+ ```
154
+
155
+ ## Component Debugging
156
+
157
+ ### 1. Component State Debugging
158
+
159
+ ```typescript
160
+ // utils/componentDebugger.ts
161
+ export function debugComponentState<T>(
162
+ componentName: string,
163
+ state: T,
164
+ prevState?: T
165
+ ) {
166
+ if (process.env.NODE_ENV === 'development') {
167
+ console.group(`${componentName} State Change`);
168
+ console.log('Previous State:', prevState);
169
+ console.log('Current State:', state);
170
+ console.log('Changes:', getStateChanges(prevState, state));
171
+ console.groupEnd();
172
+ }
173
+ }
174
+
175
+ function getStateChanges(prev: any, current: any): Record<string, any> {
176
+ if (!prev) return { initial: current };
177
+
178
+ const changes: Record<string, any> = {};
179
+
180
+ for (const key in current) {
181
+ if (prev[key] !== current[key]) {
182
+ changes[key] = {
183
+ from: prev[key],
184
+ to: current[key],
185
+ };
186
+ }
187
+ }
188
+
189
+ return changes;
190
+ }
191
+
192
+ // Usage in components
193
+ function MyComponent() {
194
+ const [state, setState] = useState({ count: 0, loading: false });
195
+ const prevState = useRef(state);
196
+
197
+ useEffect(() => {
198
+ debugComponentState('MyComponent', state, prevState.current);
199
+ prevState.current = state;
200
+ }, [state]);
201
+
202
+ return <div>{state.count}</div>;
203
+ }
204
+ ```
205
+
206
+ ### 2. Props Debugging
207
+
208
+ ```typescript
209
+ // utils/propsDebugger.ts
210
+ export function debugProps<T>(componentName: string, props: T) {
211
+ if (process.env.NODE_ENV === 'development') {
212
+ console.log(`${componentName} props:`, props);
213
+ }
214
+ }
215
+
216
+ // Higher-order component for automatic props debugging
217
+ export function withPropsDebug<P extends object>(
218
+ Component: React.ComponentType<P>,
219
+ componentName?: string
220
+ ) {
221
+ const WrappedComponent = (props: P) => {
222
+ const name = componentName || Component.displayName || Component.name;
223
+ debugProps(name, props);
224
+ return <Component {...props} />;
225
+ };
226
+
227
+ WrappedComponent.displayName = `withPropsDebug(${Component.displayName || Component.name})`;
228
+ return WrappedComponent;
229
+ }
230
+
231
+ // Usage
232
+ const DebuggedButton = withPropsDebug(Button, 'Button');
233
+ ```
234
+
235
+ ### 3. Render Performance Debugging
236
+
237
+ ```typescript
238
+ // utils/renderDebugger.ts
239
+ import { useComponentPerformance } from '@jmruthers/pace-core';
240
+
241
+ export function useRenderDebug(componentName: string) {
242
+ const { renderCount, averageRenderTime, lastRenderTime } = useComponentPerformance();
243
+
244
+ useEffect(() => {
245
+ if (process.env.NODE_ENV === 'development') {
246
+ console.log(`${componentName} render stats:`, {
247
+ renderCount,
248
+ averageRenderTime: averageRenderTime.toFixed(2),
249
+ lastRenderTime: lastRenderTime.toFixed(2),
250
+ });
251
+ }
252
+ }, [renderCount, averageRenderTime, lastRenderTime, componentName]);
253
+
254
+ // Warn if component is rendering too frequently
255
+ useEffect(() => {
256
+ if (renderCount > 10 && averageRenderTime > 16) {
257
+ console.warn(`${componentName} is rendering frequently and slowly:`, {
258
+ renderCount,
259
+ averageRenderTime: averageRenderTime.toFixed(2),
260
+ });
261
+ }
262
+ }, [renderCount, averageRenderTime, componentName]);
263
+ }
264
+
265
+ // Usage
266
+ function ExpensiveComponent() {
267
+ useRenderDebug('ExpensiveComponent');
268
+
269
+ // Component logic here
270
+ return <div>Expensive content</div>;
271
+ }
272
+ ```
273
+
274
+ ## Hook Debugging
275
+
276
+ ### 1. Authentication Hook Debugging
277
+
278
+ ```typescript
279
+ // hooks/useAuthDebug.ts
280
+ import { useUnifiedAuth } from '@jmruthers/pace-core';
281
+
282
+ export function useAuthDebug() {
283
+ const auth = useUnifiedAuth();
284
+
285
+ useEffect(() => {
286
+ if (process.env.NODE_ENV === 'development') {
287
+ console.log('Auth state changed:', {
288
+ user: auth.user,
289
+ loading: auth.loading,
290
+ error: auth.error,
291
+ isAuthenticated: !!auth.user,
292
+ });
293
+ }
294
+ }, [auth.user, auth.loading, auth.error]);
295
+
296
+ // Debug authentication errors
297
+ useEffect(() => {
298
+ if (auth.error) {
299
+ console.error('Authentication error:', auth.error);
300
+
301
+ // Log additional context
302
+ console.log('Auth error context:', {
303
+ timestamp: new Date().toISOString(),
304
+ userAgent: navigator.userAgent,
305
+ url: window.location.href,
306
+ });
307
+ }
308
+ }, [auth.error]);
309
+
310
+ return auth;
311
+ }
312
+
313
+ // Usage
314
+ function AuthDebugger() {
315
+ const auth = useAuthDebug();
316
+
317
+ if (auth.loading) return <div>Loading auth...</div>;
318
+ if (auth.error) return <div>Auth error: {auth.error}</div>;
319
+ if (!auth.user) return <div>Not authenticated</div>;
320
+
321
+ return <div>Authenticated as: {auth.user.email}</div>;
322
+ }
323
+ ```
324
+
325
+ ### 2. RBAC Hook Debugging
326
+
327
+ ```typescript
328
+ // hooks/useRBACDebug.ts
329
+ import { useRBAC } from '@jmruthers/pace-core';
330
+
331
+ export function useRBACDebug() {
332
+ const rbac = useRBAC();
333
+
334
+ useEffect(() => {
335
+ if (process.env.NODE_ENV === 'development') {
336
+ console.log('RBAC state:', {
337
+ permissions: rbac.permissions,
338
+ roles: rbac.roles,
339
+ loading: rbac.loading,
340
+ error: rbac.error,
341
+ });
342
+ }
343
+ }, [rbac.permissions, rbac.roles, rbac.loading, rbac.error]);
344
+
345
+ // Debug permission checks
346
+ const debugHasPermission = useCallback((permission: string) => {
347
+ const hasPermission = rbac.hasPermission(permission);
348
+
349
+ if (process.env.NODE_ENV === 'development') {
350
+ console.log(`Permission check: ${permission} = ${hasPermission}`, {
351
+ userPermissions: rbac.permissions,
352
+ userRoles: rbac.roles,
353
+ });
354
+ }
355
+
356
+ return hasPermission;
357
+ }, [rbac]);
358
+
359
+ return {
360
+ ...rbac,
361
+ hasPermission: debugHasPermission,
362
+ };
363
+ }
364
+
365
+ // Usage
366
+ function PermissionDebugger() {
367
+ const rbac = useRBACDebug();
368
+
369
+ const canReadUsers = rbac.hasPermission('read:users');
370
+ const canWriteEvents = rbac.hasPermission('write:events');
371
+
372
+ return (
373
+ <div>
374
+ <div>Can read users: {canReadUsers ? 'Yes' : 'No'}</div>
375
+ <div>Can write events: {canWriteEvents ? 'Yes' : 'No'}</div>
376
+ </div>
377
+ );
378
+ }
379
+ ```
380
+
381
+ ### 3. Event Hook Debugging
382
+
383
+ ```typescript
384
+ // hooks/useEventDebug.ts
385
+ import { useEvents } from '@jmruthers/pace-core';
386
+
387
+ export function useEventDebug() {
388
+ const events = useEvents();
389
+
390
+ useEffect(() => {
391
+ if (process.env.NODE_ENV === 'development') {
392
+ console.log('Events state:', {
393
+ events: events.events,
394
+ loading: events.loading,
395
+ error: events.error,
396
+ selectedEvent: events.selectedEvent,
397
+ count: events.events?.length || 0,
398
+ });
399
+ }
400
+ }, [events.events, events.loading, events.error, events.selectedEvent]);
401
+
402
+ // Debug event operations
403
+ const debugSetSelectedEvent = useCallback((event: any) => {
404
+ if (process.env.NODE_ENV === 'development') {
405
+ console.log('Setting selected event:', event);
406
+ }
407
+ events.setSelectedEvent(event);
408
+ }, [events.setSelectedEvent]);
409
+
410
+ const debugRefreshEvents = useCallback(async () => {
411
+ if (process.env.NODE_ENV === 'development') {
412
+ console.log('Refreshing events...');
413
+ }
414
+
415
+ try {
416
+ await events.refreshEvents();
417
+ console.log('Events refreshed successfully');
418
+ } catch (error) {
419
+ console.error('Failed to refresh events:', error);
420
+ }
421
+ }, [events.refreshEvents]);
422
+
423
+ return {
424
+ ...events,
425
+ setSelectedEvent: debugSetSelectedEvent,
426
+ refreshEvents: debugRefreshEvents,
427
+ };
428
+ }
429
+ ```
430
+
431
+ ## API Debugging
432
+
433
+ ### 1. Supabase Debugging
434
+
435
+ ```typescript
436
+ // utils/supabaseDebugger.ts
437
+ import { useSupabase } from '@jmruthers/pace-core';
438
+
439
+ export function useSupabaseDebug() {
440
+ const { supabase } = useSupabase();
441
+
442
+ // Debug Supabase queries
443
+ const debugQuery = useCallback(async (table: string, query: any) => {
444
+ if (process.env.NODE_ENV === 'development') {
445
+ console.log(`Supabase query to ${table}:`, query);
446
+ }
447
+
448
+ try {
449
+ const result = await supabase.from(table).select('*');
450
+
451
+ if (process.env.NODE_ENV === 'development') {
452
+ console.log(`Query result for ${table}:`, result);
453
+ }
454
+
455
+ return result;
456
+ } catch (error) {
457
+ console.error(`Query error for ${table}:`, error);
458
+ throw error;
459
+ }
460
+ }, [supabase]);
461
+
462
+ // Debug authentication
463
+ const debugAuth = useCallback(async (action: string, credentials: any) => {
464
+ if (process.env.NODE_ENV === 'development') {
465
+ console.log(`Auth action: ${action}`, credentials);
466
+ }
467
+
468
+ try {
469
+ let result;
470
+
471
+ switch (action) {
472
+ case 'signIn':
473
+ result = await supabase.auth.signInWithPassword(credentials);
474
+ break;
475
+ case 'signUp':
476
+ result = await supabase.auth.signUp(credentials);
477
+ break;
478
+ case 'signOut':
479
+ result = await supabase.auth.signOut();
480
+ break;
481
+ default:
482
+ throw new Error(`Unknown auth action: ${action}`);
483
+ }
484
+
485
+ if (process.env.NODE_ENV === 'development') {
486
+ console.log(`Auth result for ${action}:`, result);
487
+ }
488
+
489
+ return result;
490
+ } catch (error) {
491
+ console.error(`Auth error for ${action}:`, error);
492
+ throw error;
493
+ }
494
+ }, [supabase]);
495
+
496
+ return {
497
+ supabase,
498
+ debugQuery,
499
+ debugAuth,
500
+ };
501
+ }
502
+ ```
503
+
504
+ ### 2. Network Request Debugging
505
+
506
+ ```typescript
507
+ // utils/networkDebugger.ts
508
+ export function debugNetworkRequest(url: string, options: RequestInit) {
509
+ if (process.env.NODE_ENV === 'development') {
510
+ console.log('Network request:', {
511
+ url,
512
+ method: options.method || 'GET',
513
+ headers: options.headers,
514
+ body: options.body,
515
+ });
516
+ }
517
+ }
518
+
519
+ export function debugNetworkResponse(url: string, response: Response, data?: any) {
520
+ if (process.env.NODE_ENV === 'development') {
521
+ console.log('Network response:', {
522
+ url,
523
+ status: response.status,
524
+ statusText: response.statusText,
525
+ headers: Object.fromEntries(response.headers.entries()),
526
+ data,
527
+ });
528
+ }
529
+ }
530
+
531
+ // Custom fetch with debugging
532
+ export async function debugFetch(url: string, options: RequestInit = {}) {
533
+ debugNetworkRequest(url, options);
534
+
535
+ try {
536
+ const response = await fetch(url, options);
537
+ const data = await response.json();
538
+
539
+ debugNetworkResponse(url, response, data);
540
+
541
+ if (!response.ok) {
542
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
543
+ }
544
+
545
+ return { response, data };
546
+ } catch (error) {
547
+ console.error('Network request failed:', {
548
+ url,
549
+ error: error.message,
550
+ });
551
+ throw error;
552
+ }
553
+ }
554
+ ```
555
+
556
+ ## Performance Debugging
557
+
558
+ ### 1. Memory Leak Detection
559
+
560
+ ```typescript
561
+ // utils/memoryDebugger.ts
562
+ export function useMemoryLeakDetection(componentName: string) {
563
+ useEffect(() => {
564
+ const initialMemory = performance.memory?.usedJSHeapSize || 0;
565
+
566
+ return () => {
567
+ const finalMemory = performance.memory?.usedJSHeapSize || 0;
568
+ const memoryIncrease = finalMemory - initialMemory;
569
+
570
+ if (memoryIncrease > 1024 * 1024) { // 1MB threshold
571
+ console.warn(`${componentName} may have a memory leak:`, {
572
+ memoryIncrease: `${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`,
573
+ initialMemory: `${(initialMemory / 1024 / 1024).toFixed(2)}MB`,
574
+ finalMemory: `${(finalMemory / 1024 / 1024).toFixed(2)}MB`,
575
+ });
576
+ }
577
+ };
578
+ }, [componentName]);
579
+ }
580
+
581
+ // Usage
582
+ function MyComponent() {
583
+ useMemoryLeakDetection('MyComponent');
584
+
585
+ // Component logic
586
+ return <div>Content</div>;
587
+ }
588
+ ```
589
+
590
+ ### 2. Performance Monitoring
591
+
592
+ ```typescript
593
+ // utils/performanceDebugger.ts
594
+ export function usePerformanceDebug(componentName: string) {
595
+ const renderStartTime = useRef<number>();
596
+
597
+ useEffect(() => {
598
+ renderStartTime.current = performance.now();
599
+
600
+ return () => {
601
+ if (renderStartTime.current) {
602
+ const renderTime = performance.now() - renderStartTime.current;
603
+
604
+ if (renderTime > 16) { // 60fps threshold
605
+ console.warn(`${componentName} took ${renderTime.toFixed(2)}ms to render`);
606
+ }
607
+ }
608
+ };
609
+ });
610
+
611
+ // Track re-renders
612
+ const renderCount = useRef(0);
613
+ useEffect(() => {
614
+ renderCount.current += 1;
615
+
616
+ if (renderCount.current > 10) {
617
+ console.warn(`${componentName} has rendered ${renderCount.current} times`);
618
+ }
619
+ });
620
+ }
621
+
622
+ // Performance observer for custom metrics
623
+ export function setupPerformanceObserver() {
624
+ if (typeof PerformanceObserver !== 'undefined') {
625
+ const observer = new PerformanceObserver((list) => {
626
+ for (const entry of list.getEntries()) {
627
+ if (entry.entryType === 'measure') {
628
+ console.log('Performance measure:', {
629
+ name: entry.name,
630
+ duration: entry.duration,
631
+ startTime: entry.startTime,
632
+ });
633
+ }
634
+ }
635
+ });
636
+
637
+ observer.observe({ entryTypes: ['measure'] });
638
+ }
639
+ }
640
+ ```
641
+
642
+ ## Error Debugging
643
+
644
+ ### 1. Error Tracking and Analysis
645
+
646
+ ```typescript
647
+ // utils/errorDebugger.ts
648
+ export class ErrorDebugger {
649
+ private static errors: Error[] = [];
650
+ private static maxErrors = 100;
651
+
652
+ static trackError(error: Error, context?: Record<string, any>) {
653
+ const errorInfo = {
654
+ error,
655
+ context,
656
+ timestamp: new Date().toISOString(),
657
+ stack: error.stack,
658
+ userAgent: navigator.userAgent,
659
+ url: window.location.href,
660
+ };
661
+
662
+ this.errors.push(error);
663
+
664
+ // Keep only the last maxErrors
665
+ if (this.errors.length > this.maxErrors) {
666
+ this.errors.shift();
667
+ }
668
+
669
+ if (process.env.NODE_ENV === 'development') {
670
+ console.error('Error tracked:', errorInfo);
671
+ }
672
+
673
+ return errorInfo;
674
+ }
675
+
676
+ static getErrors() {
677
+ return this.errors;
678
+ }
679
+
680
+ static clearErrors() {
681
+ this.errors = [];
682
+ }
683
+
684
+ static getErrorStats() {
685
+ const errorTypes = this.errors.reduce((acc, error) => {
686
+ const type = error.constructor.name;
687
+ acc[type] = (acc[type] || 0) + 1;
688
+ return acc;
689
+ }, {} as Record<string, number>);
690
+
691
+ return {
692
+ totalErrors: this.errors.length,
693
+ errorTypes,
694
+ recentErrors: this.errors.slice(-10),
695
+ };
696
+ }
697
+ }
698
+
699
+ // Global error handler
700
+ export function setupGlobalErrorHandler() {
701
+ window.addEventListener('error', (event) => {
702
+ ErrorDebugger.trackError(event.error, {
703
+ filename: event.filename,
704
+ lineno: event.lineno,
705
+ colno: event.colno,
706
+ });
707
+ });
708
+
709
+ window.addEventListener('unhandledrejection', (event) => {
710
+ ErrorDebugger.trackError(new Error(event.reason), {
711
+ type: 'unhandledrejection',
712
+ });
713
+ });
714
+ }
715
+ ```
716
+
717
+ ### 2. Debug Console
718
+
719
+ ```typescript
720
+ // utils/debugConsole.ts
721
+ export class DebugConsole {
722
+ private static logs: any[] = [];
723
+ private static maxLogs = 1000;
724
+
725
+ static log(message: string, data?: any) {
726
+ const logEntry = {
727
+ message,
728
+ data,
729
+ timestamp: new Date().toISOString(),
730
+ level: 'log',
731
+ };
732
+
733
+ this.logs.push(logEntry);
734
+
735
+ if (this.logs.length > this.maxLogs) {
736
+ this.logs.shift();
737
+ }
738
+
739
+ if (process.env.NODE_ENV === 'development') {
740
+ console.log(message, data);
741
+ }
742
+ }
743
+
744
+ static warn(message: string, data?: any) {
745
+ const logEntry = {
746
+ message,
747
+ data,
748
+ timestamp: new Date().toISOString(),
749
+ level: 'warn',
750
+ };
751
+
752
+ this.logs.push(logEntry);
753
+
754
+ if (process.env.NODE_ENV === 'development') {
755
+ console.warn(message, data);
756
+ }
757
+ }
758
+
759
+ static error(message: string, error?: Error, data?: any) {
760
+ const logEntry = {
761
+ message,
762
+ error,
763
+ data,
764
+ timestamp: new Date().toISOString(),
765
+ level: 'error',
766
+ };
767
+
768
+ this.logs.push(logEntry);
769
+
770
+ if (process.env.NODE_ENV === 'development') {
771
+ console.error(message, error, data);
772
+ }
773
+ }
774
+
775
+ static getLogs() {
776
+ return this.logs;
777
+ }
778
+
779
+ static clearLogs() {
780
+ this.logs = [];
781
+ }
782
+
783
+ static exportLogs() {
784
+ return {
785
+ logs: this.logs,
786
+ errorStats: ErrorDebugger.getErrorStats(),
787
+ timestamp: new Date().toISOString(),
788
+ };
789
+ }
790
+ }
791
+
792
+ // Make debug console available globally in development
793
+ if (process.env.NODE_ENV === 'development') {
794
+ (window as any).debugConsole = DebugConsole;
795
+ (window as any).errorDebugger = ErrorDebugger;
796
+ }
797
+ ```
798
+
799
+ ## Debugging Tools and Utilities
800
+
801
+ ### 1. Debug Panel Component
802
+
803
+ ```typescript
804
+ // components/DebugPanel.tsx
805
+ import { useState } from 'react';
806
+ import { DebugConsole, ErrorDebugger } from '../utils';
807
+
808
+ export function DebugPanel() {
809
+ const [isOpen, setIsOpen] = useState(false);
810
+ const [activeTab, setActiveTab] = useState('logs');
811
+
812
+ if (process.env.NODE_ENV !== 'development') {
813
+ return null;
814
+ }
815
+
816
+ const logs = DebugConsole.getLogs();
817
+ const errorStats = ErrorDebugger.getErrorStats();
818
+
819
+ return (
820
+ <div className="debug-panel">
821
+ <button onClick={() => setIsOpen(!isOpen)}>
822
+ Debug Panel {isOpen ? '▼' : '▲'}
823
+ </button>
824
+
825
+ {isOpen && (
826
+ <div className="debug-content">
827
+ <div className="debug-tabs">
828
+ <button
829
+ className={activeTab === 'logs' ? 'active' : ''}
830
+ onClick={() => setActiveTab('logs')}
831
+ >
832
+ Logs ({logs.length})
833
+ </button>
834
+ <button
835
+ className={activeTab === 'errors' ? 'active' : ''}
836
+ onClick={() => setActiveTab('errors')}
837
+ >
838
+ Errors ({errorStats.totalErrors})
839
+ </button>
840
+ <button
841
+ className={activeTab === 'performance' ? 'active' : ''}
842
+ onClick={() => setActiveTab('performance')}
843
+ >
844
+ Performance
845
+ </button>
846
+ </div>
847
+
848
+ <div className="debug-content-area">
849
+ {activeTab === 'logs' && (
850
+ <div className="logs-tab">
851
+ {logs.slice(-20).map((log, index) => (
852
+ <div key={index} className={`log-entry ${log.level}`}>
853
+ <span className="timestamp">{log.timestamp}</span>
854
+ <span className="message">{log.message}</span>
855
+ {log.data && (
856
+ <pre className="data">{JSON.stringify(log.data, null, 2)}</pre>
857
+ )}
858
+ </div>
859
+ ))}
860
+ </div>
861
+ )}
862
+
863
+ {activeTab === 'errors' && (
864
+ <div className="errors-tab">
865
+ <h3>Error Statistics</h3>
866
+ <pre>{JSON.stringify(errorStats, null, 2)}</pre>
867
+
868
+ <h3>Recent Errors</h3>
869
+ {errorStats.recentErrors.map((error, index) => (
870
+ <div key={index} className="error-entry">
871
+ <div className="error-message">{error.message}</div>
872
+ <div className="error-stack">{error.stack}</div>
873
+ </div>
874
+ ))}
875
+ </div>
876
+ )}
877
+
878
+ {activeTab === 'performance' && (
879
+ <div className="performance-tab">
880
+ <h3>Memory Usage</h3>
881
+ <div>
882
+ Used: {(performance.memory?.usedJSHeapSize || 0) / 1024 / 1024}MB
883
+ </div>
884
+ <div>
885
+ Total: {(performance.memory?.totalJSHeapSize || 0) / 1024 / 1024}MB
886
+ </div>
887
+ <div>
888
+ Limit: {(performance.memory?.jsHeapSizeLimit || 0) / 1024 / 1024}MB
889
+ </div>
890
+ </div>
891
+ )}
892
+ </div>
893
+
894
+ <div className="debug-actions">
895
+ <button onClick={() => DebugConsole.clearLogs()}>Clear Logs</button>
896
+ <button onClick={() => ErrorDebugger.clearErrors()}>Clear Errors</button>
897
+ <button onClick={() => {
898
+ const data = DebugConsole.exportLogs();
899
+ const blob = new Blob([JSON.stringify(data, null, 2)], {
900
+ type: 'application/json',
901
+ });
902
+ const url = URL.createObjectURL(blob);
903
+ const a = document.createElement('a');
904
+ a.href = url;
905
+ a.download = `debug-logs-${new Date().toISOString()}.json`;
906
+ a.click();
907
+ }}>Export Logs</button>
908
+ </div>
909
+ </div>
910
+ )}
911
+ </div>
912
+ );
913
+ }
914
+ ```
915
+
916
+ ### 2. Debug Styles
917
+
918
+ ```css
919
+ /* styles/debug.css */
920
+ .debug-panel {
921
+ position: fixed;
922
+ bottom: 0;
923
+ right: 0;
924
+ width: 400px;
925
+ max-height: 500px;
926
+ background: #1a1a1a;
927
+ color: #fff;
928
+ border: 1px solid #333;
929
+ z-index: 9999;
930
+ font-family: monospace;
931
+ font-size: 12px;
932
+ }
933
+
934
+ .debug-content {
935
+ max-height: 400px;
936
+ overflow: hidden;
937
+ display: flex;
938
+ flex-direction: column;
939
+ }
940
+
941
+ .debug-tabs {
942
+ display: flex;
943
+ border-bottom: 1px solid #333;
944
+ }
945
+
946
+ .debug-tabs button {
947
+ flex: 1;
948
+ padding: 8px;
949
+ background: #2a2a2a;
950
+ border: none;
951
+ color: #fff;
952
+ cursor: pointer;
953
+ }
954
+
955
+ .debug-tabs button.active {
956
+ background: #444;
957
+ }
958
+
959
+ .debug-content-area {
960
+ flex: 1;
961
+ overflow-y: auto;
962
+ padding: 8px;
963
+ }
964
+
965
+ .log-entry {
966
+ margin-bottom: 4px;
967
+ padding: 4px;
968
+ border-radius: 2px;
969
+ }
970
+
971
+ .log-entry.error {
972
+ background: #4a1a1a;
973
+ color: #ff6b6b;
974
+ }
975
+
976
+ .log-entry.warn {
977
+ background: #4a3a1a;
978
+ color: #ffd93d;
979
+ }
980
+
981
+ .log-entry.log {
982
+ background: #1a4a1a;
983
+ color: #6bff6b;
984
+ }
985
+
986
+ .timestamp {
987
+ color: #888;
988
+ margin-right: 8px;
989
+ }
990
+
991
+ .data {
992
+ margin-top: 4px;
993
+ padding: 4px;
994
+ background: #2a2a2a;
995
+ border-radius: 2px;
996
+ font-size: 10px;
997
+ }
998
+
999
+ .error-entry {
1000
+ margin-bottom: 8px;
1001
+ padding: 8px;
1002
+ background: #4a1a1a;
1003
+ border-radius: 4px;
1004
+ }
1005
+
1006
+ .error-message {
1007
+ color: #ff6b6b;
1008
+ font-weight: bold;
1009
+ }
1010
+
1011
+ .error-stack {
1012
+ margin-top: 4px;
1013
+ font-size: 10px;
1014
+ color: #ccc;
1015
+ }
1016
+
1017
+ .debug-actions {
1018
+ padding: 8px;
1019
+ border-top: 1px solid #333;
1020
+ display: flex;
1021
+ gap: 8px;
1022
+ }
1023
+
1024
+ .debug-actions button {
1025
+ padding: 4px 8px;
1026
+ background: #444;
1027
+ border: none;
1028
+ color: #fff;
1029
+ cursor: pointer;
1030
+ border-radius: 2px;
1031
+ }
1032
+
1033
+ .debug-actions button:hover {
1034
+ background: #555;
1035
+ }
1036
+ ```
1037
+
1038
+ ## Debugging Best Practices
1039
+
1040
+ ### 1. Debugging Checklist
1041
+
1042
+ - [ ] Enable React DevTools
1043
+ - [ ] Use console.log strategically
1044
+ - [ ] Implement error boundaries
1045
+ - [ ] Track component renders
1046
+ - [ ] Monitor hook dependencies
1047
+ - [ ] Debug authentication flow
1048
+ - [ ] Check permission logic
1049
+ - [ ] Monitor API calls
1050
+ - [ ] Track performance metrics
1051
+ - [ ] Use debug panels in development
1052
+
1053
+ ### 2. Common Debugging Scenarios
1054
+
1055
+ ```typescript
1056
+ // Debugging authentication issues
1057
+ function debugAuthFlow() {
1058
+ const auth = useUnifiedAuth();
1059
+
1060
+ useEffect(() => {
1061
+ console.log('Auth state:', {
1062
+ user: auth.user,
1063
+ loading: auth.loading,
1064
+ error: auth.error,
1065
+ });
1066
+ }, [auth.user, auth.loading, auth.error]);
1067
+
1068
+ // Debug specific auth actions
1069
+ const debugSignIn = async (credentials: any) => {
1070
+ console.log('Attempting sign in with:', credentials);
1071
+ try {
1072
+ const result = await auth.signIn(credentials);
1073
+ console.log('Sign in result:', result);
1074
+ } catch (error) {
1075
+ console.error('Sign in failed:', error);
1076
+ }
1077
+ };
1078
+ }
1079
+
1080
+ // Debugging permission issues
1081
+ function debugPermissions() {
1082
+ const rbac = useRBAC();
1083
+
1084
+ useEffect(() => {
1085
+ console.log('RBAC state:', {
1086
+ permissions: rbac.permissions,
1087
+ roles: rbac.roles,
1088
+ });
1089
+ }, [rbac.permissions, rbac.roles]);
1090
+
1091
+ // Test specific permissions
1092
+ const testPermission = (permission: string) => {
1093
+ const hasPermission = rbac.hasPermission(permission);
1094
+ console.log(`Permission test: ${permission} = ${hasPermission}`);
1095
+ return hasPermission;
1096
+ };
1097
+ }
1098
+
1099
+ // Debugging API issues
1100
+ function debugAPI() {
1101
+ const { supabase } = useSupabase();
1102
+
1103
+ const debugQuery = async (table: string) => {
1104
+ console.log(`Querying ${table}...`);
1105
+ try {
1106
+ const { data, error } = await supabase.from(table).select('*');
1107
+ console.log(`${table} query result:`, { data, error });
1108
+ return { data, error };
1109
+ } catch (error) {
1110
+ console.error(`${table} query failed:`, error);
1111
+ throw error;
1112
+ }
1113
+ };
1114
+ }
1115
+ ```
1116
+
1117
+ For more information about debugging your application, see the [Common Issues Guide](./common-issues.md) and [Migration Guide](./migration.md).