diff --git a/src/components/ClaimRoyalties.tsx b/src/components/ClaimRoyalties.tsx index f1ba75b7..8e7c4ddc 100644 --- a/src/components/ClaimRoyalties.tsx +++ b/src/components/ClaimRoyalties.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useCallback } from "react"; +import { useState, useCallback, useEffect, useRef } from "react"; import { useWriteContract } from "wagmi"; import { useQuery } from "@tanstack/react-query"; import { formatUnits, type Address } from "viem"; @@ -35,17 +35,17 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo const reserveLabel = IS_TESTNET ? "WETH" : "$PLOT"; - // Fetch unclaimed royalty balance - const { data: royaltyInfo, refetch } = useQuery({ + // Fetch unclaimed royalty balance + cumulative claimed + const { data: royaltyInfo } = useQuery({ queryKey: ["royalty-info", tokenAddress, beneficiary], queryFn: async () => { - const [balance] = await publicClient.readContract({ + const [balance, claimed] = await publicClient.readContract({ address: MCV2_BOND, abi: mcv2BondAbi, functionName: "getRoyaltyInfo", args: [beneficiary, PLOT_TOKEN], }); - return { unclaimed: balance }; + return { unclaimed: balance, claimed }; }, refetchInterval: 30000, }); @@ -58,9 +58,27 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo const decimals = tvlData?.decimals ?? 18; const unclaimed = royaltyInfo?.unclaimed ?? BigInt(0); + const totalClaimed = royaltyInfo?.claimed ?? BigInt(0); const eligible = plotCount >= 2; const canClaim = eligible && unclaimed > BigInt(0); + // Track dataUpdatedAt to detect refetch after claim + const claimDoneRef = useRef(false); + useEffect(() => { + if (txState === "done") { + claimDoneRef.current = true; + } + }, [txState]); + // Reset to idle when royaltyInfo updates after a successful claim + useEffect(() => { + if (claimDoneRef.current && txState === "done") { + claimDoneRef.current = false; + setTxState("idle"); + setError(null); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [royaltyInfo]); + const executeClaim = useCallback(async () => { try { setError(null); @@ -79,12 +97,11 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo await publicClient.waitForTransactionReceipt({ hash }); setTxState("done"); - refetch(); } catch (err) { setError(err instanceof Error ? err.message : "Claim failed"); setTxState("error"); } - }, [unclaimed, writeContractAsync, refetch]); + }, [unclaimed, writeContractAsync]); const reset = useCallback(() => { setTxState("idle"); @@ -131,18 +148,24 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo BigInt(0) ? "text-accent" : "text-foreground"}`}> {formatTruncated(unclaimed, decimals)} {reserveLabel} + {totalClaimed > BigInt(0) && ( + + (claimed: {formatTruncated(totalClaimed, decimals)} {reserveLabel} so far) + + )} @@ -152,14 +175,15 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo Chain at least 2 plots to enable royalty claims ({plotCount}/2)

)} - {eligible && unclaimed === BigInt(0) && txState === "idle" && ( + {eligible && unclaimed === BigInt(0) && txState === "idle" && totalClaimed === BigInt(0) && (

No royalties yet — royalties accrue when readers trade your token

)} {txHash && txState === "done" && (

- Tx:{" "} + Claimed {formatTruncated(claimedAmount, decimals)} {reserveLabel} —{" "} + tx:{" "}