create-fluxstack 1.8.1 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/.env.example +19 -0
  2. package/README.md +653 -272
  3. package/app/client/SIMPLIFICATION.md +140 -0
  4. package/app/client/frontend-only.ts +1 -1
  5. package/app/client/src/App.tsx +148 -283
  6. package/app/client/src/index.css +5 -20
  7. package/app/client/src/lib/eden-api.ts +53 -220
  8. package/app/client/src/main.tsx +2 -3
  9. package/app/server/controllers/users.controller.ts +57 -31
  10. package/app/server/index.ts +5 -2
  11. package/app/server/live/register-components.ts +18 -7
  12. package/app/server/routes/env-test.ts +53 -2
  13. package/app/server/routes/index.ts +1 -8
  14. package/app/server/routes/users.routes.ts +192 -91
  15. package/config/fluxstack.config.ts +2 -2
  16. package/config/plugins.config.ts +22 -1
  17. package/core/build/bundler.ts +199 -55
  18. package/core/build/flux-plugins-generator.ts +5 -5
  19. package/core/build/index.ts +4 -0
  20. package/core/build/live-components-generator.ts +15 -12
  21. package/core/cli/command-registry.ts +4 -14
  22. package/core/cli/commands/plugin-deps.ts +8 -8
  23. package/core/cli/generators/component.ts +3 -3
  24. package/core/cli/generators/controller.ts +4 -4
  25. package/core/cli/generators/index.ts +8 -8
  26. package/core/cli/generators/interactive.ts +4 -4
  27. package/core/cli/generators/plugin.ts +9 -9
  28. package/core/cli/generators/prompts.ts +1 -1
  29. package/core/cli/generators/route.ts +27 -11
  30. package/core/cli/generators/service.ts +5 -5
  31. package/core/cli/generators/template-engine.ts +1 -1
  32. package/core/cli/generators/types.ts +1 -1
  33. package/core/cli/index.ts +258 -193
  34. package/core/cli/plugin-discovery.ts +3 -3
  35. package/core/client/hooks/index.ts +2 -2
  36. package/core/client/hooks/state-validator.ts +1 -1
  37. package/core/client/hooks/useAuth.ts +1 -1
  38. package/core/client/hooks/useChunkedUpload.ts +1 -1
  39. package/core/client/hooks/useHybridLiveComponent.ts +1 -1
  40. package/core/client/hooks/useWebSocket.ts +1 -1
  41. package/core/config/env.ts +1 -1
  42. package/core/config/runtime-config.ts +5 -5
  43. package/core/config/schema.ts +9 -0
  44. package/core/framework/server.ts +30 -15
  45. package/core/framework/types.ts +2 -2
  46. package/core/live/ComponentRegistry.ts +1 -1
  47. package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
  48. package/core/plugins/built-in/live-components/index.ts +1 -1
  49. package/core/plugins/built-in/monitoring/index.ts +65 -161
  50. package/core/plugins/built-in/static/index.ts +18 -47
  51. package/core/plugins/built-in/swagger/index.ts +301 -231
  52. package/core/plugins/built-in/vite/index.ts +74 -109
  53. package/core/plugins/config.ts +2 -2
  54. package/core/plugins/dependency-manager.ts +2 -2
  55. package/core/plugins/discovery.ts +1 -1
  56. package/core/plugins/executor.ts +2 -2
  57. package/core/plugins/manager.ts +19 -4
  58. package/core/plugins/module-resolver.ts +1 -1
  59. package/core/plugins/registry.ts +3 -3
  60. package/core/plugins/types.ts +147 -5
  61. package/core/server/framework.ts +2 -2
  62. package/core/server/live/ComponentRegistry.ts +9 -26
  63. package/core/server/live/FileUploadManager.ts +1 -1
  64. package/core/server/live/auto-generated-components.ts +26 -0
  65. package/core/server/live/websocket-plugin.ts +211 -19
  66. package/core/server/middleware/errorHandling.ts +1 -1
  67. package/core/server/middleware/index.ts +4 -4
  68. package/core/server/plugins/database.ts +1 -2
  69. package/core/server/plugins/static-files-plugin.ts +259 -231
  70. package/core/server/plugins/swagger.ts +1 -1
  71. package/core/server/services/BaseService.ts +1 -1
  72. package/core/server/services/ServiceContainer.ts +1 -1
  73. package/core/server/services/index.ts +4 -4
  74. package/core/server/standalone.ts +16 -1
  75. package/core/testing/index.ts +1 -1
  76. package/core/testing/setup.ts +1 -1
  77. package/core/types/build.ts +21 -0
  78. package/core/utils/logger/startup-banner.ts +7 -33
  79. package/core/utils/version.ts +1 -1
  80. package/create-fluxstack.ts +73 -30
  81. package/package.json +3 -2
  82. package/plugins/crypto-auth/index.ts +52 -47
  83. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  84. package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
  85. package/tsconfig.json +2 -1
  86. package/vitest.config.ts +11 -2
  87. package/app/client/src/App.css +0 -883
  88. package/app/client/src/components/ErrorBoundary.tsx +0 -107
  89. package/app/client/src/components/ErrorDisplay.css +0 -365
  90. package/app/client/src/components/ErrorDisplay.tsx +0 -258
  91. package/app/client/src/components/FluxStackConfig.tsx +0 -1321
  92. package/app/client/src/components/HybridLiveCounter.tsx +0 -140
  93. package/app/client/src/components/LiveClock.tsx +0 -286
  94. package/app/client/src/components/MainLayout.tsx +0 -388
  95. package/app/client/src/components/SidebarNavigation.tsx +0 -391
  96. package/app/client/src/components/StateDemo.tsx +0 -178
  97. package/app/client/src/components/SystemMonitor.tsx +0 -1044
  98. package/app/client/src/components/UserProfile.tsx +0 -809
  99. package/app/client/src/hooks/useAuth.ts +0 -39
  100. package/app/client/src/hooks/useNotifications.ts +0 -56
  101. package/app/client/src/lib/errors.ts +0 -340
  102. package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
  103. package/app/client/src/lib/index.ts +0 -45
  104. package/app/client/src/pages/ApiDocs.tsx +0 -182
  105. package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
  106. package/app/client/src/pages/Demo.tsx +0 -174
  107. package/app/client/src/pages/HybridLive.tsx +0 -263
  108. package/app/client/src/pages/Overview.tsx +0 -155
  109. package/app/client/src/store/README.md +0 -43
  110. package/app/client/src/store/index.ts +0 -16
  111. package/app/client/src/store/slices/uiSlice.ts +0 -151
  112. package/app/client/src/store/slices/userSlice.ts +0 -161
  113. package/app/client/src/test/README.md +0 -257
  114. package/app/client/src/test/setup.ts +0 -70
  115. package/app/client/src/test/types.ts +0 -12
  116. package/app/server/live/CounterComponent.ts +0 -191
  117. package/app/server/live/FluxStackConfig.ts +0 -534
  118. package/app/server/live/SidebarNavigation.ts +0 -157
  119. package/app/server/live/SystemMonitor.ts +0 -595
  120. package/app/server/live/SystemMonitorIntegration.ts +0 -151
  121. package/app/server/live/UserProfileComponent.ts +0 -141
  122. package/app/server/middleware/auth.ts +0 -136
  123. package/app/server/middleware/errorHandling.ts +0 -252
  124. package/app/server/middleware/index.ts +0 -10
  125. package/app/server/middleware/rateLimit.ts +0 -193
  126. package/app/server/middleware/requestLogging.ts +0 -215
  127. package/app/server/middleware/validation.ts +0 -270
  128. package/app/server/routes/config.ts +0 -145
  129. package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
  130. package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
  131. package/app/server/routes/exemplo-posts.routes.ts +0 -161
  132. package/app/server/routes/upload.ts +0 -92
  133. package/app/server/services/NotificationService.ts +0 -302
  134. package/app/server/services/UserService.ts +0 -222
  135. package/app/server/services/index.ts +0 -46
  136. package/app/server/types/index.ts +0 -1
@@ -1,391 +0,0 @@
1
- // 🔥 Sidebar Navigation Component
2
-
3
- import { useHybridLiveComponent } from '@/core/client'
4
- import {
5
- FaHome,
6
- FaUser,
7
- FaCog,
8
- FaFolder,
9
- FaServer,
10
- FaBars,
11
- FaTimes,
12
- FaMoon,
13
- FaSun,
14
- FaBell,
15
- FaTools
16
- } from 'react-icons/fa'
17
-
18
- export interface SidebarNavigationState {
19
- currentPage: 'dashboard' | 'profile' | 'settings' | 'files' | 'analytics' | 'config'
20
- isCollapsed: boolean
21
- theme: 'light' | 'dark'
22
- notifications: {
23
- profile: number
24
- settings: number
25
- files: number
26
- analytics: number
27
- config: number
28
- }
29
- lastNavigation: number
30
- }
31
-
32
- const initialState: SidebarNavigationState = {
33
- currentPage: 'dashboard',
34
- isCollapsed: false,
35
- theme: 'light',
36
- notifications: {
37
- profile: 0,
38
- settings: 0,
39
- files: 0,
40
- analytics: 0,
41
- config: 0
42
- },
43
- lastNavigation: Date.now()
44
- }
45
-
46
- interface SidebarNavigationProps {
47
- onPageChange: (page: string) => void
48
- }
49
-
50
- export function SidebarNavigation({ onPageChange }: SidebarNavigationProps) {
51
- const { state, call, connected, status, error } = useHybridLiveComponent<SidebarNavigationState>(
52
- 'SidebarNavigation',
53
- initialState,
54
- { debug: true }
55
- )
56
-
57
- // Show loading state
58
- if (!connected || status !== 'synced') {
59
- const getStatusMessage = () => {
60
- switch (status) {
61
- case 'connecting':
62
- return '🔄 Conectando navegação...'
63
- case 'reconnecting':
64
- return '🔄 Reconectando menu...'
65
- case 'mounting':
66
- return '🚀 Carregando menu...'
67
- case 'loading':
68
- return '⏳ Carregando...'
69
- case 'error':
70
- return '❌ Erro na navegação'
71
- default:
72
- return '🔄 Preparando menu...'
73
- }
74
- }
75
-
76
- return (
77
- <div style={{
78
- width: '280px',
79
- height: '100vh',
80
- background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
81
- color: 'white',
82
- padding: '2rem',
83
- display: 'flex',
84
- flexDirection: 'column',
85
- alignItems: 'center',
86
- justifyContent: 'center',
87
- textAlign: 'center'
88
- }}>
89
- <FaBars size={32} style={{ marginBottom: '1rem' }} />
90
- <p>{getStatusMessage()}</p>
91
- {error && (
92
- <p style={{ fontSize: '0.9rem', marginTop: '0.5rem', opacity: 0.8 }}>
93
- {error}
94
- </p>
95
- )}
96
- </div>
97
- )
98
- }
99
-
100
- const isDark = state.theme === 'dark'
101
- const sidebarWidth = state.isCollapsed ? '80px' : '280px'
102
-
103
- const menuItems = [
104
- {
105
- id: 'dashboard',
106
- label: 'Dashboard',
107
- icon: FaHome,
108
- notifications: 0
109
- },
110
- {
111
- id: 'profile',
112
- label: 'Perfil',
113
- icon: FaUser,
114
- notifications: state.notifications.profile
115
- },
116
- {
117
- id: 'settings',
118
- label: 'Configurações',
119
- icon: FaCog,
120
- notifications: state.notifications.settings
121
- },
122
- {
123
- id: 'files',
124
- label: 'Arquivos',
125
- icon: FaFolder,
126
- notifications: state.notifications.files
127
- },
128
- {
129
- id: 'analytics',
130
- label: 'Monitoramento',
131
- icon: FaServer,
132
- notifications: state.notifications.analytics
133
- },
134
- {
135
- id: 'config',
136
- label: 'FluxStack Config',
137
- icon: FaTools,
138
- notifications: state.notifications.config
139
- }
140
- ]
141
-
142
- const handleNavigate = async (page: string) => {
143
- try {
144
- await call('navigateTo', { page })
145
- onPageChange(page)
146
- } catch (error) {
147
- console.error('Navigation error:', error)
148
- }
149
- }
150
-
151
- const handleToggleSidebar = async () => {
152
- try {
153
- await call('toggleSidebar')
154
- } catch (error) {
155
- console.error('Toggle sidebar error:', error)
156
- }
157
- }
158
-
159
- const handleToggleTheme = async () => {
160
- try {
161
- const newTheme = state.theme === 'light' ? 'dark' : 'light'
162
- await call('setTheme', { theme: newTheme })
163
- } catch (error) {
164
- console.error('Theme toggle error:', error)
165
- }
166
- }
167
-
168
- const handleClearNotifications = async () => {
169
- try {
170
- await call('clearAllNotifications')
171
- } catch (error) {
172
- console.error('Clear notifications error:', error)
173
- }
174
- }
175
-
176
- return (
177
- <div style={{
178
- width: sidebarWidth,
179
- height: '100vh',
180
- backgroundColor: isDark ? '#1f2937' : '#ffffff',
181
- borderRight: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,
182
- display: 'flex',
183
- flexDirection: 'column',
184
- transition: 'width 0.3s ease',
185
- overflow: 'hidden',
186
- boxShadow: '2px 0 10px rgba(0, 0, 0, 0.1)'
187
- }}>
188
- {/* Header */}
189
- <div style={{
190
- padding: '1.5rem',
191
- borderBottom: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,
192
- display: 'flex',
193
- alignItems: 'center',
194
- justifyContent: 'space-between'
195
- }}>
196
- {!state.isCollapsed && (
197
- <h2 style={{
198
- color: isDark ? '#f9fafb' : '#111827',
199
- margin: 0,
200
- fontSize: '1.25rem',
201
- fontWeight: 'bold'
202
- }}>
203
- 🔥 FluxStack
204
- </h2>
205
- )}
206
-
207
- <button
208
- onClick={handleToggleSidebar}
209
- style={{
210
- background: 'none',
211
- border: 'none',
212
- color: isDark ? '#9ca3af' : '#6b7280',
213
- cursor: 'pointer',
214
- padding: '0.5rem',
215
- borderRadius: '0.5rem',
216
- display: 'flex',
217
- alignItems: 'center',
218
- justifyContent: 'center',
219
- fontSize: '1.1rem'
220
- }}
221
- >
222
- {state.isCollapsed ? <FaBars /> : <FaTimes />}
223
- </button>
224
- </div>
225
-
226
- {/* Navigation Menu */}
227
- <nav style={{
228
- flex: 1,
229
- padding: '1rem',
230
- display: 'flex',
231
- flexDirection: 'column',
232
- gap: '0.5rem'
233
- }}>
234
- {menuItems.map((item) => {
235
- const Icon = item.icon
236
- const isActive = state.currentPage === item.id
237
- const hasNotifications = item.notifications > 0
238
-
239
- return (
240
- <button
241
- key={item.id}
242
- onClick={() => handleNavigate(item.id)}
243
- style={{
244
- display: 'flex',
245
- alignItems: 'center',
246
- gap: '1rem',
247
- padding: '1rem',
248
- borderRadius: '0.75rem',
249
- border: 'none',
250
- cursor: 'pointer',
251
- transition: 'all 0.2s ease',
252
- backgroundColor: isActive
253
- ? (isDark ? '#3b82f6' : '#2563eb')
254
- : 'transparent',
255
- color: isActive
256
- ? '#ffffff'
257
- : (isDark ? '#d1d5db' : '#374151'),
258
- position: 'relative',
259
- justifyContent: state.isCollapsed ? 'center' : 'flex-start',
260
- minHeight: '3rem'
261
- }}
262
- onMouseEnter={(e) => {
263
- if (!isActive) {
264
- e.currentTarget.style.backgroundColor = isDark ? '#374151' : '#f3f4f6'
265
- }
266
- }}
267
- onMouseLeave={(e) => {
268
- if (!isActive) {
269
- e.currentTarget.style.backgroundColor = 'transparent'
270
- }
271
- }}
272
- >
273
- <Icon size={20} />
274
-
275
- {!state.isCollapsed && (
276
- <>
277
- <span style={{
278
- fontSize: '0.95rem',
279
- fontWeight: isActive ? 'bold' : 'normal'
280
- }}>
281
- {item.label}
282
- </span>
283
-
284
- {hasNotifications && (
285
- <span style={{
286
- backgroundColor: '#ef4444',
287
- color: 'white',
288
- borderRadius: '50%',
289
- width: '20px',
290
- height: '20px',
291
- display: 'flex',
292
- alignItems: 'center',
293
- justifyContent: 'center',
294
- fontSize: '0.75rem',
295
- fontWeight: 'bold',
296
- marginLeft: 'auto'
297
- }}>
298
- {item.notifications}
299
- </span>
300
- )}
301
- </>
302
- )}
303
-
304
- {state.isCollapsed && hasNotifications && (
305
- <div style={{
306
- position: 'absolute',
307
- top: '0.5rem',
308
- right: '0.5rem',
309
- backgroundColor: '#ef4444',
310
- borderRadius: '50%',
311
- width: '12px',
312
- height: '12px',
313
- border: '2px solid white'
314
- }} />
315
- )}
316
- </button>
317
- )
318
- })}
319
- </nav>
320
-
321
- {/* Footer Actions */}
322
- <div style={{
323
- padding: '1rem',
324
- borderTop: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,
325
- display: 'flex',
326
- flexDirection: state.isCollapsed ? 'column' : 'row',
327
- gap: '0.5rem'
328
- }}>
329
- {/* Theme Toggle */}
330
- <button
331
- onClick={handleToggleTheme}
332
- style={{
333
- display: 'flex',
334
- alignItems: 'center',
335
- justifyContent: 'center',
336
- gap: state.isCollapsed ? 0 : '0.5rem',
337
- padding: '0.75rem',
338
- borderRadius: '0.5rem',
339
- border: 'none',
340
- cursor: 'pointer',
341
- backgroundColor: isDark ? '#374151' : '#f3f4f6',
342
- color: isDark ? '#d1d5db' : '#374151',
343
- flex: state.isCollapsed ? 'none' : 1,
344
- fontSize: '0.9rem'
345
- }}
346
- >
347
- {isDark ? <FaSun /> : <FaMoon />}
348
- {!state.isCollapsed && (
349
- <span>{isDark ? 'Claro' : 'Escuro'}</span>
350
- )}
351
- </button>
352
-
353
- {/* Clear Notifications */}
354
- {!state.isCollapsed && (
355
- <button
356
- onClick={handleClearNotifications}
357
- style={{
358
- display: 'flex',
359
- alignItems: 'center',
360
- justifyContent: 'center',
361
- gap: '0.5rem',
362
- padding: '0.75rem',
363
- borderRadius: '0.5rem',
364
- border: 'none',
365
- cursor: 'pointer',
366
- backgroundColor: isDark ? '#374151' : '#f3f4f6',
367
- color: isDark ? '#d1d5db' : '#374151',
368
- flex: 1,
369
- fontSize: '0.9rem'
370
- }}
371
- >
372
- <FaBell />
373
- <span>Limpar</span>
374
- </button>
375
- )}
376
- </div>
377
-
378
- {/* Connection Status (when collapsed) */}
379
- {state.isCollapsed && (
380
- <div style={{
381
- padding: '0.5rem',
382
- textAlign: 'center',
383
- fontSize: '0.75rem',
384
- color: isDark ? '#6b7280' : '#9ca3af'
385
- }}>
386
- {connected ? '🟢' : '🔴'}
387
- </div>
388
- )}
389
- </div>
390
- )
391
- }
@@ -1,178 +0,0 @@
1
- /**
2
- * State Management Demo Component
3
- * Demonstrates the usage of FluxStack state management system with Zustand
4
- */
5
-
6
- import React from 'react'
7
- import { useNotifications } from '../hooks/useNotifications'
8
- import { useAuth } from '../hooks/useAuth'
9
- import { useUIStore } from '../store/slices/uiSlice'
10
-
11
- export function StateDemo() {
12
- const {
13
- theme,
14
- sidebarOpen,
15
- notifications,
16
- loading,
17
- setTheme,
18
- toggleSidebar,
19
- setGlobalLoading
20
- } = useUIStore()
21
-
22
- const { success, error, warning, info, clearNotifications } = useNotifications()
23
- const { currentUser, isAuthenticated, login, logout } = useAuth()
24
-
25
- const handleThemeChange = (newTheme: 'light' | 'dark' | 'system') => {
26
- setTheme(newTheme)
27
- }
28
-
29
- const handleToggleSidebar = () => {
30
- toggleSidebar()
31
- }
32
-
33
- const handleToggleLoading = () => {
34
- setGlobalLoading(!loading.global)
35
- }
36
-
37
- const handleTestNotifications = () => {
38
- success('Success!', 'This is a success notification')
39
- setTimeout(() => error('Error!', 'This is an error notification'), 1000)
40
- setTimeout(() => warning('Warning!', 'This is a warning notification'), 2000)
41
- setTimeout(() => info('Info!', 'This is an info notification'), 3000)
42
- }
43
-
44
- const handleTestAuth = async () => {
45
- if (isAuthenticated) {
46
- await logout()
47
- } else {
48
- try {
49
- await login({ email: 'test@example.com', password: 'password' })
50
- } catch (error) {
51
- // Error is handled by the hook
52
- }
53
- }
54
- }
55
-
56
- return (
57
- <div className="p-6 bg-white rounded-lg shadow-lg">
58
- <h2 className="text-2xl font-bold mb-6 text-gray-800">
59
- 🔄 State Management Demo
60
- </h2>
61
-
62
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
63
- {/* Theme Controls */}
64
- <div className="space-y-4">
65
- <h3 className="text-lg font-semibold text-gray-700">Theme</h3>
66
- <div className="flex space-x-2">
67
- {(['light', 'dark', 'system'] as const).map((themeOption) => (
68
- <button
69
- key={themeOption}
70
- onClick={() => handleThemeChange(themeOption)}
71
- className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${theme === themeOption
72
- ? 'bg-blue-500 text-white'
73
- : 'bg-gray-200 text-gray-700 hover:bg-gray-300'
74
- }`}
75
- >
76
- {themeOption.charAt(0).toUpperCase() + themeOption.slice(1)}
77
- </button>
78
- ))}
79
- </div>
80
- <p className="text-sm text-gray-600">Current theme: {theme}</p>
81
- </div>
82
-
83
- {/* UI Controls */}
84
- <div className="space-y-4">
85
- <h3 className="text-lg font-semibold text-gray-700">UI State</h3>
86
- <div className="space-y-2">
87
- <button
88
- onClick={handleToggleSidebar}
89
- className="block w-full px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors"
90
- >
91
- {sidebarOpen ? 'Close Sidebar' : 'Open Sidebar'}
92
- </button>
93
- <button
94
- onClick={handleToggleLoading}
95
- className="block w-full px-4 py-2 bg-purple-500 text-white rounded-md hover:bg-purple-600 transition-colors"
96
- >
97
- {loading.global ? 'Stop Loading' : 'Start Loading'}
98
- </button>
99
- </div>
100
- <div className="text-sm text-gray-600">
101
- <p>Sidebar: {sidebarOpen ? 'Open' : 'Closed'}</p>
102
- <p>Loading: {loading.global ? 'Yes' : 'No'}</p>
103
- </div>
104
- </div>
105
-
106
- {/* Notifications */}
107
- <div className="space-y-4">
108
- <h3 className="text-lg font-semibold text-gray-700">Notifications</h3>
109
- <div className="space-y-2">
110
- <button
111
- onClick={handleTestNotifications}
112
- className="block w-full px-4 py-2 bg-orange-500 text-white rounded-md hover:bg-orange-600 transition-colors"
113
- >
114
- Test Notifications
115
- </button>
116
- <button
117
- onClick={clearNotifications}
118
- className="block w-full px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 transition-colors"
119
- >
120
- Clear Notifications
121
- </button>
122
- </div>
123
- <p className="text-sm text-gray-600">
124
- Active notifications: {notifications.length}
125
- </p>
126
- </div>
127
-
128
- {/* Authentication */}
129
- <div className="space-y-4">
130
- <h3 className="text-lg font-semibold text-gray-700">Authentication</h3>
131
- <button
132
- onClick={handleTestAuth}
133
- className={`block w-full px-4 py-2 rounded-md transition-colors ${isAuthenticated
134
- ? 'bg-red-500 text-white hover:bg-red-600'
135
- : 'bg-blue-500 text-white hover:bg-blue-600'
136
- }`}
137
- >
138
- {isAuthenticated ? 'Logout' : 'Login (Demo)'}
139
- </button>
140
- <div className="text-sm text-gray-600">
141
- <p>Status: {isAuthenticated ? 'Authenticated' : 'Not authenticated'}</p>
142
- {currentUser && (
143
- <p>User: {currentUser.name} ({currentUser.email})</p>
144
- )}
145
- </div>
146
- </div>
147
- </div>
148
-
149
- {/* State Inspector */}
150
- <div className="mt-8 p-4 bg-gray-50 rounded-md">
151
- <h4 className="text-md font-semibold text-gray-700 mb-2">State Inspector</h4>
152
- <details className="text-sm">
153
- <summary className="cursor-pointer text-blue-600 hover:text-blue-800">
154
- View Current State (Click to expand)
155
- </summary>
156
- <pre className="mt-2 p-2 bg-white rounded border text-xs overflow-auto">
157
- {JSON.stringify({
158
- ui: {
159
- theme,
160
- sidebarOpen,
161
- notificationCount: notifications.length,
162
- globalLoading: loading.global
163
- },
164
- user: {
165
- isAuthenticated,
166
- currentUser: currentUser ? {
167
- id: currentUser.id,
168
- name: currentUser.name,
169
- email: currentUser.email
170
- } : null
171
- }
172
- }, null, 2)}
173
- </pre>
174
- </details>
175
- </div>
176
- </div>
177
- )
178
- }