diff --git a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx index e53aca25e..d1a369b9e 100644 --- a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx +++ b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx @@ -1,12 +1,11 @@ "use client"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Hashicon } from "@emeraldpay/hashicon-react"; import { AdjustmentsHorizontalIcon, InformationCircleIcon, UserIcon, } from "@heroicons/react/24/outline"; -import { ArrowPathIcon } from "@heroicons/react/24/solid"; import { usePathname, useRouter } from "next/navigation"; import { toast } from "react-toastify"; import { Address, encodeAbiParameters, formatUnits } from "viem"; @@ -14,6 +13,8 @@ import { useAccount, useToken } from "wagmi"; import { getProposalDataDocument, getProposalDataQuery, + isMemberDocument, + isMemberQuery, } from "#/subgraph/.graphclient"; import { Badge, @@ -33,7 +34,7 @@ import { usePubSubContext } from "@/contexts/pubsub.context"; import { useChainIdFromPath } from "@/hooks/useChainIdFromPath"; import { useContractWriteWithConfirmations } from "@/hooks/useContractWriteWithConfirmations"; import { useConvictionRead } from "@/hooks/useConvictionRead"; -import { useDisableButtons } from "@/hooks/useDisableButtons"; +import { ConditionObject, useDisableButtons } from "@/hooks/useDisableButtons"; import { useMetadataIpfsFetch } from "@/hooks/useIpfsFetch"; import { useSubgraphQuery } from "@/hooks/useSubgraphQuery"; import { alloABI } from "@/src/generated"; @@ -43,10 +44,11 @@ import { useErrorDetails } from "@/utils/getErrorName"; import { prettyTimestamp } from "@/utils/text"; export default function Page({ - params: { proposalId, garden, poolId }, + params: { proposalId, garden, community: communityAddr, poolId }, }: { params: { proposalId: string; + community: string; poolId: string; chain: string; garden: string; @@ -56,6 +58,7 @@ export default function Page({ const router = useRouter(); const { address } = useAccount(); + const [, proposalNumber] = proposalId.split("-"); const { data } = useSubgraphQuery({ query: getProposalDataDocument, @@ -71,11 +74,26 @@ export default function Page({ }, }); + //query to get member registry in community + const { data: memberData } = useSubgraphQuery({ + query: isMemberDocument, + variables: { + me: address?.toLowerCase(), + comm: communityAddr?.toLowerCase(), + }, + enabled: !!address, + }); + + const isMemberCommunity = + !!memberData?.member?.memberCommunity?.[0]?.isRegistered; + // + const proposalData = data?.cvproposal; const proposalIdNumber = proposalData?.proposalNumber ? BigInt(proposalData.proposalNumber) : undefined; + const poolTokenAddr = proposalData?.strategy.token as Address; const { publish } = usePubSubContext(); @@ -102,7 +120,18 @@ export default function Page({ chainId, }); - const { tooltipMessage, isConnected, missmatchUrl } = useDisableButtons(); + const disableManSupportBtn = useMemo( + () => [ + { + condition: !isMemberCommunity, + message: "Join community to dispute", + }, + ], + [address], + ); + + const { tooltipMessage, isConnected, missmatchUrl } = + useDisableButtons(disableManSupportBtn); const { currentConvictionPct, @@ -262,6 +291,7 @@ export default function Page({ proposalData={{ ...proposalData, ...metadata }} /> : } @@ -285,7 +315,7 @@ export default function Page({ ; token: Pick; poolToken?: FetchTokenResult; + maxAmount: number; }; function calculateConvictionGrowthInSeconds( @@ -102,6 +104,7 @@ export default function PoolHeader({ arbitrableConfig, token, poolToken, + maxAmount, }: Props) { const [isOpenModal, setIsOpenModal] = useState(false); const { address } = useAccount(); @@ -149,6 +152,14 @@ export default function PoolHeader({ +token.decimals, ); + const totalPointsActivatedInPool = formatTokenAmount( + strategy.totalEffectiveActivePoints, + +token.decimals, + ); + + const minThGtTotalEffPoints = + +minThresholdPoints > +totalPointsActivatedInPool; + const spendingLimit = (strategy.config.maxRatio / CV_SCALE_PRECISION) * (1 - Math.sqrt(minimumConviction / 100)) * @@ -197,10 +208,15 @@ export default function PoolHeader({ info: "It's the time for conviction to reach proposal support. This parameter is logarithmic, represented as a half life and may vary slightly over time depending on network block times.", }, { - label: "Min Threshold", + label: "Min threshold", value: `${minThresholdPoints}`, info: `A fixed amount of ${token.symbol} that overrides Minimum Conviction when the Pool's activated governance is low.`, }, + { + label: "Max voting weight", + value: `${formatTokenAmount(maxAmount, token.decimals)} ${token.symbol}`, + info: "Staking above this specified limit won’t increase your voting weight.", + }, { label: "Protection", value: @@ -220,17 +236,31 @@ export default function PoolHeader({ : "", }, ]; - const filteredPoolConfig = - PoolTypes[proposalType] === "signaling" ? + ( + PoolTypes[proposalType] === "signaling" && + PointSystems[pointSystem] !== "capped" + ) ? + poolConfig.filter( + (config) => + !!config.value && + ![ + "Spending limit", + "Min threshold", + "Min conviction", + "Pool staked cap", + ].includes(config.label), + ) + : PoolTypes[proposalType] === "signaling" ? poolConfig.filter( (config) => !!config.value && - !["Spending limit", "Min Threshold", "Min conviction"].includes( + !["Spending limit", "Min threshold", "Min conviction"].includes( config.label, ), ) - : poolConfig; + : PointSystems[pointSystem] === "capped" ? poolConfig + : poolConfig.filter((config) => config.label !== "Pool staked cap"); //hooks const { data: isCouncilMember } = useContractRead({ @@ -449,6 +479,13 @@ export default function PoolHeader({ ))} + {minThGtTotalEffPoints && isEnabled && ( + + )} {!isEnabled ?
diff --git a/apps/web/components/Proposals.tsx b/apps/web/components/Proposals.tsx index 9d1e9d5e0..53192f476 100644 --- a/apps/web/components/Proposals.tsx +++ b/apps/web/components/Proposals.tsx @@ -192,6 +192,8 @@ export function Proposals({ !!memberData?.member?.memberCommunity?.[0]?.isRegistered; const memberActivatedStrategy = Number(memberStrategyData?.memberStrategy?.activatedPoints) > 0; + const memberTokensInCommunity = + memberData?.member?.memberCommunity?.[0].stakedTokens ?? 0; const proposals = strategy.proposals; @@ -444,7 +446,7 @@ export function Proposals({ tokenDecimals={tokenDecimals} strategy={strategy} communityAddress={communityAddress} - memberTokensInCommunity={memberActivatedPoints} + memberTokensInCommunity={memberTokensInCommunity} isMemberCommunity={isMemberCommunity} memberActivatedStrategy={memberActivatedStrategy} /> diff --git a/apps/web/types/index.ts b/apps/web/types/index.ts index 0b9e097cc..4226c0112 100644 --- a/apps/web/types/index.ts +++ b/apps/web/types/index.ts @@ -9,7 +9,7 @@ export const PoolTypes: Record = export const PointSystems: Record< string, - "fixed" | "capped" | "capped" | "unlimited" | "quadratic" + "fixed" | "capped" | "unlimited" | "quadratic" > = { 0: "fixed", 1: "capped",