feat: add payout confirmation dialogue component that showcases fees#187
Conversation
WalkthroughAdds a new client-side React component PayoutConfirmationDialog with a ref-based imperative API, supporting direct and batch payout modes, fee computations (platform/protocol), formatted address/amount display, and confirm/cancel actions in a modal dialog. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Greptile OverviewGreptile SummaryThis PR introduces a What Changed:
Issues Found:
The component integrates well with the existing payment flow and follows the codebase's UI patterns using shadcn components. The fee calculation logic is sound for direct mode but needs completion for batch mode. Confidence Score: 2/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant Parent as Parent Component
participant Dialog as PayoutConfirmationDialog
participant User as User
Parent->>Dialog: ref.onConfirm(callback)
Note over Parent,Dialog: Register callback function
Parent->>Dialog: ref.show(data)
activate Dialog
Note over Dialog: Set data & open=true
Dialog->>User: Display fee breakdown
Note over Dialog: Calculate fees:<br/>- Platform fee % of amount<br/>- Protocol fee % of amount
alt Direct Mode
Dialog->>User: Show single payment details<br/>+ Initial amount<br/>- Platform fee (from recipient)<br/>+ Protocol fee (to payer)<br/>= Recipient receives<br/>= Total to pay
else Batch Mode
Dialog->>User: Show multiple currencies<br/>+ List of amounts by currency<br/>- Platform/Protocol fees<br/>= Total Net Amount
Note over Dialog: ISSUE: Missing "Total to pay"<br/>with protocol fee
end
User->>Dialog: Click "Confirm & Send Payment"
Dialog->>Dialog: setOpen(false)
Dialog->>Parent: confirmCallback()
deactivate Dialog
Note over Parent: Execute payment logic
alt User Cancels
User->>Dialog: Click "Cancel"
Dialog->>Dialog: setOpen(false)
Note over Parent: No callback executed
end
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @src/components/payout-confirmation-dialog.tsx:
- Around line 141-162: The protocol fee is shown with a hardcoded "-" sign
despite being added to the total; remove the negative prefix and ensure the
displayed sign matches how the fee is applied to the computed total. Update the
render sites that reference hasProtocolFee, protocolFee, protocolFeePct,
protocolFeeAmount, formatAmount and formatAddress so the protocol fee is shown
as a positive/added cost (no leading "-" or use "+" if you explicitly show
signs) and adjust the batch-mode fee cell to derive its sign from the same total
calculation logic rather than hardcoding a "-" so both single and batch modes
are consistent.
- Around line 90-93: The confirm handler (handleConfirm) currently closes the
dialog and calls confirmCallback even when required data is missing because
renderDirectMode()/renderBatchMode() can return null; update the dialog logic to
compute a boolean like isConfirmEnabled (e.g., based on whether fee
summary/details exist and renderXMode() !== null or a validation function) and
use that to both disable the Confirm button and short-circuit handleConfirm
(return early if !isConfirmEnabled); apply the same gating to the other similar
blocks mentioned (the occurrences around lines 195-204 and 356-390) so
confirmCallback is never invoked when required data is absent or invalid.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/payout-confirmation-dialog.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*
⚙️ CodeRabbit configuration file
**/*: - Only comment on issues that would block merging — ignore minor or stylistic concerns.
- Restrict feedback to errors, security risks, or functionality-breaking problems.
- Do not post comments on code style, formatting, or non-critical improvements.
- Keep reviews short: flag only issues that make the PR unsafe to merge.
- Limit review comments to 3–5 items maximum, unless additional blockers exist.
- Group similar issues into a single comment instead of posting multiple notes.
- Skip repetition — if a pattern repeats, mention it once at a summary level only.
- Do not add general suggestions; focus strictly on merge-blocking concerns.
- If there are no critical problems, respond with minimal approval (e.g., 'Looks good'). Do not add additional review.
- Avoid line-by-line commentary unless it highlights a critical bug or security hole.
- Highlight only issues that could cause runtime errors, data loss, or severe maintainability issues.
- Ignore minor optimization opportunities — focus solely on correctness and safety.
- Provide a top-level summary of critical blockers rather than detailed per-line notes.
- Comment only when the issue must be resolved before merge — otherwise, remain silent.
- When in doubt, err on the side of fewer comments — brevity and blocking issues only.
- Avoid posting any refactoring issues
Files:
src/components/payout-confirmation-dialog.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/README.md:29-31
Timestamp: 2025-10-28T12:17:14.899Z
Learning: The payment-widget component in src/components/payment-widget/ is an external component installed via ShadCN from the Request Network registry (https://ui.request.network). Its README and documentation should not be modified as it's maintained externally.
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/utils/payment.ts:86-87
Timestamp: 2025-10-28T12:17:42.971Z
Learning: The src/components/payment-widget/ directory contains an external component installed via ShadCN from the requestnetwork registry (https://ui.request.network/r/{name}.json) and should be treated as a vendored dependency. Modifications to files in this directory should not be suggested during code review.
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/components/payment-success.tsx:57-60
Timestamp: 2025-10-28T12:16:58.341Z
Learning: The payment widget at src/components/payment-widget/** is an external component installed via ShadCN registry and should not receive detailed code modification suggestions. The project treats this directory as external/third-party code (configured in biome.json to be ignored).
Learnt from: rodrigopavezi
Repo: RequestNetwork/easy-invoice PR: 45
File: src/components/invoice-form.tsx:316-319
Timestamp: 2025-05-19T13:00:48.790Z
Learning: The handleFormSubmit function in src/components/invoice-form.tsx correctly uses data.clientEmail from the form submission data to find matching payers, which is the proper implementation.
📚 Learning: 2025-10-28T12:16:58.341Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/components/payment-success.tsx:57-60
Timestamp: 2025-10-28T12:16:58.341Z
Learning: The payment widget at src/components/payment-widget/** is an external component installed via ShadCN registry and should not receive detailed code modification suggestions. The project treats this directory as external/third-party code (configured in biome.json to be ignored).
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:17:14.899Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/README.md:29-31
Timestamp: 2025-10-28T12:17:14.899Z
Learning: The payment-widget component in src/components/payment-widget/ is an external component installed via ShadCN from the Request Network registry (https://ui.request.network). Its README and documentation should not be modified as it's maintained externally.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:17:42.971Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/utils/payment.ts:86-87
Timestamp: 2025-10-28T12:17:42.971Z
Learning: The src/components/payment-widget/ directory contains an external component installed via ShadCN from the requestnetwork registry (https://ui.request.network/r/{name}.json) and should be treated as a vendored dependency. Modifications to files in this directory should not be suggested during code review.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-06-04T10:08:40.123Z
Learnt from: aimensahnoun
Repo: RequestNetwork/easy-invoice PR: 64
File: src/components/batch-payout.tsx:100-106
Timestamp: 2025-06-04T10:08:40.123Z
Learning: In src/components/batch-payout.tsx, the user prefers to keep the simple 2-second timeout for AppKit initialization over more complex polling mechanisms when the current approach is working adequately. They favor simplicity over potentially more robust but complex solutions.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-05-19T13:00:48.790Z
Learnt from: rodrigopavezi
Repo: RequestNetwork/easy-invoice PR: 45
File: src/components/invoice-form.tsx:316-319
Timestamp: 2025-05-19T13:00:48.790Z
Learning: The handleFormSubmit function in src/components/invoice-form.tsx correctly uses data.clientEmail from the form submission data to find matching payers, which is the proper implementation.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:17:03.639Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/context/payment-widget-context/payment-widget-provider.tsx:43-46
Timestamp: 2025-10-28T12:17:03.639Z
Learning: The payment widget components under src/components/payment-widget/ are installed via ShadCN from the Request Network registry and should not be modified locally to maintain compatibility with upstream.
Applied to files:
src/components/payout-confirmation-dialog.tsx
🧬 Code graph analysis (1)
src/components/payout-confirmation-dialog.tsx (1)
src/lib/constants/currencies.ts (1)
formatCurrencyLabel(94-139)
⏰ 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). (1)
- GitHub Check: Build
I think the greptile reviews should be addressed before
b901c99 to
fd2c4f7
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @src/components/payout-confirmation-dialog.tsx:
- Around line 390-396: The multi-currency branch currently renders only
totalProtocolFee (an invalid cross-currency sum); replace that single aggregated
display with per-currency totals from totalToPay: iterate over
Object.entries(totalToPay) (or the same structure used in the single-currency
branch) and render each currency and its formatted amount using formatAmountRaw,
preserving styling (e.g., map to individual rows inside the same container
instead of showing totalProtocolFee), and remove the "+" prefix logic tied to
totalProtocolFee so each currency line shows its own sign/amount.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/payout-confirmation-dialog.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*
⚙️ CodeRabbit configuration file
**/*: - Only comment on issues that would block merging — ignore minor or stylistic concerns.
- Restrict feedback to errors, security risks, or functionality-breaking problems.
- Do not post comments on code style, formatting, or non-critical improvements.
- Keep reviews short: flag only issues that make the PR unsafe to merge.
- Limit review comments to 3–5 items maximum, unless additional blockers exist.
- Group similar issues into a single comment instead of posting multiple notes.
- Skip repetition — if a pattern repeats, mention it once at a summary level only.
- Do not add general suggestions; focus strictly on merge-blocking concerns.
- If there are no critical problems, respond with minimal approval (e.g., 'Looks good'). Do not add additional review.
- Avoid line-by-line commentary unless it highlights a critical bug or security hole.
- Highlight only issues that could cause runtime errors, data loss, or severe maintainability issues.
- Ignore minor optimization opportunities — focus solely on correctness and safety.
- Provide a top-level summary of critical blockers rather than detailed per-line notes.
- Comment only when the issue must be resolved before merge — otherwise, remain silent.
- When in doubt, err on the side of fewer comments — brevity and blocking issues only.
- Avoid posting any refactoring issues
Files:
src/components/payout-confirmation-dialog.tsx
🧠 Learnings (11)
📓 Common learnings
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/README.md:29-31
Timestamp: 2025-10-28T12:17:14.899Z
Learning: The payment-widget component in src/components/payment-widget/ is an external component installed via ShadCN from the Request Network registry (https://ui.request.network). Its README and documentation should not be modified as it's maintained externally.
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/utils/payment.ts:86-87
Timestamp: 2025-10-28T12:17:42.971Z
Learning: The src/components/payment-widget/ directory contains an external component installed via ShadCN from the requestnetwork registry (https://ui.request.network/r/{name}.json) and should be treated as a vendored dependency. Modifications to files in this directory should not be suggested during code review.
📚 Learning: 2025-10-28T12:17:14.899Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/README.md:29-31
Timestamp: 2025-10-28T12:17:14.899Z
Learning: The payment-widget component in src/components/payment-widget/ is an external component installed via ShadCN from the Request Network registry (https://ui.request.network). Its README and documentation should not be modified as it's maintained externally.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:16:58.341Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/components/payment-success.tsx:57-60
Timestamp: 2025-10-28T12:16:58.341Z
Learning: The payment widget at src/components/payment-widget/** is an external component installed via ShadCN registry and should not receive detailed code modification suggestions. The project treats this directory as external/third-party code (configured in biome.json to be ignored).
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:17:42.971Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/utils/payment.ts:86-87
Timestamp: 2025-10-28T12:17:42.971Z
Learning: The src/components/payment-widget/ directory contains an external component installed via ShadCN from the requestnetwork registry (https://ui.request.network/r/{name}.json) and should be treated as a vendored dependency. Modifications to files in this directory should not be suggested during code review.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-05-19T13:00:48.790Z
Learnt from: rodrigopavezi
Repo: RequestNetwork/easy-invoice PR: 45
File: src/components/invoice-form.tsx:316-319
Timestamp: 2025-05-19T13:00:48.790Z
Learning: The handleFormSubmit function in src/components/invoice-form.tsx correctly uses data.clientEmail from the form submission data to find matching payers, which is the proper implementation.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:17:03.639Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/context/payment-widget-context/payment-widget-provider.tsx:43-46
Timestamp: 2025-10-28T12:17:03.639Z
Learning: The payment widget components under src/components/payment-widget/ are installed via ShadCN from the Request Network registry and should not be modified locally to maintain compatibility with upstream.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-28T12:17:27.662Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 168
File: src/components/payment-widget/payment-widget.tsx:86-96
Timestamp: 2025-10-28T12:17:27.662Z
Learning: The src/components/payment-widget/ directory contains external components from the Request Network component registry and should not be modified locally, similar to how ShadCN components are treated.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-13T19:12:34.359Z
Learnt from: MantisClone
Repo: RequestNetwork/easy-invoice PR: 0
File: :0-0
Timestamp: 2025-10-13T19:12:34.359Z
Learning: In `src/server/routers/ecommerce.ts`, the `create` procedure for client IDs should use `?? undefined` for `feePercentage` and `feeAddress` when calling the external API, because the backend create endpoint uses `.optional()` and rejects `null`. However, the `edit` procedure should use `?? null` for these fields because the backend update endpoint uses `.nullable().optional()`, which allows `null` values to support explicitly unsetting fees.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-10-22T08:44:20.491Z
Learnt from: bassgeta
Repo: RequestNetwork/easy-invoice PR: 164
File: src/app/(dashboard)/s/[id]/_components/subscription-plan-preview.tsx:66-75
Timestamp: 2025-10-22T08:44:20.491Z
Learning: In the EasyInvoice codebase, amounts are normalized to 18 decimals internally for all calculations. The pattern is: parse user-facing amounts with 18 decimals using utils.parseUnits(), perform calculations with ethers BigNumber, and format back with 18 decimals using utils.formatUnits(). This normalization strategy avoids floating-point arithmetic issues and maintains consistency across different token types.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-06-04T12:02:39.411Z
Learnt from: aimensahnoun
Repo: RequestNetwork/easy-invoice PR: 67
File: src/server/routers/payment.ts:47-49
Timestamp: 2025-06-04T12:02:39.411Z
Learning: In `src/server/routers/payment.ts`, the batchPay input validation already handles empty arrays correctly. The `batchPaymentFormSchema.shape.payouts.optional()` inherits the `.min(1, "At least one payment is required")` validation from the original schema, so empty payouts arrays are automatically rejected even when the field is made optional.
Applied to files:
src/components/payout-confirmation-dialog.tsx
📚 Learning: 2025-06-04T10:08:40.123Z
Learnt from: aimensahnoun
Repo: RequestNetwork/easy-invoice PR: 64
File: src/components/batch-payout.tsx:100-106
Timestamp: 2025-06-04T10:08:40.123Z
Learning: In src/components/batch-payout.tsx, the user prefers to keep the simple 2-second timeout for AppKit initialization over more complex polling mechanisms when the current approach is working adequately. They favor simplicity over potentially more robust but complex solutions.
Applied to files:
src/components/payout-confirmation-dialog.tsx
🧬 Code graph analysis (1)
src/components/payout-confirmation-dialog.tsx (5)
src/lib/constants/currencies.ts (1)
formatCurrencyLabel(94-139)src/components/ui/separator.tsx (1)
Separator(31-31)src/components/ui/dialog.tsx (2)
Dialog(112-112)DialogContent(117-117)src/components/ui/card.tsx (2)
Card(79-79)CardContent(79-79)src/components/ui/button.tsx (1)
Button(56-56)
⏰ 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). (1)
- GitHub Check: Build
Merge activity
|

Add Payout Confirmation Dialog Component
This PR adds a new
PayoutConfirmationDialogcomponent that displays a modal for confirming payment details before finalizing a transaction.Payouts do not have any route detecting, we only get the applicable fees AFTER we get the calldata. Hence the confirmation modal.
The component:
The dialog is implemented as a forwardRef component with an imperative handle API that allows parent components to control when and how the dialog appears, making it easy to integrate with payment flows.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.