mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-22 09:07:55 +00:00
fix: replace mock governance data with live chain queries and fix trust score formulas
This commit is contained in:
@@ -26,12 +26,13 @@ const TrustScoreCalculator: React.FC = () => {
|
||||
return 2.0;
|
||||
};
|
||||
|
||||
// Calculate referral score
|
||||
// Calculate referral score (matches pezpallet-referral tiered scoring)
|
||||
const getReferralScore = (count: number) => {
|
||||
if (count === 0) return 0;
|
||||
if (count <= 5) return count * 4;
|
||||
if (count <= 20) return 20 + ((count - 5) * 2);
|
||||
return 50;
|
||||
if (count <= 10) return count * 10;
|
||||
if (count <= 50) return 100 + ((count - 10) * 5);
|
||||
if (count <= 100) return 300 + ((count - 50) * 4);
|
||||
return 500;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -120,7 +121,7 @@ const TrustScoreCalculator: React.FC = () => {
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="50"
|
||||
max="150"
|
||||
value={referralCount}
|
||||
onChange={(e) => setReferralCount(parseInt(e.target.value) || 0)}
|
||||
className="w-full mt-2 px-4 py-2 bg-gray-800 text-white rounded-lg border border-gray-700 focus:border-cyan-500 focus:outline-none"
|
||||
@@ -157,7 +158,7 @@ const TrustScoreCalculator: React.FC = () => {
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
max="250"
|
||||
value={tikiScore}
|
||||
onChange={(e) => setTikiScore(parseInt(e.target.value))}
|
||||
className="w-full"
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Vote, Users, Gavel, FileText, TrendingUpIcon,
|
||||
CheckCircle,
|
||||
PieChart, Activity, Shield
|
||||
Users, Gavel, FileText, TrendingUpIcon,
|
||||
Shield
|
||||
} from 'lucide-react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
|
||||
import { Badge } from '../ui/badge';
|
||||
import { Progress } from '../ui/progress';
|
||||
import { usePezkuwi } from '../../contexts/PezkuwiContext';
|
||||
import { formatBalance } from '@pezkuwi/lib/wallet';
|
||||
import { LoadingState } from '@pezkuwi/components/AsyncComponent';
|
||||
import { getActiveElections, getActiveProposals, getParliamentMembers, getDiwanMembers } from '@pezkuwi/lib/welati';
|
||||
|
||||
interface GovernanceStats {
|
||||
activeProposals: number;
|
||||
@@ -17,8 +16,11 @@ interface GovernanceStats {
|
||||
totalVoters: number;
|
||||
participationRate: number;
|
||||
parliamentMembers: number;
|
||||
parliamentMax: number;
|
||||
diwanMembers: number;
|
||||
nextElection: string;
|
||||
diwanMax: number;
|
||||
pendingVotes: number;
|
||||
diwanPendingReviews: number;
|
||||
treasuryBalance: string;
|
||||
}
|
||||
|
||||
@@ -30,8 +32,11 @@ const GovernanceOverview: React.FC = () => {
|
||||
totalVoters: 0,
|
||||
participationRate: 0,
|
||||
parliamentMembers: 0,
|
||||
parliamentMax: 201,
|
||||
diwanMembers: 0,
|
||||
nextElection: '-',
|
||||
diwanMax: 9,
|
||||
pendingVotes: 0,
|
||||
diwanPendingReviews: 0,
|
||||
treasuryBalance: '0 HEZ'
|
||||
});
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -44,17 +49,53 @@ const GovernanceOverview: React.FC = () => {
|
||||
}
|
||||
|
||||
try {
|
||||
if (import.meta.env.DEV) console.log('📊 Fetching governance data from blockchain...');
|
||||
if (import.meta.env.DEV) console.log('Fetching governance data from blockchain...');
|
||||
setLoading(true);
|
||||
|
||||
// Fetch active referenda (proposals)
|
||||
// Fetch active proposals via welati
|
||||
let activeProposals = 0;
|
||||
let pendingVotes = 0;
|
||||
let diwanPendingReviews = 0;
|
||||
try {
|
||||
const referendaCount = await api.query.referenda.referendumCount();
|
||||
if (import.meta.env.DEV) console.log('Referenda count:', referendaCount.toNumber());
|
||||
activeProposals = referendaCount.toNumber();
|
||||
const proposals = await getActiveProposals(api);
|
||||
activeProposals = proposals.length;
|
||||
pendingVotes = proposals.length;
|
||||
diwanPendingReviews = proposals.filter(
|
||||
p => p.decisionType === 'ConstitutionalReview' || p.decisionType === 'ConstitutionalUnanimous'
|
||||
).length;
|
||||
if (import.meta.env.DEV) console.log('Active proposals:', activeProposals);
|
||||
} catch (err) {
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch referenda count:', err);
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch proposals:', err);
|
||||
}
|
||||
|
||||
// Fetch active elections via welati
|
||||
let activeElections = 0;
|
||||
try {
|
||||
const elections = await getActiveElections(api);
|
||||
activeElections = elections.length;
|
||||
if (import.meta.env.DEV) console.log('Active elections:', activeElections);
|
||||
} catch (err) {
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch elections:', err);
|
||||
}
|
||||
|
||||
// Fetch parliament members via welati
|
||||
let parliamentMembers = 0;
|
||||
try {
|
||||
const members = await getParliamentMembers(api);
|
||||
parliamentMembers = members.length;
|
||||
if (import.meta.env.DEV) console.log('Parliament members:', parliamentMembers);
|
||||
} catch (err) {
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch parliament members:', err);
|
||||
}
|
||||
|
||||
// Fetch diwan members via welati
|
||||
let diwanMembers = 0;
|
||||
try {
|
||||
const members = await getDiwanMembers(api);
|
||||
diwanMembers = members.length;
|
||||
if (import.meta.env.DEV) console.log('Diwan members:', diwanMembers);
|
||||
} catch (err) {
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch diwan members:', err);
|
||||
}
|
||||
|
||||
// Fetch treasury balance
|
||||
@@ -70,31 +111,25 @@ const GovernanceOverview: React.FC = () => {
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch treasury balance:', err);
|
||||
}
|
||||
|
||||
// Fetch council members
|
||||
let parliamentMembers = 0;
|
||||
try {
|
||||
const members = await api.query.council.members();
|
||||
parliamentMembers = members.length;
|
||||
if (import.meta.env.DEV) console.log('Council members:', parliamentMembers);
|
||||
} catch (err) {
|
||||
if (import.meta.env.DEV) console.warn('Failed to fetch council members:', err);
|
||||
}
|
||||
|
||||
// Update stats
|
||||
setStats({
|
||||
activeProposals,
|
||||
activeElections: 0, // Not implemented yet
|
||||
totalVoters: 0, // Will be calculated from conviction voting
|
||||
activeElections,
|
||||
totalVoters: 0,
|
||||
participationRate: 0,
|
||||
parliamentMembers,
|
||||
diwanMembers: 0, // Not implemented yet
|
||||
nextElection: '-',
|
||||
parliamentMax: 201,
|
||||
diwanMembers,
|
||||
diwanMax: 9,
|
||||
pendingVotes,
|
||||
diwanPendingReviews,
|
||||
treasuryBalance
|
||||
});
|
||||
|
||||
if (import.meta.env.DEV) console.log('✅ Governance data updated:', {
|
||||
if (import.meta.env.DEV) console.log('Governance data updated:', {
|
||||
activeProposals,
|
||||
activeElections,
|
||||
parliamentMembers,
|
||||
diwanMembers,
|
||||
treasuryBalance
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -107,23 +142,6 @@ const GovernanceOverview: React.FC = () => {
|
||||
fetchGovernanceData();
|
||||
}, [api, isApiReady]);
|
||||
|
||||
const [recentActivity] = useState([
|
||||
{ type: 'proposal', action: 'New proposal submitted', title: 'Treasury Allocation Update', time: '2 hours ago' },
|
||||
{ type: 'vote', action: 'Vote cast', title: 'Infrastructure Development Fund', time: '3 hours ago' },
|
||||
{ type: 'election', action: 'Election started', title: 'Parliamentary Elections 2024', time: '1 day ago' },
|
||||
{ type: 'approved', action: 'Proposal approved', title: 'Community Grant Program', time: '2 days ago' }
|
||||
]);
|
||||
|
||||
const getActivityIcon = (type: string) => {
|
||||
switch(type) {
|
||||
case 'proposal': return <FileText className="w-4 h-4 text-blue-400" />;
|
||||
case 'vote': return <Vote className="w-4 h-4 text-purple-400" />;
|
||||
case 'election': return <Users className="w-4 h-4 text-cyan-400" />;
|
||||
case 'approved': return <CheckCircle className="w-4 h-4 text-green-400" />;
|
||||
default: return <Activity className="w-4 h-4 text-gray-400" />;
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <LoadingState message="Loading governance data..." />;
|
||||
}
|
||||
@@ -138,7 +156,6 @@ const GovernanceOverview: React.FC = () => {
|
||||
<div>
|
||||
<p className="text-gray-400 text-sm">Active Proposals</p>
|
||||
<p className="text-2xl font-bold text-white mt-1">{stats.activeProposals}</p>
|
||||
<p className="text-xs text-green-400 mt-2">+3 this week</p>
|
||||
</div>
|
||||
<div className="p-3 bg-blue-500/10 rounded-lg">
|
||||
<FileText className="w-6 h-6 text-blue-400" />
|
||||
@@ -153,7 +170,6 @@ const GovernanceOverview: React.FC = () => {
|
||||
<div>
|
||||
<p className="text-gray-400 text-sm">Active Elections</p>
|
||||
<p className="text-2xl font-bold text-white mt-1">{stats.activeElections}</p>
|
||||
<p className="text-xs text-cyan-400 mt-2">Next in {stats.nextElection}</p>
|
||||
</div>
|
||||
<div className="p-3 bg-cyan-500/10 rounded-lg">
|
||||
<Users className="w-6 h-6 text-cyan-400" />
|
||||
@@ -166,9 +182,8 @@ const GovernanceOverview: React.FC = () => {
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-gray-400 text-sm">Participation Rate</p>
|
||||
<p className="text-2xl font-bold text-white mt-1">{stats.participationRate}%</p>
|
||||
<Progress value={stats.participationRate} className="mt-2 h-1" />
|
||||
<p className="text-gray-400 text-sm">Total Voters</p>
|
||||
<p className="text-2xl font-bold text-white mt-1">{stats.totalVoters}</p>
|
||||
</div>
|
||||
<div className="p-3 bg-kurdish-green/10 rounded-lg">
|
||||
<TrendingUpIcon className="w-6 h-6 text-kurdish-green" />
|
||||
@@ -206,21 +221,17 @@ const GovernanceOverview: React.FC = () => {
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Active Members</span>
|
||||
<span className="text-white font-semibold">{stats.parliamentMembers}/27</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Current Session</span>
|
||||
<Badge className="bg-green-500/10 text-green-400 border-green-500/20">In Session</Badge>
|
||||
<span className="text-white font-semibold">{stats.parliamentMembers}/{stats.parliamentMax}</span>
|
||||
</div>
|
||||
{stats.activeElections > 0 && (
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Elections</span>
|
||||
<Badge className="bg-green-500/10 text-green-400 border-green-500/20">Active</Badge>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Pending Votes</span>
|
||||
<span className="text-white font-semibold">5</span>
|
||||
</div>
|
||||
<div className="pt-2 border-t border-gray-800">
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-gray-400">Quorum Status</span>
|
||||
<span className="text-green-400">Met (85%)</span>
|
||||
</div>
|
||||
<span className="text-white font-semibold">{stats.pendingVotes}</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -230,94 +241,25 @@ const GovernanceOverview: React.FC = () => {
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center">
|
||||
<Shield className="w-5 h-5 mr-2 text-cyan-400" />
|
||||
Dîwan (Constitutional Court)
|
||||
Diwan (Constitutional Court)
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Active Judges</span>
|
||||
<span className="text-white font-semibold">{stats.diwanMembers}/9</span>
|
||||
<span className="text-white font-semibold">{stats.diwanMembers}/{stats.diwanMax}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Pending Reviews</span>
|
||||
<span className="text-white font-semibold">3</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Recent Decisions</span>
|
||||
<span className="text-white font-semibold">12</span>
|
||||
</div>
|
||||
<div className="pt-2 border-t border-gray-800">
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-gray-400">Next Hearing</span>
|
||||
<span className="text-cyan-400">Tomorrow, 14:00 UTC</span>
|
||||
</div>
|
||||
<span className="text-white font-semibold">{stats.diwanPendingReviews}</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Recent Activity */}
|
||||
<Card className="bg-gray-900/50 border-gray-800">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center">
|
||||
<Activity className="w-5 h-5 mr-2 text-purple-400" />
|
||||
Recent Governance Activity
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-3">
|
||||
{recentActivity.map((activity, index) => (
|
||||
<div key={index} className="flex items-start space-x-3 p-3 rounded-lg hover:bg-gray-800/50 transition-colors">
|
||||
{getActivityIcon(activity.type)}
|
||||
<div className="flex-1">
|
||||
<p className="text-sm text-gray-300">{activity.action}</p>
|
||||
<p className="text-xs text-white font-medium mt-1">{activity.title}</p>
|
||||
</div>
|
||||
<span className="text-xs text-gray-500">{activity.time}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Voting Power Distribution */}
|
||||
<Card className="bg-gray-900/50 border-gray-800">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-white flex items-center">
|
||||
<PieChart className="w-5 h-5 mr-2 text-purple-400" />
|
||||
Voting Power Distribution
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Direct Votes</span>
|
||||
<span className="text-white font-semibold">45%</span>
|
||||
</div>
|
||||
<Progress value={45} className="h-2 bg-gray-800" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Delegated Votes</span>
|
||||
<span className="text-white font-semibold">35%</span>
|
||||
</div>
|
||||
<Progress value={35} className="h-2 bg-gray-800" />
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-gray-400">Proxy Votes</span>
|
||||
<span className="text-white font-semibold">20%</span>
|
||||
</div>
|
||||
<Progress value={20} className="h-2 bg-gray-800" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GovernanceOverview;
|
||||
export default GovernanceOverview;
|
||||
|
||||
Reference in New Issue
Block a user