Skip to content

Bug: outstanding issues on the payment widget #8

@bassgeta

Description

@bassgeta

Pasting CodeRabbit's review of the widget from another repo.


🐛 Code Quality Issues in Payment Widget Component

Component Source: Request Network Registry (https://ui.request.network)
Installation Method: ShadCN registry via npx shadcn add payment-widget
Discovered in: RequestNetwork/easy-invoice#168

Summary

During integration of the payment widget into our dashboard, automated code review identified 11 issues ranging from critical API bugs to minor documentation inconsistencies. Since this is an external component, we're reporting these upstream for fixes in the registry.


🔴 Critical Issues

1. Missing onComplete Callback Prop

File: src/components/payment-widget/payment-widget.tsx (Line 96)
Severity: Critical

The onComplete prop is defined in PaymentWidgetProps but never destructured or forwarded to the provider, breaking the public API.

Fix:

export function PaymentWidget({
  amountInUsd,
  recipientWallet,
  paymentConfig,
  receiptInfo,
  onPaymentSuccess,
  onPaymentError,
+ onComplete,
  uiConfig,
  walletAccount,
  children,
}: PaymentWidgetProps) {
  return (
    <Web3Provider walletConnectProjectId={paymentConfig.walletConnectProjectId}>
      <PaymentWidgetProvider
        amountInUsd={amountInUsd}
        recipientWallet={recipientWallet}
        walletAccount={walletAccount}
        paymentConfig={paymentConfig}
        uiConfig={uiConfig}
        receiptInfo={receiptInfo}
        onPaymentSuccess={onPaymentSuccess}
        onPaymentError={onPaymentError}
+       onComplete={onComplete}
      >
        <PaymentWidgetInner>{children}</PaymentWidgetInner>
      </PaymentWidgetProvider>
    </Web3Provider>
  );
}

2. Receipt Number Property Mismatch

File: src/components/payment-widget/components/payment-success.tsx (Line 60)
Severity: Critical

Form registers receiptInfo.invoiceNumber, but code reads receiptInfo.receiptNumber, causing user input to be ignored.

Fix:

-      receiptNumber: receiptInfo?.receiptNumber
-        ? receiptInfo.receiptNumber
+      receiptNumber: receiptInfo?.invoiceNumber
+        ? receiptInfo.invoiceNumber
         : generateReceiptNumber(),

Also update ReceiptInfo interface to include invoiceNumber or rename the form field to receiptNumber consistently.


3. Invalid ShadCN Installation Command

File: src/components/payment-widget/README.md (Line 31)
Severity: Critical

Documentation shows npx shadcn add payment-widget, which is not a standard shadcn command. Since this is a custom registry component, the installation instructions should be updated.

Suggested fix: Document the proper registry-based installation or direct import method.


🟠 Major Issues

4. Missing Fetch Timeout

File: src/components/payment-widget/utils/payment.ts (Line 150)
Severity: Major

The fetch call to create payouts has no timeout, which could cause the UI to hang indefinitely if the API is unresponsive.

Fix:

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000);

try {
  const response = await fetch(`${RN_API_URL}/v2/payouts`, {
    signal: controller.signal,
    method: "POST",
    headers: {
      "x-client-id": rnApiClientId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount: amountInUsd,
      payerWallet: payerWallet,
      payee: recipientWallet,
      invoiceCurrency: "USD",
      paymentCurrency: paymentCurrency,
      feePercentage: feeInfo?.feePercentage || undefined,
      feeAddress: feeInfo?.feeAddress || undefined,
      customerInfo: params.customerInfo,
      reference,
    }),
  });
  
  return response;
} catch (error) {
  if (error instanceof Error && error.name === 'AbortError') {
    throw new Error('Request timeout: API took too long to respond');
  }
  throw error;
} finally {
  clearTimeout(timeoutId);
}

5. Empty Transaction Receipts Array Not Handled

File: src/components/payment-widget/components/payment-modal.tsx (Line 67)
Severity: Major

Code assumes transactionReceipts is non-empty when accessing the last element, which will throw if the array is empty.

Fix:

  const handlePaymentSuccess = async (
    requestId: string,
    transactionReceipts: TransactionReceipt[],
  ) => {
    setRequestId(requestId);
-   setTxHash(
-     transactionReceipts[transactionReceipts.length - 1].transactionHash,
-   );
+   if (transactionReceipts.length > 0) {
+     setTxHash(
+       transactionReceipts[transactionReceipts.length - 1].transactionHash,
+     );
+   }
    setActiveStep("payment-success");
    await onPaymentSuccess?.(requestId, transactionReceipts);
  };

6. Incorrect Totals Visibility Logic

File: src/components/payment-widget/components/receipt/receipt-template.tsx (Line 156)
Severity: Major

Using .length > 0 on string totals means "0".length > 0 evaluates to true, showing zero values incorrectly.

Fix:

-          {receipt.totals.totalDiscount.length > 0 && (
+          {Number.parseFloat(receipt.totals.totalDiscount) > 0 && (
             <div className="total-line">
               <span>Discount:</span>
               <span className="total-amount">
                 -
                 {formatCryptoAmount(
                   receipt.totals.totalDiscount.toString(),
                   receipt.payment.currency,
                 )}
               </span>
             </div>
           )}

-          {receipt.totals.totalTax.length > 0 && (
+          {Number.parseFloat(receipt.totals.totalTax) > 0 && (
             <div className="total-line">
               <span>Tax:</span>
               <span className="total-amount">
                 {formatCryptoAmount(
                   receipt.totals.totalTax.toString(),
                   receipt.payment.currency,
                 )}
               </span>
             </div>
           )}

🟡 Minor Issues

7. Wallet Override Flag Logic

File: src/components/payment-widget/context/payment-widget-context/payment-widget-provider.tsx (Line 46)
Severity: Minor

isWalletOverride is true if walletAccount exists, even when account.address is undefined.

Fix:

- const isWalletOverride = walletAccount !== undefined;
- const connectedWalletAddress = walletAccount
-   ? walletAccount.account?.address
-   : address;
+ const overriddenAddress = walletAccount?.account?.address;
+ const isWalletOverride = Boolean(overriddenAddress);
+ const connectedWalletAddress = overriddenAddress ?? address;

8. Redundant Console Warning Before Throw

File: src/components/payment-widget/utils/payment.ts (Line 87)
Severity: Minor

console.warn immediately followed by throw makes the warning less useful.

Fix:

- console.warn("Unknown value format, defaulting to 0:", value);
- throw new Error("Unknown value format");
+ throw new Error(`Unknown value format: ${JSON.stringify(value)}`);

9. Documentation: Hyphenation

File: src/components/payment-widget/README.md (Line 17)
Severity: Minor

"logged in Viem account" should be "logged-in Viem account" (compound adjective).


10. Documentation: Type Inconsistency in Example

File: src/components/payment-widget/README.md (Line 76)
Severity: Minor

Receipt totals example shows numbers, but the type definition requires strings.

Fix:

        totals: {
-         total: 100,
-         totalUSD: 100.00,
-         totalDiscount: 0.00,
-         totalTax: 0.00,
+         total: "100.00",
+         totalUSD: "100.00",
+         totalDiscount: "0.00",
+         totalTax: "0.00",
        },

11. Documentation: Callback Parameter Mismatch

File: src/components/payment-widget/README.md (Line 221)
Severity: Minor

API reference documents onPaymentSuccess(requestId) with one parameter, but the basic usage example passes (requestId, transactionReceipts).

Fix: Either update the type signature to include the second parameter or correct the usage example.


Environment

  • Integration repository: RequestNetwork/easy-invoice
  • Component version: Latest from https://ui.request.network registry
  • Discovery method: Automated code review via CodeRabbit

Impact

These issues affect API completeness, runtime stability, and documentation accuracy. Fixing them would improve the developer experience and prevent potential runtime errors in production applications using this component.


Would you like me to create this as an actual GitHub issue in a specific repository?

Originally posted by @coderabbitai[bot] in RequestNetwork/easy-invoice#168 (comment)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

Status

🎫 Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions