diff --git a/src/app/demo/page.tsx b/src/app/demo/page.tsx index 6868e3c..2709c31 100644 --- a/src/app/demo/page.tsx +++ b/src/app/demo/page.tsx @@ -4,7 +4,6 @@ import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; -import { Progress } from "@/components/ui/progress"; import Link from "next/link"; import { ChevronUp, @@ -95,30 +94,52 @@ export default function DemoPage() { const maxWeight = Math.floor(Math.sqrt(credits)); - function incrementVote(proposalId: number) { + function handleUpvote(proposalId: number) { setProposals((prev) => prev.map((p) => { - if (p.id === proposalId) { - const newPending = p.pendingVote + 1; - const newCost = newPending * newPending; - if (newCost <= credits) { - return { ...p, pendingVote: newPending }; - } + if (p.id !== proposalId) return p; + + // If already voted up, remove the vote + if (p.userVote > 0) { + const refund = p.userVote * p.userVote; + setCredits((c) => c + refund); + return { ...p, score: p.score - p.userVote, userVote: 0, pendingVote: 0 }; + } + + // If already voted down, can't upvote + if (p.userVote < 0) return p; + + // Increment pending vote + const newPending = p.pendingVote + 1; + const newCost = newPending * newPending; + if (newCost <= credits && newPending <= maxWeight) { + return { ...p, pendingVote: newPending }; } return p; }) ); } - function decrementVote(proposalId: number) { + function handleDownvote(proposalId: number) { setProposals((prev) => prev.map((p) => { - if (p.id === proposalId) { - const newPending = p.pendingVote - 1; - const newCost = newPending * newPending; - if (newCost <= credits) { - return { ...p, pendingVote: newPending }; - } + if (p.id !== proposalId) return p; + + // If already voted down, remove the vote + if (p.userVote < 0) { + const refund = p.userVote * p.userVote; + setCredits((c) => c + refund); + return { ...p, score: p.score - p.userVote, userVote: 0, pendingVote: 0 }; + } + + // If already voted up, can't downvote + if (p.userVote > 0) return p; + + // Decrement pending vote + const newPending = p.pendingVote - 1; + const newCost = newPending * newPending; + if (newCost <= credits && Math.abs(newPending) <= maxWeight) { + return { ...p, pendingVote: newPending }; } return p; }) @@ -131,44 +152,26 @@ export default function DemoPage() { ); } - function castVote(proposalId: number) { + function confirmVote(proposalId: number) { setProposals((prev) => prev.map((p) => { - if (p.id === proposalId && p.pendingVote !== 0) { - const cost = p.pendingVote * p.pendingVote; - const newScore = p.score + p.pendingVote; - const promoted = newScore >= 100 && p.stage === "ranking"; + if (p.id !== proposalId || p.pendingVote === 0) return p; - setCredits((c) => c - cost); + const cost = p.pendingVote * p.pendingVote; + const newScore = p.score + p.pendingVote; + const promoted = newScore >= 100 && p.stage === "ranking"; - return { - ...p, - score: newScore, - userVote: p.pendingVote, - pendingVote: 0, - stage: promoted ? "voting" : p.stage, - yesVotes: promoted ? 8 : p.yesVotes, - noVotes: promoted ? 3 : p.noVotes, - }; - } - return p; - }) - ); - } + setCredits((c) => c - cost); - function removeVote(proposalId: number) { - setProposals((prev) => - prev.map((p) => { - if (p.id === proposalId && p.userVote !== 0) { - const refund = p.userVote * p.userVote; - setCredits((c) => c + refund); - return { - ...p, - score: p.score - p.userVote, - userVote: 0, - }; - } - return p; + return { + ...p, + score: newScore, + userVote: p.pendingVote, + pendingVote: 0, + stage: promoted ? "voting" : p.stage, + yesVotes: promoted ? 8 : p.yesVotes, + noVotes: promoted ? 3 : p.noVotes, + }; }) ); } @@ -255,7 +258,7 @@ export default function DemoPage() { : "bg-muted/50 border-muted text-muted-foreground" }`} > -
{w > 0 ? "+" : ""}{w}
+
+{w}
vote{w > 1 ? "s" : ""}
{w * w}ยข
@@ -279,163 +282,135 @@ export default function DemoPage() { const hasPending = proposal.pendingVote !== 0; const hasVoted = proposal.userVote !== 0; const pendingCost = proposal.pendingVote * proposal.pendingVote; - const previewScore = proposal.score + proposal.pendingVote; - const progressPercent = Math.min((proposal.score / 100) * 100, 100); - const previewPercent = Math.min((previewScore / 100) * 100, 100); + const displayScore = hasPending ? proposal.score + proposal.pendingVote : proposal.score; + const progressPercent = Math.min((displayScore / 100) * 100, 100); + + const isUpvoted = (hasVoted && proposal.userVote > 0) || proposal.pendingVote > 0; + const isDownvoted = (hasVoted && proposal.userVote < 0) || proposal.pendingVote < 0; return ( - 0 - ? "ring-2 ring-orange-500/50 bg-orange-500/5" - : "ring-2 ring-blue-500/50 bg-blue-500/5" - : hasVoted - ? proposal.userVote > 0 - ? "bg-orange-500/5" - : "bg-blue-500/5" - : "" + ? "ring-2 ring-orange-500/50" + : "ring-2 ring-blue-500/50" + : "" }`} > -
- {/* Reddit-style vote column */} -
- {/* Upvote button */} - + {/* Reddit-style vote column */} +
+ - {/* Score display */} -
0 - ? "text-orange-500" - : "text-blue-500" - : hasVoted - ? proposal.userVote > 0 - ? "text-orange-500" - : "text-blue-500" - : "text-foreground" - }`}> - {hasPending ? previewScore : proposal.score} -
+ + {displayScore} + - {/* Downvote button */} - -
- - {/* Proposal content */} -
-

{proposal.title}

-

- {proposal.description} -

- - {/* Progress bar */} -
-
- Progress to voting stage - 0 ? "text-orange-500" : "text-blue-500") : ""}> - {hasPending ? previewScore : proposal.score}/100 - -
-
-
0 - ? "bg-orange-500" - : "bg-blue-500" - : "bg-primary" - }`} - style={{ width: `${hasPending ? previewPercent : progressPercent}%` }} - /> -
-
- - {/* Vote status / pending confirmation */} - {(hasPending || hasVoted) && ( -
- {hasPending ? ( - <> - 0 - ? "border-orange-500/50 text-orange-600 bg-orange-500/10" - : "border-blue-500/50 text-blue-600 bg-blue-500/10" - } - > - {proposal.pendingVote > 0 ? "+" : ""}{proposal.pendingVote} vote = {pendingCost} credits - - - - - ) : hasVoted && ( - 0 - ? "bg-orange-500/20 text-orange-600 border-orange-500/30" - : "bg-blue-500/20 text-blue-600 border-blue-500/30" - } - > - You voted: {proposal.userVote > 0 ? "+" : ""}{proposal.userVote} - - )} -
- )} -
+
- + + {/* Proposal content */} +
+

{proposal.title}

+

+ {proposal.description} +

+ + {/* Progress bar */} +
+
+ Progress to voting stage + + {displayScore}/100 + +
+
+
+
+
+ + {/* Pending vote confirmation */} + {hasPending && ( +
+ 0 + ? "border-orange-500/50 text-orange-600 bg-orange-500/10" + : "border-blue-500/50 text-blue-600 bg-blue-500/10" + } + > + {proposal.pendingVote > 0 ? "+" : ""}{proposal.pendingVote} vote = {pendingCost} credits + + + +
+ )} + + {/* Existing vote indicator */} + {hasVoted && !hasPending && ( +
+ 0 + ? "bg-orange-500/20 text-orange-600" + : "bg-blue-500/20 text-blue-600" + } + > + You voted: {proposal.userVote > 0 ? "+" : ""}{proposal.userVote} + +
+ )} +
+
); })}
@@ -468,7 +443,6 @@ export default function DemoPage() { {proposal.description} - {/* Vote bar */}
- {/* Vote buttons */}