Skip to content
Open
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
6 changes: 6 additions & 0 deletions src/app-styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,12 @@ footer {

width: 100%;
}
.permit-cell .button-small {
height: 28px;
font-size: 12px;
padding-inline: 8px;
margin-top: 6px;
}
.permit-cell button:not([disabled]):hover {
opacity: 1;
background-color: #ffffff1a;
Expand Down
9 changes: 9 additions & 0 deletions src/components/dashboard-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,14 @@ export function DashboardPage() {
[handleInvalidatePermit]
);

const onDismissPermit = useCallback(
(permit: PermitData) => {
// Local-only dismissal: mark as invalid so it naturally gets filtered out from the UI.
updatePermitStatusCache(permit.signature, { status: "Invalid" });
},
[updatePermitStatusCache]
);
Comment on lines +236 to +242
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Local-only dismissal — be aware of the persistence gap.

This stores the override only in browser storage. Clearing site data or switching browsers restores dismissed permits. The PR reviewer (@gentlementlegen) flagged that the spec expects server-side invalidation.

If local-only is intentional for now, consider adding a brief comment noting the limitation and linking to the follow-up plan.


// --- UI Logic ---
const toggleTableVisibility = () => {
setIsTableVisible((prev) => !prev);
Expand Down Expand Up @@ -550,6 +558,7 @@ export function DashboardPage() {
onClaimPermit={handleClaimPermit}
onClaimPermits={claimPermits}
onInvalidatePermit={onInvalidatePermit}
onDismissPermit={onDismissPermit}
isConnected={isConnected}
chain={chain}
isLoading={isLoading}
Expand Down
18 changes: 18 additions & 0 deletions src/components/permit-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface PermitRowProps {
permit: PermitData;
onClaimPermit: (permit: PermitData) => Promise<{ success: boolean; txHash: string }>;
onInvalidatePermit?: (permit: PermitData) => Promise<{ success: boolean; txHash: string }>;
onDismissPermit?: (permit: PermitData) => void;
isConnected: boolean;
chain: Chain | undefined;
isQuoting: boolean;
Expand All @@ -29,6 +30,7 @@ export function PermitRow({
permit,
onClaimPermit,
onInvalidatePermit,
onDismissPermit,
isConnected,
chain,
isQuoting,
Expand Down Expand Up @@ -59,6 +61,8 @@ export function PermitRow({

const isOwner = !!address && permit.owner.toLowerCase() === address.toLowerCase();
const canInvalidate = isOwner && !isClaimed && !isInvalidating;
const isBeneficiary = !!address && permit.beneficiary.toLowerCase() === address.toLowerCase();
const canDismiss = Boolean(onDismissPermit && isConnected && isBeneficiary && !isClaimed && !isClaimingThis);

const rowClassName = (() => {
if (!isReadyToClaim) return "row-invalid";
Expand Down Expand Up @@ -142,6 +146,15 @@ export function PermitRow({
}
};

const handleDismissClick = () => {
if (!canDismiss || !onDismissPermit) return;
const ok = window.confirm(
"Dismiss this permit?\n\nThis will mark the permit as invalid and hide it from your pending list. It only affects your current browser (stored locally) and can be undone by clearing site storage."
);
if (!ok) return;
onDismissPermit(permit);
};

const finalButtonText = networkMismatch ? (isSwitchingNetwork ? "Switching..." : `Switch to ${targetNetworkName}`) : buttonText;

const formatGithubLink = (url: string | undefined): JSX.Element | string => {
Expand Down Expand Up @@ -273,6 +286,11 @@ export function PermitRow({
{showButtonIcon && buttonIcon}
<span>{finalButtonText}</span>
</button>
{canDismiss && (
<button onClick={handleDismissClick} className="button-as-link button-small" title="Mark this permit as invalid and hide it from your pending list">
Dismiss
</button>
)}
{!networkMismatch && permit.claimError && <div className="status-error extra-small-font margin-top-4">Error: {permit.claimError}</div>}
{!networkMismatch && permit.checkError && <div className="status-error extra-small-font margin-top-4">Check Failed: {permit.checkError}</div>}
{!permit.claimError && !permit.checkError && permit.testError && (
Expand Down
3 changes: 3 additions & 0 deletions src/components/permits-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ interface PermitsTableProps {
onClaimPermit: (permit: PermitData) => Promise<{ success: boolean; txHash: string }>;
onClaimPermits: (permit: PermitData[]) => Promise<void>;
onInvalidatePermit?: (permit: PermitData) => Promise<{ success: boolean; txHash: string }>;
onDismissPermit?: (permit: PermitData) => void;
isConnected: boolean;
chain: Chain | undefined;
isLoading: boolean;
Expand All @@ -23,6 +24,7 @@ export function PermitsTable({
permits,
onClaimPermit,
onInvalidatePermit,
onDismissPermit,
isConnected,
chain,
isLoading,
Expand Down Expand Up @@ -62,6 +64,7 @@ export function PermitsTable({
permit={permit}
onClaimPermit={onClaimPermit}
onInvalidatePermit={onInvalidatePermit}
onDismissPermit={onDismissPermit}
isConnected={isConnected}
chain={chain}
isQuoting={isQuoting}
Expand Down
5 changes: 4 additions & 1 deletion src/hooks/use-permit-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export function usePermitData({ address, isConnected, preferredRewardTokenAddres
const filtered: PermitData[] = [];
permitsMap.forEach((permit) => {
const nonceCheckFailed = !!(permit.checkError && permit.checkError.toLowerCase().includes("nonce"));
const shouldFilter = permit.isNonceUsed === true || nonceCheckFailed || permit.status === "Claimed";
// Only show permits that are actionable to the current user.
// "Invalid" includes user-dismissed bogus permits (persisted locally) and other explicit invalid states.
const shouldFilter = permit.isNonceUsed === true || nonceCheckFailed || permit.status === "Claimed" || permit.status === "Invalid";
if (!shouldFilter) filtered.push(permit);
});
setPermits(filtered);
Expand All @@ -67,6 +69,7 @@ export function usePermitData({ address, isConnected, preferredRewardTokenAddres
permit.tokenAddress &&
permit.type === "erc20-permit" &&
permit.status !== "Claimed" &&
permit.status !== "Invalid" &&
permit.claimStatus !== "Success" &&
permit.claimStatus !== "Pending"
) {
Expand Down