From 7f1eb88f53d030d2d88de6b54a640fd461c4eafe Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 19:26:11 +0545 Subject: [PATCH 01/12] display quorum and threshold in main card --- src/components/proposals/ProposalCard.tsx | 138 ++++++++++++++++++---- 1 file changed, 116 insertions(+), 22 deletions(-) diff --git a/src/components/proposals/ProposalCard.tsx b/src/components/proposals/ProposalCard.tsx index bb8d2376..0c91261f 100644 --- a/src/components/proposals/ProposalCard.tsx +++ b/src/components/proposals/ProposalCard.tsx @@ -7,7 +7,6 @@ import { format } from "date-fns"; import { truncateString, getExplorerLink, formatAction } from "@/utils/format"; import Link from "next/link"; import { useRouter } from "next/navigation"; -import VoteStatusChart from "./VoteStatusChart"; import { useMemo } from "react"; import { TokenBalance } from "../reusables/BalanceDisplay"; import { ProposalStatusBadge } from "./ProposalBadge"; @@ -16,26 +15,27 @@ import { useProposalVote } from "@/hooks/useProposalVote"; import { Button } from "@/components/ui/button"; import { RefreshCw, AlertCircle } from "lucide-react"; import { motion } from "framer-motion"; +import { safeNumberFromBigInt } from "@/utils/proposal"; +import { cn } from "@/lib/utils"; interface ProposalCardProps { proposal: Proposal | ProposalWithDAO; - tokenSymbol?: string; showDAOInfo?: boolean; } export default function ProposalCard({ proposal, - tokenSymbol = "", showDAOInfo = false, }: ProposalCardProps) { const router = useRouter(); // Use the unified status system - const { statusConfig, isActive, isPassed } = useProposalStatus(proposal); + const { status, statusConfig, isActive } = useProposalStatus(proposal); // Use centralized vote hook for consistent data fetching const { voteDisplayData, + calculations, error: hasVoteDataError, refreshVoteData, isLoading: isLoadingVotes, @@ -90,6 +90,43 @@ export default function ProposalCard({ // const liquidTokens = Number(proposal.liquid_tokens); const { totalVotes, hasVoteData } = voteSummary; + // Enhanced calculations for quorum and threshold display + const enhancedCalculations = useMemo(() => { + if (!calculations) return null; + + const quorumPercentage = safeNumberFromBigInt(proposal.voting_quorum); + const thresholdPercentage = safeNumberFromBigInt(proposal.voting_threshold); + + // Calculate if requirements are met + const metQuorum = calculations.participationRate >= quorumPercentage; + const metThreshold = + calculations.totalVotes > 0 + ? calculations.approvalRate >= thresholdPercentage + : false; + + return { + ...calculations, + quorumPercentage, + thresholdPercentage, + metQuorum, + metThreshold, + }; + }, [calculations, proposal]); + + // Helper function for status display + const getStatusText = (met: boolean, percentage?: number) => { + // If voting hasn't started (PENDING, DRAFT), show "Pending" + if (status === "PENDING" || status === "DRAFT") { + return "Pending"; + } + + if (isActive) { + return percentage !== undefined ? `${percentage.toFixed(1)}%` : "0%"; + } + + return met ? "Passed" : "Failed"; + }; + // Memoize DAO info const daoInfo = useMemo(() => { const proposalWithDAO = proposal as ProposalWithDAO; @@ -130,12 +167,86 @@ export default function ProposalCard({ ? `#${proposal.proposal_id}: ${proposal.title}` : proposal.title} -
+
+ + {/* Quorum and Threshold Badges */} + {enhancedCalculations && + statusConfig.label !== "Pending" && + statusConfig.label !== "Draft" && ( + <> + {/* Quorum Badge */} +
+ Quorum:{" "} + + {getStatusText( + enhancedCalculations.metQuorum, + enhancedCalculations.participationRate + )} + +
+ + {/* Threshold Badge */} +
+ + Threshold: + {" "} + + {getStatusText( + enhancedCalculations.metThreshold, + enhancedCalculations.approvalRate + )} + +
+ + )} +
@@ -363,23 +474,6 @@ export default function ProposalCard({
)} */} - - {/* Enhanced Chart Section for detailed view - Hide for pending proposals */} - {(isActive || - statusConfig.label === "Veto Period" || - statusConfig.label === "Execution Window" || - isPassed || - statusConfig.label === "Failed") && - statusConfig.label !== "Pending" && ( -
- -
- )}
From 2400337903aee01591fc975eae88364861478d9a Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 19:39:33 +0545 Subject: [PATCH 02/12] fix: build --- src/components/proposals/ProposalCard.tsx | 35 ++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/components/proposals/ProposalCard.tsx b/src/components/proposals/ProposalCard.tsx index 0c91261f..699a7271 100644 --- a/src/components/proposals/ProposalCard.tsx +++ b/src/components/proposals/ProposalCard.tsx @@ -7,6 +7,7 @@ import { format } from "date-fns"; import { truncateString, getExplorerLink, formatAction } from "@/utils/format"; import Link from "next/link"; import { useRouter } from "next/navigation"; +import VoteStatusChart from "./VoteStatusChart"; import { useMemo } from "react"; import { TokenBalance } from "../reusables/BalanceDisplay"; import { ProposalStatusBadge } from "./ProposalBadge"; @@ -20,11 +21,13 @@ import { cn } from "@/lib/utils"; interface ProposalCardProps { proposal: Proposal | ProposalWithDAO; + tokenSymbol?: string; showDAOInfo?: boolean; } export default function ProposalCard({ proposal, + tokenSymbol = "", showDAOInfo = false, }: ProposalCardProps) { const router = useRouter(); @@ -458,22 +461,22 @@ export default function ProposalCard({
)} - {/* Completed Status */} - {/* {isPassed && ( -
- Final result: - - - For - - ,{" "} - - {" "} - Against - - -
- )} */} + {/* Vote Status Chart - Show for active, veto period, execution window, passed, and failed proposals */} + {(isActive || + statusConfig.label === "Veto Period" || + statusConfig.label === "Execution Window" || + statusConfig.label === "Passed" || + statusConfig.label === "Failed") && + statusConfig.label !== "Pending" && ( +
+ +
+ )} From b9a7b090022fe91639bdc550a90118195cdbc50d Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 19:44:51 +0545 Subject: [PATCH 03/12] no need to display the liquid token --- src/components/proposals/VoteStatusChart.tsx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/components/proposals/VoteStatusChart.tsx b/src/components/proposals/VoteStatusChart.tsx index 8c884ac8..10888b1b 100644 --- a/src/components/proposals/VoteStatusChart.tsx +++ b/src/components/proposals/VoteStatusChart.tsx @@ -171,26 +171,6 @@ const VoteStatusChart = ({ className="font-medium sm:hidden" /> - - {/* Liquid Tokens - Right */} - {liquidTokens && Number(liquidTokens) > 0 && ( -
- Liquid Token: - - -
- )} ); From c3a050be5633ad66599ba119ec1ccf5ed5964328 Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 19:45:45 +0545 Subject: [PATCH 04/12] remove unused var --- src/components/proposals/VoteStatusChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/proposals/VoteStatusChart.tsx b/src/components/proposals/VoteStatusChart.tsx index 10888b1b..e8d41380 100644 --- a/src/components/proposals/VoteStatusChart.tsx +++ b/src/components/proposals/VoteStatusChart.tsx @@ -22,7 +22,7 @@ const VoteStatusChart = ({ initialVotesAgainst, // refreshing = false, tokenSymbol = "", - liquidTokens, + // liquidTokens, proposal, }: VoteStatusChartProps) => { const [localRefreshing, setLocalRefreshing] = useState(false); From c07c2cbf0dc24dd4a9f6020a0192ab06a6fba61a Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 22:56:41 +0545 Subject: [PATCH 05/12] add veto check and veto badge in proposal card and details --- src/components/proposals/ProposalCard.tsx | 8 ++ src/components/proposals/VotesTable.tsx | 4 +- .../proposals/VotingProgressChart.tsx | 22 +++++- src/hooks/useProposalVote.ts | 10 +++ src/hooks/useVetoCheck.ts | 79 +++++++++++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/hooks/useVetoCheck.ts diff --git a/src/components/proposals/ProposalCard.tsx b/src/components/proposals/ProposalCard.tsx index 699a7271..23f598f7 100644 --- a/src/components/proposals/ProposalCard.tsx +++ b/src/components/proposals/ProposalCard.tsx @@ -42,6 +42,7 @@ export default function ProposalCard({ error: hasVoteDataError, refreshVoteData, isLoading: isLoadingVotes, + vetoCheck, } = useProposalVote({ proposal, contractPrincipal: proposal.contract_principal, @@ -250,6 +251,13 @@ export default function ProposalCard({ )} + {/* Veto Override Warning Badge */} + {vetoCheck?.vetoExceedsForVote && !isActive && ( +
+ ⚠️ Vetoed +
+ )} +
diff --git a/src/components/proposals/VotesTable.tsx b/src/components/proposals/VotesTable.tsx index 69af88d6..c3c35108 100644 --- a/src/components/proposals/VotesTable.tsx +++ b/src/components/proposals/VotesTable.tsx @@ -170,9 +170,9 @@ const VotesTable = ({ proposalId, limit }: VotesTableProps) => { - {displayedVotes.map((vote, index) => ( + {displayedVotes.map((vote) => ( {/* Voter */} diff --git a/src/components/proposals/VotingProgressChart.tsx b/src/components/proposals/VotingProgressChart.tsx index 9a42d253..3facf42b 100644 --- a/src/components/proposals/VotingProgressChart.tsx +++ b/src/components/proposals/VotingProgressChart.tsx @@ -57,6 +57,7 @@ const VotingProgressChart = ({ error: voteDataError, hasData, refreshVoteData, + vetoCheck, } = useProposalVote({ proposal, contractPrincipal, @@ -172,6 +173,17 @@ const VotingProgressChart = ({ const getResultStatus = () => { const StatusIcon = statusConfig.icon; + // Check if veto amount exceeds For votes - this overrides other status + if (vetoCheck.vetoExceedsForVote && !isActive) { + return { + status: "Failed", + color: "text-destructive", + icon: , + bgColor: "bg-destructive/10 border-destructive/20", + reason: "Veto amount exceeds For votes", + }; + } + switch (status) { case "DRAFT": return { @@ -742,6 +754,13 @@ const VotingProgressChart = ({ />
+ {/* Veto override message */} + {resultStatus.reason && ( +
+ ⚠️ {resultStatus.reason} +
+ )} + {/* Additional status-specific information */} {status === "EXECUTION_WINDOW" && (
@@ -760,7 +779,8 @@ const VotingProgressChart = ({ )} {status === "FAILED" && enhancedCalculations.metQuorum && - enhancedCalculations.metThreshold && ( + enhancedCalculations.metThreshold && + !resultStatus.reason && (
⚠️ Failed despite meeting requirements
diff --git a/src/hooks/useProposalVote.ts b/src/hooks/useProposalVote.ts index 3a5d92ee..79d5441e 100644 --- a/src/hooks/useProposalVote.ts +++ b/src/hooks/useProposalVote.ts @@ -3,6 +3,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; import { fetchProposalVotes } from "@/services/vote.service"; import { useProposalStatus } from "@/hooks/useProposalStatus"; import { useSmartCacheBusting } from "@/hooks/useSmartCacheBusting"; +import { useVetoCheck } from "@/hooks/useVetoCheck"; import type { Proposal, ProposalWithDAO } from "@/types"; interface UseProposalVoteProps { @@ -270,6 +271,12 @@ export function useProposalVote({ return !voteDisplayData && primaryQuery.error; }, [voteDisplayData, primaryQuery.error]); + // Check if veto amount exceeds For votes + const vetoCheck = useVetoCheck({ + proposal, + votesForNum: calculations?.votesForNum || 0, + }); + return { // Data voteDisplayData, @@ -291,6 +298,9 @@ export function useProposalVote({ // Raw data rawData: activeVoteData, + // Veto check + vetoCheck, + // Debug info cacheInfo: { shouldAlwaysBustCache, diff --git a/src/hooks/useVetoCheck.ts b/src/hooks/useVetoCheck.ts new file mode 100644 index 00000000..8309a423 --- /dev/null +++ b/src/hooks/useVetoCheck.ts @@ -0,0 +1,79 @@ +import { useQuery } from "@tanstack/react-query"; +import { fetchProposalVetos } from "@/services/veto.service"; +import type { Proposal, ProposalWithDAO } from "@/types"; +import { useMemo } from "react"; + +interface UseVetoCheckProps { + proposal: Proposal | ProposalWithDAO; + votesForNum?: number; +} + +interface VetoCheckResult { + totalVetoAmount: number; + rawTotalVetoAmount: string; + vetoExceedsForVote: boolean; + isLoading: boolean; + error: boolean; +} + +/** + * Hook to check if veto amount exceeds the For votes + * Vetos are formatted the same way as votes (divided by 1e8) + */ +export function useVetoCheck({ + proposal, + votesForNum = 0, +}: UseVetoCheckProps): VetoCheckResult { + // Fetch vetos for this proposal + const { + data: vetos, + isLoading, + error, + } = useQuery({ + queryKey: ["proposalVetos", proposal.id], + queryFn: async () => { + if (!proposal.id) { + return []; + } + return await fetchProposalVetos(proposal.id); + }, + enabled: !!proposal.id, + staleTime: 30000, // 30 seconds + retry: 2, + }); + + // Calculate total veto amount + const vetoCalculations = useMemo(() => { + if (!vetos || vetos.length === 0) { + return { + totalVetoAmount: 0, + rawTotalVetoAmount: "0", + vetoExceedsForVote: false, + }; + } + + // Sum up all veto amounts + const totalRaw = vetos.reduce((sum, veto) => { + const amount = veto.amount ? parseFloat(veto.amount) : 0; + return sum + amount; + }, 0); + + // Format veto amount the same way as votes (divide by 1e8) + const totalFormatted = totalRaw; + + // Check if veto exceeds For votes + const vetoExceedsForVote = totalFormatted > votesForNum; + + return { + totalVetoAmount: totalFormatted, + rawTotalVetoAmount: totalRaw.toString(), + vetoExceedsForVote, + }; + }, [vetos, votesForNum]); + + return { + ...vetoCalculations, + isLoading, + error: !!error, + }; +} From 7d85a89354fb2fbd7ea793d543470e9e3944800a Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 23:05:02 +0545 Subject: [PATCH 06/12] update veto check to use existing query --- src/components/proposals/VoteStatusChart.tsx | 59 ++++++++++++++++++-- src/hooks/useVetoCheck.ts | 21 +------ 2 files changed, 57 insertions(+), 23 deletions(-) diff --git a/src/components/proposals/VoteStatusChart.tsx b/src/components/proposals/VoteStatusChart.tsx index e8d41380..589d86d2 100644 --- a/src/components/proposals/VoteStatusChart.tsx +++ b/src/components/proposals/VoteStatusChart.tsx @@ -1,10 +1,11 @@ "use client"; -import { useState, useCallback } from "react"; +import { useState, useCallback, useMemo } from "react"; import { TokenBalance } from "@/components/reusables/BalanceDisplay"; import { Button } from "@/components/ui/button"; import { RefreshCw, AlertCircle } from "lucide-react"; import { useProposalVote } from "@/hooks/useProposalVote"; +import { safeNumberFromBigInt } from "@/utils/proposal"; import type { Proposal, ProposalWithDAO } from "@/types"; interface VoteStatusChartProps { @@ -112,6 +113,44 @@ const VoteStatusChart = ({ // const isRefreshingAny = localRefreshing || refreshing; + // Calculate progress bar size based on quorum + const progressBarCalculations = useMemo(() => { + if (!proposal || !calculations) return null; + + const quorumPercentage = safeNumberFromBigInt(proposal.voting_quorum); + const liquidTokensNum = calculations.liquidTokensNum; + + // Calculate quorum amount in tokens + const quorumAmount = (liquidTokensNum * quorumPercentage) / 100; + + // Bar width is quorum + 10%, or total votes if exceeded + const barWidth = Math.max(quorumAmount * 1.1, calculations.totalVotes); + + // Calculate percentages based on the bar width + const votesForPercentage = (calculations.votesForNum / barWidth) * 100; + const votesAgainstPercentage = + (calculations.votesAgainstNum / barWidth) * 100; + const quorumLinePercentage = (quorumAmount / barWidth) * 100; + + return { + votesForPercentage, + votesAgainstPercentage, + quorumLinePercentage, + quorumAmount, + barWidth, + }; + }, [proposal, calculations]); + + if (!progressBarCalculations) { + return ( +
+ + No vote data available + +
+ ); + } + // Main vote display return (
@@ -122,17 +161,29 @@ const VoteStatusChart = ({
{/* Votes against (red) */}
+ {/* Quorum line indicator */} +
+
+
diff --git a/src/hooks/useVetoCheck.ts b/src/hooks/useVetoCheck.ts index 8309a423..d85b90b3 100644 --- a/src/hooks/useVetoCheck.ts +++ b/src/hooks/useVetoCheck.ts @@ -1,7 +1,6 @@ -import { useQuery } from "@tanstack/react-query"; -import { fetchProposalVetos } from "@/services/veto.service"; import type { Proposal, ProposalWithDAO } from "@/types"; import { useMemo } from "react"; +import { useProposalVetos } from "@/hooks/useVetos"; interface UseVetoCheckProps { proposal: Proposal | ProposalWithDAO; @@ -24,23 +23,7 @@ export function useVetoCheck({ proposal, votesForNum = 0, }: UseVetoCheckProps): VetoCheckResult { - // Fetch vetos for this proposal - const { - data: vetos, - isLoading, - error, - } = useQuery({ - queryKey: ["proposalVetos", proposal.id], - queryFn: async () => { - if (!proposal.id) { - return []; - } - return await fetchProposalVetos(proposal.id); - }, - enabled: !!proposal.id, - staleTime: 30000, // 30 seconds - retry: 2, - }); + const { data: vetos, isLoading, error } = useProposalVetos(proposal.id || ""); // Calculate total veto amount const vetoCalculations = useMemo(() => { From 53bde062370d16b045e4c2f72b83745eb2325661 Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 23:10:59 +0545 Subject: [PATCH 07/12] fix: build --- src/components/proposals/VoteStatusChart.tsx | 70 ++++++++------------ 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/src/components/proposals/VoteStatusChart.tsx b/src/components/proposals/VoteStatusChart.tsx index 589d86d2..94c15e6f 100644 --- a/src/components/proposals/VoteStatusChart.tsx +++ b/src/components/proposals/VoteStatusChart.tsx @@ -63,6 +63,34 @@ const VoteStatusChart = ({ [refreshVoteData] ); + // Calculate progress bar size based on quorum (must be before early returns) + const progressBarCalculations = useMemo(() => { + if (!proposal || !calculations) return null; + + const quorumPercentage = safeNumberFromBigInt(proposal.voting_quorum); + const liquidTokensNum = calculations.liquidTokensNum; + + // Calculate quorum amount in tokens + const quorumAmount = (liquidTokensNum * quorumPercentage) / 100; + + // Bar width is quorum + 10%, or total votes if exceeded + const barWidth = Math.max(quorumAmount * 1.1, calculations.totalVotes); + + // Calculate percentages based on the bar width + const votesForPercentage = (calculations.votesForNum / barWidth) * 100; + const votesAgainstPercentage = + (calculations.votesAgainstNum / barWidth) * 100; + const quorumLinePercentage = (quorumAmount / barWidth) * 100; + + return { + votesForPercentage, + votesAgainstPercentage, + quorumLinePercentage, + quorumAmount, + barWidth, + }; + }, [proposal, calculations]); + // Show loading state if (isLoadingVotes && !error) { return ( @@ -101,47 +129,7 @@ const VoteStatusChart = ({ ); } - if (!voteDisplayData || !calculations) { - return ( -
- - No vote data available - -
- ); - } - - // const isRefreshingAny = localRefreshing || refreshing; - - // Calculate progress bar size based on quorum - const progressBarCalculations = useMemo(() => { - if (!proposal || !calculations) return null; - - const quorumPercentage = safeNumberFromBigInt(proposal.voting_quorum); - const liquidTokensNum = calculations.liquidTokensNum; - - // Calculate quorum amount in tokens - const quorumAmount = (liquidTokensNum * quorumPercentage) / 100; - - // Bar width is quorum + 10%, or total votes if exceeded - const barWidth = Math.max(quorumAmount * 1.1, calculations.totalVotes); - - // Calculate percentages based on the bar width - const votesForPercentage = (calculations.votesForNum / barWidth) * 100; - const votesAgainstPercentage = - (calculations.votesAgainstNum / barWidth) * 100; - const quorumLinePercentage = (quorumAmount / barWidth) * 100; - - return { - votesForPercentage, - votesAgainstPercentage, - quorumLinePercentage, - quorumAmount, - barWidth, - }; - }, [proposal, calculations]); - - if (!progressBarCalculations) { + if (!voteDisplayData || !calculations || !progressBarCalculations) { return (
From 928150dfe0a05ce7e6f9eb067db26e5f3bcaef17 Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Fri, 21 Nov 2025 23:29:17 +0545 Subject: [PATCH 08/12] refactor(proposals): Remove unnecessary 'more vetos' indicator --- src/components/proposals/sections/VetosSection.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/proposals/sections/VetosSection.tsx b/src/components/proposals/sections/VetosSection.tsx index 29e53e85..0767037d 100644 --- a/src/components/proposals/sections/VetosSection.tsx +++ b/src/components/proposals/sections/VetosSection.tsx @@ -144,11 +144,6 @@ function VetosContent({
))} - {vetos && vetos.length > 3 && ( -

- +{vetos.length - 3} more vetos -

- )}
); From 9a2a3efa544bc99e97015722247d90ecc80ca2e5 Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Sun, 23 Nov 2025 18:29:59 +0545 Subject: [PATCH 09/12] feat(proposals): Add user blocking for submission --- .../proposals/ProposalSubmission.tsx | 69 +++++++++++-------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/src/components/proposals/ProposalSubmission.tsx b/src/components/proposals/ProposalSubmission.tsx index f8fc91d8..41e90e54 100644 --- a/src/components/proposals/ProposalSubmission.tsx +++ b/src/components/proposals/ProposalSubmission.tsx @@ -69,6 +69,13 @@ import { } from "@/services/x-auth.service"; import AuthButton from "@/components/home/AuthButton"; +// Blocked usernames list - users who cannot submit contributions +const BLOCKED_USERNAMES = [ + "blockeduser1", + "blockeduser2", + // Add more usernames here as needed +]; + interface WebSocketTransactionMessage { tx_id: string; tx_status: @@ -1266,54 +1273,48 @@ export function ProposalSubmission({ )} {/* X Verification Lock Overlay */} + + {/* X Verification Pending Lock Overlay */} {hasAccessToken && + /* hasAgentDaoTokens && */ !needsXLink && !isXLoading && - verificationStatus.status === "not_verified" && ( + verificationStatus.status === "pending" && (
-
- +
+
-

- - - - Your X account{" "} - {xProfile?.username ? `@${xProfile.username} ` : ""}must - have a blue check to submit contribution +

+ X Verification Pending

+

+ Your X account verification is being processed. +

)} - {/* X Verification Pending Lock Overlay */} + {/* Blocked User Lock Overlay */} {hasAccessToken && - /* hasAgentDaoTokens && */ !needsXLink && !isXLoading && - verificationStatus.status === "pending" && ( + xProfile?.username && + BLOCKED_USERNAMES.includes(xProfile.username.toLowerCase()) && (
-
- +
+
-

- X Verification Pending +

+ Account Restricted

-

- Your X account verification is being processed. +

+ Your account (@{xProfile.username}) is restricted from + submitting contributions.

@@ -1694,7 +1695,11 @@ export function ProposalSubmission({ isLoadingEmbed || !twitterEmbedData || !!xUsernameError || - !canSubmitContribution + !canSubmitContribution || + !!( + xProfile?.username && + BLOCKED_USERNAMES.includes(xProfile.username.toLowerCase()) + ) } className="bg-primary hover:bg-primary/90 text-primary-foreground font-bold px-6 py-2 text-sm rounded-sm shadow-md hover:shadow-lg transition-all duration-200" > @@ -1746,6 +1751,14 @@ export function ProposalSubmission({ Loading Post Content...
+ ) : xProfile?.username && + BLOCKED_USERNAMES.includes( + xProfile.username.toLowerCase() + ) ? ( +
+ + Account Restricted +
) : (
From f4bd209d6670b6f018526b174a080f38843c0985 Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Sun, 23 Nov 2025 18:30:43 +0545 Subject: [PATCH 10/12] re-implement the x verified locked overlay --- .../proposals/ProposalSubmission.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/components/proposals/ProposalSubmission.tsx b/src/components/proposals/ProposalSubmission.tsx index 41e90e54..bd52bdac 100644 --- a/src/components/proposals/ProposalSubmission.tsx +++ b/src/components/proposals/ProposalSubmission.tsx @@ -73,6 +73,7 @@ import AuthButton from "@/components/home/AuthButton"; const BLOCKED_USERNAMES = [ "blockeduser1", "blockeduser2", + "ablino", // Add more usernames here as needed ]; @@ -1273,6 +1274,36 @@ export function ProposalSubmission({ )} {/* X Verification Lock Overlay */} + {hasAccessToken && + !needsXLink && + !isXLoading && + verificationStatus.status === "not_verified" && ( +
+
+
+ +
+
+

+ + + + Your X account{" "} + {xProfile?.username ? `@${xProfile.username} ` : ""}must + have a blue check to submit contribution +

+
+
+
+ )} {/* X Verification Pending Lock Overlay */} {hasAccessToken && From 2d540e6485ad9e88ccf267dd608f51fcf6aaecfb Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Sun, 23 Nov 2025 20:49:07 +0545 Subject: [PATCH 11/12] refactor(user-blocking): Use `profile.is_blocked` for user restrictions --- .../proposals/ProposalSubmission.tsx | 28 ++++--------------- src/types/user.ts | 1 + 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/src/components/proposals/ProposalSubmission.tsx b/src/components/proposals/ProposalSubmission.tsx index bd52bdac..de679b1b 100644 --- a/src/components/proposals/ProposalSubmission.tsx +++ b/src/components/proposals/ProposalSubmission.tsx @@ -69,14 +69,6 @@ import { } from "@/services/x-auth.service"; import AuthButton from "@/components/home/AuthButton"; -// Blocked usernames list - users who cannot submit contributions -const BLOCKED_USERNAMES = [ - "blockeduser1", - "blockeduser2", - "ablino", - // Add more usernames here as needed -]; - interface WebSocketTransactionMessage { tx_id: string; tx_status: @@ -1274,7 +1266,7 @@ export function ProposalSubmission({ )} {/* X Verification Lock Overlay */} - {hasAccessToken && + {/* {hasAccessToken && !needsXLink && !isXLoading && verificationStatus.status === "not_verified" && ( @@ -1303,7 +1295,7 @@ export function ProposalSubmission({
- )} + )} */} {/* X Verification Pending Lock Overlay */} {hasAccessToken && @@ -1332,8 +1324,7 @@ export function ProposalSubmission({ {hasAccessToken && !needsXLink && !isXLoading && - xProfile?.username && - BLOCKED_USERNAMES.includes(xProfile.username.toLowerCase()) && ( + profile?.is_blocked === true && (
@@ -1344,8 +1335,7 @@ export function ProposalSubmission({ Account Restricted

- Your account (@{xProfile.username}) is restricted from - submitting contributions. + Your account is restricted from submitting contributions.

@@ -1727,10 +1717,7 @@ export function ProposalSubmission({ !twitterEmbedData || !!xUsernameError || !canSubmitContribution || - !!( - xProfile?.username && - BLOCKED_USERNAMES.includes(xProfile.username.toLowerCase()) - ) + profile?.is_blocked === true } className="bg-primary hover:bg-primary/90 text-primary-foreground font-bold px-6 py-2 text-sm rounded-sm shadow-md hover:shadow-lg transition-all duration-200" > @@ -1782,10 +1769,7 @@ export function ProposalSubmission({ Loading Post Content...
- ) : xProfile?.username && - BLOCKED_USERNAMES.includes( - xProfile.username.toLowerCase() - ) ? ( + ) : profile?.is_blocked === true ? (
Account Restricted diff --git a/src/types/user.ts b/src/types/user.ts index c5374a00..321d430b 100644 --- a/src/types/user.ts +++ b/src/types/user.ts @@ -5,6 +5,7 @@ export interface Profile { username: string | null; // Twitter username provider_id: string | null; // Twitter/X provider user ID is_verified: boolean | null; // X verification status: true=verified, false=not verified, null=pending + is_blocked: boolean; // Whether the user account is blocked mainnet_address: string | null; testnet_address: string | null; role?: string; From 0623c1b8369977f2ba4d26e07505c8c35e5deed3 Mon Sep 17 00:00:00 2001 From: biwasbhandari Date: Sun, 23 Nov 2025 20:49:54 +0545 Subject: [PATCH 12/12] update --- src/components/proposals/ProposalSubmission.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/proposals/ProposalSubmission.tsx b/src/components/proposals/ProposalSubmission.tsx index de679b1b..f0791827 100644 --- a/src/components/proposals/ProposalSubmission.tsx +++ b/src/components/proposals/ProposalSubmission.tsx @@ -1266,7 +1266,7 @@ export function ProposalSubmission({ )} {/* X Verification Lock Overlay */} - {/* {hasAccessToken && + {hasAccessToken && !needsXLink && !isXLoading && verificationStatus.status === "not_verified" && ( @@ -1295,7 +1295,7 @@ export function ProposalSubmission({
- )} */} + )} {/* X Verification Pending Lock Overlay */} {hasAccessToken &&