-
Notifications
You must be signed in to change notification settings - Fork 618
Dashboard: fix payments tx history table crashing on onramp type purchase #7982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughRefactors Payment into a discriminated union (Bridge vs Onramp), moves bridge-specific fields into the Bridge variant, converts numeric amounts to strings, adds clientId/receiver/developer fee fields, exports BridgePayment, and updates UI components to filter for BridgePayment and convert string amounts to BigInt for formatting and CSV. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as Payments UI
participant API as getPayments()
participant TF as TokenFormatter (toTokens)
UI->>API: fetchPayments()
API-->>UI: Payment[] (Bridge | Onramp)
UI->>UI: filter isBridgePayment() → BridgePayment[]
rect rgb(220,245,230)
note right of UI: Render rows & generate CSV from BridgePayment[]
UI->>TF: toTokens(BigInt(originAmount), originToken)
TF-->>UI: formatted origin
UI->>TF: toTokens(BigInt(destinationAmount), destinationToken)
TF-->>UI: formatted destination
end
UI->>UI: produce CSV from BridgePayment[]
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7982 +/- ##
=======================================
Coverage 56.53% 56.53%
=======================================
Files 904 904
Lines 58626 58626
Branches 4146 4146
=======================================
Hits 33145 33145
Misses 25375 25375
Partials 106 106
🚀 New features to boost your workflow:
|
5ddc5f9 to
d8611da
Compare
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx (1)
88-90: Consider handling edge cases in payment filteringWhile the filtering implementation is correct, consider what happens when all payments are filtered out (all onramp payments). The UI already handles empty state, but you might want to add a more specific message for this scenario.
Consider adding a specific message when payments exist but are all filtered out:
-{isEmpty && !isLoading ? ( +{isEmpty && !isLoading ? ( <div className="flex min-h-[150px] w-full items-center justify-center text-muted-foreground text-sm"> - No data available + {payPurchaseData?.data.length > 0 ? "No bridge payments available" : "No data available"} </div> ) : payPurchaseData ? (
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/dashboard/src/@/api/universal-bridge/developer.ts(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx(4 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
🧠 Learnings (3)
📓 Common learnings
Learnt from: gregfromstl
PR: thirdweb-dev/js#7450
File: packages/thirdweb/src/bridge/Webhook.ts:57-81
Timestamp: 2025-06-26T19:46:04.024Z
Learning: In the onramp webhook schema (`packages/thirdweb/src/bridge/Webhook.ts`), the `currencyAmount` field is intentionally typed as `z.number()` while other amount fields use `z.string()` because `currencyAmount` represents fiat currency amounts in decimals (like $10.50), whereas other amount fields represent token amounts in wei (very large integers that benefit from bigint representation). The different naming convention (`currencyAmount` vs `amount`) reflects this intentional distinction.
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
🧬 Code graph analysis (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx (1)
TableRow(10-90)apps/dashboard/src/@/api/universal-bridge/developer.ts (2)
Payment(304-344)BridgePayment(346-346)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx (1)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
BridgePayment(346-346)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Size
- GitHub Check: Lint Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (9)
apps/dashboard/src/@/api/universal-bridge/developer.ts (4)
300-303: Good type refactoring for discriminated unionThe introduction of explicit type aliases for
BridgePaymentTypeandOnrampPaymentTypeimproves code readability and type safety. This discriminated union pattern is a solid approach to prevent type-related crashes.
316-317: String type for amounts aligns with webhook patternsUsing
stringfordestinationAmountis consistent with the established pattern for token amounts in wei, as noted in the retrieved learnings about amount field types in the codebase.
328-329: Consider makingblockNumberrequired for data consistencyThe
blockNumberfield is marked as optional. If this field is expected to be present for completed transactions, consider making it required to ensure data consistency.
346-346: Clean type extraction for bridge paymentsThe
BridgePaymenttype extraction using TypeScript'sExtractutility type is a clean and type-safe way to narrow the union type.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx (2)
3-13: Type update properly constrains input to bridge payments onlyThe function signature correctly updates to accept
BridgePaymentinstead ofPayment, ensuring that only bridge-type payments with the required fields are processed. This prevents runtime errors from accessing undefined fields.
16-17: Proper BigInt conversion for string amountsConverting string amounts to BigInt before passing to
toTokensis correct and necessary. This handles the API's string representation of wei amounts properly.Also applies to: 20-21
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx (3)
127-129: Type guard correctly filters out onramp paymentsThe type guard implementation is correct and efficiently filters out onramp payments. The condition
purchase.type !== "onramp"properly narrows the type.
63-65: CSV export correctly filters bridge paymentsGood practice to filter payments before CSV export, ensuring only bridge payments with the required fields are processed.
131-141: CSV function signature and BigInt conversion are correctThe function correctly accepts
BridgePayment[]and properly converts string amounts to BigInt. This ensures type safety throughout the CSV export process.
d8611da to
29be72e
Compare
...app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
295-320: Fix mislabeled destructive action: “Delete Webhook” → “Delete Payment Link”User-facing copy is incorrect for this dialog.
- Delete Webhook + Delete Payment Link
🧹 Nitpick comments (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
187-201: Avoid float precision loss; sum in base units (bigint) then format onceCurrent code converts each usage to a Number and sums, which can lose precision for 18‑dec tokens and large totals. Sum as bigint in base units, then format with
toTokens+formatTokenAmount.- `${( - paymentLinkUsagesQuery.data - ?.find((x) => x.paymentLink.id === paymentLink.id) - ?.usages?.reduce( - (acc, curr) => - acc + - Number( - toTokens( - BigInt(curr.destinationAmount), - curr.destinationToken.decimals, - ), - ), - 0, - ) || 0 - ).toString()} ${paymentLink.destinationToken.symbol}` + `${formatTokenAmount( + toTokens( + (paymentLinkUsagesQuery.data + ?.find((x) => x.paymentLink.id === paymentLink.id) + ?.usages?.reduce( + (acc, curr) => + acc + BigInt(curr.destinationAmount ?? "0"), + 0n, + )) ?? 0n, + paymentLink.destinationToken.decimals, + ), + )} ${paymentLink.destinationToken.symbol}`Nit: cache the
.find(...)result per row to avoid repeating the lookup.apps/dashboard/src/@/api/universal-bridge/developer.ts (2)
316-339: Tighten address fields toAddressfor stronger type safetySeveral address-like strings can use the existing
Addresstype.export type Payment = { @@ - receiver: string; + receiver: Address; @@ destinationToken: { - address: string; + address: Address; @@ | { type: BridgePaymentType; transactionId: string; blockNumber?: string; - sender: string; - developerFeeRecipient: string; + sender: Address; + developerFeeRecipient: Address; developerFeeBps: number; originAmount: string; originToken: { - address: string; + address: Address; symbol: string; decimals: number; chainId: number; }; }
346-347: Export a narrow type guard for Bridge paymentsCentralizing the guard makes downstream filtering simpler and type-safe.
export type BridgePayment = Extract<Payment, { type: BridgePaymentType }>; + +export function isBridgePayment(p: Payment): p is BridgePayment { + return p.type !== "onramp"; +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
apps/dashboard/src/@/api/universal-bridge/developer.ts(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx(4 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
🧠 Learnings (2)
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Build Packages
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
301-344: Good discriminated union; aligns types and prevents onramp crashesUsing
typewith a Bridge vs Onramp union and moving bridge-only fields behind the discriminant is the right call.
Merge activity
|
…hase (#7982) <!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR focuses on refactoring the payment-related types and logic in the application to improve type safety and clarity. It introduces a new `BridgePayment` type, updates the `TableRow` component, and modifies how payments are filtered and processed. ### Detailed summary - Changed `Payment` type to `BridgePayment` in `TableRow` component. - Updated `originAmount` and `destinationAmount` to use `BigInt`. - Introduced `BridgePaymentType` and `OnrampPaymentType`. - Modified `getCSVData` to accept only `BridgePayment` types. - Added `isBridgePayment` function to filter payments. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Payments views and CSV export now explicitly show only bridge payments; onramp entries are excluded. - Bug Fixes - Improved accuracy for large origin/destination amounts by converting amounts to integer form before token conversion. - Consistent token conversions across table, links, and CSV exports. - Refactor - Payment data reorganized into distinct bridge vs onramp variants to improve filtering and export consistency. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
29be72e to
17d40af
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
317-317: Fix mislabeled destructive action (“Delete Webhook” → “Delete payment”)User-facing string is incorrect for this dialog.
- Delete Webhook + Delete payment
♻️ Duplicate comments (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx (1)
15-22: Harden amount parsing to prevent crashes on invalid/empty stringsDirect BigInt(...) will throw on "", nullish, or malformed numerics. This was already flagged earlier and still applies here.
- const originAmount = toTokens( - BigInt(purchase.originAmount), - purchase.originToken.decimals, - ); + const originAmount = toTokens( + toBigIntOrZero(purchase.originAmount), + purchase.originToken.decimals, + ); @@ - const destinationAmount = toTokens( - BigInt(purchase.destinationAmount), - purchase.destinationToken.decimals, - ); + const destinationAmount = toTokens( + toBigIntOrZero(purchase.destinationAmount), + purchase.destinationToken.decimals, + );Add this helper near the top of the file:
function toBigIntOrZero(v: unknown): bigint { if (typeof v !== "string") return 0n; const s = v.trim(); if (s === "" || !/^\d+$/.test(s)) return 0n; try { return BigInt(s); } catch { return 0n; } }
🧹 Nitpick comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
58-66: Set sensible React Query cache to reduce refetch churnAdd staleTime to both queries (≥ 60s per guidelines) and gate usages query on links being loaded.
const paymentLinksQuery = useQuery({ queryFn: async () => { return getPaymentLinks({ clientId: props.clientId, teamId: props.teamId, }); }, queryKey: ["payment-links", props.clientId, props.teamId], + staleTime: 60_000, }); @@ const paymentLinkUsagesQuery = useQuery({ queryFn: async () => { const paymentLinks = paymentLinksQuery.data || []; return await Promise.all( paymentLinks.map(async (paymentLink) => { const { data } = await getPayments({ clientId: props.clientId, teamId: props.teamId, paymentLinkId: paymentLink.id, }); return { paymentLink, usages: data, }; }), ); }, queryKey: [ "payment-link-usages", paymentLinksQuery.dataUpdatedAt, props.clientId, props.teamId, ], + enabled: !!paymentLinksQuery.data, + staleTime: 60_000, });Also applies to: 68-91
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
301-347: Tighten address typing; export a shared type guard
- Use Address for all EVM addresses for stronger type guarantees.
- Export a reusable isBridgePayment guard here so UI can share a single source of truth.
type BridgePaymentType = "buy" | "sell" | "transfer"; type OnrampPaymentType = "onramp"; export type Payment = { // common id: string; createdAt: string; clientId: string; - receiver: string; + receiver: Address; transactions: Array<{ chainId: number; transactionHash: string; }>; status: "PENDING" | "COMPLETED" | "FAILED" | "NOT_FOUND"; destinationAmount: string; destinationToken: { - address: string; + address: Address; symbol: string; decimals: number; chainId: number; }; purchaseData: unknown; } & ( | { type: BridgePaymentType; transactionId: string; blockNumber?: string; - sender: string; - developerFeeRecipient: string; + sender: Address; + developerFeeRecipient: Address; developerFeeBps: number; originAmount: string; originToken: { - address: string; + address: Address; symbol: string; decimals: number; chainId: number; }; } | { onrampId: string; type: OnrampPaymentType; } ); export type BridgePayment = Extract<Payment, { type: BridgePaymentType }>;Add (outside the changed block) for reuse across the app:
export function isBridgePayment(p: Payment): p is BridgePayment { return p.type === "buy" || p.type === "sell" || p.type === "transfer"; }If the backend can ever return non-decimal numeric strings (e.g., "0x..."), let me know and I’ll adjust the parsers accordingly.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
apps/dashboard/src/@/api/universal-bridge/developer.ts(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx(4 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/typesor localtypes.tsbarrels
Prefer type aliases over interface except for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial,Pick, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/typeswhere applicable
Prefertypealiases overinterfaceexcept for nominal shapes
Avoidanyandunknownunless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/*(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLinkfor internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()from@/lib/utilsfor conditional class logic
Use design system tokens (e.g.,bg-card,border-border,text-muted-foreground)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()to retrieve JWT from cookies on server side
UseAuthorization: Bearerheader – never embed tokens in URLs
Return typed results (e.g.,Project[],User[]) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stablequeryKeysfor React Query cache hits
ConfigurestaleTime/cacheTimein React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-jsin server components
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from@/components/ui/_(e.g., Button, Input, Tabs, Card)
UseNavLinkfor internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names withcn()from@/lib/utilsfor conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start withimport "server-only"; usenext/headers, server‑only env, heavy data fetching, andredirect()where appropriate
Client Components must start with'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: callgetAuthToken()from cookies, sendAuthorization: Bearer <token>header, and return typed results (avoidany)
Client-side data fetching: wrap calls in React Query with descriptive, stablequeryKeysand set sensiblestaleTime/cacheTime(≥ 60s default); keep tokens secret via internal routes or server actions
Do not importposthog-jsin server components (client-side only)
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsxapps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Expose a
classNameprop on the root element of every component
Files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
🧠 Learnings (2)
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout PR #7888.
Applied to files:
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsxapps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx
🧬 Code graph analysis (1)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx (1)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
BridgePayment(346-346)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Size
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
187-201: It looks likedestinationAmountis typed asz.string(), so it may contain empty or invalid strings, andBigInt(curr.destinationAmount)would indeed throw in those cases. Also, converting each value to human‐readable form viaNumber(toTokens(...))loses precision when decimals are large (e.g., 18) and summing in JavaScript numbers is unsafe for big integers. The suggested refactor to:
- Accumulate a single BigInt sum in base units
- Safely parse each string to BigInt (guarding empty/invalid)
- Convert the final sum once with
toTokensis valid. Add the
toBigIntOrZerohelper as proposed.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentsTableRow.tsx (1)
10-13: Good switch to BridgePayment propsThe prop narrowing eliminates onramp-only shapes from this row and aligns with the PR’s intent.

PR-Codex overview
This PR primarily refines the payment handling in the application by introducing a new
BridgePaymenttype, updating the data types for payment amounts, and ensuring that only bridge payments are processed in relevant components.Detailed summary
Paymenttype withBridgePaymentinTableRowandgetCSVData.BridgePaymentto usestringinstead ofbigint.isBridgePaymentfunction to filter payments.PaymentHistoryto filter and display only bridge payments.BigInt.Summary by CodeRabbit
New Features
Bug Fixes
Refactor