Skip to content

Commit 67f3f22

Browse files
Implement full plan
Implement all planned features including CoNetWorKing page enhancements, Clubs page restoration, About page UI/UX improvements, and AI Chatbot error fixes. This includes creating new components like DAODashboard, utility functions for AI key generation, and modifying existing pages to integrate these features.
1 parent 35eb3ac commit 67f3f22

File tree

8 files changed

+645
-41
lines changed

8 files changed

+645
-41
lines changed

src/components/AIChatbot.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1-
import React, { useState } from 'react';
1+
import React from 'react';
22
import { motion, AnimatePresence } from 'framer-motion';
3-
import { Brain, X, Minimize2 } from 'lucide-react';
3+
import { Brain, X } from 'lucide-react';
4+
import { toast } from 'sonner';
45

56
const AIChatbot = () => {
6-
const [isOpen, setIsOpen] = useState(false);
7+
const [isOpen, setIsOpen] = React.useState(false);
8+
9+
const handleOpen = () => {
10+
setIsOpen(true);
11+
toast.info('AI Assistant Loading', {
12+
description: 'Opening Aitor AI Assistant...'
13+
});
14+
};
715

816
return (
917
<>
@@ -12,7 +20,7 @@ const AIChatbot = () => {
1220
initial={{ opacity: 0, scale: 0.5 }}
1321
animate={{ opacity: 1, scale: 1 }}
1422
transition={{ delay: 0.5 }}
15-
onClick={() => setIsOpen(!isOpen)}
23+
onClick={handleOpen}
1624
className="fixed bottom-24 right-8 z-40 p-4 bg-gradient-to-br from-alien-gold to-alien-gold-dark backdrop-blur-md border-2 border-alien-gold-light rounded-full text-alien-space-dark hover:scale-110 transition-all duration-300 shadow-2xl hover:shadow-alien-gold/50"
1725
aria-label="Open AI Assistant"
1826
>
@@ -57,6 +65,11 @@ const AIChatbot = () => {
5765
className="w-full h-[calc(100%-4rem)] border-none"
5866
title="Aitor AI Assistant"
5967
allow="microphone; camera"
68+
onError={() => {
69+
toast.error('AI Assistant Error', {
70+
description: 'Failed to load AI assistant. Please try again.'
71+
});
72+
}}
6073
/>
6174
</motion.div>
6275
)}

src/components/DAODashboard.tsx

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
import React, { useState, useEffect } from 'react';
2+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
3+
import { Button } from '@/components/ui/button';
4+
import { Users, TrendingUp, FileText, Clock, CheckCircle, XCircle, RefreshCw } from 'lucide-react';
5+
import { PieChart, Pie, Cell, ResponsiveContainer, BarChart, Bar, XAxis, YAxis, Tooltip, Legend } from 'recharts';
6+
7+
type Proposal = {
8+
id: number;
9+
title: string;
10+
status: 'active' | 'passed' | 'rejected';
11+
votesFor: number;
12+
votesAgainst: number;
13+
deadline: string;
14+
};
15+
16+
const DAODashboard: React.FC = () => {
17+
const [lastUpdate, setLastUpdate] = useState(new Date());
18+
19+
// Mock data - In production, fetch from blockchain
20+
const [stats] = useState({
21+
activeVoters: 12847,
22+
totalProposals: 156,
23+
votingPower: '2.4M',
24+
participationRate: 68
25+
});
26+
27+
const [treasury] = useState([
28+
{ name: 'BTC', value: 145.7, change: 3.2, color: '#F7931A' },
29+
{ name: 'ETH', value: 2890.5, change: -1.5, color: '#627EEA' },
30+
{ name: 'USDC', value: 450000, change: 0, color: '#2775CA' },
31+
{ name: 'Other', value: 89000, change: 2.1, color: '#22C55E' }
32+
]);
33+
34+
const [proposals] = useState<Proposal[]>([
35+
{ id: 1, title: 'Expand Academy Programs', status: 'active', votesFor: 8450, votesAgainst: 1200, deadline: '2025-12-15' },
36+
{ id: 2, title: 'Partner with ESL Gaming', status: 'active', votesFor: 6800, votesAgainst: 3400, deadline: '2025-12-10' },
37+
{ id: 3, title: 'Launch ReFi Initiative', status: 'passed', votesFor: 9200, votesAgainst: 890, deadline: '2025-11-30' },
38+
{ id: 4, title: 'Increase Treasury APY', status: 'rejected', votesFor: 4100, votesAgainst: 7800, deadline: '2025-11-28' }
39+
]);
40+
41+
const [votingData] = useState([
42+
{ month: 'Aug', proposals: 12, votes: 45000 },
43+
{ month: 'Sep', proposals: 15, votes: 52000 },
44+
{ month: 'Oct', proposals: 18, votes: 61000 },
45+
{ month: 'Nov', proposals: 21, votes: 68000 }
46+
]);
47+
48+
useEffect(() => {
49+
const interval = setInterval(() => {
50+
setLastUpdate(new Date());
51+
}, 30000); // Auto-refresh every 30 seconds
52+
53+
return () => clearInterval(interval);
54+
}, []);
55+
56+
const handleRefresh = () => {
57+
setLastUpdate(new Date());
58+
};
59+
60+
const getTotalValue = () => {
61+
return treasury.reduce((sum, token) => sum + token.value, 0).toLocaleString('en-US', { maximumFractionDigits: 0 });
62+
};
63+
64+
const getProposalStats = () => {
65+
const passed = proposals.filter(p => p.status === 'passed').length;
66+
const rejected = proposals.filter(p => p.status === 'rejected').length;
67+
const pending = proposals.filter(p => p.status === 'active').length;
68+
return { passed, rejected, pending };
69+
};
70+
71+
const proposalStats = getProposalStats();
72+
73+
return (
74+
<div className="space-y-8">
75+
{/* Header */}
76+
<div className="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
77+
<div>
78+
<h2 className="text-3xl font-bold text-alien-green font-nasalization mb-2">
79+
DAO Dashboard
80+
</h2>
81+
<p className="text-gray-400 text-sm">
82+
Last updated: {lastUpdate.toLocaleTimeString()}
83+
</p>
84+
</div>
85+
<Button
86+
onClick={handleRefresh}
87+
className="bg-alien-gold/20 hover:bg-alien-gold/30 text-alien-gold border border-alien-gold/50"
88+
>
89+
<RefreshCw className="h-4 w-4 mr-2" />
90+
Refresh Data
91+
</Button>
92+
</div>
93+
94+
{/* Stats Grid */}
95+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
96+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-gold/30">
97+
<CardHeader className="pb-3">
98+
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
99+
<Users className="h-4 w-4" />
100+
Active Voters
101+
</CardTitle>
102+
</CardHeader>
103+
<CardContent>
104+
<div className="text-3xl font-bold text-alien-gold font-nasalization">
105+
{stats.activeVoters.toLocaleString()}
106+
</div>
107+
<p className="text-xs text-gray-500 mt-1">
108+
{stats.participationRate}% participation rate
109+
</p>
110+
</CardContent>
111+
</Card>
112+
113+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-green/30">
114+
<CardHeader className="pb-3">
115+
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
116+
<TrendingUp className="h-4 w-4" />
117+
Voting Power
118+
</CardTitle>
119+
</CardHeader>
120+
<CardContent>
121+
<div className="text-3xl font-bold text-alien-green font-nasalization">
122+
{stats.votingPower}
123+
</div>
124+
<p className="text-xs text-gray-500 mt-1">
125+
Total governance tokens
126+
</p>
127+
</CardContent>
128+
</Card>
129+
130+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-gold/30">
131+
<CardHeader className="pb-3">
132+
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
133+
<FileText className="h-4 w-4" />
134+
Total Proposals
135+
</CardTitle>
136+
</CardHeader>
137+
<CardContent>
138+
<div className="text-3xl font-bold text-alien-gold font-nasalization">
139+
{stats.totalProposals}
140+
</div>
141+
<p className="text-xs text-gray-500 mt-1">
142+
{proposalStats.passed} passed · {proposalStats.rejected} rejected
143+
</p>
144+
</CardContent>
145+
</Card>
146+
147+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-green/30">
148+
<CardHeader className="pb-3">
149+
<CardTitle className="text-sm font-medium text-gray-400 flex items-center gap-2">
150+
<Clock className="h-4 w-4" />
151+
Active Proposals
152+
</CardTitle>
153+
</CardHeader>
154+
<CardContent>
155+
<div className="text-3xl font-bold text-alien-green font-nasalization">
156+
{proposalStats.pending}
157+
</div>
158+
<p className="text-xs text-gray-500 mt-1">
159+
Awaiting community vote
160+
</p>
161+
</CardContent>
162+
</Card>
163+
</div>
164+
165+
{/* Treasury & Voting Activity */}
166+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
167+
{/* Treasury Balance */}
168+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-gold/30">
169+
<CardHeader>
170+
<CardTitle className="text-alien-gold font-nasalization">
171+
Treasury Balance
172+
</CardTitle>
173+
<p className="text-2xl font-bold text-gray-200 mt-2">
174+
${getTotalValue()}
175+
</p>
176+
</CardHeader>
177+
<CardContent>
178+
<ResponsiveContainer width="100%" height={200}>
179+
<PieChart>
180+
<Pie
181+
data={treasury}
182+
cx="50%"
183+
cy="50%"
184+
labelLine={false}
185+
label={(entry) => `${entry.name}: $${entry.value.toLocaleString()}`}
186+
outerRadius={80}
187+
fill="#8884d8"
188+
dataKey="value"
189+
>
190+
{treasury.map((entry, index) => (
191+
<Cell key={`cell-${index}`} fill={entry.color} />
192+
))}
193+
</Pie>
194+
<Tooltip />
195+
</PieChart>
196+
</ResponsiveContainer>
197+
<div className="mt-4 space-y-2">
198+
{treasury.map((token, idx) => (
199+
<div key={idx} className="flex justify-between items-center text-sm">
200+
<span className="text-gray-400">{token.name}</span>
201+
<span className={token.change >= 0 ? 'text-green-400' : 'text-red-400'}>
202+
{token.change >= 0 ? '+' : ''}{token.change}%
203+
</span>
204+
</div>
205+
))}
206+
</div>
207+
</CardContent>
208+
</Card>
209+
210+
{/* Voting Activity */}
211+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-green/30">
212+
<CardHeader>
213+
<CardTitle className="text-alien-green font-nasalization">
214+
Voting Activity
215+
</CardTitle>
216+
</CardHeader>
217+
<CardContent>
218+
<ResponsiveContainer width="100%" height={250}>
219+
<BarChart data={votingData}>
220+
<XAxis dataKey="month" stroke="#9CA3AF" />
221+
<YAxis stroke="#9CA3AF" />
222+
<Tooltip
223+
contentStyle={{
224+
backgroundColor: 'rgba(17, 17, 25, 0.95)',
225+
border: '1px solid rgba(240, 216, 130, 0.3)',
226+
borderRadius: '8px'
227+
}}
228+
/>
229+
<Legend />
230+
<Bar dataKey="proposals" fill="#F0D882" name="Proposals" />
231+
<Bar dataKey="votes" fill="#22C55E" name="Total Votes" />
232+
</BarChart>
233+
</ResponsiveContainer>
234+
</CardContent>
235+
</Card>
236+
</div>
237+
238+
{/* Active Proposals */}
239+
<Card className="bg-alien-space-dark/80 backdrop-blur-md border-alien-gold/30">
240+
<CardHeader>
241+
<CardTitle className="text-alien-gold font-nasalization">
242+
Recent Proposals
243+
</CardTitle>
244+
</CardHeader>
245+
<CardContent>
246+
<div className="space-y-4">
247+
{proposals.map((proposal) => (
248+
<div
249+
key={proposal.id}
250+
className="border border-alien-gold/20 rounded-lg p-4 hover:border-alien-gold/40 transition-all"
251+
>
252+
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
253+
<div className="flex-1">
254+
<div className="flex items-center gap-3 mb-2">
255+
<h4 className="font-semibold text-gray-200">{proposal.title}</h4>
256+
{proposal.status === 'active' && (
257+
<span className="px-2 py-1 text-xs bg-blue-500/20 text-blue-400 rounded-full border border-blue-500/30">
258+
Active
259+
</span>
260+
)}
261+
{proposal.status === 'passed' && (
262+
<span className="px-2 py-1 text-xs bg-green-500/20 text-green-400 rounded-full border border-green-500/30 flex items-center gap-1">
263+
<CheckCircle className="h-3 w-3" />
264+
Passed
265+
</span>
266+
)}
267+
{proposal.status === 'rejected' && (
268+
<span className="px-2 py-1 text-xs bg-red-500/20 text-red-400 rounded-full border border-red-500/30 flex items-center gap-1">
269+
<XCircle className="h-3 w-3" />
270+
Rejected
271+
</span>
272+
)}
273+
</div>
274+
<div className="flex items-center gap-4 text-sm text-gray-400">
275+
<span className="flex items-center gap-1">
276+
<CheckCircle className="h-4 w-4 text-green-400" />
277+
{proposal.votesFor.toLocaleString()} For
278+
</span>
279+
<span className="flex items-center gap-1">
280+
<XCircle className="h-4 w-4 text-red-400" />
281+
{proposal.votesAgainst.toLocaleString()} Against
282+
</span>
283+
{proposal.status === 'active' && (
284+
<span className="flex items-center gap-1">
285+
<Clock className="h-4 w-4" />
286+
Ends {new Date(proposal.deadline).toLocaleDateString()}
287+
</span>
288+
)}
289+
</div>
290+
{/* Progress bar */}
291+
<div className="mt-3 w-full bg-gray-700 rounded-full h-2">
292+
<div
293+
className="bg-gradient-to-r from-green-400 to-alien-green h-2 rounded-full"
294+
style={{
295+
width: `${(proposal.votesFor / (proposal.votesFor + proposal.votesAgainst)) * 100}%`
296+
}}
297+
/>
298+
</div>
299+
</div>
300+
{proposal.status === 'active' && (
301+
<div className="flex gap-2">
302+
<Button
303+
size="sm"
304+
className="bg-green-500/20 hover:bg-green-500/30 text-green-400 border border-green-500/50"
305+
>
306+
Vote For
307+
</Button>
308+
<Button
309+
size="sm"
310+
className="bg-red-500/20 hover:bg-red-500/30 text-red-400 border border-red-500/50"
311+
>
312+
Vote Against
313+
</Button>
314+
</div>
315+
)}
316+
</div>
317+
</div>
318+
))}
319+
</div>
320+
</CardContent>
321+
</Card>
322+
</div>
323+
);
324+
};
325+
326+
export default DAODashboard;

0 commit comments

Comments
 (0)