Skip to content

Revamp/4 request page#443

Open
madhurMongia wants to merge 10 commits into
feature/ui-revamp-and-referral-systemfrom
revamp/4-request-page
Open

Revamp/4 request page#443
madhurMongia wants to merge 10 commits into
feature/ui-revamp-and-referral-systemfrom
revamp/4-request-page

Conversation

@madhurMongia

@madhurMongia madhurMongia commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added streamlined request modals for funding, vouching, withdrawing, appeals, challenges, and evidence submission.
    • Added policy confirmation, evidence attachments, appeal funding guidance, and clearer request status actions.
    • Evidence now displays submitter profiles and pending submissions.
    • Added compact timelines, improved identity details, and enhanced media previews.
  • Bug Fixes

    • Improved transaction error messages and prevented duplicate submissions.
    • Updated progress, validation, chain checks, and “Waiting for indexer” feedback.
  • Style

    • Refined request layouts, buttons, tooltips, accordions, loading states, and responsive presentation.

Restyle request detail (ActionBar, Appeal, Challenge, Evidence, Timeline,
RequestIdentityCard, skeletons), claim wizard (Info, Photo, Video, Review,
Finalized, Form stepper) and cross-chain sections to the new design system.
Referral wiring in the claim flow is added later in the referral PR.
Write evidence attachments with fileURI for ERC-1497 interop, and use a
2-column challenge-reason grid on small screens.
- Introduced new accordion item animation in Tailwind configuration.
- Updated global styles to ensure buttons do not wrap text and added uniform sizing for action buttons.
- Refactored Challenge component to improve state management and user experience with new evidence form fields.
- Implemented a new RequestModal for consistent modal behavior across the application.
- Enhanced InfoTooltip component for better user interaction and information display.
- Improved accessibility and styling in various components, including ActionButton, CurrencyField, and Progress.
- Added skeleton loading states for evidence sections to enhance user feedback during data fetching.
…raction

- Added VouchingActions component to streamline vouching and funding processes.
- Integrated new modal components for better user experience during request actions.
- Updated ActionBar to manage state for withdraw and appeal functionalities.
- Improved loading states and error handling across various components.
- Refactored existing components to utilize new hooks for better state management and user feedback.
@madhurMongia madhurMongia self-assigned this Jul 16, 2026
@netlify

netlify Bot commented Jul 16, 2026

Copy link
Copy Markdown

Deploy Preview for proof-of-humanity-v2 ready!

Name Link
🔨 Latest commit 34bf1e2
🔍 Latest deploy log https://app.netlify.com/projects/proof-of-humanity-v2/deploys/6a5a4c2613d3e50008b51686
😎 Deploy Preview https://deploy-preview-443--proof-of-humanity-v2.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@madhurMongia
madhurMongia requested a review from kemuru July 16, 2026 19:25
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors request actions into reusable modal-driven flows, adds appeal and evidence workflows, improves transaction error context, updates identity and timeline presentation, and extends shared UI components for loading, tooltips, accordions, funding, and status display.

Changes

Request workflow

Layer / File(s) Summary
Shared interaction and transaction foundations
src/components/*, src/contracts/hooks/*, src/hooks/*, src/app/globals.css, tailwind.config.cjs
Reusable request modals, accordion transitions, tooltip handling, funding validation, structured write errors, status sizing, form controls, and request-specific layout styles were added or extended.
Request actions and funding flows
src/app/[pohid]/[chain]/[request]/ActionBar.tsx, Appeal.tsx, Funding.tsx, Vouch.tsx, RemoveVouch.tsx, VouchModalContent.tsx
Vouch, fund, withdraw, appeal, advance, execute, and remove-vouch actions now use centralized state, modal flows, duplicate-vouch checks, and “Waiting for indexer” messaging.
Challenge and evidence submission
src/app/[pohid]/[chain]/[request]/Challenge.tsx, Evidence.tsx, RequestEvidenceSection.tsx, src/components/AddEvidenceModal.tsx, src/data/evidence.ts, schemas/historicalWinnerClaim.gql
Challenge validation adds policy confirmation and reason metadata; evidence upload, optimistic rendering, pending ordering, and submitter profile resolution were reworked.
Identity, timeline, and request composition
src/app/[pohid]/[chain]/[request]/RequestIdentityCard.tsx, Timeline*.tsx, RequestVouchSection.tsx, page.tsx, RequestLoadingSkeleton.tsx
Identity references, registration video, timeline compact mode, voucher sections, request layout, and loading skeletons were updated.
Supporting presentation and integrations
src/app/[pohid]/cross-chain/*, src/app/[pohid]/claim/Form.tsx, RevokeModal.tsx, RequestErrorState.tsx, error.tsx, src/components/CopyButton.tsx, RequestPunishedVouchNotice.tsx
Structured write-error messages, copy labels, tooltip stacking, retry styling, cross-chain error propagation, and supporting request presentation were updated.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: kemuru

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly points to the main change: a revamp of the request page.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch revamp/4-request-page

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (1)
src/app/[pohid]/[chain]/[request]/RequestIdentityCard.tsx (1)

270-272: 📐 Maintainability & Code Quality | 🔵 Trivial

Solidity-style doc comment on a React component.

@notice/@dev tags are Solidity NatSpec conventions; for a TS/React function, standard TSDoc (/** ... */ with @param/@returns) would be more idiomatic and consistent with typical frontend tooling.
[optional_and_nitpick]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`[pohid]/[chain]/[request]/RequestIdentityCard.tsx around lines 270 -
272, Update the documentation comment for the React component rendering the
registration video to use standard TSDoc wording instead of Solidity-specific
`@notice` and `@dev` tags. Preserve the existing description about waiting for
identity data and reusing the media block across responsive layouts.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/`[pohid]/[chain]/[request]/ActionBar.tsx:
- Around line 152-164: Update the disabled condition on FundButton in ActionBar
so funding is disabled for all users whenever lockClaimed is true, while
preserving the existing enabled behavior when the humanity is not claimed and
the claimed tooltip handling.

In `@src/app/`[pohid]/[chain]/[request]/Appeal.tsx:
- Around line 299-347: The appeal deadline state in the query flow is stale and
does not gate funding after expiration. Update the snapshot and surrounding
Appeal component logic to retain the midpoint and final deadline timestamps,
schedule a state update or refetch when each boundary is reached while the page
remains open, and recompute deadline status; use the resulting state to disable
both funding forms after appealPeriodEnd while preserving midpoint-specific
losing-side restrictions.

In `@src/app/`[pohid]/[chain]/[request]/RequestEvidenceSection.tsx:
- Around line 80-85: The evidence rendering flow in RequestEvidenceSection.tsx
must render immediately with fallback identities instead of awaiting unbounded
profile enrichment; update EvidenceWithProfiles usage to enrich profiles
progressively. In src/data/evidence.ts lines 45-71, bound concurrent profile
lookups and cache results using normalized submitter addresses so repeated
identities reuse a single lookup.

In `@src/app/`[pohid]/[chain]/[request]/Vouch.tsx:
- Around line 254-257: Unify the pending/submission guard across the vouch flow
in the RequestModal usage and the related gasless, on-chain, close, and
Return-button handlers. Reuse one lock that blocks overlapping submissions and
prevents closing or returning until callbacks complete, and reset the lock and
submitted state when opening a new request so setSubmitted(true) cannot persist
stale success state.
- Around line 304-318: Replace the clickable span in the on-chain vouch action
with a native button, preserving its styling and “or vouch on chain” label. Bind
addVouch to the button’s onClick, use disabled={isOnchainLoading ||
isReconciling}, and retain the existing loading-dependent visual states without
manually relying on aria-disabled or aria-busy.

In `@src/components/Accordion.tsx`:
- Around line 127-132: Update the persisted content container in Accordion so it
becomes non-focusable immediately when open is false, rather than waiting for
the close animation or relying only on aria-hidden. Apply inert or the
component’s established equivalent focus guard while preserving the existing
mounting and visibility behavior controlled by hasOpened and isRendered.

In `@src/components/AddEvidenceModal.tsx`:
- Around line 161-179: Pass the expected chain ID into AddEvidenceModal and use
it in both the submit flow and the relevant tooltip. Before uploadEvidence runs
in submit, revalidate the connected wallet’s current chain against that expected
ID and return without uploading when it differs; keep the existing upload and
prepare behavior for a matching chain, and update the tooltip to communicate the
same chain requirement.

In `@src/components/InfoTooltip.tsx`:
- Around line 27-44: Update the InfoTooltip component’s visibility handling so
hover, focus, and click all derive from one shared visibility state, keeping
aria-expanded synchronized whenever the tooltip is shown. Assign the tooltip a
stable unique ID and reference it from the trigger via aria-describedby, while
ensuring hidden tooltip content is excluded from assistive technology when not
visible.

In `@src/contracts/hooks/useWagmiWrite.ts`:
- Around line 173-175: Update the "error" case in the write-status handling of
useWagmiWrite so it does not clear writeInFlightRef.current after a transaction
hash exists. Preserve the guard while receipt polling fails, and use the
existing hash to retry or reconcile the transaction before allowing another
non-idempotent write.

---

Nitpick comments:
In `@src/app/`[pohid]/[chain]/[request]/RequestIdentityCard.tsx:
- Around line 270-272: Update the documentation comment for the React component
rendering the registration video to use standard TSDoc wording instead of
Solidity-specific `@notice` and `@dev` tags. Preserve the existing description about
waiting for identity data and reusing the media block across responsive layouts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0a7de5de-513b-4156-93da-d35766e695f2

📥 Commits

Reviewing files that changed from the base of the PR and between 4774e76 and 53c3816.

⛔ Files ignored due to path filters (3)
  • src/icons/ArrowRight.svg is excluded by !**/*.svg
  • src/icons/XdaiToken.svg is excluded by !**/*.svg
  • src/icons/upload.svg is excluded by !**/*.svg
📒 Files selected for processing (41)
  • src/app/[pohid]/[chain]/[request]/ActionBar.tsx
  • src/app/[pohid]/[chain]/[request]/Appeal.tsx
  • src/app/[pohid]/[chain]/[request]/Challenge.tsx
  • src/app/[pohid]/[chain]/[request]/Evidence.tsx
  • src/app/[pohid]/[chain]/[request]/Funding.tsx
  • src/app/[pohid]/[chain]/[request]/Info.tsx
  • src/app/[pohid]/[chain]/[request]/RemoveVouch.tsx
  • src/app/[pohid]/[chain]/[request]/RequestErrorState.tsx
  • src/app/[pohid]/[chain]/[request]/RequestEvidenceSection.tsx
  • src/app/[pohid]/[chain]/[request]/RequestIdentityCard.tsx
  • src/app/[pohid]/[chain]/[request]/RequestLoadingSkeleton.tsx
  • src/app/[pohid]/[chain]/[request]/RequestVouchSection.tsx
  • src/app/[pohid]/[chain]/[request]/Timeline.tsx
  • src/app/[pohid]/[chain]/[request]/TimelineSection.tsx
  • src/app/[pohid]/[chain]/[request]/Vouch.tsx
  • src/app/[pohid]/[chain]/[request]/error.tsx
  • src/app/[pohid]/[chain]/[request]/page.tsx
  • src/app/[pohid]/cross-chain/crossChainUi.tsx
  • src/app/globals.css
  • src/components/Accordion.tsx
  • src/components/ActionButton.tsx
  • src/components/AddEvidenceModal.tsx
  • src/components/CopyButton.tsx
  • src/components/CurrencyField.tsx
  • src/components/EvidenceFormFields.tsx
  • src/components/Field.tsx
  • src/components/FileUploadZone.tsx
  • src/components/IdentityReferenceRow.tsx
  • src/components/InfoTooltip.tsx
  • src/components/Progress.tsx
  • src/components/Request/Grid.tsx
  • src/components/Request/StatusBadge.tsx
  • src/components/RequestModal.tsx
  • src/components/RequestPunishedVouchNotice.tsx
  • src/components/StatusIcon.tsx
  • src/components/VideoThumbnail.tsx
  • src/config/chains.ts
  • src/contracts/hooks/useWagmiWrite.ts
  • src/data/evidence.ts
  • src/hooks/useFundingAmount.ts
  • tailwind.config.cjs

Comment thread src/app/[pohid]/[chain]/[request]/ActionBar.tsx
Comment thread src/app/[pohid]/[chain]/[request]/Appeal.tsx
Comment thread src/app/[pohid]/[chain]/[request]/RequestEvidenceSection.tsx
Comment thread src/app/[pohid]/[chain]/[request]/Vouch.tsx Outdated
Comment thread src/app/[pohid]/[chain]/[request]/Vouch.tsx Outdated
Comment thread src/components/Accordion.tsx
Comment thread src/components/AddEvidenceModal.tsx
Comment thread src/components/InfoTooltip.tsx
Comment thread src/contracts/hooks/useWagmiWrite.ts Outdated
…ponents

- Added new mediaResolve animation to Tailwind configuration for improved visual effects.
- Updated global styles to ensure consistent button sizing and layout on larger screens.
- Refactored ActionBar and Vouch components to improve user interaction and loading states.
- Enhanced Evidence and AddEvidenceModal components for better user feedback during evidence submission.
- Improved accessibility and responsiveness in various components, including InfoTooltip and LoadableImage.
…proved user experience

- Replaced inline modal content in Vouch component with a dedicated VouchModalContent component for better organization and readability.
- Added new icons and improved layout for vouching methods, enhancing visual clarity and user interaction.
- Implemented acknowledgment checkbox and method selection for vouching, streamlining the submission process.
- Introduced new SVG icons for enhanced visual representation of vouching options.
… and RequestIdentityCard components

- Simplified the layout in RemoveVouch by removing unnecessary div wrappers around the ActionButton.
- Enhanced the fallback UI in RequestIdentityCard's Suspense components for better user experience during loading states.
- Updated IPFS fetch function to include a timeout for improved error handling during data retrieval.
@kemuru

kemuru commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

looks nice. just this I would add maybe 8px or 16px gap or whichever number looks better.
image

@madhurMongia

Copy link
Copy Markdown
Contributor Author

@kemuru took the spacing from design here https://www.figma.com/design/3RAWp2mZC9zB2pKtoJ8jWu/POH-NEW?node-id=62-6415&t=sLtbzjrYh6jYhTHg-0 , I believe it was intentional

…rience

- Added detailed error context handling in various components, including Vouch, Appeal, Challenge, and Funding, to provide clearer feedback on transaction failures.
- Updated GraphQL queries to include additional fields such as creationTime and submitter in the HistoricalWinnerClaim query for better data representation.
- Enhanced CopyButton and ActionButton components with improved accessibility features and tooltip support for better user interaction.
- Refactored the Vouch component to streamline modal handling and improve the overall user experience during vouching actions.
@madhurMongia

Copy link
Copy Markdown
Contributor Author

@coderabbitai review all

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@madhurMongia I’ll perform a full review of all changes in #443.

✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🧹 Nitpick comments (1)
src/components/ActionButton.tsx (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding the "use client" directive.

Since this shared component relies on React hooks (useState, useId), it fundamentally requires client-side execution. Adding the "use client" directive explicitly marks it as a client boundary, preventing Next.js from throwing build or runtime errors if a Server Component accidentally imports it directly.

♻️ Proposed refactor
+"use client";
+
 import React, { useId, useState } from "react";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ActionButton.tsx` at line 1, Add the "use client" directive at
the top of the ActionButton module, before imports, so the component’s useState
and useId hooks execute within a Next.js client boundary.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/`[pohid]/[chain]/[request]/Appeal.tsx:
- Around line 301-311: Update handleFundSuccess and closeAppealModal so a
successful funding action keeps the appeal funding controls locked until
currentChallenge/claimerFunds or challengerFunds reflects the new contribution.
Preserve the success state or add an optimistic funded-side
update/reconciliation flag across modal close and reopen, and clear it only
after indexed totals catch up; prevent another funding submission while
reconciliation is pending.

In `@src/app/`[pohid]/[chain]/[request]/Evidence.tsx:
- Around line 229-249: Update the evidence anchor IDs and matching hrefs in the
Evidence component, including the current and historical accordion sections, to
incorporate both pohId and requestIndex. Ensure each request instance generates
unique request-evidence-top and request-evidence-bottom anchors while preserving
the existing scroll-link behavior.

In `@src/app/`[pohid]/[chain]/[request]/RemoveVouch.tsx:
- Around line 116-126: Update the render condition in RemoveVouch so
ActionButton is rendered whenever web3Loaded is true, removing the
userChainId/chain.id and disabled gating. Preserve trigger.disabled and
trigger.tooltip so the button remains visible on the wrong chain and provides
the chain-switch guidance.

In `@src/app/`[pohid]/[chain]/[request]/RequestIdentityCard.tsx:
- Around line 146-150: Update the LoadableImage alt text in RequestIdentityCard
to use the displayed claimer name for the profile photo, with a generic fallback
when that name is unavailable; leave the existing fallbackLabel and image
behavior unchanged.

In `@src/app/`[pohid]/[chain]/[request]/RequestLoadingSkeleton.tsx:
- Around line 17-69: Reorder the skeleton children inside the main flex
container to match RequestIdentityCard’s mobile order: render the header,
request details, and profile aside in that sequence, while preserving the
desktop layout through the existing responsive classes. Update the surrounding
containers as needed so the profile content remains the aside on larger screens
without changing the skeleton’s visual placeholders.

In `@src/app/`[pohid]/[chain]/[request]/RequestVouchSection.tsx:
- Around line 112-117: Update the vouching-state labels to use “Potential
vouchers” while the request status is “vouching,” retaining “Vouched by” for
confirmed states. Apply this consistently in RequestVouchSection.tsx lines
112-117 and both fallback label sites in page.tsx lines 140 and 283, including
the existing optimistic indicator behavior where applicable.

In `@src/components/ActionButton.tsx`:
- Around line 110-117: Update the tooltip span in ActionButton to include
aria-hidden bound to the existing tooltipVisible state, so hidden tooltips are
excluded from the accessibility tree while visible tooltips remain accessible;
preserve the current styling and visibility behavior.
- Around line 81-84: Update the onClick handler in ActionButton to accept the
click event, preserve the isDisabled early return, and invoke the optional
onClick callback safely while forwarding that event object.

In `@src/components/InfoTooltip.tsx`:
- Around line 24-28: Update the outer wrapper in InfoTooltip to handle keydown
events and dismiss the tooltip when the Escape key is pressed, reusing the
existing hide handler. Preserve the current mouse enter and leave behavior and
ensure other keys remain unaffected.

In `@src/components/VideoThumbnail.tsx`:
- Around line 43-47: Update the video element in VideoThumbnail to use
metadata-only preloading instead of preload="auto", while preserving the
existing first-frame loading and error handlers.

In `@src/contracts/hooks/useWagmiWrite.ts`:
- Around line 188-197: Update the unknown receipt-failure handling in
useWagmiWrite.ts around the transactionError and onError path so it uses a
non-terminal callback, or otherwise supports a later onSuccess for the same
transaction hash; do not leave the hash unsettled after invoking a terminal
onError. Update the callback contract in src/contracts/hooks/types.ts lines
44-51 to keep terminal callbacks mutually exclusive only when unknown polling
failures no longer invoke onError.
- Around line 170-205: In the success case of the write status handler, inspect
receipt.status before constructing the success context or invoking
effectsRef.current?.onSuccess?. Treat a receipt with status "reverted" as an
error and route it through the existing reverted-error handling, while
preserving normal success behavior for successful receipts.

---

Nitpick comments:
In `@src/components/ActionButton.tsx`:
- Line 1: Add the "use client" directive at the top of the ActionButton module,
before imports, so the component’s useState and useId hooks execute within a
Next.js client boundary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e14b188d-2cd1-4a00-980f-745ddf4bcf7a

📥 Commits

Reviewing files that changed from the base of the PR and between 4774e76 and 34bf1e2.

⛔ Files ignored due to path filters (9)
  • src/generated/graphql.ts is excluded by !**/generated/**
  • src/icons/AlertTriangle.svg is excluded by !**/*.svg
  • src/icons/ArrowRight.svg is excluded by !**/*.svg
  • src/icons/ChainLink.svg is excluded by !**/*.svg
  • src/icons/FileText.svg is excluded by !**/*.svg
  • src/icons/Signature.svg is excluded by !**/*.svg
  • src/icons/Users.svg is excluded by !**/*.svg
  • src/icons/XdaiToken.svg is excluded by !**/*.svg
  • src/icons/upload.svg is excluded by !**/*.svg
📒 Files selected for processing (53)
  • schemas/historicalWinnerClaim.gql
  • src/app/[pohid]/(profile)/page.tsx
  • src/app/[pohid]/RevokeModal.tsx
  • src/app/[pohid]/[chain]/[request]/ActionBar.tsx
  • src/app/[pohid]/[chain]/[request]/Appeal.tsx
  • src/app/[pohid]/[chain]/[request]/Challenge.tsx
  • src/app/[pohid]/[chain]/[request]/Evidence.tsx
  • src/app/[pohid]/[chain]/[request]/Funding.tsx
  • src/app/[pohid]/[chain]/[request]/Info.tsx
  • src/app/[pohid]/[chain]/[request]/RemoveVouch.tsx
  • src/app/[pohid]/[chain]/[request]/RequestErrorState.tsx
  • src/app/[pohid]/[chain]/[request]/RequestEvidenceSection.tsx
  • src/app/[pohid]/[chain]/[request]/RequestIdentityCard.tsx
  • src/app/[pohid]/[chain]/[request]/RequestLoadingSkeleton.tsx
  • src/app/[pohid]/[chain]/[request]/RequestVouchSection.tsx
  • src/app/[pohid]/[chain]/[request]/Timeline.tsx
  • src/app/[pohid]/[chain]/[request]/TimelineSection.tsx
  • src/app/[pohid]/[chain]/[request]/Vouch.tsx
  • src/app/[pohid]/[chain]/[request]/VouchModalContent.tsx
  • src/app/[pohid]/[chain]/[request]/error.tsx
  • src/app/[pohid]/[chain]/[request]/page.tsx
  • src/app/[pohid]/claim/Form.tsx
  • src/app/[pohid]/cross-chain/PendingRelaySection.tsx
  • src/app/[pohid]/cross-chain/TransferSection.tsx
  • src/app/[pohid]/cross-chain/UpdateStateSection.tsx
  • src/app/[pohid]/cross-chain/crossChainUi.tsx
  • src/app/globals.css
  • src/components/Accordion.tsx
  • src/components/ActionButton.tsx
  • src/components/AddEvidenceModal.tsx
  • src/components/CopyButton.tsx
  • src/components/CurrencyField.tsx
  • src/components/EvidenceFormFields.tsx
  • src/components/Field.tsx
  • src/components/FileUploadZone.tsx
  • src/components/IdentityReferenceRow.tsx
  • src/components/InfoTooltip.tsx
  • src/components/LoadableImage.tsx
  • src/components/Progress.tsx
  • src/components/Request/Grid.tsx
  • src/components/Request/StatusBadge.tsx
  • src/components/RequestModal.tsx
  • src/components/RequestPunishedVouchNotice.tsx
  • src/components/StatusIcon.tsx
  • src/components/VideoThumbnail.tsx
  • src/config/chains.ts
  • src/contracts/hooks/types.ts
  • src/contracts/hooks/useWagmiWrite.ts
  • src/data/evidence.ts
  • src/hooks/useActionFeedback.ts
  • src/hooks/useFundingAmount.ts
  • src/utils/ipfs.ts
  • tailwind.config.cjs

Comment on lines +301 to +311
const handleFundSuccess = (amount: bigint, txHash?: Hash) => {
setFundSuccess({ amount, txHash });
};

const closeAppealModal = () => {
setAppealModalOpen(false);
router.refresh();
setFundSuccess(null);
if (fundSuccess) {
void queryClient.invalidateQueries({ queryKey: appealSnapshotQueryKey });
router.refresh();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep appeal funding locked until the indexed totals catch up.

After success, closing clears fundSuccess, while claimerFunds and challengerFunds still come from the potentially stale subgraph currentChallenge. Reopening can therefore submit another funding transaction against outdated remaining amounts. Optimistically update the funded side or retain a reconciliation lock until currentChallenge reflects the contribution.

Also applies to: 428-547

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`[pohid]/[chain]/[request]/Appeal.tsx around lines 301 - 311, Update
handleFundSuccess and closeAppealModal so a successful funding action keeps the
appeal funding controls locked until currentChallenge/claimerFunds or
challengerFunds reflects the new contribution. Preserve the success state or add
an optimistic funded-side update/reconciliation flag across modal close and
reopen, and clear it only after indexed totals catch up; prevent another funding
submission while reconciliation is pending.

Comment on lines +229 to +249
<div
className="mb-4 mt-4 flex animate-accordionItemIn flex-col items-center gap-3"
id="request-evidence-top"
>
<ActionButton
disabled={evidenceTrigger.disabled}
onClick={() => setModalOpen(true)}
label="Add Evidence"
tooltip={evidenceTrigger.tooltip}
className="w-[min(100%,10.625rem)]"
/>
{evidenceItems.length > 1 &&
!lastEvidenceVisible &&
!isAnimating && (
<a
className="text-sm text-peach"
href="#request-evidence-bottom"
>
Scroll to oldest evidence ↓
</a>
)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the evidence anchor IDs instance-specific.

Current and historical evidence accordions can coexist, causing duplicate request-evidence-top/request-evidence-bottom IDs and shortcuts that scroll to the wrong section. Include pohId and requestIndex in both IDs and matching hrefs.

Also applies to: 270-270, 289-297

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`[pohid]/[chain]/[request]/Evidence.tsx around lines 229 - 249,
Update the evidence anchor IDs and matching hrefs in the Evidence component,
including the current and historical accordion sections, to incorporate both
pohId and requestIndex. Ensure each request instance generates unique
request-evidence-top and request-evidence-bottom anchors while preserving the
existing scroll-link behavior.

Comment on lines 116 to +126
return (
web3Loaded &&
(userChainId === chain.id || disabled) && (
<div className="flex gap-4">
<ActionButton
onClick={removeOnchainVouch}
label="Remove Vouch"
className="mb-2 w-auto"
isLoading={status.write === "pending"}
disabled={trigger.disabled}
tooltip={trigger.tooltip}
/>
</div>
<ActionButton
onClick={removeOnchainVouch}
label="Remove Vouch"
className="mb-2 w-auto"
isLoading={isRemoveVouchLoading}
disabled={trigger.disabled}
tooltip={trigger.tooltip}
/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep “Remove Vouch” visible on the wrong chain.

The render condition hides the button when userChainId !== chain.id, making the wrong-chain trigger and tooltip unreachable. Render it whenever Web3 is loaded and let trigger.disabled provide the chain-switch guidance.

Proposed fix
   return (
-    web3Loaded &&
-    (userChainId === chain.id || disabled) && (
+    web3Loaded && (
       <ActionButton
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
web3Loaded &&
(userChainId === chain.id || disabled) && (
<div className="flex gap-4">
<ActionButton
onClick={removeOnchainVouch}
label="Remove Vouch"
className="mb-2 w-auto"
isLoading={status.write === "pending"}
disabled={trigger.disabled}
tooltip={trigger.tooltip}
/>
</div>
<ActionButton
onClick={removeOnchainVouch}
label="Remove Vouch"
className="mb-2 w-auto"
isLoading={isRemoveVouchLoading}
disabled={trigger.disabled}
tooltip={trigger.tooltip}
/>
return (
web3Loaded && (
<ActionButton
onClick={removeOnchainVouch}
label="Remove Vouch"
className="mb-2 w-auto"
isLoading={isRemoveVouchLoading}
disabled={trigger.disabled}
tooltip={trigger.tooltip}
/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`[pohid]/[chain]/[request]/RemoveVouch.tsx around lines 116 - 126,
Update the render condition in RemoveVouch so ActionButton is rendered whenever
web3Loaded is true, removing the userChainId/chain.id and disabled gating.
Preserve trigger.disabled and trigger.tooltip so the button remains visible on
the wrong chain and provides the chain-switch guidance.

Comment on lines +146 to 150
<LoadableImage
className="h-32 w-32 cursor-pointer rounded-full object-cover md:bg-cover md:bg-center md:bg-no-repeat"
alt="image"
fallbackLabel="Profile photo unavailable"
src={photoUrl}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Give the profile photo meaningful alt text.

alt="image" conveys no identity or purpose. Use the displayed claimer name, with a generic fallback.

Proposed fix
-              alt="image"
+              alt={
+                displayedClaimerName
+                  ? `${displayedClaimerName} profile photo`
+                  : "Profile photo"
+              }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<LoadableImage
className="h-32 w-32 cursor-pointer rounded-full object-cover md:bg-cover md:bg-center md:bg-no-repeat"
alt="image"
fallbackLabel="Profile photo unavailable"
src={photoUrl}
<LoadableImage
className="h-32 w-32 cursor-pointer rounded-full object-cover md:bg-cover md:bg-center md:bg-no-repeat"
alt={
displayedClaimerName
? `${displayedClaimerName} profile photo`
: "Profile photo"
}
fallbackLabel="Profile photo unavailable"
src={photoUrl}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`[pohid]/[chain]/[request]/RequestIdentityCard.tsx around lines 146 -
150, Update the LoadableImage alt text in RequestIdentityCard to use the
displayed claimer name for the profile photo, with a generic fallback when that
name is unavailable; leave the existing fallbackLabel and image behavior
unchanged.

Comment on lines +17 to 69
{/* Identity card */}
<div className="border-stroke bg-whiteBackground mb-1 overflow-hidden rounded-card border shadow-soft-inset">
<div className="flex flex-col md:flex-row">
{/* Profile aside */}
<div className="border-stroke flex animate-pulse flex-col items-center gap-4 border-b px-6 py-6 md:w-[26%] md:min-w-[16rem] md:shrink-0 md:border-b-0 md:border-r">
<div className="bg-grey h-32 w-32 rounded-full" />
<div className="bg-grey h-7 w-40 rounded" />
<div className="bg-grey h-4 w-52 max-w-full rounded" />
<div className="bg-grey h-4 w-44 max-w-full rounded" />
<div className="border-stroke mt-4 flex w-full flex-col items-center gap-3 border-y py-4">
<div className="bg-grey h-3 w-20 rounded" />
<div className="flex gap-2">
<div className="bg-grey h-8 w-8 rounded-full" />
<div className="bg-grey h-8 w-8 rounded-full" />
<div className="bg-grey h-8 w-8 rounded-full" />
</div>
</div>
<div className="bg-grey mt-2 h-3 w-28 rounded" />
</div>

<div className="bg-grey aspect-video w-full rounded" />
<div className="bg-grey mt-3 h-4 w-52 rounded" />

<div className="mt-8 flex flex-wrap gap-2">
<div className="bg-grey h-9 w-28 rounded" />
<div className="bg-grey h-9 w-28 rounded" />
<div className="bg-grey h-9 w-28 rounded" />
{/* Request details */}
<div className="flex w-full min-w-0 animate-pulse flex-col gap-4 p-6 lg:p-8">
<div className="bg-grey h-[8.25rem] w-full rounded-input md:h-12" />
<div className="bg-grey h-12 w-full rounded-input" />
<div className="flex justify-center">
<div className="bg-grey h-4 w-32 rounded" />
</div>
<div className="bg-grey aspect-[1.8] w-full rounded-2xl" />
<div className="flex justify-center md:justify-end">
<div className="bg-grey h-4 w-28 rounded" />
</div>
<div className="border-stroke border-t pt-6">
<div className="bg-grey h-5 w-24 rounded" />
<div className="mt-6 flex flex-col gap-6">
{[0, 1, 2].map((index) => (
<div key={index} className="flex gap-4">
<div className="flex w-6 shrink-0 flex-col items-center">
<div className="bg-grey h-5 w-5 rounded-full" />
{index < 2 && (
<div className="bg-grey mt-2 h-10 w-px" />
)}
</div>
<div className="min-w-0 flex-1">
<div className="bg-grey h-4 w-40 max-w-full rounded" />
<div className="bg-grey mt-2 h-3 w-24 rounded" />
</div>
</div>
))}
</div>
</div>
</div>
</div>
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

Mirror the resolved card’s mobile ordering to avoid layout shift.

The skeleton renders the complete profile aside first, while RequestIdentityCard uses contents and ordered children to render header → request info → profile on mobile. Match those orders in the skeleton to avoid a large shift when Suspense resolves.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/`[pohid]/[chain]/[request]/RequestLoadingSkeleton.tsx around lines 17
- 69, Reorder the skeleton children inside the main flex container to match
RequestIdentityCard’s mobile order: render the header, request details, and
profile aside in that sequence, while preserving the desktop layout through the
existing responsive classes. Update the surrounding containers as needed so the
profile content remains the aside on larger screens without changing the
skeleton’s visual placeholders.

Comment on lines +110 to +117
<span
id={tooltipId}
role="tooltip"
className={twMerge(
"tooltip-surface pointer-events-none absolute bottom-full left-1/2 z-50 mb-2 w-max max-w-[240px] -translate-x-1/2 text-center text-sm transition-opacity",
tooltipVisible ? "opacity-100" : "opacity-0",
)}
>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Hide invisible tooltip content from assistive technology.

Using opacity-0 visually hides the tooltip, but it remains present in the DOM's accessibility tree. Adding aria-hidden={!tooltipVisible} prevents screen readers from discovering and reading the tooltip content when navigating the document normally, aligning with the accessible pattern implemented in InfoTooltip.

♿ Proposed accessibility fix
           <span
             id={tooltipId}
             role="tooltip"
+            aria-hidden={!tooltipVisible}
             className={twMerge(
               "tooltip-surface pointer-events-none absolute bottom-full left-1/2 z-50 mb-2 w-max max-w-[240px] -translate-x-1/2 text-center text-sm transition-opacity",
               tooltipVisible ? "opacity-100" : "opacity-0",
             )}
           >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span
id={tooltipId}
role="tooltip"
className={twMerge(
"tooltip-surface pointer-events-none absolute bottom-full left-1/2 z-50 mb-2 w-max max-w-[240px] -translate-x-1/2 text-center text-sm transition-opacity",
tooltipVisible ? "opacity-100" : "opacity-0",
)}
>
<span
id={tooltipId}
role="tooltip"
aria-hidden={!tooltipVisible}
className={twMerge(
"tooltip-surface pointer-events-none absolute bottom-full left-1/2 z-50 mb-2 w-max max-w-[240px] -translate-x-1/2 text-center text-sm transition-opacity",
tooltipVisible ? "opacity-100" : "opacity-0",
)}
>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ActionButton.tsx` around lines 110 - 117, Update the tooltip
span in ActionButton to include aria-hidden bound to the existing tooltipVisible
state, so hidden tooltips are excluded from the accessibility tree while visible
tooltips remain accessible; preserve the current styling and visibility
behavior.

Comment on lines +24 to +28
<span
className={cn("relative inline-flex", className)}
onMouseEnter={show}
onMouseLeave={hide}
>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add an Escape key handler to dismiss the tooltip.

WCAG 1.4.13 requires that content triggered by hover or focus be dismissible without moving the pointer or shifting focus. Adding an onKeyDown handler to the outer wrapper ensures keyboard users can close the tooltip using the Escape key, maintaining consistency with the pattern implemented in ActionButton.

♿ Proposed accessibility fix
     <span
       className={cn("relative inline-flex", className)}
       onMouseEnter={show}
       onMouseLeave={hide}
+      onKeyDown={(e) => {
+        if (e.key === "Escape") hide();
+      }}
     >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<span
className={cn("relative inline-flex", className)}
onMouseEnter={show}
onMouseLeave={hide}
>
<span
className={cn("relative inline-flex", className)}
onMouseEnter={show}
onMouseLeave={hide}
onKeyDown={(e) => {
if (e.key === "Escape") hide();
}}
>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/InfoTooltip.tsx` around lines 24 - 28, Update the outer
wrapper in InfoTooltip to handle keydown events and dismiss the tooltip when the
Escape key is pressed, reusing the existing hide handler. Preserve the current
mouse enter and leave behavior and ensure other keys remain unaffected.

Comment on lines 43 to +47
src={videoSrc}
preload="metadata"
preload="auto"
playsInline
onLoadedData={() => setIsLoading(false)}
onError={() => {
setIsLoading(false);
setHasError(true);
}}
onError={() => setHasError(true)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

According to WHATWG HTML and MDN, how may browsers load video data for preload="auto" versus preload="metadata"?

💡 Result:

According to the WHATWG HTML specification and MDN documentation, the preload attribute is an enumerated attribute that serves as a hint to the browser regarding how much video data should be buffered upon page load [1][2][3]. Because it is a hint, browsers are not strictly required to follow it, and implementation behavior can vary based on the browser, its configuration, and network conditions [3][4][5]. The two values function as follows: preload="metadata": This indicates that the browser should fetch only the video's metadata—such as dimensions, track list, duration, and potentially the first few frames—rather than the entire file [2][3][4]. The specification notes that while the goal is to stop at metadata, browsers may sometimes fetch additional frames as well [2]. preload="auto": This signals that the browser may optimistically download the entire video file, even if playback is not immediately expected [3][4]. The browser aims to cache enough data so that playback can proceed without requiring pauses for further buffering [2][4]. Important considerations regarding these hints: 1. Precedence: The autoplay attribute takes precedence over the preload attribute [2][3][5]. If autoplay is specified, the browser will naturally begin buffering the video to enable playback, regardless of the preload hint [2][3]. 2. Browser-Specific Implementation: Browser behavior is not uniform [6]. For example, a browser might force preload="none" under specific conditions, such as when Data Saver mode is enabled or on certain cellular connections, regardless of the author's specified hint [4]. 3. Default Behavior: The specification advises that the default value for the preload attribute be set to metadata [3][7]. However, as noted in the MDN documentation, the actual default can vary between browsers [3]. If a video element has the loading="lazy" attribute applied, that attribute takes precedence over the preload attribute, deferring any data fetching until the video is near or within the viewport [1][3][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files 'src/components/VideoThumbnail.tsx' 'src/components/*' | sed -n '1,120p'
echo '---'
ast-grep outline src/components/VideoThumbnail.tsx --view expanded
echo '---'
cat -n src/components/VideoThumbnail.tsx | sed -n '1,220p'

Repository: Proof-Of-Humanity/proof-of-humanity-v2-web

Length of output: 4893


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- VideoThumbnail usages ---'
rg -n "VideoThumbnail" src
echo '--- MediaFallback ---'
ast-grep outline src/components/MediaFallback.tsx --view expanded
echo '--- file ---'
cat -n src/components/MediaFallback.tsx | sed -n '1,220p'

Repository: Proof-Of-Humanity/proof-of-humanity-v2-web

Length of output: 1595


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- RequestIdentityCard excerpt ---'
cat -n src/app/[pohid]/[chain]/[request]/RequestIdentityCard.tsx | sed -n '250,330p'
echo '--- video-related patterns ---'
rg -n 'preload="|<video|`#t`=0\.001|onLoadedData|onError' src/components src/app

Repository: Proof-Of-Humanity/proof-of-humanity-v2-web

Length of output: 8904


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n src/components/Previewed.tsx | sed -n '1,220p'

Repository: Proof-Of-Humanity/proof-of-humanity-v2-web

Length of output: 4085


Use metadata preload for the thumbnail src/components/VideoThumbnail.tsx:37-47 — this only needs the first frame, and the preview modal already loads the full video on demand. preload="auto" can pull the entire IPFS asset during page render.

Proposed fix
-        preload="auto"
+        preload="metadata"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
src={videoSrc}
preload="metadata"
preload="auto"
playsInline
onLoadedData={() => setIsLoading(false)}
onError={() => {
setIsLoading(false);
setHasError(true);
}}
onError={() => setHasError(true)}
src={videoSrc}
preload="metadata"
playsInline
onLoadedData={() => setIsLoading(false)}
onError={() => setHasError(true)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/VideoThumbnail.tsx` around lines 43 - 47, Update the video
element in VideoThumbnail to use metadata-only preloading instead of
preload="auto", while preserving the existing first-frame loading and error
handlers.

Comment on lines +170 to +205
case "success": {
if (lastSettledHashRef.current === txHash) break;
lastSettledHashRef.current = txHash;
writeInFlightRef.current = false;
const ctx: WriteSuccessContext = {
contract,
functionName: String(functionName),
args: lastWriteRef.current?.args,
value: lastWriteRef.current?.value,
chainId: lastWriteRef.current?.chainId ?? currentChainId,
// A sped-up (repriced) tx confirms under a different hash, and the
// wait resolves with that replacement receipt.
txHash: receipt?.transactionHash ?? txHash,
receipt,
};
effectsRef.current?.onSuccess?.(ctx);
break;
}
case "error": {
if (transactionError instanceof BaseError) {
if (lastUnknownHashRef.current !== txHash) {
lastUnknownHashRef.current = txHash;
effectsRef.current?.onError?.(transactionError, {
kind: "unknown",
txHash,
});
}
break;
}
if (lastSettledHashRef.current === txHash) break;
lastSettledHashRef.current = txHash;
writeInFlightRef.current = false;
effectsRef.current?.onError?.(transactionError, {
kind: "reverted",
txHash,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n '"viem"|viem@' package.json pnpm-lock.yaml yarn.lock package-lock.json 2>/dev/null || true
curl -fsSL \
  https://raw.githubusercontent.com/wevm/viem/v2.34.0/src/actions/public/waitForTransactionReceipt.ts |
  rg -n -C3 'status|BaseError|revert'

Repository: Proof-Of-Humanity/proof-of-humanity-v2-web

Length of output: 425


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant hook implementation.
sed -n '130,230p' src/contracts/hooks/useWagmiWrite.ts

# Inspect viem receipt/error typing for the installed version.
node - <<'JS'
const fs = require('fs');
const path = require('path');

const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log('viem version in package.json:', pkg.dependencies?.viem || pkg.devDependencies?.viem || 'not found');

const lock = fs.readFileSync('yarn.lock', 'utf8');
for (const line of lock.split('\n')) {
  if (line.startsWith('viem@2.34.0') || line.startsWith('viem@>=2.33.3') || line.startsWith('viem@^2.31.7')) {
    console.log(line);
  }
}
JS

# Search for all status checks and BaseError handling in the hook.
rg -n 'receipt\.status|BaseError|onSuccess|onError|waitForTransactionReceipt' src/contracts/hooks/useWagmiWrite.ts

Repository: Proof-Of-Humanity/proof-of-humanity-v2-web

Length of output: 4032


🌐 Web query:

viem v2.34.0 waitForTransactionReceipt receipt.status reverted success branch BaseError

💡 Result:

In Viem, the waitForTransactionReceipt action is designed to return a transaction receipt upon the successful inclusion of a transaction in a block [1][2]. Regarding reverted transactions, while some earlier documentation or user expectations suggested the action should throw an error when a transaction reverts [3][4][5], the current implementation returns the transaction receipt object, which includes a status field of 'reverted' [3][4]. There is a dedicated error class named TransactionReceiptRevertedError that inherits from BaseError, which is defined in the Viem source code [6]. However, this error is not automatically thrown by the standard waitForTransactionReceipt action simply because a transaction reverts; rather, the action returns the receipt, allowing developers to inspect the status manually [3][4][7]. If you need to handle reverted transactions, you should check the status property of the returned receipt object [7]: const receipt = await publicClient.waitForTransactionReceipt({ hash }); if (receipt.status === 'reverted') { // Handle the revert, for example by throwing a custom error throw new TransactionReceiptRevertedError({ receipt }); } This approach is consistent with the library's design, which separates the act of waiting for receipt confirmation from the interpretation of the transaction's outcome [7]. For developers who require earlier detection of revert reasons, using simulateContract before executing a transaction is the recommended practice to identify potential failures without incurring gas costs for a transaction that is likely to revert [6][7].

Citations:


Check receipt.status before calling onSuccess. BaseError only covers thrown failures; a mined receipt with status: "reverted" still reaches the success branch and gets reported as success.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/contracts/hooks/useWagmiWrite.ts` around lines 170 - 205, In the success
case of the write status handler, inspect receipt.status before constructing the
success context or invoking effectsRef.current?.onSuccess?. Treat a receipt with
status "reverted" as an error and route it through the existing reverted-error
handling, while preserving normal success behavior for successful receipts.

Comment on lines +188 to +197
case "error": {
if (transactionError instanceof BaseError) {
if (lastUnknownHashRef.current !== txHash) {
lastUnknownHashRef.current = txHash;
effectsRef.current?.onError?.(transactionError, {
kind: "unknown",
txHash,
});
}
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Unknown receipt failures violate the terminal callback contract.

The hook reports onError while deliberately leaving the hash unsettled, allowing a later onSuccess for the same transaction.

  • src/contracts/hooks/useWagmiWrite.ts#L188-L197: route unknown receipt failures through a non-terminal callback, or explicitly support a later success.
  • src/contracts/hooks/types.ts#L44-L51: only promise mutually exclusive terminal callbacks if unknown polling failures no longer use onError.
📍 Affects 2 files
  • src/contracts/hooks/useWagmiWrite.ts#L188-L197 (this comment)
  • src/contracts/hooks/types.ts#L44-L51
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/contracts/hooks/useWagmiWrite.ts` around lines 188 - 197, Update the
unknown receipt-failure handling in useWagmiWrite.ts around the transactionError
and onError path so it uses a non-terminal callback, or otherwise supports a
later onSuccess for the same transaction hash; do not leave the hash unsettled
after invoking a terminal onError. Update the callback contract in
src/contracts/hooks/types.ts lines 44-51 to keep terminal callbacks mutually
exclusive only when unknown polling failures no longer invoke onError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants