import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { usePolkadot } from '@/contexts/PolkadotContext'; import { useAuth } from '@/contexts/AuthContext'; import { useDashboard } from '@/contexts/DashboardContext'; import { ArrowLeft, Plus, ThumbsUp, ThumbsDown, Filter, Search, MessageSquare, AlertCircle, CheckCircle2, Clock, XCircle, Users, Crown, FileText, UserPlus, UserMinus } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; // Issue categories const CATEGORIES = [ { value: 'Governance', label: 'Rêveberî (Governance)', color: 'bg-blue-500' }, { value: 'Security', label: 'Ewlehî (Security)', color: 'bg-red-500' }, { value: 'Economy', label: 'Aborî (Economy)', color: 'bg-green-500' }, { value: 'Infrastructure', label: 'Binesaz (Infrastructure)', color: 'bg-gray-500' }, { value: 'Education', label: 'Perwerde (Education)', color: 'bg-purple-500' }, { value: 'Healthcare', label: 'Tenduristî (Healthcare)', color: 'bg-pink-500' }, { value: 'Environment', label: 'Jîngeh (Environment)', color: 'bg-emerald-500' }, { value: 'Other', label: 'Din (Other)', color: 'bg-orange-500' } ]; // Issue statuses const STATUSES = [ { value: 'Pending', label: 'Li Benda (Pending)', color: 'bg-yellow-500' }, { value: 'InProgress', label: 'Di Pêşketin de (In Progress)', color: 'bg-blue-500' }, { value: 'Resolved', label: 'Çareser kirin (Resolved)', color: 'bg-green-500' }, { value: 'Closed', label: 'Girtî (Closed)', color: 'bg-gray-500' } ]; interface Issue { id: number; submitter: string; description: string; category: string; status: string; supportVotes: number; opposeVotes: number; response?: string; blockNumber: number; } interface ParliamentCandidate { address: string; votes: number; isNominated: boolean; } interface PresidentCandidate { address: string; votes: number; isNominated: boolean; } interface LegislationProposal { id: number; proposer: string; title: string; description: string; supportVotes: number; opposeVotes: number; status: string; blockNumber: number; } export default function CitizensIssues() { const { api, isApiReady, selectedAccount } = usePolkadot(); const { user } = useAuth(); const { nftDetails } = useDashboard(); const navigate = useNavigate(); const { toast } = useToast(); const [activeTab, setActiveTab] = useState('issues'); const [loading, setLoading] = useState(true); // Tab 1: Issues const [issues, setIssues] = useState([]); const [filteredIssues, setFilteredIssues] = useState([]); const [userVotes, setUserVotes] = useState>(new Map()); const [categoryFilter, setCategoryFilter] = useState('all'); const [statusFilter, setStatusFilter] = useState('all'); const [searchQuery, setSearchQuery] = useState(''); const [showSubmitModal, setShowSubmitModal] = useState(false); const [newIssueDescription, setNewIssueDescription] = useState(''); const [newIssueCategory, setNewIssueCategory] = useState('Governance'); const [isSubmitting, setIsSubmitting] = useState(false); // Tab 2: Parliament const [parliamentCandidates, setParliamentCandidates] = useState([]); const [userParliamentVote, setUserParliamentVote] = useState(null); const [userParliamentNomination, setUserParliamentNomination] = useState(null); const [showNominateParliamentModal, setShowNominateParliamentModal] = useState(false); const [nominateParliamentAddress, setNominateParliamentAddress] = useState(''); // Tab 3: President const [presidentCandidates, setPresidentCandidates] = useState([]); const [userPresidentVote, setUserPresidentVote] = useState(null); const [userPresidentNomination, setUserPresidentNomination] = useState(null); const [showNominatePresidentModal, setShowNominatePresidentModal] = useState(false); const [nominatePresidentAddress, setNominatePresidentAddress] = useState(''); // Tab 4: Legislation const [legislationProposals, setLegislationProposals] = useState([]); const [userLegislationVotes, setUserLegislationVotes] = useState>(new Map()); const [showProposeLegislationModal, setShowProposeLegislationModal] = useState(false); const [legislationTitle, setLegislationTitle] = useState(''); const [legislationDescription, setLegislationDescription] = useState(''); useEffect(() => { if (isApiReady && selectedAccount) { fetchAllData(); } }, [isApiReady, selectedAccount, activeTab]); useEffect(() => { applyFilters(); }, [issues, categoryFilter, statusFilter, searchQuery]); const fetchAllData = async () => { setLoading(true); try { if (activeTab === 'issues') { await fetchIssues(); await fetchUserVotes(); } else if (activeTab === 'parliament') { await fetchParliamentCandidates(); } else if (activeTab === 'president') { await fetchPresidentCandidates(); } else if (activeTab === 'legislation') { await fetchLegislationProposals(); } } finally { setLoading(false); } }; // ============= TAB 1: ISSUES ============= const fetchIssues = async () => { if (!api || !isApiReady) return; try { const issueCountResult = await api.query.welati.issueCount(); const issueCount = issueCountResult.toNumber(); const fetchedIssues: Issue[] = []; for (let i = 0; i < issueCount; i++) { const issueOption = await api.query.welati.issues(i); if (!issueOption.isEmpty) { const issue = issueOption.unwrap(); fetchedIssues.push({ id: i, submitter: issue.submitter.toString(), description: issue.description.toString(), category: issue.category.toString(), status: issue.status.toString(), supportVotes: issue.supportVotes.toNumber(), opposeVotes: issue.opposeVotes.toNumber(), response: issue.response.isSome ? issue.response.unwrap().toString() : undefined, blockNumber: issue.blockNumber.toNumber() }); } } setIssues(fetchedIssues.reverse()); } catch (error) { console.error('Error fetching issues:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di barkirina pirsan de (Error loading issues)', variant: 'destructive' }); } }; const fetchUserVotes = async () => { if (!api || !isApiReady || !selectedAccount) return; try { const votesEntries = await api.query.welati.issueVotes.entries(selectedAccount.address); const votes = new Map(); votesEntries.forEach(([key, value]) => { const issueId = key.args[1].toNumber(); const support = value.toJSON() as boolean; votes.set(issueId, support); }); setUserVotes(votes); } catch (error) { console.error('Error fetching user votes:', error); } }; const applyFilters = () => { let filtered = [...issues]; if (categoryFilter !== 'all') { filtered = filtered.filter(issue => issue.category === categoryFilter); } if (statusFilter !== 'all') { filtered = filtered.filter(issue => issue.status === statusFilter); } if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); filtered = filtered.filter(issue => issue.description.toLowerCase().includes(query) ); } setFilteredIssues(filtered); }; const handleSubmitIssue = async () => { if (!api || !selectedAccount || !newIssueDescription.trim()) return; setIsSubmitting(true); try { const tx = api.tx.welati.submitIssue(newIssueDescription, newIssueCategory); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Pirsgirêk hate şandin (Issue Submitted)', description: 'Pirsgirêka we bi serkeftî hate şandin (Your issue has been submitted successfully)', }); setShowSubmitModal(false); setNewIssueDescription(''); setNewIssueCategory('Governance'); setIsSubmitting(false); fetchIssues(); } }); } catch (error) { console.error('Error submitting issue:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina pirsgirêkê de (Error submitting issue)', variant: 'destructive' }); setIsSubmitting(false); } }; const handleVote = async (issueId: number, support: boolean) => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.voteOnIssue(issueId, support); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Deng hate şandin (Vote Submitted)', description: support ? 'Hûn piştgiriya xwe nîşan da (You voted in support)' : 'Hûn dijberiya xwe nîşan da (You voted in opposition)', }); setUserVotes(prev => new Map(prev).set(issueId, support)); fetchIssues(); } }); } catch (error) { console.error('Error voting:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina dengê de (Error submitting vote)', variant: 'destructive' }); } }; // ============= TAB 2: PARLIAMENT ============= const fetchParliamentCandidates = async () => { if (!api || !isApiReady) return; try { const candidatesEntries = await api.query.welati.parliamentCandidates.entries(); const candidates: ParliamentCandidate[] = []; candidatesEntries.forEach(([key, value]) => { const address = key.args[0].toString(); const candidateData: any = value.toJSON(); candidates.push({ address, votes: candidateData.votes || 0, isNominated: candidateData.isNominated || true }); }); setParliamentCandidates(candidates.sort((a, b) => b.votes - a.votes)); // Check user's vote and nomination if (selectedAccount) { const userVoteResult = await api.query.welati.parliamentVotes(selectedAccount.address); if (!userVoteResult.isEmpty) { setUserParliamentVote(userVoteResult.toString()); } const isNominated = candidates.some(c => c.address === selectedAccount.address); if (isNominated) { setUserParliamentNomination(selectedAccount.address); } } } catch (error) { console.error('Error fetching parliament candidates:', error); } }; const handleSelfNominateParliament = async () => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.nominateForParliament(selectedAccount.address); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Namzedî hate şandin (Nomination Submitted)', description: 'Hûn bi serkeftî bûne namzed (You have successfully become a candidate)', }); fetchParliamentCandidates(); } }); } catch (error) { console.error('Error self-nominating for parliament:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina namzediyê de (Error submitting nomination)', variant: 'destructive' }); } }; const handleNominateParliament = async () => { if (!api || !selectedAccount || !nominateParliamentAddress.trim()) return; try { const tx = api.tx.welati.nominateForParliament(nominateParliamentAddress); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Namzedî hate şandin (Nomination Submitted)', description: 'Namzediya Parlamentoyê bi serkeftî hate şandin (Parliament nomination submitted successfully)', }); setShowNominateParliamentModal(false); setNominateParliamentAddress(''); fetchParliamentCandidates(); } }); } catch (error) { console.error('Error nominating for parliament:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina namzediyê de (Error submitting nomination)', variant: 'destructive' }); } }; const handleVoteParliament = async (address: string) => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.voteForParliament(address); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Deng hate şandin (Vote Submitted)', description: 'Denga we ji bo Parlamentoyê hate şandin (Your vote for Parliament has been submitted)', }); setUserParliamentVote(address); fetchParliamentCandidates(); } }); } catch (error) { console.error('Error voting for parliament:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina dengê de (Error submitting vote)', variant: 'destructive' }); } }; const handleRemoveParliamentNomination = async () => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.removeParliamentNomination(selectedAccount.address); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Namzedî hate jêbirin (Nomination Removed)', description: 'Namzediya we hate jêbirin (Your nomination has been removed)', }); setUserParliamentNomination(null); fetchParliamentCandidates(); } }); } catch (error) { console.error('Error removing parliament nomination:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di jêbirina namzediyê de (Error removing nomination)', variant: 'destructive' }); } }; // ============= TAB 3: PRESIDENT ============= const fetchPresidentCandidates = async () => { if (!api || !isApiReady) return; try { const candidatesEntries = await api.query.welati.presidentCandidates.entries(); const candidates: PresidentCandidate[] = []; candidatesEntries.forEach(([key, value]) => { const address = key.args[0].toString(); const candidateData: any = value.toJSON(); candidates.push({ address, votes: candidateData.votes || 0, isNominated: candidateData.isNominated || true }); }); setPresidentCandidates(candidates.sort((a, b) => b.votes - a.votes)); // Check user's vote and nomination if (selectedAccount) { const userVoteResult = await api.query.welati.presidentVotes(selectedAccount.address); if (!userVoteResult.isEmpty) { setUserPresidentVote(userVoteResult.toString()); } const isNominated = candidates.some(c => c.address === selectedAccount.address); if (isNominated) { setUserPresidentNomination(selectedAccount.address); } } } catch (error) { console.error('Error fetching president candidates:', error); } }; const handleSelfNominatePresident = async () => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.nominateForPresident(selectedAccount.address); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Namzedî hate şandin (Nomination Submitted)', description: 'Hûn bi serkeftî bûne namzedê Serokê (You have successfully become a presidential candidate)', }); fetchPresidentCandidates(); } }); } catch (error) { console.error('Error self-nominating for president:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina namzediyê de (Error submitting nomination)', variant: 'destructive' }); } }; const handleNominatePresident = async () => { if (!api || !selectedAccount || !nominatePresidentAddress.trim()) return; try { const tx = api.tx.welati.nominateForPresident(nominatePresidentAddress); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Namzedî hate şandin (Nomination Submitted)', description: 'Namzediya Serokê bi serkeftî hate şandin (President nomination submitted successfully)', }); setShowNominatePresidentModal(false); setNominatePresidentAddress(''); fetchPresidentCandidates(); } }); } catch (error) { console.error('Error nominating for president:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina namzediyê de (Error submitting nomination)', variant: 'destructive' }); } }; const handleVotePresident = async (address: string) => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.voteForPresident(address); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Deng hate şandin (Vote Submitted)', description: 'Denga we ji bo Serokê hate şandin (Your vote for President has been submitted)', }); setUserPresidentVote(address); fetchPresidentCandidates(); } }); } catch (error) { console.error('Error voting for president:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina dengê de (Error submitting vote)', variant: 'destructive' }); } }; const handleRemovePresidentNomination = async () => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.removePresidentNomination(selectedAccount.address); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Namzedî hate jêbirin (Nomination Removed)', description: 'Namzediya we hate jêbirin (Your nomination has been removed)', }); setUserPresidentNomination(null); fetchPresidentCandidates(); } }); } catch (error) { console.error('Error removing president nomination:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di jêbirina namzediyê de (Error removing nomination)', variant: 'destructive' }); } }; // ============= TAB 4: LEGISLATION ============= const fetchLegislationProposals = async () => { if (!api || !isApiReady) return; try { const proposalsEntries = await api.query.welati.legislationProposals.entries(); const proposals: LegislationProposal[] = []; proposalsEntries.forEach(([key, value]) => { const proposalId = key.args[0].toNumber(); const proposalData: any = value.toJSON(); proposals.push({ id: proposalId, proposer: proposalData.proposer, title: proposalData.title, description: proposalData.description, supportVotes: proposalData.supportVotes || 0, opposeVotes: proposalData.opposeVotes || 0, status: proposalData.status || 'Active', blockNumber: proposalData.blockNumber || 0 }); }); setLegislationProposals(proposals.reverse()); // Fetch user votes if (selectedAccount) { const votesEntries = await api.query.welati.legislationVotes.entries(selectedAccount.address); const votes = new Map(); votesEntries.forEach(([key, value]) => { const proposalId = key.args[1].toNumber(); const support = value.toJSON() as boolean; votes.set(proposalId, support); }); setUserLegislationVotes(votes); } } catch (error) { console.error('Error fetching legislation proposals:', error); } }; const handleProposeLegislation = async () => { if (!api || !selectedAccount || !legislationTitle.trim() || !legislationDescription.trim()) return; try { const tx = api.tx.welati.proposeLegislation(legislationTitle, legislationDescription); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Pêşniyar hate şandin (Proposal Submitted)', description: 'Pêşniyara Yasayê bi serkeftî hate şandin (Legislation proposal submitted successfully)', }); setShowProposeLegislationModal(false); setLegislationTitle(''); setLegislationDescription(''); fetchLegislationProposals(); } }); } catch (error) { console.error('Error proposing legislation:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina pêşniyarê de (Error submitting proposal)', variant: 'destructive' }); } }; const handleVoteLegislation = async (proposalId: number, support: boolean) => { if (!api || !selectedAccount) return; try { const tx = api.tx.welati.voteOnLegislation(proposalId, support); await tx.signAndSend(selectedAccount.address, ({ status }) => { if (status.isInBlock || status.isFinalized) { toast({ title: '✅ Deng hate şandin (Vote Submitted)', description: support ? 'Hûn piştgiriya xwe nîşan da (You voted in support)' : 'Hûn dijberiya xwe nîşan da (You voted in opposition)', }); setUserLegislationVotes(prev => new Map(prev).set(proposalId, support)); fetchLegislationProposals(); } }); } catch (error) { console.error('Error voting on legislation:', error); toast({ title: 'Xeletî (Error)', description: 'Pirsgirêk di şandina dengê de (Error submitting vote)', variant: 'destructive' }); } }; // ============= HELPER FUNCTIONS ============= const getCategoryColor = (category: string) => { return CATEGORIES.find(c => c.value === category)?.color || 'bg-gray-500'; }; const getStatusColor = (status: string) => { return STATUSES.find(s => s.value === status)?.color || 'bg-gray-500'; }; const getStatusIcon = (status: string) => { switch (status) { case 'Pending': return ; case 'InProgress': return ; case 'Resolved': return ; case 'Closed': return ; default: return null; } }; if (loading && activeTab === 'issues' && issues.length === 0) { return (

Pirsgirêkên Welatî tê barkirin... (Loading Citizens Issues...)

); } return (
{/* Back Button */}
{/* Header */}

Karên Welatiyên (Citizens Portal)

Beşdarî rêveberiyê bibin (Participate in Governance)

{/* Tabs */} Pirsgirêk (Issues) Parleman (Parliament) Serok (President) Yasa (Legislation) {/* ========== TAB 1: ISSUES ========== */} {/* Submit Issue Button */}
{/* Filters */}
setSearchQuery(e.target.value)} className="pl-10" />
{/* Issues List */}
{filteredIssues.length === 0 ? (

Tu pirsgirêk nehat dîtin (No issues found)

) : ( filteredIssues.map(issue => (
{CATEGORIES.find(c => c.value === issue.category)?.label} {getStatusIcon(issue.status)} {STATUSES.find(s => s.value === issue.status)?.label}
Pirsgirêk #{issue.id} • Block #{issue.blockNumber}

{issue.description}

{issue.response && (

Bersiva Hikûmetê (Government Response)

{issue.response}

)}
{userVotes.has(issue.id) && (

Hûn berê deng dane (You already voted)

)}
)) )}
{/* Submit Issue Modal */} Pirsgirêkeke Nû Şandin (Submit New Issue) Pirsgirêka xwe bi rêveberiyê re parve bikin (Share your concern with governance)