fix(payout): show payout on content pages, comments and waves (match web)#3282
Conversation
…llback The shared UpvoteButton hid the payout chip whenever computed total_payout was 0. That also blanked the value on post/content detail pages and on waves/comments, diverging from the web client where entry-payout always renders the amount (including $0.000). - Drop the _hasPayoutToShow gate so posts, comments and waves render the payout consistently, matching web. - parsePost/parseComment: fall back to a numeric `payout` when the asset-string fields are absent (search-API / RPC shapes), mirroring web's entry-payout, so a real payout is not shown as 0. Adds regression tests for both fallbacks.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3b7df3f0fd
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const _isNumericPayoutOnly = typeof post.payout === 'number' && !post.max_accepted_payout; | ||
|
|
||
| const totalPayout = _isNumericPayoutOnly | ||
| ? post.payout |
There was a problem hiding this comment.
Preserve numeric search-result payouts
When a post is opened from search, postsResultsContainer primes the post query cache with the search item, and the SDK SearchResult shape exposes the numeric amount as total_payout, not payout. In that cached-entry path the asset-string fields are absent, but this check stays false and the following parseAsset(...) sum overwrites the existing nonzero total_payout with 0, so the content page can still show $0.000 until a fresh entry response replaces the cache. Include the existing numeric total_payout in this fallback before recomputing it from missing asset strings.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR fixes a regression where the payout chip was hidden on post detail pages, comment views, and waves whenever
Confidence Score: 5/5Safe to merge — the changes are narrowly scoped, well-tested, and the removed gate was causing real display regressions. The UpvoteButton change is a one-line removal of an over-eager display guard with no downstream side effects. The numeric-payout fallback in parsePost/parseComment is gated on !max_accepted_payout, which is a reliable discriminator for the search-API/RPC-only shapes. Nine new regression tests cover both parsers across all relevant shapes. No existing tests were removed or weakened. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Raw API / RPC response] --> B{has max_accepted_payout?}
B -- Yes\nnormal Hive post/comment --> C[Asset-string sum\npending + author + curator]
B -- No\nsearch-API / numeric-only shape --> D{has numeric payout?}
D -- post.payout is number --> E[Use post.payout]
D -- post.total_payout is number --> F[Use post.total_payout]
D -- neither --> G[parseAsset sum to 0]
C --> H[post.total_payout]
E --> H
F --> H
G --> H
H --> I[UpvoteButton]
I --> J{isShowPayoutValue?}
J -- false --> K[chip hidden]
J -- true --> L[FormattedCurrency, Number total_payout OR 0, always renders incl dollar 0.000]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Raw API / RPC response] --> B{has max_accepted_payout?}
B -- Yes\nnormal Hive post/comment --> C[Asset-string sum\npending + author + curator]
B -- No\nsearch-API / numeric-only shape --> D{has numeric payout?}
D -- post.payout is number --> E[Use post.payout]
D -- post.total_payout is number --> F[Use post.total_payout]
D -- neither --> G[parseAsset sum to 0]
C --> H[post.total_payout]
E --> H
F --> H
G --> H
H --> I[UpvoteButton]
I --> J{isShowPayoutValue?}
J -- false --> K[chip hidden]
J -- true --> L[FormattedCurrency, Number total_payout OR 0, always renders incl dollar 0.000]
Reviews (2): Last reviewed commit: "fix(payout): handle search-API total_pay..." | Re-trigger Greptile |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough
ChangesPayout Numeric Fallback and Zero Display
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
| // asset-string payout fields, so parseAsset would yield 0 and hide a real payout. | ||
| // Mirror the web client's entry-payout: fall back to the numeric payout when the | ||
| // asset-string fields are absent (detected by the missing max_accepted_payout). | ||
| const _isNumericPayoutOnly = typeof post.payout === 'number' && !post.max_accepted_payout; |
There was a problem hiding this comment.
Detection heuristic breaks when
max_accepted_payout is absent but asset-string fields are valid
The condition !post.max_accepted_payout is used as a proxy for "search-API / RPC-shaped entry without asset-string fields." If any API path returns a post that has real pending_payout_value / author_payout_value / curator_payout_value strings but omits max_accepted_payout, and the object also carries a numeric payout field, the fallback would silently use post.payout (which could differ from the true asset-string sum). The same logic exists in parseComment at line 286. This is a reasonable heuristic given the Hive API always includes max_accepted_payout for normal posts, but it's worth a brief comment noting the assumption so future callers don't inadvertently create this shape.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/utils/postParser.tsx (1)
41-74:⚠️ Potential issue | 🟠 Major | ⚡ Quick winCross-post numeric payout fallback misses
original_entry.payout.Line 41-74 normalizes payout fields from
post.original_entry, but it never copiesorig.payout.
Then at Line 110, the new fallback checkspost.payout, notorig.payout, so cross-posts with numeric-only payouts can still end up withpost.total_payout = 0.💡 Proposed fix
if (post.original_entry) { const orig = post.original_entry; @@ post.pending_payout_value = orig.pending_payout_value; post.author_payout_value = orig.author_payout_value; post.curator_payout_value = orig.curator_payout_value; post.max_accepted_payout = orig.max_accepted_payout; + post.payout = orig.payout; post.active_votes = orig.active_votes; post.children = orig.children; post.stats = orig.stats; }Also applies to: 106-116
🤖 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/utils/postParser.tsx` around lines 41 - 74, In the cross-post normalization block where post.original_entry fields are being copied to post (including pending_payout_value, author_payout_value, curator_payout_value, max_accepted_payout, etc.), add a line to also copy orig.payout to post.payout. This ensures that when the later fallback logic checks post.payout to calculate total_payout, it will have the correct numeric payout value from the original entry instead of remaining undefined or zero for cross-posts.
🧹 Nitpick comments (1)
src/utils/postParser.test.ts (1)
159-191: ⚡ Quick winAdd a regression test for cross-post numeric-only payout.
Current new cases validate direct post/comment shapes, but they don’t cover
parsePost’soriginal_entryremap path. A test wherepost.original_entryhas{ payout: number, max_accepted_payout: undefined }would catch the payout-loss path before it regresses again.Also applies to: 411-421
🤖 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/utils/postParser.test.ts` around lines 159 - 191, The current test cases validate direct post and comment payout handling but do not cover the parsePost function's original_entry remap path, which can be a source of payout-loss regressions. Add a new test case that creates a post where the original_entry object contains a numeric payout value with max_accepted_payout set to undefined, then verify that parsePost correctly preserves and processes that payout value. This regression test should be similar in structure to the existing test cases (using makePost to set up the scenario and checking result.total_payout) but specifically exercises the original_entry remap code path.
🤖 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.
Outside diff comments:
In `@src/utils/postParser.tsx`:
- Around line 41-74: In the cross-post normalization block where
post.original_entry fields are being copied to post (including
pending_payout_value, author_payout_value, curator_payout_value,
max_accepted_payout, etc.), add a line to also copy orig.payout to post.payout.
This ensures that when the later fallback logic checks post.payout to calculate
total_payout, it will have the correct numeric payout value from the original
entry instead of remaining undefined or zero for cross-posts.
---
Nitpick comments:
In `@src/utils/postParser.test.ts`:
- Around line 159-191: The current test cases validate direct post and comment
payout handling but do not cover the parsePost function's original_entry remap
path, which can be a source of payout-loss regressions. Add a new test case that
creates a post where the original_entry object contains a numeric payout value
with max_accepted_payout set to undefined, then verify that parsePost correctly
preserves and processes that payout value. This regression test should be
similar in structure to the existing test cases (using makePost to set up the
scenario and checking result.total_payout) but specifically exercises the
original_entry remap code path.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: eb23760c-66b3-4b05-8fb3-f89d9c54b61f
📒 Files selected for processing (3)
src/components/postCard/children/upvoteButton.tsxsrc/utils/postParser.test.tssrc/utils/postParser.tsx
Address PR review feedback: - parsePost/parseComment fall back to numeric `total_payout` as well as `payout` when the asset-string fields are absent. The SDK SearchResult shape exposes the amount as `total_payout` (not `payout`), so the cached search -> detail path no longer overwrites the real value with 0. - Cross-post swap also copies orig.payout / orig.total_payout so the fallback uses the original entry's value. - Add symmetrical parseComment tests (asset-string preference, genuine zero) plus search-shape and cross-post regression tests for parsePost.
Problem
Pending/total payout was not showing on post (content) detail pages in the app. Reported via a device screenshot.
Root cause: the waves card fix in
763b73fc37added a_hasPayoutToShowgate to the sharedUpvoteButton, which renders the payout chip only when the computedtotal_payout > 0(or payout is declined). ButUpvoteButtonis reused in four places, not just waves cards:postCard/children/postCardActionsPanel.tsx(feed cards)comment/view/commentView.tsx(comments and waves)postView/view/postDisplayView.tsx(post/content detail action bar)So on any entry whose computed payout was 0, the chip disappeared entirely instead of showing
$0.000. This diverges from the web client, whereentry-payoutalways renders the amount (posts, comments, waves alike:entry-payout/index.tsx,discussion-item.tsx,wave-actions.tsxwithshowPayoutdefaulting totrue).Note: real wave/comment payouts were never missing from the data.
bridge.get_discussionreturnspending_payout_valueas a proper"X.XXX HBD"string (verified live waves at 0.001 to 0.034 HBD), andparsePostalready parses them correctly. The gate only blanked the chip when the value was exactly 0.000.Changes
Drop the
_hasPayoutToShowgate inUpvoteButtonso the payout renders consistently for posts, comments and waves, including$0.000, matching web. NaN/undefined is still coerced to 0 soFormattedCurrencynever getsundefined.Numeric
payoutfallback inparsePostandparseComment: some entries (search-API / RPC shapes) expose a numericpayoutand lack the asset-string fields, soparseAssetwould yield 0 and hide a real payout. Fall back to the numericpayoutwhen the asset-string fields are absent (detected by missingmax_accepted_payout), mirroring web'sentry-payoutisSearchResultbranch.Tests
Added regression tests to
postParser.test.tsfor bothparsePostandparseComment:postParser.test.ts: 58 passed. Lint: 0 errors on changed files.Follow-up (not in this PR)
The original waves report also had a stale vote count (3 vs real 29). That is a wave-card data-freshness issue (query
staleTime/refetch), separate from display, and the right fix for the live count/payout staleness. Tracking separately.Summary by CodeRabbit
Bug Fixes
Tests