@blocklet/payment-react
Version:
Reusable react components for payment kit v2
205 lines (176 loc) • 10.7 kB
Markdown
# OverdueInvoicePayment
The `OverdueInvoicePayment` component is a specialized tool designed to handle the payment of overdue invoices for a specific customer or subscription. It simplifies the process by automatically fetching overdue invoices and presenting users with a clear interface to settle their outstanding payments.
This component can operate in two modes: a default mode that displays a pre-built dialog for quick integration, and a custom mode that provides the flexibility to build a unique user interface using a render prop. It must be wrapped within a `PaymentProvider` to function correctly.
## Props
The `OverdueInvoicePayment` component accepts the following props to customize its behavior:
<x-field-group>
<x-field data-name="subscriptionId" data-type="string" data-required="false">
<x-field-desc markdown>The ID of the subscription to check for overdue invoices. Either `subscriptionId` or `customerId` must be provided.</x-field-desc>
</x-field>
<x-field data-name="customerId" data-type="string" data-required="false">
<x-field-desc markdown>The ID or DID of the customer. Use this to handle all overdue invoices for a specific customer.</x-field-desc>
</x-field>
<x-field data-name="mode" data-type="'default' | 'custom'" data-default="default" data-required="false">
<x-field-desc markdown>The rendering mode. `'default'` shows a pre-built dialog. `'custom'` uses the `children` render prop for a custom UI.</x-field-desc>
</x-field>
<x-field data-name="onPaid" data-type="function" data-required="false">
<x-field-desc markdown>An optional callback function that is triggered after payment for a specific currency is successfully completed. It receives `(id, currencyId, type)`, where `id` is the `subscriptionId` or `customerId`, and `type` is `'subscription'` or `'customer'`.</x-field-desc>
<x-field data-name="parameters" data-type="object">
<x-field data-name="id" data-type="string" data-desc="The subscriptionId or customerId."></x-field>
<x-field data-name="currencyId" data-type="string" data-desc="The ID of the currency used for payment."></x-field>
<x-field data-name="type" data-type="'subscription' | 'customer'" data-desc="Indicates if the payment was for a subscription or a customer."></x-field>
</x-field>
</x-field>
<x-field data-name="dialogProps" data-type="object" data-required="false">
<x-field-desc markdown>Optional props to pass to the underlying Material-UI `Dialog` component in `default` mode. For example, `{ open: true, title: 'Custom Title', onClose: handleClose }`.</x-field-desc>
</x-field>
<x-field data-name="detailLinkOptions" data-type="object" data-required="false">
<x-field-desc markdown>Optional settings for the "View Details" link. Can be used to disable the link, change its text, or provide a custom `onClick` handler.</x-field-desc>
<x-field data-name="enabled" data-type="boolean" data-required="false" data-desc="Whether the link is enabled."></x-field>
<x-field data-name="onClick" data-type="(e: React.MouseEvent) => void" data-required="false" data-desc="Custom click handler."></x-field>
<x-field data-name="title" data-type="string" data-required="false" data-desc="Custom link text."></x-field>
</x-field>
<x-field data-name="successToast" data-type="boolean" data-default="true" data-required="false">
<x-field-desc markdown>If `true`, a success toast notification is shown upon successful payment.</x-field-desc>
</x-field>
<x-field data-name="alertMessage" data-type="string" data-required="false">
<x-field-desc markdown>An optional message to append to the default title text when in customer mode.</x-field-desc>
</x-field>
<x-field data-name="children" data-type="function" data-required="false">
<x-field-desc markdown>A render prop function used only when `mode` is `'custom'`. It receives a `handlePay` function and a `data` object.</x-field-desc>
<x-field data-name="parameters" data-type="object">
<x-field data-name="handlePay" data-type="(item: SummaryItem) => void" data-desc="Function to initiate the payment process for a specific currency group."></x-field>
<x-field data-name="data" data-type="object" data-desc="An object containing the fetched payment information."></x-field>
</x-field>
</x-field>
<x-field data-name="authToken" data-type="string" data-required="false">
<x-field-desc markdown>An optional authentication token for API requests, useful for server-to-server or cross-origin scenarios.</x-field-desc>
</x-field>
</x-field-group>
### `children` Render Prop Data
When using `mode="custom"`, the `data` object passed to the `children` function contains the following fields:
<x-field-group>
<x-field data-name="subscription" data-type="Subscription" data-required="false">
<x-field-desc markdown>The subscription details, if `subscriptionId` was provided.</x-field-desc>
</x-field>
<x-field data-name="summary" data-type="{ [key: string]: SummaryItem }" data-required="true">
<x-field-desc markdown>An object where each key is a currency ID. The value contains the total amount, currency details, and payment method for that currency.</x-field-desc>
</x-field>
<x-field data-name="invoices" data-type="Invoice[]" data-required="true">
<x-field-desc markdown>An array of all overdue invoice objects.</x-field-desc>
</x-field>
<x-field data-name="subscriptionCount" data-type="number" data-required="false">
<x-field-desc markdown>The number of subscriptions with overdue invoices (for customer mode).</x-field-desc>
</x-field>
<x-field data-name="detailUrl" data-type="string" data-required="true">
<x-field-desc markdown>The URL to view detailed invoice information.</x-field-desc>
</x-field>
</x-field-group>
## Usage Examples
All examples assume you have `PaymentProvider` set up in your application as detailed in the [PaymentProvider documentation](./providers-payment-provider.md).
### 1. Default Mode for a Subscription
This is the simplest way to handle overdue payments for a specific subscription. The component will automatically render a dialog if any overdue invoices are found.
```javascript SubscriptionOverdue.jsx icon=logos:react
import { OverdueInvoicePayment, PaymentProvider } from '@blocklet/payment-react';
import { useSessionContext } from '../hooks/session'; // Your custom session hook
function SubscriptionPage({ subscriptionId }) {
const { session, connect } = useSessionContext();
const handlePaymentSuccess = (id, currencyId, type) => {
console.log(`Payment successful for ${type} ${id} with currency ${currencyId}`);
// You can refetch subscription data here to update its status
};
return (
<PaymentProvider session={session} connect={connect}>
{/* This component will be null if there are no overdue invoices */}
<OverdueInvoicePayment subscriptionId={subscriptionId} onPaid={handlePaymentSuccess} />
{/* Other subscription details can be rendered here */}
</PaymentProvider>
);
}
```
### 2. Default Mode for a Customer
Use this to create a centralized place for a customer to pay all their overdue invoices across multiple subscriptions.
```javascript CustomerDashboard.jsx icon=logos:react
import { OverdueInvoicePayment, PaymentProvider } from '@blocklet/payment-react';
import { useSessionContext } from '../hooks/session'; // Your custom session hook
function CustomerDashboard() {
const { session, connect } = useSessionContext();
return (
<PaymentProvider session={session} connect={connect}>
<h2>Payment Center</h2>
<p>Please settle any outstanding payments to ensure uninterrupted service.</p>
<OverdueInvoicePayment
customerId={session.user.did}
onPaid={() => {
console.log('All customer overdue invoices paid for a currency!');
// Refresh customer account status
}}
/>
{/* The rest of the customer dashboard */}
</PaymentProvider>
);
}
```
### 3. Custom UI Mode
For full control over the user experience, use `mode="custom"`. This allows you to integrate the payment functionality directly into your existing UI instead of using a dialog.
```javascript CustomOverdueUI.jsx icon=logos:react
import { OverdueInvoicePayment, PaymentProvider } from '@blocklet/payment-react';
import { useSessionContext } from '../hooks/session'; // Your custom session hook
import { Card, CardContent, Typography, Button, Stack } from '@mui/material';
function CustomOverdueUI({ subscriptionId }) {
const { session, connect } = useSessionContext();
// A simple Amount component for formatting
const Amount = ({ amount, decimal, symbol }) => {
const formattedAmount = (parseInt(amount, 10) / 10 ** (decimal || 0)).toFixed(2);
return (
<strong>
{formattedAmount} {symbol}
</strong>
);
};
return (
<PaymentProvider session={session} connect={connect}>
<OverdueInvoicePayment
subscriptionId={subscriptionId}
mode="custom"
onPaid={() => console.log('Custom UI payment successful!')}>
{(handlePay, { summary, invoices }) => {
const summaryList = Object.values(summary);
if (invoices.length === 0) {
return <Typography>No overdue payments. All clear!</Typography>;
}
return (
<Card variant="outlined">
<CardContent>
<Typography variant="h6" color="error" gutterBottom>
You have {invoices.length} overdue invoice(s).
</Typography>
<Stack spacing={2} mt={2}>
{summaryList.map(item => (
<Stack key={item.currency.id} direction="row" justifyContent="space-between" alignItems="center">
<Typography>
Total Due:{' '}
<Amount
amount={item.amount}
decimal={item.currency.decimal}
symbol={item.currency.symbol}
/>
</Typography>
<Button variant="contained" color="primary" onClick={() => handlePay(item)}>
Pay with {item.currency.symbol}
</Button>
</Stack>
))}
</Stack>
</CardContent>
</Card>
);
}}
</OverdueInvoicePayment>
</PaymentProvider>
);
}
```
<!-- DIAGRAM_IMAGE_START:flowchart:4:3:1765377372 -->

<!-- DIAGRAM_IMAGE_END -->