@digilogiclabs/create-saas-app 1.17.1 → 1.18.0
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/CHANGELOG.md +51 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +6 -2
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/template-generator.d.ts.map +1 -1
- package/dist/generators/template-generator.js +13 -7
- package/dist/generators/template-generator.js.map +1 -1
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
- package/dist/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
- package/dist/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
- package/package.json +1 -1
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/README.md +655 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/app/(tabs)/ai.tsx +683 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/docs/MOBILE-SETUP.md +787 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +346 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/lib/rag/config.ts +180 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/package.json +113 -0
- package/src/templates/mobile/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +599 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/README.md +434 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/KnowledgeManager.tsx +642 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGAnalytics.tsx +466 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/components/rag/RAGChatInterface.tsx +393 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/docs/GETTING-STARTED.md +457 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/hooks/useRAGSystem.ts +478 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/lib/rag/config.ts +250 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/package.json +74 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/scripts/setup-rag.js +622 -0
- package/src/templates/web/ui-auth-payments-ai-rag/template/src/app/ai/page.tsx +396 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
PageTransition,
|
|
7
|
+
MobileContainer,
|
|
8
|
+
ResponsiveGrid,
|
|
9
|
+
useAnimationTokens,
|
|
10
|
+
useGlassmorphism
|
|
11
|
+
} from '@digilogiclabs/saas-factory-ui'
|
|
12
|
+
import {
|
|
13
|
+
ArrowLeft,
|
|
14
|
+
MessageSquare,
|
|
15
|
+
Database,
|
|
16
|
+
BookOpen,
|
|
17
|
+
BarChart3,
|
|
18
|
+
Settings,
|
|
19
|
+
Search,
|
|
20
|
+
Plus,
|
|
21
|
+
Zap,
|
|
22
|
+
Brain,
|
|
23
|
+
Activity,
|
|
24
|
+
FileText,
|
|
25
|
+
Lightbulb,
|
|
26
|
+
Sparkles,
|
|
27
|
+
Clock,
|
|
28
|
+
TrendingUp,
|
|
29
|
+
Users,
|
|
30
|
+
Download,
|
|
31
|
+
Share2,
|
|
32
|
+
RefreshCw,
|
|
33
|
+
AlertCircle,
|
|
34
|
+
CheckCircle,
|
|
35
|
+
Loader2
|
|
36
|
+
} from 'lucide-react'
|
|
37
|
+
import { useAuth } from '@digilogiclabs/saas-factory-auth'
|
|
38
|
+
import Link from 'next/link'
|
|
39
|
+
import { useRAGSystem } from '../../../hooks/useRAGSystem'
|
|
40
|
+
import { RAGChatInterface } from '../../../components/rag/RAGChatInterface'
|
|
41
|
+
import { KnowledgeManager } from '../../../components/rag/KnowledgeManager'
|
|
42
|
+
import { RAGAnalytics } from '../../../components/rag/RAGAnalytics'
|
|
43
|
+
import type { GenericRAGDocumentSchema } from '@digilogiclabs/saas-factory-ai-types'
|
|
44
|
+
import { toast } from 'sonner'
|
|
45
|
+
|
|
46
|
+
export default function AIPage() {
|
|
47
|
+
const { user, loading } = useAuth()
|
|
48
|
+
const [activeTab, setActiveTab] = useState<'dashboard' | 'chat' | 'knowledge' | 'analytics' | 'settings'>('dashboard')
|
|
49
|
+
|
|
50
|
+
const animations = useAnimationTokens()
|
|
51
|
+
const glass = useGlassmorphism()
|
|
52
|
+
|
|
53
|
+
// Initialize RAG system
|
|
54
|
+
const ragSystem = useRAGSystem<GenericRAGDocumentSchema>({
|
|
55
|
+
domain: 'generic', // Can be configured: 'plants', 'ecommerce', 'education'
|
|
56
|
+
enableStreaming: true,
|
|
57
|
+
enableCache: true,
|
|
58
|
+
autoInitialize: true
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const handleSync = async () => {
|
|
62
|
+
try {
|
|
63
|
+
await ragSystem.syncKnowledgeBase()
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error('Sync failed:', error)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const getHealthColor = (health: string) => {
|
|
70
|
+
switch (health) {
|
|
71
|
+
case 'healthy': return 'text-green-500'
|
|
72
|
+
case 'degraded': return 'text-yellow-500'
|
|
73
|
+
case 'down': return 'text-red-500'
|
|
74
|
+
default: return 'text-gray-500'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const getHealthIcon = (health: string) => {
|
|
79
|
+
switch (health) {
|
|
80
|
+
case 'healthy': return CheckCircle
|
|
81
|
+
case 'degraded': return AlertCircle
|
|
82
|
+
case 'down': return AlertCircle
|
|
83
|
+
default: return Loader2
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (loading) {
|
|
88
|
+
return (
|
|
89
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
90
|
+
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!user) {
|
|
96
|
+
return (
|
|
97
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
98
|
+
<div className="text-center">
|
|
99
|
+
<h2 className="text-2xl font-bold mb-4">Access Denied</h2>
|
|
100
|
+
<p className="mb-4">You need to sign in to access the AI dashboard.</p>
|
|
101
|
+
<Link href="/login" className="text-blue-500 hover:underline">
|
|
102
|
+
Sign In
|
|
103
|
+
</Link>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const renderDashboard = () => {
|
|
110
|
+
const HealthIcon = getHealthIcon(ragSystem.health)
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div className="space-y-6">
|
|
114
|
+
{/* System Status */}
|
|
115
|
+
<Card className={`${glass.card} ${glass.border} p-6`}>
|
|
116
|
+
<div className="flex items-center justify-between mb-4">
|
|
117
|
+
<h3 className="text-xl font-semibold">System Status</h3>
|
|
118
|
+
<button
|
|
119
|
+
onClick={handleSync}
|
|
120
|
+
disabled={ragSystem.isLoading}
|
|
121
|
+
className={`p-2 rounded-xl ${glass.card} ${glass.border} ${animations.hover.scale} disabled:opacity-50`}
|
|
122
|
+
>
|
|
123
|
+
{ragSystem.isLoading ? (
|
|
124
|
+
<Loader2 className="w-4 h-4 animate-spin" />
|
|
125
|
+
) : (
|
|
126
|
+
<RefreshCw className="w-4 h-4" />
|
|
127
|
+
)}
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
132
|
+
<div className="flex items-center gap-3">
|
|
133
|
+
<HealthIcon className={`w-5 h-5 ${getHealthColor(ragSystem.health)}`} />
|
|
134
|
+
<div>
|
|
135
|
+
<p className="font-medium">System Health</p>
|
|
136
|
+
<p className="text-sm text-gray-600 dark:text-gray-300 capitalize">
|
|
137
|
+
{ragSystem.health}
|
|
138
|
+
</p>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div className="flex items-center gap-3">
|
|
143
|
+
<Activity className="w-5 h-5 text-blue-500" />
|
|
144
|
+
<div>
|
|
145
|
+
<p className="font-medium">Status</p>
|
|
146
|
+
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
147
|
+
{ragSystem.isReady ? 'Ready' : 'Initializing...'}
|
|
148
|
+
</p>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div className="flex items-center gap-3">
|
|
153
|
+
<Clock className="w-5 h-5 text-purple-500" />
|
|
154
|
+
<div>
|
|
155
|
+
<p className="font-medium">Last Sync</p>
|
|
156
|
+
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
157
|
+
{ragSystem.lastSyncAt
|
|
158
|
+
? ragSystem.lastSyncAt.toLocaleString()
|
|
159
|
+
: 'Never'
|
|
160
|
+
}
|
|
161
|
+
</p>
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</Card>
|
|
166
|
+
|
|
167
|
+
{/* Statistics Overview */}
|
|
168
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
169
|
+
<Card className={`${glass.card} ${glass.border} p-6 text-center ${animations.hover.lift}`}>
|
|
170
|
+
<div className="text-3xl font-bold text-blue-500 mb-2">
|
|
171
|
+
{ragSystem.totalQueries}
|
|
172
|
+
</div>
|
|
173
|
+
<div className="text-sm text-gray-600 dark:text-gray-300">Total Queries</div>
|
|
174
|
+
</Card>
|
|
175
|
+
|
|
176
|
+
<Card className={`${glass.card} ${glass.border} p-6 text-center ${animations.hover.lift}`}>
|
|
177
|
+
<div className="text-3xl font-bold text-green-500 mb-2">
|
|
178
|
+
{ragSystem.totalDocuments}
|
|
179
|
+
</div>
|
|
180
|
+
<div className="text-sm text-gray-600 dark:text-gray-300">Knowledge Docs</div>
|
|
181
|
+
</Card>
|
|
182
|
+
|
|
183
|
+
<Card className={`${glass.card} ${glass.border} p-6 text-center ${animations.hover.lift}`}>
|
|
184
|
+
<div className="text-3xl font-bold text-purple-500 mb-2">
|
|
185
|
+
{ragSystem.cacheSize}
|
|
186
|
+
</div>
|
|
187
|
+
<div className="text-sm text-gray-600 dark:text-gray-300">Cached Responses</div>
|
|
188
|
+
</Card>
|
|
189
|
+
|
|
190
|
+
<Card className={`${glass.card} ${glass.border} p-6 text-center ${animations.hover.lift}`}>
|
|
191
|
+
<div className="text-3xl font-bold text-orange-500 mb-2">
|
|
192
|
+
{ragSystem.queryHistory.length}
|
|
193
|
+
</div>
|
|
194
|
+
<div className="text-sm text-gray-600 dark:text-gray-300">Recent Queries</div>
|
|
195
|
+
</Card>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
{/* Quick Actions */}
|
|
199
|
+
<Card className={`${glass.card} ${glass.border} p-6`}>
|
|
200
|
+
<h3 className="text-xl font-semibold mb-4">Quick Actions</h3>
|
|
201
|
+
|
|
202
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
203
|
+
<button
|
|
204
|
+
onClick={() => setActiveTab('chat')}
|
|
205
|
+
disabled={!ragSystem.canQuery}
|
|
206
|
+
className={`p-4 rounded-xl ${glass.card} ${glass.border} ${animations.hover.lift} ${animations.transition.smooth} disabled:opacity-50 text-left`}
|
|
207
|
+
>
|
|
208
|
+
<MessageSquare className="w-8 h-8 text-blue-500 mb-3" />
|
|
209
|
+
<h4 className="font-semibold mb-1">AI Chat</h4>
|
|
210
|
+
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
211
|
+
Chat with your knowledge base
|
|
212
|
+
</p>
|
|
213
|
+
</button>
|
|
214
|
+
|
|
215
|
+
<button
|
|
216
|
+
onClick={() => setActiveTab('knowledge')}
|
|
217
|
+
className={`p-4 rounded-xl ${glass.card} ${glass.border} ${animations.hover.lift} ${animations.transition.smooth} text-left`}
|
|
218
|
+
>
|
|
219
|
+
<Database className="w-8 h-8 text-green-500 mb-3" />
|
|
220
|
+
<h4 className="font-semibold mb-1">Knowledge Base</h4>
|
|
221
|
+
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
222
|
+
Manage your documents
|
|
223
|
+
</p>
|
|
224
|
+
</button>
|
|
225
|
+
|
|
226
|
+
<button
|
|
227
|
+
onClick={() => setActiveTab('analytics')}
|
|
228
|
+
className={`p-4 rounded-xl ${glass.card} ${glass.border} ${animations.hover.lift} ${animations.transition.smooth} text-left`}
|
|
229
|
+
>
|
|
230
|
+
<BarChart3 className="w-8 h-8 text-purple-500 mb-3" />
|
|
231
|
+
<h4 className="font-semibold mb-1">Analytics</h4>
|
|
232
|
+
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
233
|
+
View usage insights
|
|
234
|
+
</p>
|
|
235
|
+
</button>
|
|
236
|
+
|
|
237
|
+
<button
|
|
238
|
+
onClick={() => ragSystem.clearCache()}
|
|
239
|
+
className={`p-4 rounded-xl ${glass.card} ${glass.border} ${animations.hover.lift} ${animations.transition.smooth} text-left`}
|
|
240
|
+
>
|
|
241
|
+
<RefreshCw className="w-8 h-8 text-orange-500 mb-3" />
|
|
242
|
+
<h4 className="font-semibold mb-1">Clear Cache</h4>
|
|
243
|
+
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
244
|
+
Reset cached responses
|
|
245
|
+
</p>
|
|
246
|
+
</button>
|
|
247
|
+
</div>
|
|
248
|
+
</Card>
|
|
249
|
+
|
|
250
|
+
{/* Recent Query History */}
|
|
251
|
+
{ragSystem.queryHistory.length > 0 && (
|
|
252
|
+
<Card className={`${glass.card} ${glass.border} p-6`}>
|
|
253
|
+
<h3 className="text-xl font-semibold mb-4">Recent Queries</h3>
|
|
254
|
+
|
|
255
|
+
<div className="space-y-3">
|
|
256
|
+
{ragSystem.queryHistory.slice(0, 5).map((query, index) => (
|
|
257
|
+
<div
|
|
258
|
+
key={index}
|
|
259
|
+
className={`p-3 rounded-lg bg-gray-50 dark:bg-gray-800/50 ${animations.hover.lift}`}
|
|
260
|
+
>
|
|
261
|
+
<div className="flex items-start justify-between">
|
|
262
|
+
<div className="flex-1">
|
|
263
|
+
<p className="font-medium line-clamp-1">{query.query}</p>
|
|
264
|
+
<div className="flex items-center gap-2 mt-1 text-sm text-gray-600 dark:text-gray-300">
|
|
265
|
+
<Clock className="w-3 h-3" />
|
|
266
|
+
{new Date(query.timestamp).toLocaleTimeString()}
|
|
267
|
+
{query.category && (
|
|
268
|
+
<>
|
|
269
|
+
<span>•</span>
|
|
270
|
+
<span className="capitalize">{query.category}</span>
|
|
271
|
+
</>
|
|
272
|
+
)}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
<button
|
|
276
|
+
onClick={() => {
|
|
277
|
+
setActiveTab('chat')
|
|
278
|
+
// Would trigger a new query with this text
|
|
279
|
+
}}
|
|
280
|
+
className={`p-1 rounded ${animations.hover.scale}`}
|
|
281
|
+
>
|
|
282
|
+
<RefreshCw className="w-4 h-4" />
|
|
283
|
+
</button>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
))}
|
|
287
|
+
</div>
|
|
288
|
+
</Card>
|
|
289
|
+
)}
|
|
290
|
+
</div>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const renderChat = () => (
|
|
295
|
+
<Card className={`${glass.card} ${glass.border} p-6 h-[calc(100vh-200px)]`}>
|
|
296
|
+
<RAGChatInterface
|
|
297
|
+
ragSystem={ragSystem}
|
|
298
|
+
enableStreaming={true}
|
|
299
|
+
showSources={true}
|
|
300
|
+
showConfidence={true}
|
|
301
|
+
onError={(error) => toast.error(error.message)}
|
|
302
|
+
/>
|
|
303
|
+
</Card>
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
const renderKnowledge = () => (
|
|
307
|
+
<Card className={`${glass.card} ${glass.border} p-6`}>
|
|
308
|
+
<KnowledgeManager
|
|
309
|
+
ragSystem={ragSystem}
|
|
310
|
+
enableBulkOperations={true}
|
|
311
|
+
enableExport={true}
|
|
312
|
+
onSuccess={(message) => toast.success(message)}
|
|
313
|
+
onError={(error) => toast.error(error)}
|
|
314
|
+
/>
|
|
315
|
+
</Card>
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
const renderAnalytics = () => (
|
|
319
|
+
<Card className={`${glass.card} ${glass.border} p-6`}>
|
|
320
|
+
<RAGAnalytics
|
|
321
|
+
ragSystem={ragSystem}
|
|
322
|
+
timeRange="7d"
|
|
323
|
+
showDetailedMetrics={true}
|
|
324
|
+
/>
|
|
325
|
+
</Card>
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
const tabs = [
|
|
329
|
+
{ id: 'dashboard', label: 'Dashboard', icon: Brain },
|
|
330
|
+
{ id: 'chat', label: 'AI Chat', icon: MessageSquare },
|
|
331
|
+
{ id: 'knowledge', label: 'Knowledge', icon: BookOpen },
|
|
332
|
+
{ id: 'analytics', label: 'Analytics', icon: BarChart3 },
|
|
333
|
+
]
|
|
334
|
+
|
|
335
|
+
return (
|
|
336
|
+
<PageTransition type="slide" direction="up" duration={300}>
|
|
337
|
+
<main className={`min-h-screen ${glass.background.primary} relative overflow-hidden`}>
|
|
338
|
+
<div className={`absolute inset-0 ${glass.background.accent} opacity-30`} />
|
|
339
|
+
<div className="relative z-10">
|
|
340
|
+
<MobileContainer className="py-8">
|
|
341
|
+
{/* Header */}
|
|
342
|
+
<div className="flex items-center justify-between mb-8">
|
|
343
|
+
<div className="flex items-center gap-4">
|
|
344
|
+
<Link href="/" className={`${glass.card} ${glass.border} p-2 rounded-xl ${animations.hover.scale}`}>
|
|
345
|
+
<ArrowLeft className="w-5 h-5" />
|
|
346
|
+
</Link>
|
|
347
|
+
<div>
|
|
348
|
+
<h1 className="text-2xl font-bold">AI Knowledge Assistant</h1>
|
|
349
|
+
<p className="text-gray-600 dark:text-gray-300">
|
|
350
|
+
Powered by RAG v4.0.0
|
|
351
|
+
</p>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
|
|
355
|
+
{ragSystem.hasError && (
|
|
356
|
+
<div className="flex items-center gap-2 text-red-500">
|
|
357
|
+
<AlertCircle className="w-5 h-5" />
|
|
358
|
+
<span className="text-sm">System Error</span>
|
|
359
|
+
</div>
|
|
360
|
+
)}
|
|
361
|
+
</div>
|
|
362
|
+
|
|
363
|
+
{/* Tab Navigation */}
|
|
364
|
+
<div className={`${glass.card} ${glass.border} rounded-2xl p-1 mb-8 inline-flex`}>
|
|
365
|
+
{tabs.map((tab) => {
|
|
366
|
+
const Icon = tab.icon
|
|
367
|
+
return (
|
|
368
|
+
<button
|
|
369
|
+
key={tab.id}
|
|
370
|
+
onClick={() => setActiveTab(tab.id as any)}
|
|
371
|
+
className={`flex items-center gap-2 px-4 py-2 rounded-xl text-sm font-medium transition-all duration-200 ${
|
|
372
|
+
activeTab === tab.id
|
|
373
|
+
? 'bg-blue-500 text-white shadow-lg'
|
|
374
|
+
: 'text-gray-600 dark:text-gray-300 hover:bg-white/10'
|
|
375
|
+
}`}
|
|
376
|
+
>
|
|
377
|
+
<Icon className="w-4 h-4" />
|
|
378
|
+
{tab.label}
|
|
379
|
+
</button>
|
|
380
|
+
)
|
|
381
|
+
})}
|
|
382
|
+
</div>
|
|
383
|
+
|
|
384
|
+
{/* Tab Content */}
|
|
385
|
+
<div className="space-y-6">
|
|
386
|
+
{activeTab === 'dashboard' && renderDashboard()}
|
|
387
|
+
{activeTab === 'chat' && renderChat()}
|
|
388
|
+
{activeTab === 'knowledge' && renderKnowledge()}
|
|
389
|
+
{activeTab === 'analytics' && renderAnalytics()}
|
|
390
|
+
</div>
|
|
391
|
+
</MobileContainer>
|
|
392
|
+
</div>
|
|
393
|
+
</main>
|
|
394
|
+
</PageTransition>
|
|
395
|
+
)
|
|
396
|
+
}
|