Skip to content

Conversation

@aimensahnoun
Copy link
Member

@aimensahnoun aimensahnoun commented Jun 3, 2025

Batch Payment System Enhancement & Dashboard Refactor

Resolves #28

Changes Overview

  • Refactored dashboard UI to support batch invoice selection and payment
  • Extracted batch payment logic into a dedicated utility module

Key Features

  • Multi-invoice selection with network compatibility validation
  • Unified batch payment processing with comprehensive error handling
  • Enhanced UI feedback during payment processing
  • Network-aware invoice selection (prevents mixing invoices from different networks)

Technical Details

  • Created new handleBatchPayment utility for centralized payment processing
  • Implemented DashboardView component with batch payment capabilities
  • Added checkbox selection to invoice table for batch processing
  • Enhanced error handling with specific error types and user-friendly messages

Testing Notes

Please test the following scenarios:

  • Single and multiple invoice selection
  • Cross-network invoice selection (should be prevented)
  • Paid invoice selection (Should be prevented)
  • Payment approval flow

Screenshots

Invoice selection

CleanShot 2025-06-04 at 15 45 06

Cross-network error

CleanShot 2025-06-04 at 15 45 21

Paid invoice error

CleanShot 2025-06-04 at 15 45 55

Summary by CodeRabbit

  • New Features

    • Added the ability to select multiple invoices and perform batch payments directly from the dashboard.
    • Introduced a new dashboard view with improved invoice management and selection capabilities.
    • Batch payment process now provides real-time feedback and detailed error handling for a smoother user experience.
  • Refactor

    • Streamlined dashboard and batch payout components for improved maintainability and user interface consistency.
  • Bug Fixes

    • Enhanced invoice selection logic to prevent incompatible or already-paid invoices from being selected for batch actions.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 3, 2025

Walkthrough

This update introduces a new DashboardView component to centralize invoice display and batch payment actions, refactors the batch payout logic to use a shared handleBatchPayment helper, and implements invoice selection for batch operations. Supporting modules and schemas are updated to facilitate these changes, including backend adjustments for batch payment requests.

Changes

File(s) Change Summary
src/app/dashboard/page.tsx Refactored to use the new DashboardView component, removing direct rendering of header, "Create Invoice" link, and InvoiceTable.
src/components/dashboard-view.tsx Added new DashboardView component for invoice management, selection, and batch payment handling. Integrates wallet connection, batch payment logic, and UI for batch actions.
src/components/batch-payout.tsx Refactored onSubmit to delegate batch payment logic to the new handleBatchPayment helper, simplifying control flow and error handling; updated payee uniqueness check and totals formatting.
src/components/invoice-table.tsx Extended to support invoice selection via checkboxes, including new props and logic to manage selected invoices and enforce network consistency; added "Select" column with checkboxes in rows.
src/lib/invoice/batch-payment.ts New module exporting handleBatchPayment to manage ERC20 approvals and batch payment transactions with comprehensive error handling and status callbacks.
src/server/routers/payment.ts Updated batchPay input schema to allow optional payouts and requestIds; mutation logic adjusted to handle these changes and include requestIds in API payload; added input refinement requiring at least one field.
src/lib/constants/chains.ts Added NETWORK_TO_ID constant mapping lowercase/hyphenated network names to numeric chain IDs.
src/components/direct-payout.tsx Removed unnecessary await from ethersProvider.getSigner() call in onSubmit.
src/components/payment-section.tsx Removed unnecessary await from ethersProvider.getSigner() call in handlePayment.
src/server/routers/invoice.ts Changed endpoint URL in sendPaymentIntent mutation from /v2/request/${paymentIntent}/send to /v2/request/payment-intents/${paymentIntent}.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DashboardView
    participant Wallet
    participant Backend
    participant handleBatchPayment

    User->>DashboardView: Select invoices, click "Batch Pay"
    DashboardView->>Wallet: Check connection / Prompt connect if needed
    alt Connected
        DashboardView->>Backend: Request batch payment data (requestIds)
        Backend-->>DashboardView: Return batch payment data (approvals, tx)
        DashboardView->>handleBatchPayment: Execute batch payment (signer, data, callbacks)
        handleBatchPayment->>Wallet: Send approval tx(s) if needed
        handleBatchPayment->>Wallet: Send batch payment tx
        handleBatchPayment-->>DashboardView: Callbacks for status/success/error
        DashboardView-->>User: Show toast, update UI
    else Not connected
        DashboardView-->>User: Prompt wallet connection
    end
Loading

Suggested reviewers

  • rodrigopavezi
  • bassgeta
  • MantisClone

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca82d80 and 8207c36.

📒 Files selected for processing (6)
  • src/components/batch-payout.tsx (5 hunks)
  • src/components/dashboard-view.tsx (1 hunks)
  • src/components/direct-payout.tsx (1 hunks)
  • src/components/payment-section.tsx (1 hunks)
  • src/lib/invoice/batch-payment.ts (1 hunks)
  • src/server/routers/invoice.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/components/direct-payout.tsx
  • src/server/routers/invoice.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/dashboard-view.tsx
  • src/components/batch-payout.tsx
  • src/lib/invoice/batch-payment.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build
🔇 Additional comments (1)
src/components/payment-section.tsx (1)

320-320: Correct removal of unnecessary await keyword.

The getSigner() method in ethers.js v5 returns a JsonRpcSigner instance synchronously, not a Promise. Removing the await keyword makes the code more accurate and aligns with the ethers.js API specification.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@aimensahnoun aimensahnoun linked an issue Jun 3, 2025 that may be closed by this pull request
3 tasks
Base automatically changed from 27-easyinvoice---one-time-batch-payments-from-payout-page to main June 4, 2025 10:46
…-easyinvoice---one-time-batch-payments-from-the-invoice-dashboard-not-recurring
…ardView components

- Introduced a new `handleBatchPayment` function to encapsulate batch payment logic, improving code reusability and readability.
- Updated `BatchPayout` and `DashboardView` components to utilize the new function, enhancing error handling and user feedback through toast notifications.
- Removed redundant code and improved state management during payment processing.
…invoice currencies

- Updated the invoice form and schema to use `INVOICE_CURRENCIES` instead of `EXTENDED_INVOICE_CURRENCIES`, ensuring consistency across the application.
- Adjusted type definitions for invoice currency to reflect the change, improving type safety and clarity.
@aimensahnoun aimensahnoun marked this pull request as ready for review June 4, 2025 11:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/components/batch-payout.tsx (1)

197-197: Consider migrating to ethers v6 for consistency.

Similar to the dashboard view, this component uses ethers v5 API.

🧹 Nitpick comments (3)
src/components/dashboard-view.tsx (1)

48-50: Consider migrating to ethers v6 for better compatibility and features.

The code uses ethers.providers.Web3Provider which is the ethers v5 API. Consider updating to ethers v6 for improved performance and modern features.

For ethers v6, the pattern would be:

-const ethersProvider = new ethers.providers.Web3Provider(
-  walletProvider as ethers.providers.ExternalProvider,
-);
+const ethersProvider = new ethers.BrowserProvider(walletProvider);
src/components/invoice-table.tsx (1)

294-319: Robust selection logic with good validation.

The handleSelectInvoice function implements solid business rules:

  • Prevents mixing invoices from different networks
  • Blocks selection of paid invoices
  • Properly manages selection state

The network extraction logic invoice.paymentCurrency.split("-")[1] appears to rely on a specific format. Consider adding validation to ensure the split operation is safe.

Consider adding validation for the network extraction:

-      const invoiceNetwork = invoice.paymentCurrency.split("-")[1];
+      const parts = invoice.paymentCurrency.split("-");
+      if (parts.length < 2) {
+        toast.error("Invalid payment currency format");
+        return false;
+      }
+      const invoiceNetwork = parts[1];
src/lib/invoice/batch-payment.ts (1)

122-154: Consider simplifying the error message extraction logic.

The nested error message extraction logic is quite complex and could be prone to runtime errors if the error object structure is unexpected.

Consider creating a helper function to safely extract error messages:

+const extractErrorMessage = (error: any): string => {
+  const defaultMessage = "There was an error processing your batch payment. Please try again.";
+  
+  if (!error || typeof error !== "object") return defaultMessage;
+  
+  // Try common error message paths
+  const paths = [
+    error.data?.message,
+    error.message,
+    error.response?.data?.message,
+    error.error?.message
+  ];
+  
+  for (const path of paths) {
+    if (typeof path === "string" && path.trim()) {
+      return path;
+    }
+  }
+  
+  return defaultMessage;
+};

-    let errorMessage =
-      "There was an error processing your batch payment. Please try again.";
-
-    if (error && typeof error === "object") {
-      if (
-        "data" in error &&
-        error.data &&
-        typeof error.data === "object" &&
-        "message" in error.data
-      ) {
-        errorMessage = error.data.message || errorMessage;
-      } else if ("message" in error) {
-        errorMessage = error.message || errorMessage;
-      } else if ("response" in error && error.response?.data?.message) {
-        errorMessage = error.response.data.message;
-      } else if (
-        "error" in error &&
-        typeof error.error === "object" &&
-        error.error &&
-        "message" in error.error
-      ) {
-        errorMessage = error.error.message;
-      }
-    }
+    const errorMessage = extractErrorMessage(error);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 635e104 and 8b53219.

📒 Files selected for processing (6)
  • src/app/dashboard/page.tsx (2 hunks)
  • src/components/batch-payout.tsx (2 hunks)
  • src/components/dashboard-view.tsx (1 hunks)
  • src/components/invoice-table.tsx (9 hunks)
  • src/lib/invoice/batch-payment.ts (1 hunks)
  • src/server/routers/payment.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/server/routers/payment.ts (1)
src/lib/schemas/payment.ts (1)
  • batchPaymentFormSchema (19-24)
src/components/batch-payout.tsx (1)
src/lib/invoice/batch-payment.ts (1)
  • handleBatchPayment (14-155)
src/components/invoice-table.tsx (3)
src/server/db/schema.ts (1)
  • Request (273-273)
src/components/ui/table.tsx (3)
  • TableRow (114-114)
  • TableCell (115-115)
  • TableHead (113-113)
src/components/ui/checkbox.tsx (1)
  • Checkbox (30-30)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Build
🔇 Additional comments (14)
src/app/dashboard/page.tsx (1)

1-37: LGTM! Clean refactoring to use the new DashboardView component.

The refactor successfully delegates the dashboard UI rendering and batch payment logic to the new DashboardView component, improving separation of concerns and maintainability.

src/components/dashboard-view.tsx (1)

39-86: The batch payment implementation looks solid.

The error handling is comprehensive, with proper UI state management and user feedback through toast notifications. The integration with the handleBatchPayment utility effectively centralizes the payment logic.

src/components/batch-payout.tsx (1)

205-232: Excellent refactoring to use the centralized handleBatchPayment utility.

The delegation to handleBatchPayment significantly simplifies the component by removing complex transaction handling logic while maintaining all the necessary functionality. The error handling and UI state management through callbacks is well implemented.

src/components/invoice-table.tsx (6)

5-5: LGTM!

The Checkbox import is correctly added for the new selection functionality.


50-53: Well-structured props for selection state management.

The new props properly encapsulate the selection state and network tracking functionality needed for batch payments.


78-84: Component signature correctly updated.

The function signature properly accepts all the new selection-related props with appropriate typing.


323-328: Checkbox integration looks good.

The checkbox is properly integrated with the selection logic and state management.


411-411: Table header updated appropriately.

The "Select" column header is correctly added with proper styling and width constraint.


185-188: Props properly passed to child components.

The selection-related props are correctly passed down to InvoiceRow components in both tabs.

Also applies to: 230-233

src/lib/invoice/batch-payment.ts (5)

29-58: Well-structured approval transaction processing.

The sequential processing of approval transactions with proper error handling is implemented correctly. The user rejection handling (code 4001) is specifically handled with appropriate feedback.


59-81: Batch payment transaction logic is sound.

The main transaction processing follows the same pattern as approvals with proper user rejection handling and success callbacks.


85-97: Comprehensive insufficient funds detection.

The error handling covers multiple ways insufficient funds errors can manifest across different providers and network conditions.


99-111: Good network error detection.

The network error handling covers various network-related error patterns effectively.


113-120: Smart contract error handling is appropriate.

Using the error.reason field for smart contract errors provides useful debugging information to users.

- Integrated `useAppKitNetwork` to manage network switching during batch payments.
- Added logic to switch networks based on the last selected network, improving user experience with toast notifications for network changes.
- Updated constants in `chains.ts` to support new network mappings.
…ce-dashboard-not-recurring' of github.com:RequestNetwork/easy-invoice into 28-easyinvoice---one-time-batch-payments-from-the-invoice-dashboard-not-recurring
- Updated `BatchPaymentData` interface to use `providers.TransactionRequest` for improved type safety.
- Added validation to the `batchPay` input schema to ensure either `payouts` or `requestIds` is provided, enhancing input integrity.
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9ba614 and ca82d80.

📒 Files selected for processing (2)
  • src/lib/invoice/batch-payment.ts (1 hunks)
  • src/server/routers/payment.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/lib/invoice/batch-payment.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/server/routers/payment.ts (1)
src/lib/schemas/payment.ts (1)
  • batchPaymentFormSchema (19-24)
🔇 Additional comments (2)
src/server/routers/payment.ts (2)

41-49: Good implementation of flexible input validation.

The schema change successfully addresses the past review comment by allowing both payouts and requestIds as optional fields while ensuring at least one is provided through the refinement validation.


62-70: Correct conditional handling of payouts and requestIds.

The mutation logic properly handles both input scenarios:

  • When payouts is provided, it maps the data to the expected API format
  • When only requestIds is provided, the requests field is set to undefined
  • The requestIds field is always included, allowing the backend to handle the appropriate case

Copy link
Member

@MantisClone MantisClone left a comment

Choose a reason for hiding this comment

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

Approved 👍 pending comment resolution 🚧

…ndling

- Updated `duplicatePayment` function to remove unnecessary payee reset.
- Enhanced `getUniquePayeesCount` to handle payee addresses in a case-insensitive manner.
- Modified `getTotalsByCurrency` to return human-readable totals instead of BigNumber, improving display clarity.
- Simplified signer retrieval in `BatchPayout`, `DirectPayment`, and `PaymentSection` components for consistency.
- Added validation to check for a selected network before proceeding with batch payments.
- Implemented error handling to notify users when no network is selected, improving user experience.
- Updated network switching logic to ensure proper state management during payment processing.
- Removed toast notifications for various error states during batch payment processing to simplify user feedback.
- Enhanced the error handling logic to focus on status changes without displaying redundant messages, improving code clarity and maintainability.
@aimensahnoun aimensahnoun merged commit e38532c into main Jun 5, 2025
5 checks passed
@aimensahnoun aimensahnoun deleted the 28-easyinvoice---one-time-batch-payments-from-the-invoice-dashboard-not-recurring branch June 5, 2025 05:34
@coderabbitai coderabbitai bot mentioned this pull request Aug 15, 2025
@coderabbitai coderabbitai bot mentioned this pull request Sep 14, 2025
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.

EasyInvoice - One-Time Batch Payments from the Invoice Dashboard (NOT Recurring)

3 participants