From 66f170a21d491cf4ca680ab10da39a440f82c972 Mon Sep 17 00:00:00 2001 From: Justin Carper Date: Mon, 24 Mar 2025 16:25:03 -0400 Subject: [PATCH] ui prototyping --- discovery/initial/HIGH_LEVEL_CORE_MVP.md | 2 +- discovery/initial/PLAN.md | 4 +- .../SERVICE_SEGREGATION_RESPONSIBILITIES.md | 6 +- discovery/initial/STACK_GUIDANCE.md | 22 +- discovery/refined/DECENTRALIZATION.md | 18 +- discovery/refined/IMPLEMENTATION_PLAN.md | 14 +- discovery/refined/INTRO.md | 2 +- .../app/contributions/[id]/loading.tsx | 3 + ui/prototype/app/contributions/[id]/page.tsx | 499 +++++++++++++++++ ui/prototype/app/insights/page.tsx | 67 ++- ui/prototype/app/issues/[id]/page.tsx | 460 +++++++++++++++ ui/prototype/app/issues/page.tsx | 250 +++++++++ ui/prototype/app/issues/propose/page.tsx | 293 ++++++++++ ui/prototype/app/resolutions/[id]/loading.tsx | 3 + ui/prototype/app/resolutions/[id]/page.tsx | 529 ++++++++++++++++++ ui/prototype/app/submit/page.tsx | 411 ++++++++++---- ui/prototype/components/app-sidebar.tsx | 11 +- .../components/connect-wallet-button.tsx | 58 +- .../components/wallet-connection-modal.tsx | 245 ++++++++ .../public/images/wallets/coinbase.svg | 4 + .../public/images/wallets/metamask.svg | 5 + .../public/images/wallets/privado.svg | 5 + .../public/images/wallets/walletconnect.svg | 4 + 23 files changed, 2691 insertions(+), 224 deletions(-) create mode 100644 ui/prototype/app/contributions/[id]/loading.tsx create mode 100644 ui/prototype/app/contributions/[id]/page.tsx create mode 100644 ui/prototype/app/issues/[id]/page.tsx create mode 100644 ui/prototype/app/issues/page.tsx create mode 100644 ui/prototype/app/issues/propose/page.tsx create mode 100644 ui/prototype/app/resolutions/[id]/loading.tsx create mode 100644 ui/prototype/app/resolutions/[id]/page.tsx create mode 100644 ui/prototype/components/wallet-connection-modal.tsx create mode 100644 ui/prototype/public/images/wallets/coinbase.svg create mode 100644 ui/prototype/public/images/wallets/metamask.svg create mode 100644 ui/prototype/public/images/wallets/privado.svg create mode 100644 ui/prototype/public/images/wallets/walletconnect.svg diff --git a/discovery/initial/HIGH_LEVEL_CORE_MVP.md b/discovery/initial/HIGH_LEVEL_CORE_MVP.md index bd44a03..bfa4c41 100644 --- a/discovery/initial/HIGH_LEVEL_CORE_MVP.md +++ b/discovery/initial/HIGH_LEVEL_CORE_MVP.md @@ -57,7 +57,7 @@ ## System Architecture Overview -- **Frontend**: A user-friendly interface (e.g., built with **Elm**) for submitting feedback, viewing legislation, and editing collaboratively. +- **Frontend**: A user-friendly interface (e.g., built with **Next.js**) for submitting feedback, viewing legislation, and editing collaboratively. - **Backend**: Core logic (e.g., in **Go**) to process feedback, integrate AI, and interact with the blockchain. - **Blockchain**: **Hyperledger Fabric** for storing data and managing smart contracts. - **AI Services**: **Python**-based NLP and text generation models. diff --git a/discovery/initial/PLAN.md b/discovery/initial/PLAN.md index 4c52b0f..1d1585c 100644 --- a/discovery/initial/PLAN.md +++ b/discovery/initial/PLAN.md @@ -41,7 +41,7 @@ The system’s architecture is modular, allowing each component to be developed ### 5. Frontend Layer - **Purpose**: Offers a user-friendly interface for feedback submission, editing, and tracking. - **Technology**: - - Elm for a secure, functional UI. + - Next.js for a secure, functional UI. - JavaScript for cryptographic tasks (e.g., ZKP generation). - **Key Features**: - Accessible design (WCAG-compliant). @@ -68,7 +68,7 @@ We’ll use a phased, iterative approach to build the system, ensuring each comp 1. Deploy Hyperledger Fabric network. 2. Implement chaincode for feedback submission with simulated ZKPs (e.g., token-based). 3. Build an AI microservice for feedback categorization and text generation. - 4. Create a basic Elm frontend for feedback submission. + 4. Create a basic Next.js frontend for feedback submission. - **Success Metrics**: - Blockchain stores test feedback. - AI accurately categorizes and generates text from sample data. diff --git a/discovery/initial/SERVICE_SEGREGATION_RESPONSIBILITIES.md b/discovery/initial/SERVICE_SEGREGATION_RESPONSIBILITIES.md index c3fa651..af8d852 100644 --- a/discovery/initial/SERVICE_SEGREGATION_RESPONSIBILITIES.md +++ b/discovery/initial/SERVICE_SEGREGATION_RESPONSIBILITIES.md @@ -51,9 +51,9 @@ Your system can be broken down into six core services, each with distinct respon - Provide a user-friendly interface for feedback submission, editing, and tracking. - Handle client-side cryptographic operations (e.g., ZKP generation). - **Languages**: - - **Elm**: For the core UI logic (secure, functional, and maintainable). + - **Next.js**: For the core UI logic (secure, functional, and maintainable). - **JavaScript**: For cryptographic tasks (e.g., ZKP generation via `snarkjs`). -- **Why Elm and JavaScript?**: Elm ensures a robust, type-safe UI, while JavaScript handles browser-based cryptography. +- **Why Next.js and JavaScript?**: Next.js ensures a robust, type-safe UI, while JavaScript handles browser-based cryptography. - **Integration**: - Communicates with backend services via gRPC-Web or a proxy. - Uses WebSockets or polling for real-time updates (e.g., live legislative tracking). @@ -81,7 +81,7 @@ legislative-platform/ ├── ai-service/ # Python: AI analysis and text generation ├── zkp-service/ # Go: ZKP verification ├── collaboration-service/ # Go: Git-like collaboration logic -├── frontend-service/ # Elm + JS: User interface and client-side crypto +├── frontend-service/ # Next.js + JS: User interface and client-side crypto ├── integration-service/ # Go: External system integration ├── shared/ # Common libraries, protos, etc. ├── docs/ # Documentation diff --git a/discovery/initial/STACK_GUIDANCE.md b/discovery/initial/STACK_GUIDANCE.md index c7ce6e2..120c162 100644 --- a/discovery/initial/STACK_GUIDANCE.md +++ b/discovery/initial/STACK_GUIDANCE.md @@ -8,13 +8,13 @@ - **Why**: While you’re more comfortable in Go, Python offers mature libraries for advanced cryptography, like blind signatures (e.g., `blind-signatures` package), which are less developed in Go. Python’s ecosystem also supports prototyping complex cryptographic components quickly. - **Use Case**: Implement cryptographic primitives like blind signatures in Python, then expose them to your Go services via gRPC. -### 3. **JavaScript and Elm for the Frontend** -- **Why**: Your experience with JavaScript, combined with your colleague’s Elm expertise, makes this a strong frontend combo. Elm’s type safety and functional nature ensure a secure, reliable user interface, while JavaScript can handle client-side cryptographic tasks via interop. -- **Use Case**: Use Elm to build the UI, guiding users through processes like submitting data or generating tokens. Leverage JavaScript libraries (e.g., `crypto-js`) for client-side cryptography when needed. +### 3. **JavaScript and Next.js for the Frontend** +- **Why**: Your experience with JavaScript, combined with your colleague’s Next.js expertise, makes this a strong frontend combo. Typescript’s type safety and functional nature ensure a secure, reliable user interface, while JavaScript can handle client-side cryptographic tasks via interop. +- **Use Case**: Use Next.js to build the UI, guiding users through processes like submitting data or generating tokens. Leverage JavaScript libraries (e.g., `crypto-js`) for client-side cryptography when needed. ### 4. **Protocol Buffers and gRPC** - **Why**: Your preference for Protocol Buffers and gRPC aligns perfectly with building secure, efficient communication between services. Go has excellent gRPC support, and Connect-wrapped gRPC adds HTTP/1.1 compatibility for broader client access. -- **Use Case**: Define service interfaces with Protocol Buffers and use gRPC for communication between your Go backend, Python cryptographic services, and Elm frontend (via JavaScript interop). +- **Use Case**: Define service interfaces with Protocol Buffers and use gRPC for communication between your Go backend, Python cryptographic services, and Next.js frontend (via JavaScript interop). --- @@ -45,10 +45,10 @@ - **What**: Transition to a blockchain like Ethereum for decentralization. - **How**: Write smart contracts in Solidity and use `go-ethereum` in your Go services to interact with the chain. -### **4. Frontend with Elm** -- **What**: Build a secure, user-friendly interface in Elm, leveraging your colleague’s expertise. +### **4. Frontend with Next.js** +- **What**: Build a secure, user-friendly interface in Next.js, leveraging your colleague’s expertise. - **How**: - - Handle user interactions (e.g., submitting opinions, generating tokens) in Elm. + - Handle user interactions (e.g., submitting opinions, generating tokens) in Next.js. - For cryptographic operations (e.g., commitments), use JavaScript interop to call libraries like `crypto-js` or `sjcl`. ### **5. Communication with gRPC** @@ -56,13 +56,13 @@ - **How**: - Define your APIs in Protocol Buffers (e.g., `.proto` files). - Implement gRPC servers in Go for the backend and in Python for cryptographic services. - - Use gRPC clients in Elm (via JavaScript interop) to connect to the backend. + - Use gRPC clients in Next.js (via JavaScript interop) to connect to the backend. --- ## Why This Approach Works for You - **Plays to Your Strengths**: Go is your core skill, so it handles the heavy lifting. Python and JavaScript fill gaps where Go’s ecosystem is less mature, using languages you’ve worked with before. -- **Leverages Your Team**: Your Elm developer can own the frontend, ensuring a high-quality UI while you focus on the backend and integration. +- **Leverages Your Team**: Your Next.js developer can own the frontend, ensuring a high-quality UI while you focus on the backend and integration. - **Matches Your Preferences**: Protocol Buffers and gRPC are central to the architecture, providing the efficient, secure communication you enjoy working with. - **Scalable Design**: Start simple with a centralized database, then scale to a blockchain if needed, all while keeping your codebase modular and maintainable. @@ -71,11 +71,11 @@ ## Next Steps to Get Started 1. **Go Backend**: Set up a basic gRPC server in Go using Protocol Buffers. Implement a simple hashing function with `crypto/sha256` to test commitments. 2. **Python Cryptography**: Prototype blind signatures in Python with `blind-signatures` and expose them via a gRPC service. -3. **Elm Frontend**: Work with your Elm developer to create a basic UI that sends requests to your Go backend via gRPC (using JS interop). +3. **Next.js Frontend**: Work with your Next.js developer to create a basic UI that sends requests to your Go backend via gRPC (using JS interop). 4. **ZKP Exploration**: Experiment with Circom and `snarkjs` to build a small ZKP circuit, then verify it in Go with `gnark`. 5. **Ledger Setup**: Start with PostgreSQL in Go, storing hashed data, and plan for a blockchain pivot later if required. --- ## Conclusion -This approach lets you use Go for the core, Python for cryptography where Go lacks, Elm for a secure frontend, and gRPC for communication—all aligned with your skills and preferences. You’ll build a solid system that’s secure, efficient, and extensible, with room to grow into more advanced features like blockchain integration. \ No newline at end of file +This approach lets you use Go for the core, Python for cryptography where Go lacks, Next.js for a secure frontend, and gRPC for communication—all aligned with your skills and preferences. You’ll build a solid system that’s secure, efficient, and extensible, with room to grow into more advanced features like blockchain integration. \ No newline at end of file diff --git a/discovery/refined/DECENTRALIZATION.md b/discovery/refined/DECENTRALIZATION.md index a0d1138..5fe9350 100644 --- a/discovery/refined/DECENTRALIZATION.md +++ b/discovery/refined/DECENTRALIZATION.md @@ -3,7 +3,7 @@ Your commitment to full decentralization is a brilliant shift—it aligns with blockchain’s ethos and makes your system resilient, uncensorable, and community-driven. Stepping outside your comfort zone is a worthwhile trade-off for this level of robustness. Here’s how it changes your system design, languages, architecture, and development approach: #### 1. **Decentralized Frontend Hosting** -- **Change**: Host your frontend (e.g., Elm app) on **IPFS** or **Arweave** instead of a traditional server. +- **Change**: Host your frontend (e.g., Next.js app) on **IPFS** or **Arweave** instead of a traditional server. - **Impact**: Users access the app via decentralized gateways (e.g., `ipfs.io`), eliminating reliance on centralized hosting that could be shut down. - **Tech**: Use tools like **Fleek** or **Pinata** to deploy and pin your frontend on IPFS. - **Comfort Zone Shift**: You’ll need to learn IPFS deployment, but these tools provide straightforward workflows. @@ -57,7 +57,7 @@ Your commitment to full decentralization is a brilliant shift—it aligns with b Here’s how decentralization reshapes your tech stack: - **Frontend**: - - **Language**: Elm remains, but you’ll add wallet integration (e.g., MetaMask) and IPFS gateway logic. + - **Language**: Next.js remains, but you’ll add wallet integration (e.g., MetaMask) and IPFS gateway logic. - **Architecture**: Hosted on IPFS, interacting directly with smart contracts. - **Backend**: - **Language**: Go or TypeScript, but minimized—most logic shifts to smart contracts or decentralized services. @@ -149,13 +149,13 @@ Even in a decentralized system, certain backend-like responsibilities persist, b To clarify, here’s a quick comparison: -| **Responsibility** | **Traditional Backend** | **Decentralized Backend** | -|---------------------------|------------------------------|-----------------------------------| -| **Data Storage** | Central database | Blockchain (key data), IPFS (bulk data) | -| **Business Logic** | Server-side code | Smart contracts | -| **Heavy Computation** | Server processing | Decentralized compute platforms | -| **Authentication** | Centralized login (e.g., OAuth) | Decentralized identity (e.g., SSI) | -| **Communication** | WebSockets on servers | P2P protocols (e.g., libp2p) | +| **Responsibility** | **Traditional Backend** | **Decentralized Backend** | +|---------------------------|---------------------------------|-----------------------------------------| +| **Data Storage** | Central database | Blockchain (key data), IPFS (bulk data) | +| **Business Logic** | Server-side code | Smart contracts | +| **Heavy Computation** | Server processing | Decentralized compute platforms | +| **Authentication** | Centralized login (e.g., OAuth) | Decentralized identity (e.g., SSI) | +| **Communication** | WebSockets on servers | P2P protocols (e.g., libp2p) | In a decentralized system, the backend’s role is minimized—smart contracts handle most logic, and other tasks are offloaded to decentralized services or user devices. diff --git a/discovery/refined/IMPLEMENTATION_PLAN.md b/discovery/refined/IMPLEMENTATION_PLAN.md index 3c662a3..b33568f 100644 --- a/discovery/refined/IMPLEMENTATION_PLAN.md +++ b/discovery/refined/IMPLEMENTATION_PLAN.md @@ -38,7 +38,7 @@ ### 6. User Experience (UX) - **Focus**: Intuitive and welcoming UX to drive adoption. -- **Tech**: Build the frontend with **Elm** for a reliable, clean interface. +- **Tech**: Build the frontend with **Next.js** for a reliable, clean interface. - **Goals**: Easy onboarding and clear feedback submission process. ### 7. Development Phases @@ -49,7 +49,7 @@ 2. Integrate Privado ID and simpler logins. 3. Set up IPFS with Pinata. 4. Deploy a subgraph on The Graph. - 5. Build an Elm frontend. + 5. Build an Next.js frontend. 6. Add off-chain AI and moderation. 7. Test end-to-end. - **Phase 2: Production** @@ -127,7 +127,7 @@ Here’s a detailed breakdown of the full suite of dependencies, components, ser ## 6. System Architecture - **Technology**: Microservices Architecture (production), Monolithic Architecture (Proof of Concept) -- **Language**: Go (backend services), Elm (frontend) +- **Language**: Go (backend services), Next.js (frontend) - **Responsibilities**: - **Identity Service**: Manages ZKP verification and simpler login options for users. - **Feedback Service**: Handles submission, storage, and retrieval of feedback data. @@ -137,8 +137,8 @@ Here’s a detailed breakdown of the full suite of dependencies, components, ser --- ## 7. User Experience (UX) -- **Technology**: Elm -- **Language**: Elm (frontend), CSS/HTML (styling) +- **Technology**: Next.js +- **Language**: TypeScript (frontend), CSS/HTML (styling) - **Responsibilities**: - Delivers an intuitive, welcoming interface to enhance user engagement. - Streamlines onboarding and feedback submission for ease of use. @@ -181,6 +181,6 @@ Here’s a detailed breakdown of the full suite of dependencies, components, ser | Storage | IPFS with Pinata | JS/TS | Cost-efficient data storage | | Indexing | The Graph | GraphQL, AssemblyScript| Efficient data querying | | Analysis | Hugging Face or spaCy | Python | Insightful feedback analysis | -| Architecture | Microservices/Monolithic | Go (backend), Elm | Scalable system design | -| Frontend | Elm | Elm, CSS/HTML | User-friendly interface | +| Architecture | Microservices/Monolithic | Go (backend), Next.js | Scalable system design | +| Frontend | Next.js | Next.js, CSS/HTML | User-friendly interface | | Development Tools | Hardhat, Pinata | JS/TS | Streamlined development | diff --git a/discovery/refined/INTRO.md b/discovery/refined/INTRO.md index 0aa1462..d65f8fb 100644 --- a/discovery/refined/INTRO.md +++ b/discovery/refined/INTRO.md @@ -77,7 +77,7 @@ Discourse’s architecture is designed to be decentralized, scalable, and resili - **Why**: Robust tools for natural language processing and sentiment analysis. - **Role**: Synthesizes Perspectives into Insights off-chain, feeding results back to the blockchain. -- **Frontend: Elm (Hosted on IPFS)** +- **Frontend: Next.js (TypeScript) (Hosted on IPFS)** - **Why**: A reliable, functional programming language paired with decentralized hosting for accessibility and resilience. - **Role**: Provides a user-friendly interface for submitting Perspectives, voting, and viewing Resolutions. diff --git a/ui/prototype/app/contributions/[id]/loading.tsx b/ui/prototype/app/contributions/[id]/loading.tsx new file mode 100644 index 0000000..6f95832 --- /dev/null +++ b/ui/prototype/app/contributions/[id]/loading.tsx @@ -0,0 +1,3 @@ +export default function Loading() { + return
Loading contribution details...
+} \ No newline at end of file diff --git a/ui/prototype/app/contributions/[id]/page.tsx b/ui/prototype/app/contributions/[id]/page.tsx new file mode 100644 index 0000000..493f956 --- /dev/null +++ b/ui/prototype/app/contributions/[id]/page.tsx @@ -0,0 +1,499 @@ +"use client" + +import { useState, useEffect } from "react" +import Link from "next/link" +import { use } from "react" +import { + ArrowLeft, + CheckCircle, + Clock, + ExternalLink, + MessageCircle, + ThumbsUp, + Users, + FileText, + CalendarDays, + LineChart, + AlertCircle +} from "lucide-react" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger +} from "@/components/ui/tabs" +import { Badge } from "@/components/ui/badge" +import { Separator } from "@/components/ui/separator" +import { Progress } from "@/components/ui/progress" +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" + +// Mock data for a single contribution +const mockContributions = [ + { + id: 1, + title: "After-School Programs", + description: "Create free after-school programs for K-8 students in public schools", + category: "Education", + votes: { yes: 312, no: 28 }, + perspectives: 42, + dateCreated: "2023-10-05", + dateValidated: "2023-11-15", + status: "Validated", + resolutionId: 12, + resolutionTitle: "Education and Community Health Improvements", + metrics: { + sentimentScore: 0.87, + participationRate: 0.62, + consensusSpeed: "Fast", + implementationComplexity: "Medium", + }, + sourceInsight: { + id: 3, + title: "After-School Programs", + description: "Create free after-school programs for K-8 students in public schools" + }, + relatedPerspectives: [ + { + id: 101, + username: "parent87", + content: "As a working parent, having free after-school programs would be life-changing for me and my children.", + date: "2023-09-15", + votes: 43, + }, + { + id: 102, + username: "educator22", + content: "After-school programs provide crucial educational support and keep children engaged in positive activities.", + date: "2023-09-18", + votes: 38, + }, + { + id: 103, + username: "communityLeader", + content: "These programs would reduce juvenile crime rates in neighborhoods where working parents can't be home until evening.", + date: "2023-09-22", + votes: 29, + }, + { + id: 104, + username: "budgetAnalyst", + content: "The ROI is excellent - the cost of these programs is lower than dealing with the social issues that arise without them.", + date: "2023-09-25", + votes: 36, + }, + { + id: 105, + username: "socialWorker42", + content: "Many families in underserved areas would greatly benefit from structured after-school care and enrichment.", + date: "2023-09-28", + votes: 41, + }, + ], + }, + { + id: 2, + title: "Community Health Clinics", + description: "Establish walk-in clinics in underserved areas with sliding scale fees", + category: "Healthcare", + votes: { yes: 278, no: 42 }, + perspectives: 36, + dateCreated: "2023-11-10", + dateValidated: "2023-12-03", + status: "Validated", + resolutionId: 12, + resolutionTitle: "Education and Community Health Improvements", + metrics: { + sentimentScore: 0.82, + participationRate: 0.58, + consensusSpeed: "Medium", + implementationComplexity: "High", + }, + sourceInsight: { + id: 4, + title: "Community Health Clinics", + description: "Establish walk-in clinics in underserved areas with sliding scale fees" + }, + relatedPerspectives: [ + // Perspectives data would go here + ] + }, + // Other contributions would go here +] + +export default function ContributionPage({ params }: { params: Promise<{ id: string }> }) { + // Properly handle the params with React.use() + const { id } = use(params) + const contributionId = parseInt(id) + const [activeTab, setActiveTab] = useState("overview") + + // Find the contribution from mock data + const contribution = mockContributions.find(c => c.id === contributionId) + + if (!contribution) { + return ( +
+ +

Contribution Not Found

+

The contribution you're looking for doesn't exist or has been removed.

+ +
+ ) + } + + // Approval percentage + const approvalPercentage = Math.round((contribution.votes.yes / (contribution.votes.yes + contribution.votes.no)) * 100) + + return ( +
+
+
+ +
+ {contribution.category} + ID: {contribution.id} +
+

+ + {contribution.title} +

+

{contribution.description}

+
+
+ + {contribution.status} + +
+ + Validated: + {new Date(contribution.dateValidated).toLocaleDateString()} +
+ +
+
+ + + + Overview + Source Perspectives + Metrics & Analysis + + + {/* Overview Tab */} + +
+ + + Consensus Details + How this contribution reached consensus + + +
+
+
+ Approval: {approvalPercentage}% + + {contribution.votes.yes} Yes / {contribution.votes.no} No + +
+ +
+ +
+
+

Based On

+

{contribution.perspectives}

+

unique perspectives

+
+
+

Consensus Speed

+

{contribution.metrics.consensusSpeed}

+

relative to average

+
+
+ +
+

Timeline

+
+
+
+
+ +
+
+
+
+

Perspectives Collection

+

Started: {new Date('2023-09-01').toLocaleDateString()}

+
+
+ +
+
+
+ +
+
+
+
+

Insight Generated

+

Date: {new Date(contribution.dateCreated).toLocaleDateString()}

+
+
+ +
+
+
+ +
+
+
+

Consensus Reached

+

Date: {new Date(contribution.dateValidated).toLocaleDateString()}

+
+
+
+
+
+
+
+ + + + Resolution Integration + How this contribution impacts policy + + +
+
+

Included in Resolution

+
+ +
+

Resolution #{contribution.resolutionId}

+

{contribution.resolutionTitle}

+
+
+
+ +
+

Implementation Complexity

+ + {contribution.metrics.implementationComplexity} + +

+ This contribution has been assessed as having {contribution.metrics.implementationComplexity.toLowerCase()} + implementation complexity based on required resources, timeline, and regulatory considerations. +

+
+ +
+

Source Insight

+ +
+
+

{contribution.sourceInsight.title}

+

{contribution.sourceInsight.description}

+
+ +
+ +
+
+
+
+
+
+ + {/* Perspectives Tab */} + + + + Source Perspectives + Original community input that led to this contribution + + +
+ {contribution.relatedPerspectives.map((perspective) => ( +
+
+
+ + + {perspective.username.substring(0, 2).toUpperCase()} + +
+

{perspective.username}

+

{new Date(perspective.date).toLocaleDateString()}

+
+
+ + + +
+ + {perspective.votes} +
+
+ +

Community upvotes

+
+
+
+
+

{perspective.content}

+
+ ))} +
+
+
+
+ + {/* Metrics Tab */} + + + + Metrics & Analysis + Statistical breakdown of community engagement + + +
+
+
+

Sentiment Analysis

+
+
+ {contribution.metrics.sentimentScore * 10} +
+
+

Positive Sentiment

+

+ {contribution.metrics.sentimentScore > 0.8 ? "Very Positive" : + contribution.metrics.sentimentScore > 0.6 ? "Positive" : + contribution.metrics.sentimentScore > 0.4 ? "Neutral" : "Mixed"} +

+
+
+

+ AI analysis of perspective text shows strong support for this contribution. +

+
+ +
+

Demographic Distribution

+
+
+
+ Age Groups +
+
+
+
+
+
+
+
+
+ 18-24 + 25-34 + 35-44 + 45-64 + 65+ +
+
+
+
+
+ +
+
+

Participation Rate

+
+
+ + + + +
+ {Math.round(contribution.metrics.participationRate * 100)}% +
+
+
+

Community Engagement

+

+ {contribution.metrics.participationRate > 0.7 ? "Exceptional" : + contribution.metrics.participationRate > 0.5 ? "High" : + contribution.metrics.participationRate > 0.3 ? "Moderate" : "Low"} +

+
+
+
+ +
+

Geographic Impact

+
+
+ +

City-wide Relevance

+
+

+ This contribution has been flagged as having city-wide relevance with particular + significance for underserved communities. +

+
+ Downtown + South Side + West End +
+
+
+
+
+
+
+
+
+ +
+ +
+
+ ) +} \ No newline at end of file diff --git a/ui/prototype/app/insights/page.tsx b/ui/prototype/app/insights/page.tsx index b436786..098eda4 100644 --- a/ui/prototype/app/insights/page.tsx +++ b/ui/prototype/app/insights/page.tsx @@ -105,6 +105,8 @@ export default function InsightsDashboard() { const [sortBy, setSortBy] = useState<"votes" | "date">("votes") const { walletConnected } = useWalletStore() const [userVotes, setUserVotes] = useState>({}) + const [pendingToast, setPendingToast] = useState<{ type: "single" | "batch"; voteType?: "yes" | "no"; insightId?: number; batchSize?: number } | null>(null) + const lastToastRef = useRef<{ type: string, id?: number, time: number }>({ type: "", time: 0 }) // Batch voting state const [batchMode, setBatchMode] = useState(false) @@ -178,6 +180,11 @@ export default function InsightsDashboard() { return insight }), ) + + // Queue toast for individual votes (not batch mode) + if (!batchMode) { + setPendingToast({ type: "single", voteType, insightId: id }) + } } // Toggle batch mode @@ -244,32 +251,66 @@ export default function InsightsDashboard() { // Process all votes in the batch const processBatchVotes = () => { + const batchSize = Object.keys(selectedInsights).length + if (batchSize === 0) return + // Apply all votes Object.entries(selectedInsights).forEach(([idStr, voteType]) => { const id = Number.parseInt(idStr) handleVote(id, voteType) }) - // Show success toast - toast({ - title: "Votes submitted successfully", - description: `You've voted on ${selectedCount} insights.`, - action: OK, - }) + // Queue toast for batch submission + setPendingToast({ type: "batch", batchSize }) // Reset batch state setSelectedInsights({}) setIsSubmittingBatch(false) } - // Clean up interval on unmount + // Handle toast notifications useEffect(() => { - return () => { - if (countdownRef.current) { - clearInterval(countdownRef.current) + if (pendingToast) { + // Check for duplicate toast prevention (only show if different from last toast or more than 2 seconds passed) + const now = Date.now() + const isDuplicate = + pendingToast.type === lastToastRef.current.type && + (pendingToast.type === "single" ? pendingToast.insightId === lastToastRef.current.id : true) && + now - lastToastRef.current.time < 2000; + + if (!isDuplicate) { + if (pendingToast.type === "single") { + const insight = insights.find(i => i.id === pendingToast.insightId) + toast({ + title: "Vote submitted", + description: `You voted ${pendingToast.voteType} on "${insight?.title}"`, + action: OK, + }) + + // Update last toast reference + lastToastRef.current = { + type: "single", + id: pendingToast.insightId, + time: now + } + } else if (pendingToast.type === "batch") { + toast({ + title: "Batch votes submitted", + description: `Successfully submitted ${pendingToast.batchSize} votes`, + action: OK, + }) + + // Update last toast reference + lastToastRef.current = { + type: "batch", + time: now + } + } } + + setPendingToast(null) } - }, []) + }, [pendingToast, insights]) // Enhanced HoldButton component with improved animation and feedback function HoldButton({ @@ -294,12 +335,13 @@ export default function InsightsDashboard() { const [isHolding, setIsHolding] = useState(false) const [progress, setProgress] = useState(0) const [completed, setCompleted] = useState(false) + const [localVoted, setLocalVoted] = useState(false) // Track local vote state const timerRef = useRef(null) const startTimeRef = useRef(0) const animationRef = useRef(null) // Check if this insight has already been voted on - const hasVoted = userVotes[insightId] !== undefined + const hasVoted = userVotes[insightId] !== undefined || localVoted const isThisVote = userVotes[insightId] === voteType // Reset completed state when the insight changes @@ -324,6 +366,7 @@ export default function InsightsDashboard() { setCompleted(true) // Add a small delay before triggering the action for visual feedback timerRef.current = setTimeout(() => { + setLocalVoted(true) // Set local vote state immediately onComplete() setIsHolding(false) setProgress(0) diff --git a/ui/prototype/app/issues/[id]/page.tsx b/ui/prototype/app/issues/[id]/page.tsx new file mode 100644 index 0000000..680b8e8 --- /dev/null +++ b/ui/prototype/app/issues/[id]/page.tsx @@ -0,0 +1,460 @@ +"use client" + +import { useState, use } from "react" +import { ArrowLeft, MessageSquare, ThumbsUp, ThumbsDown, Share2, FileText, Filter } from "lucide-react" +import Link from "next/link" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" +import { Textarea } from "@/components/ui/textarea" +import { Separator } from "@/components/ui/separator" +import { Progress } from "@/components/ui/progress" + +// Mock data for the issue +const mockIssues = { + "climate-action": { + id: "climate-action", + title: "Climate Action Policies", + description: "Discussion on policies to address climate change and reduce carbon emissions.", + category: "Environmental Policy", + dateCreated: "2024-01-10", + status: "active", + metrics: { + perspectives: 324, + insights: 18, + contributions: 5, + participants: 156 + } + }, + "education-reform": { + id: "education-reform", + title: "Education System Reform", + description: "Ideas for improving educational outcomes and accessibility for all students.", + category: "Education", + status: "active", + metrics: { + perspectives: 187, + insights: 12, + contributions: 3, + participants: 89 + } + } +} + +// Mock perspectives for issues +const mockPerspectivesByIssue = { + "climate-action": [ + { + id: 1, + userId: "user1", + userName: "Alex Johnson", + userAvatar: "", + content: "We should focus on renewable energy investments. Solar and wind power have become more cost-effective and could replace fossil fuels in many regions.", + dateSubmitted: "2024-03-01", + likes: 45, + dislikes: 3 + }, + { + id: 2, + userId: "user2", + userName: "Jamie Smith", + userAvatar: "", + content: "Carbon pricing is the most efficient way to reduce emissions. It creates market incentives for businesses to innovate and cut their carbon footprint.", + dateSubmitted: "2024-02-28", + likes: 38, + dislikes: 7 + }, + { + id: 3, + userId: "user3", + userName: "Taylor Reed", + userAvatar: "", + content: "We need to address transportation emissions through better public transit and EV infrastructure. This sector is a major contributor to greenhouse gases.", + dateSubmitted: "2024-02-25", + likes: 52, + dislikes: 4 + } + ], + "education-reform": [ + { + id: 1, + userId: "user4", + userName: "Morgan Lee", + userAvatar: "", + content: "Teachers need better resources and smaller class sizes to effectively improve student outcomes.", + dateSubmitted: "2024-03-02", + likes: 62, + dislikes: 5 + }, + { + id: 2, + userId: "user5", + userName: "Casey Wilson", + userAvatar: "", + content: "Access to early childhood education should be a priority as it sets the foundation for all future learning.", + dateSubmitted: "2024-02-27", + likes: 41, + dislikes: 2 + } + ] +} + +// Mock insights for issues +const mockInsightsByIssue = { + "climate-action": [ + { + id: 1, + title: "Renewable Energy Investment", + description: "67% of perspectives support increased government funding for renewable energy projects, with solar and wind being the most frequently mentioned technologies.", + votes: { yes: 124, no: 18 }, + status: "consensus", // voting, consensus, rejected + perspectives: [1, 5, 8, 12] // Reference to perspective IDs + }, + { + id: 2, + title: "Carbon Pricing Mechanism", + description: "A majority of users advocate for carbon pricing policies, with 58% specifically mentioning tax incentives for low-emission businesses.", + votes: { yes: 98, no: 32 }, + status: "voting", // voting, consensus, rejected + perspectives: [2, 7, 15] // Reference to perspective IDs + } + ], + "education-reform": [ + { + id: 1, + title: "Teacher Support Systems", + description: "78% of perspectives emphasize the need for better resources and support for teachers, including smaller class sizes and professional development.", + votes: { yes: 112, no: 15 }, + status: "consensus", + perspectives: [1, 3, 7] + }, + { + id: 2, + title: "Early Childhood Education Access", + description: "64% of perspectives advocate for universal access to early childhood education to establish a strong foundation for learning.", + votes: { yes: 87, no: 34 }, + status: "voting", + perspectives: [2, 8, 10] + } + ] +} + +export default function IssueDetails({ params }: { params: Promise<{ id: string }> }) { + // Properly unwrap params using React.use() + const { id: issueId } = use(params) + const [activeTab, setActiveTab] = useState("overview") + const [commentText, setCommentText] = useState("") + + // Get the issue data from our mock data + const issue = mockIssues[issueId as keyof typeof mockIssues] || mockIssues["climate-action"] + const perspectives = mockPerspectivesByIssue[issueId as keyof typeof mockPerspectivesByIssue] || [] + const insights = mockInsightsByIssue[issueId as keyof typeof mockInsightsByIssue] || [] + + const handleSubmitComment = (e: React.FormEvent) => { + e.preventDefault() + if (commentText.trim()) { + // In a real app, submit the comment to the backend + console.log("Submitting comment:", commentText) + setCommentText("") + } + } + + return ( +
+
+ + +
+
+

{issue.title}

+
+ {issue.category} + {issue.status} +
+
+
+ + +
+
+ +

{issue.description}

+ +
+ + +
{issue.metrics.perspectives}
+

Perspectives

+
+
+ + +
{issue.metrics.insights}
+

Insights

+
+
+ + +
{issue.metrics.contributions}
+

Contributions

+
+
+ + +
{issue.metrics.participants}
+

Participants

+
+
+
+
+ + + + Overview + Perspectives + Insights + + + + + + Issue Summary + Key information and progress on this issue + + +
+
+

Progress

+
+
+
+ Perspectives Gathering + 75% +
+ +
+
+
+ Insight Formation + 45% +
+ +
+
+
+ Contribution Validation + 20% +
+ +
+
+
+ +
+

Timeline

+
+
+
+ 1 +
+
+

Perspectives Collection

+

In progress - Ends Apr 15, 2024

+
+
+
+
+ 2 +
+
+

Insight Voting

+

Apr 16 - May 1, 2024

+
+
+
+
+ 3 +
+
+

Resolution Formation

+

May 2 - May 15, 2024

+
+
+
+
+
+
+
+
+ + +
+

Recent Perspectives

+
+ + +
+
+ +
+ {perspectives.map((perspective) => ( + + +
+
+ + + {perspective.userName.charAt(0)} + +
+

{perspective.userName}

+

{perspective.dateSubmitted}

+
+
+
+
+ +

{perspective.content}

+
+ +
+ + +
+ +
+
+ ))} +
+ + + + Add Your Perspective + + +
+