+ {discussion.title} +
++ {discussion.content} +
+ + {/* Tags */} ++ No discussions found matching your search. +
+diff --git a/client/app/community/page.tsx b/client/app/community/page.tsx new file mode 100644 index 0000000..85efd99 --- /dev/null +++ b/client/app/community/page.tsx @@ -0,0 +1,539 @@ +"use client"; +import React, { useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + ChatBubbleLeftRightIcon, + FireIcon, + ClockIcon, + CheckBadgeIcon, + ArrowUpIcon, + ArrowDownIcon, + MagnifyingGlassIcon, + PlusCircleIcon, + TagIcon, + UserCircleIcon, + CalendarIcon, + ChatBubbleBottomCenterTextIcon, +} from "@heroicons/react/24/outline"; +import { HeartIcon as HeartIconSolid } from "@heroicons/react/24/solid"; + +interface Discussion { + id: number; + title: string; + content: string; + author: string; + authorBadge?: string; + votes: number; + replies: number; + views: number; + category: string; + tags: string[]; + timestamp: string; + isPinned?: boolean; +} + +const mockDiscussions: Discussion[] = [ + { + id: 1, + title: "Best voting algorithm for university elections?", + content: + "We're planning to use Agora for our university student council elections. Which voting algorithm would you recommend for 500+ voters?", + author: "Alex Chen", + authorBadge: "Verified Creator", + votes: 24, + replies: 15, + views: 342, + category: "Voting Algorithms", + tags: ["borda", "irv", "advice"], + timestamp: "2 hours ago", + isPinned: true, + }, + { + id: 2, + title: "How to ensure voter anonymity with ZK-SNARKs?", + content: + "I'm interested in implementing anonymous voting. Can someone explain how the zero-knowledge proofs work in Agora?", + author: "Sarah Johnson", + votes: 18, + replies: 8, + views: 256, + category: "Security & Privacy", + tags: ["zk-snarks", "anonymity", "privacy"], + timestamp: "5 hours ago", + }, + { + id: 3, + title: "Smart contract deployment costs on different networks", + content: + "Has anyone compared gas fees for deploying elections on Sepolia vs Polygon Amoy? Looking for real-world data.", + author: "Michael Torres", + authorBadge: "Top Contributor", + votes: 32, + replies: 22, + views: 489, + category: "Blockchain & Gas", + tags: ["gas-fees", "deployment", "networks"], + timestamp: "1 day ago", + }, + { + id: 4, + title: "Feature request: Multi-signature election creation", + content: + "Would be great to have multiple admins approve election creation. Anyone else need this feature?", + author: "Emma Davis", + votes: 15, + replies: 12, + views: 178, + category: "Feature Requests", + tags: ["multi-sig", "governance", "feature"], + timestamp: "2 days ago", + }, + { + id: 5, + title: "Integrating Agora with Discord for community voting", + content: + "Working on a Discord bot that integrates with Agora. Has anyone done this before? Looking for guidance.", + author: "David Kim", + votes: 28, + replies: 19, + views: 412, + category: "Integrations", + tags: ["discord", "bot", "integration"], + timestamp: "3 days ago", + }, + { + id: 6, + title: "Troubleshooting: Wallet won't connect on mobile", + content: + "Users reporting issues connecting MetaMask on mobile browsers. Any solutions?", + author: "Lisa Wang", + votes: 12, + replies: 7, + views: 145, + category: "Technical Support", + tags: ["mobile", "wallet", "bug"], + timestamp: "4 days ago", + }, +]; + +const categories = [ + { name: "All Topics", icon: ChatBubbleLeftRightIcon, count: 156 }, + { name: "Voting Algorithms", icon: CheckBadgeIcon, count: 42 }, + { name: "Security & Privacy", icon: FireIcon, count: 38 }, + { name: "Blockchain & Gas", icon: TagIcon, count: 29 }, + { name: "Feature Requests", icon: PlusCircleIcon, count: 24 }, + { name: "Integrations", icon: ChatBubbleBottomCenterTextIcon, count: 15 }, + { name: "Technical Support", icon: ClockIcon, count: 8 }, +]; + +export default function CommunityPage() { + const [searchQuery, setSearchQuery] = useState(""); + const [selectedCategory, setSelectedCategory] = useState("All Topics"); + const [sortBy, setSortBy] = useState<"hot" | "new" | "top">("hot"); + const [votedPosts, setVotedPosts] = useState<{ + [key: number]: "up" | "down" | null; + }>({}); + const [isNewDiscussionOpen, setIsNewDiscussionOpen] = useState(false); + const [newDiscussion, setNewDiscussion] = useState({ + title: "", + content: "", + category: "General", + tags: "", + }); + + const handleVote = (postId: number, voteType: "up" | "down") => { + setVotedPosts((prev) => ({ + ...prev, + [postId]: prev[postId] === voteType ? null : voteType, + })); + }; + + const handleCreateDiscussion = (e: React.FormEvent) => { + e.preventDefault(); + // In a real app, this would POST to an API + alert(`New discussion created:\nTitle: ${newDiscussion.title}\nCategory: ${newDiscussion.category}`); + setNewDiscussion({ title: "", content: "", category: "General", tags: "" }); + setIsNewDiscussionOpen(false); + }; + + const filteredDiscussions = mockDiscussions.filter((discussion) => { + const matchesSearch = + discussion.title.toLowerCase().includes(searchQuery.toLowerCase()) || + discussion.content.toLowerCase().includes(searchQuery.toLowerCase()) || + discussion.tags.some((tag) => + tag.toLowerCase().includes(searchQuery.toLowerCase()) + ); + const matchesCategory = + selectedCategory === "All Topics" || + discussion.category === selectedCategory; + return matchesSearch && matchesCategory; + }); + + return ( +
+ Discuss voting algorithms, share ideas, and connect with the + community +
++ {discussion.content} +
+ + {/* Tags */} ++ No discussions found matching your search. +
+