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
10 changes: 10 additions & 0 deletions src/pages/VerifyPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,16 @@ html.verify-shell, body.verify-shell{
color: rgba(255,205,205,0.95);
background: rgba(92,33,33,0.35);
}
.vnote-claim--checking{
border-color: rgba(255,226,138,0.55);
color: rgba(255,236,190,0.95);
background: rgba(88,72,30,0.35);
}
.vnote-claim--unknown{
border-color: rgba(210,210,210,0.4);
color: rgba(220,220,220,0.9);
background: rgba(42,42,42,0.35);
}
.vbtn--ghost{ padding: 8px 12px; border-radius: 999px; font-size: 0.78rem; background: rgba(14,24,36,0.72); border: 1px solid rgba(120,180,255,0.22); color: rgba(230,242,255,0.92); }
.vbtn--ghost:hover{ border-color: rgba(120,200,255,0.45); }

Expand Down
78 changes: 65 additions & 13 deletions src/pages/VerifyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,7 @@ export default function VerifyPage(): ReactElement {
const [noteSendMeta, setNoteSendMeta] = useState<NoteSendMeta | null>(null);
const [noteSendPayloadRaw, setNoteSendPayloadRaw] = useState<Record<string, unknown> | null>(null);
const [noteClaimedImmediate, setNoteClaimedImmediate] = useState<boolean>(false);
const [noteClaimRemoteStatus, setNoteClaimRemoteStatus] = useState<"idle" | "checking" | "fresh" | "stale">("idle");
const [noteSvgFromPng, setNoteSvgFromPng] = useState<string>("");
const [noteProofBundleJson, setNoteProofBundleJson] = useState<string>("");

Expand Down Expand Up @@ -1176,12 +1177,33 @@ useEffect(() => {
readRecordString(noteSendPayloadRaw, "transferLeafHashSend") ??
noteSendRecord?.transferLeafHashSend ??
"";
const noteClaimedFinal =
Boolean(noteSendRecord?.confirmed) ||
(effectiveNoteMeta ? isNoteClaimed(effectiveNoteMeta.parentCanonical, effectiveNoteMeta.transferNonce) : false);
const noteClaimedFinal =
Boolean(noteSendRecord?.confirmed) ||
(effectiveNoteMeta ? isNoteClaimed(effectiveNoteMeta.parentCanonical, effectiveNoteMeta.transferNonce) : false);
const noteClaimKey = useMemo(
() => (effectiveNoteMeta ? `${effectiveNoteMeta.parentCanonical}|${effectiveNoteMeta.transferNonce}` : null),
[effectiveNoteMeta],
);

const noteClaimed = noteClaimedImmediate || noteClaimedFinal;
const noteClaimStatus = effectiveNoteMeta ? (noteClaimed ? "CLAIMED — SEAL Owned" : "UNCLAIMED — SEAL Available") : null;
const noteClaimState = !effectiveNoteMeta
? null
: noteClaimed
? "claimed"
: noteClaimRemoteStatus === "fresh"
? "unclaimed"
: noteClaimRemoteStatus === "stale"
? "unknown"
: "checking";
const noteClaimStatus = effectiveNoteMeta
? noteClaimState === "claimed"
? "CLAIMED — SEAL Owned"
: noteClaimState === "unclaimed"
? "UNCLAIMED — SEAL Available"
: noteClaimState === "unknown"
? "UNKNOWN — CHECK REGISTRY"
: "VERIFYING — PULLING REGISTRY"
: null;
const noteClaimPulseLabel = useMemo(() => formatClaimPulse(noteClaimedPulse), [noteClaimedPulse]);
const noteClaimNonceShort = noteClaimNonce ? ellipsizeMiddle(noteClaimNonce, 8, 6) : "—";
const noteClaimLeaderShort = noteClaimLeaderNonce ? ellipsizeMiddle(noteClaimLeaderNonce, 8, 6) : "—";
Expand All @@ -1190,26 +1212,44 @@ const noteClaimedFinal =
const isExhaleNoteUpload = isNoteUpload;

useEffect(() => {
if (!effectiveNoteMeta || noteClaimedFinal) return;
const key = `${effectiveNoteMeta.parentCanonical}|${effectiveNoteMeta.transferNonce}`;
if (noteClaimRemoteCheckedRef.current === key) return;
noteClaimRemoteCheckedRef.current = key;
setNoteClaimRemoteStatus(effectiveNoteMeta ? "idle" : "idle");
noteClaimRemoteCheckedRef.current = null;
}, [noteClaimKey]);

useEffect(() => {
if (!effectiveNoteMeta || noteClaimedFinal || !noteClaimKey) return;
if (noteClaimRemoteStatus === "checking") return;
if (noteClaimRemoteStatus === "fresh" && noteClaimRemoteCheckedRef.current === noteClaimKey) return;
if (noteClaimRemoteStatus === "stale" && noteClaimRemoteCheckedRef.current === noteClaimKey) return;
noteClaimRemoteCheckedRef.current = noteClaimKey;
Comment thread
kojibai marked this conversation as resolved.
setNoteClaimRemoteStatus("checking");
const ac = new AbortController();
const timeoutId = window.setTimeout(() => {
ac.abort();
}, 2500);

(async () => {
try {
const res = await pullAndImportRemoteUrls(ac.signal);
if (ac.signal.aborted) return;
if (res.imported > 0) setRegistryTick((prev) => prev + 1);
setNoteClaimRemoteStatus("fresh");
} catch {
// ignore remote registry failures
if (ac.signal.aborted) {
setNoteClaimRemoteStatus("stale");
return;
}
setNoteClaimRemoteStatus("stale");
} finally {
window.clearTimeout(timeoutId);
}
})();

return () => {
window.clearTimeout(timeoutId);
ac.abort();
};
}, [effectiveNoteMeta, noteClaimedFinal]);
}, [effectiveNoteMeta, noteClaimedFinal, noteClaimKey, noteClaimRemoteStatus]);

const isReceiveGlyph = useMemo(() => {
const mode = embeddedProof?.mode ?? sharedReceipt?.mode;
Expand Down Expand Up @@ -3860,11 +3900,23 @@ if (!noteDownloadBypassRef.current && alreadySpent) {
{noteClaimStatus ? (
<div className="vnote-claim-wrap">
<div
className={`vnote-claim ${noteClaimed ? "vnote-claim--claimed" : "vnote-claim--unclaimed"}`}
className={`vnote-claim ${
noteClaimState === "claimed"
? "vnote-claim--claimed"
: noteClaimState === "unclaimed"
? "vnote-claim--unclaimed"
: noteClaimState === "unknown"
? "vnote-claim--unknown"
: "vnote-claim--checking"
}`}
title={
noteClaimed
noteClaimState === "claimed"
? `Rotation-Seal owned: ${noteClaimNonce || "—"}\nClaimed pulse: ${noteClaimPulseLabel}\nLeaf hash: ${noteClaimTransferHash || "—"}`
: "Rotation-Seal available: this note has not been claimed yet."
: noteClaimState === "unclaimed"
? "Rotation-Seal available: this note has not been claimed yet."
: noteClaimState === "unknown"
? "Claim status unknown: registry refresh failed."
: "Verifying claim status against the registry."
}
>
{noteClaimStatus}
Expand Down