Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/dashboard/writer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,14 @@ function StorylineDetail({ storyline, writerAddress }: { storyline: Storyline; w
)}

{storyline.token_address && (
<>
<div className="mt-3 space-y-2">
<WriterTradingStats storyline={storyline} />
<ClaimRoyalties
tokenAddress={storyline.token_address as Address}
plotCount={storyline.plot_count}
beneficiary={writerAddress}
/>
</>
</div>
)}
</div>
);
Expand Down
46 changes: 27 additions & 19 deletions src/components/ClaimRoyalties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import { publicClient } from "../../lib/rpc";
import { mcv2BondAbi, getTokenTVL } from "../../lib/price";
import { MCV2_BOND, IS_TESTNET, EXPLORER_URL } from "../../lib/contracts/constants";

function formatTruncated(value: bigint, decimals: number, digits = 10): string {
const raw = formatUnits(value, decimals);
const dot = raw.indexOf(".");
if (dot === -1 || raw.length - dot - 1 <= digits) return raw;
const truncated = raw.slice(0, dot + 1 + digits).replace(/0+$/, "").replace(/\.$/, "");
return truncated === "0" && value > BigInt(0) ? raw.slice(0, dot + 1 + digits) : truncated;
}

type TxState = "idle" | "confirming" | "pending" | "done" | "error";

interface ClaimRoyaltiesProps {
Expand Down Expand Up @@ -84,8 +92,8 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo
}, []);

return (
<div className="mt-3">
<div className="flex items-center justify-between text-xs">
<div>
<div className="flex flex-wrap items-center gap-1.5 text-xs">
<div className="flex items-center gap-1.5">
<span className="text-muted text-[10px] uppercase tracking-wider">
Royalties
Expand Down Expand Up @@ -114,30 +122,30 @@ export function ClaimRoyalties({ tokenAddress, plotCount, beneficiary }: ClaimRo
Chain at least 2 plots ({plotCount}/2)
</li>
<li>
Unclaimed &gt; 0 ({formatUnits(unclaimed, decimals)} {reserveLabel})
Unclaimed &gt; 0 ({formatTruncated(unclaimed, decimals)} {reserveLabel})
</li>
</ul>
</div>
)}
</div>
<span className="text-foreground ml-1">
{formatUnits(unclaimed, decimals)} {reserveLabel}
<span className={`ml-1 font-medium ${unclaimed > BigInt(0) ? "text-accent" : "text-foreground"}`}>
{formatTruncated(unclaimed, decimals)} {reserveLabel}
</span>
<button
onClick={txState === "done" || txState === "error" ? reset : executeClaim}
disabled={
(txState === "idle" && !canClaim) ||
(txState !== "idle" && txState !== "done" && txState !== "error")
}
className="bg-accent text-background ml-2 rounded px-3 py-0.5 text-[10px] font-medium transition-opacity disabled:opacity-40"
>
{txState === "idle" && "Claim"}
{txState === "confirming" && "Confirm..."}
{txState === "pending" && "Pending..."}
{txState === "done" && `Claimed ${formatTruncated(claimedAmount, decimals)} ${reserveLabel}`}
{txState === "error" && "Retry"}
</button>
</div>
<button
onClick={txState === "done" || txState === "error" ? reset : executeClaim}
disabled={
(txState === "idle" && !canClaim) ||
(txState !== "idle" && txState !== "done" && txState !== "error")
}
className="bg-accent text-background rounded px-3 py-1 text-[10px] font-medium transition-opacity disabled:opacity-40"
>
{txState === "idle" && "Claim"}
{txState === "confirming" && "Confirm..."}
{txState === "pending" && "Pending..."}
{txState === "done" && `Claimed ${formatUnits(claimedAmount, decimals)} ${reserveLabel}`}
{txState === "error" && "Retry"}
</button>
</div>
{!eligible && txState === "idle" && (
<p className="text-muted mt-1 text-[10px]">
Expand Down
34 changes: 1 addition & 33 deletions src/components/WriterTradingStats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@ import { publicClient } from "../../lib/rpc";
import { mcv2BondAbi, getTokenTVL } from "../../lib/price";
import { MCV2_BOND, IS_TESTNET } from "../../lib/contracts/constants";
import type { Storyline } from "../../lib/supabase";
import { supabase } from "../../lib/supabase";

function formatTruncated(value: bigint, decimals: number, digits = 6): string {
const raw = formatUnits(value, decimals);
const dot = raw.indexOf(".");
if (dot === -1 || raw.length - dot - 1 <= digits) return raw;
return raw.slice(0, dot + 1 + digits).replace(/0+$/, "").replace(/\.$/, "");
}

interface WriterTradingStatsProps {
storyline: Storyline;
Expand Down Expand Up @@ -45,34 +37,10 @@ export function WriterTradingStats({ storyline }: WriterTradingStatsProps) {
enabled: !!tokenAddress,
});

// Fetch total donations for this storyline
const { data: donationsTotal } = useQuery({
queryKey: ["writer-donations", storyline.storyline_id],
queryFn: async () => {
if (!supabase) return BigInt(0);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { data } = await (supabase.from("donations") as any)
.select("amount")
.eq("storyline_id", storyline.storyline_id);
if (!data) return BigInt(0);
return (data as { amount: string }[]).reduce((sum, d) => sum + BigInt(d.amount), BigInt(0));
},
});

const decimals = tvlData?.decimals;

return (
<div className="text-muted mt-3 grid grid-cols-3 gap-2 text-xs">
<div>
<span className="block text-[10px] uppercase tracking-wider">
Donations
</span>
<span className="text-accent font-medium">
{donationsTotal !== undefined && decimals !== undefined
? `${formatTruncated(donationsTotal, decimals)} ${reserveLabel}`
: "—"}
</span>
</div>
<div className="text-muted grid grid-cols-2 gap-2 text-xs">
<div>
<span className="block text-[10px] uppercase tracking-wider">
Token Price
Expand Down
Loading