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.
- package/.env.example +19 -0
- package/README.md +653 -272
- package/app/client/SIMPLIFICATION.md +140 -0
- package/app/client/frontend-only.ts +1 -1
- package/app/client/src/App.tsx +148 -283
- package/app/client/src/index.css +5 -20
- package/app/client/src/lib/eden-api.ts +53 -220
- package/app/client/src/main.tsx +2 -3
- package/app/server/controllers/users.controller.ts +57 -31
- package/app/server/index.ts +5 -2
- package/app/server/live/register-components.ts +18 -7
- package/app/server/routes/env-test.ts +53 -2
- package/app/server/routes/index.ts +1 -8
- package/app/server/routes/users.routes.ts +192 -91
- package/config/fluxstack.config.ts +2 -2
- package/config/plugins.config.ts +22 -1
- package/core/build/bundler.ts +199 -55
- package/core/build/flux-plugins-generator.ts +5 -5
- package/core/build/index.ts +4 -0
- package/core/build/live-components-generator.ts +15 -12
- package/core/cli/command-registry.ts +4 -14
- package/core/cli/commands/plugin-deps.ts +8 -8
- package/core/cli/generators/component.ts +3 -3
- package/core/cli/generators/controller.ts +4 -4
- package/core/cli/generators/index.ts +8 -8
- package/core/cli/generators/interactive.ts +4 -4
- package/core/cli/generators/plugin.ts +9 -9
- package/core/cli/generators/prompts.ts +1 -1
- package/core/cli/generators/route.ts +27 -11
- package/core/cli/generators/service.ts +5 -5
- package/core/cli/generators/template-engine.ts +1 -1
- package/core/cli/generators/types.ts +1 -1
- package/core/cli/index.ts +258 -193
- package/core/cli/plugin-discovery.ts +3 -3
- package/core/client/hooks/index.ts +2 -2
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +1 -1
- package/core/client/hooks/useChunkedUpload.ts +1 -1
- package/core/client/hooks/useHybridLiveComponent.ts +1 -1
- package/core/client/hooks/useWebSocket.ts +1 -1
- package/core/config/env.ts +1 -1
- package/core/config/runtime-config.ts +5 -5
- package/core/config/schema.ts +9 -0
- package/core/framework/server.ts +30 -15
- package/core/framework/types.ts +2 -2
- package/core/live/ComponentRegistry.ts +1 -1
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +65 -161
- package/core/plugins/built-in/static/index.ts +18 -47
- package/core/plugins/built-in/swagger/index.ts +301 -231
- package/core/plugins/built-in/vite/index.ts +74 -109
- package/core/plugins/config.ts +2 -2
- package/core/plugins/dependency-manager.ts +2 -2
- package/core/plugins/discovery.ts +1 -1
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/manager.ts +19 -4
- package/core/plugins/module-resolver.ts +1 -1
- package/core/plugins/registry.ts +3 -3
- package/core/plugins/types.ts +147 -5
- package/core/server/framework.ts +2 -2
- package/core/server/live/ComponentRegistry.ts +9 -26
- package/core/server/live/FileUploadManager.ts +1 -1
- package/core/server/live/auto-generated-components.ts +26 -0
- package/core/server/live/websocket-plugin.ts +211 -19
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +4 -4
- package/core/server/plugins/database.ts +1 -2
- package/core/server/plugins/static-files-plugin.ts +259 -231
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +4 -4
- package/core/server/standalone.ts +16 -1
- package/core/testing/index.ts +1 -1
- package/core/testing/setup.ts +1 -1
- package/core/types/build.ts +21 -0
- package/core/utils/logger/startup-banner.ts +7 -33
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +73 -30
- package/package.json +3 -2
- package/plugins/crypto-auth/index.ts +52 -47
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
- package/tsconfig.json +2 -1
- package/vitest.config.ts +11 -2
- package/app/client/src/App.css +0 -883
- package/app/client/src/components/ErrorBoundary.tsx +0 -107
- package/app/client/src/components/ErrorDisplay.css +0 -365
- package/app/client/src/components/ErrorDisplay.tsx +0 -258
- package/app/client/src/components/FluxStackConfig.tsx +0 -1321
- package/app/client/src/components/HybridLiveCounter.tsx +0 -140
- package/app/client/src/components/LiveClock.tsx +0 -286
- package/app/client/src/components/MainLayout.tsx +0 -388
- package/app/client/src/components/SidebarNavigation.tsx +0 -391
- package/app/client/src/components/StateDemo.tsx +0 -178
- package/app/client/src/components/SystemMonitor.tsx +0 -1044
- package/app/client/src/components/UserProfile.tsx +0 -809
- package/app/client/src/hooks/useAuth.ts +0 -39
- package/app/client/src/hooks/useNotifications.ts +0 -56
- package/app/client/src/lib/errors.ts +0 -340
- package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
- package/app/client/src/lib/index.ts +0 -45
- package/app/client/src/pages/ApiDocs.tsx +0 -182
- package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
- package/app/client/src/pages/Demo.tsx +0 -174
- package/app/client/src/pages/HybridLive.tsx +0 -263
- package/app/client/src/pages/Overview.tsx +0 -155
- package/app/client/src/store/README.md +0 -43
- package/app/client/src/store/index.ts +0 -16
- package/app/client/src/store/slices/uiSlice.ts +0 -151
- package/app/client/src/store/slices/userSlice.ts +0 -161
- package/app/client/src/test/README.md +0 -257
- package/app/client/src/test/setup.ts +0 -70
- package/app/client/src/test/types.ts +0 -12
- package/app/server/live/CounterComponent.ts +0 -191
- package/app/server/live/FluxStackConfig.ts +0 -534
- package/app/server/live/SidebarNavigation.ts +0 -157
- package/app/server/live/SystemMonitor.ts +0 -595
- package/app/server/live/SystemMonitorIntegration.ts +0 -151
- package/app/server/live/UserProfileComponent.ts +0 -141
- package/app/server/middleware/auth.ts +0 -136
- package/app/server/middleware/errorHandling.ts +0 -252
- package/app/server/middleware/index.ts +0 -10
- package/app/server/middleware/rateLimit.ts +0 -193
- package/app/server/middleware/requestLogging.ts +0 -215
- package/app/server/middleware/validation.ts +0 -270
- package/app/server/routes/config.ts +0 -145
- package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
- package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
- package/app/server/routes/exemplo-posts.routes.ts +0 -161
- package/app/server/routes/upload.ts +0 -92
- package/app/server/services/NotificationService.ts +0 -302
- package/app/server/services/UserService.ts +0 -222
- package/app/server/services/index.ts +0 -46
- 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
|
-
}
|