@blocklet/payment-react 1.19.23 → 1.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.aigne/doc-smith/config.yaml +114 -0
- package/.aigne/doc-smith/output/structure-plan.json +361 -0
- package/.aigne/doc-smith/preferences.yml +55 -0
- package/.aigne/doc-smith/upload-cache.yaml +264 -0
- package/README.md +2 -3
- package/docs/_sidebar.md +33 -0
- package/docs/components-business-auto-topup.md +238 -0
- package/docs/components-business-overdue-invoice-payment.md +231 -0
- package/docs/components-business-resume-subscription.md +177 -0
- package/docs/components-business.md +45 -0
- package/docs/components-checkout-checkout-donate.md +199 -0
- package/docs/components-checkout-checkout-form.md +185 -0
- package/docs/components-checkout-checkout-table.md +228 -0
- package/docs/components-checkout.md +131 -0
- package/docs/components-history-credit-grants-list.md +98 -0
- package/docs/components-history-credit-transactions-list.md +116 -0
- package/docs/components-history-invoice-list.md +104 -0
- package/docs/components-history-payment-list.md +65 -0
- package/docs/components-history.md +92 -0
- package/docs/components-ui-form-elements-address-form.md +150 -0
- package/docs/components-ui-form-elements-country-select.md +105 -0
- package/docs/components-ui-form-elements-currency-selector.md +124 -0
- package/docs/components-ui-form-elements-phone-input.md +160 -0
- package/docs/components-ui-form-elements.md +125 -0
- package/docs/components-ui-payment-summary.md +157 -0
- package/docs/components-ui-pricing-table.md +227 -0
- package/docs/components-ui.md +44 -0
- package/docs/components.md +95 -0
- package/docs/getting-started.md +111 -0
- package/docs/guides-theming.md +175 -0
- package/docs/guides-utilities.md +235 -0
- package/docs/guides.md +95 -0
- package/docs/hooks-use-mobile.md +70 -0
- package/docs/hooks-use-subscription.md +129 -0
- package/docs/hooks.md +84 -0
- package/docs/overview.md +87 -0
- package/docs/providers-donate-provider.md +175 -0
- package/docs/providers-payment-provider.md +245 -0
- package/docs/providers.md +101 -0
- package/es/libs/util.d.ts +1 -1
- package/es/payment/form/index.js +15 -1
- package/es/payment/summary.js +1 -1
- package/lib/libs/util.d.ts +1 -1
- package/lib/payment/form/index.js +14 -1
- package/lib/payment/summary.js +1 -1
- package/package.json +9 -9
- package/src/libs/util.ts +1 -0
- package/src/payment/form/index.tsx +16 -1
- package/src/payment/summary.tsx +1 -2
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# OverdueInvoicePayment
|
|
2
|
+
|
|
3
|
+
The `OverdueInvoicePayment` component is designed to handle the payment of overdue invoices for a specific customer or subscription. It can operate in two modes: a default dialog mode that presents a pre-built UI for payment, or a custom mode that provides data and a payment handler to build a custom user interface.
|
|
4
|
+
|
|
5
|
+
This component streamlines the process of collecting late payments by summarizing amounts by currency and initiating a batch payment process through the user's DID Wallet.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
Use this component in your application's subscription management or customer billing sections to:
|
|
10
|
+
|
|
11
|
+
- Prompt users to pay for a subscription that has fallen into a `past_due` status.
|
|
12
|
+
- Allow customers to clear all outstanding invoices across multiple subscriptions in a single operation.
|
|
13
|
+
|
|
14
|
+
## Component Logic Flow
|
|
15
|
+
|
|
16
|
+
The component follows a clear sequence to manage overdue payments:
|
|
17
|
+
|
|
18
|
+
```d2
|
|
19
|
+
shape: sequence_diagram
|
|
20
|
+
|
|
21
|
+
User: "User"
|
|
22
|
+
App: "Your Application"
|
|
23
|
+
OIP: "OverdueInvoicePayment"
|
|
24
|
+
PaymentProvider: "PaymentProvider"
|
|
25
|
+
API: "Payment Service API"
|
|
26
|
+
|
|
27
|
+
User -> App: "Views page with overdue invoices"
|
|
28
|
+
App -> OIP: "Renders with subscriptionId or customerId"
|
|
29
|
+
OIP -> API: "GET /overdue/invoices"
|
|
30
|
+
API -> OIP: "Returns summary & invoices list"
|
|
31
|
+
|
|
32
|
+
alt "Invoices exist"
|
|
33
|
+
OIP -> App: "Renders payment UI (dialog/custom)"
|
|
34
|
+
User -> OIP: "Clicks 'Pay Now'"
|
|
35
|
+
OIP -> PaymentProvider: "Calls connect.open()"
|
|
36
|
+
PaymentProvider -> User: "Shows DID Wallet connect modal"
|
|
37
|
+
User -> PaymentProvider: "Scans & confirms payment"
|
|
38
|
+
PaymentProvider -> API: "Processes batch payment"
|
|
39
|
+
API -> PaymentProvider: "Payment successful"
|
|
40
|
+
PaymentProvider -> OIP: "Triggers onSuccess"
|
|
41
|
+
OIP -> OIP: "Refreshes invoice data"
|
|
42
|
+
OIP -> App: "Calls onPaid() & closes UI"
|
|
43
|
+
else "No overdue invoices"
|
|
44
|
+
OIP -> App: "Displays success/empty message"
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Props
|
|
49
|
+
|
|
50
|
+
| Prop | Type | Description |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| `subscriptionId` | `string` | Optional. The ID of the subscription to check for overdue invoices. Either `subscriptionId` or `customerId` must be provided. |
|
|
53
|
+
| `customerId` | `string` | Optional. The customer's ID (or DID) to check for all overdue invoices across their subscriptions. |
|
|
54
|
+
| `mode` | `'default' \| 'custom'` | Optional. The rendering mode. `'default'` displays a pre-built dialog. `'custom'` uses a render prop for a custom UI. Defaults to `'default'`. |
|
|
55
|
+
| `onPaid` | `(id, currencyId, type) => void` | Optional. A callback function executed after all overdue invoices are paid. It receives the source ID (`subscriptionId` or `customerId`), the currency ID, and the source type (`'subscription'` or `'customer'`). |
|
|
56
|
+
| `dialogProps` | `object` | Optional. Props to pass to the underlying Material-UI `Dialog` component in `default` mode. Can be used to control its `open` state, `title`, and `onClose` behavior. |
|
|
57
|
+
| `detailLinkOptions` | `object` | Optional. An object to configure the "view details" link in the default dialog. Shape: `{ enabled?: boolean, onClick?: (e) => void, title?: string }`. |
|
|
58
|
+
| `successToast` | `boolean` | Optional. If `true`, a success toast notification is shown upon successful payment. Defaults to `true`. |
|
|
59
|
+
| `alertMessage` | `string` | Optional. A custom message to append to the default alert text when checking by `customerId`. |
|
|
60
|
+
| `children` | `function` | Optional. A render prop function used only when `mode="custom"`. It receives `handlePay` and `data` as arguments. |
|
|
61
|
+
| `authToken` | `string` | Optional. An authentication token for API requests, useful for cross-origin scenarios where session cookies are not available. |
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
> All examples assume you have set up `PaymentProvider` and a `useSessionContext` hook to provide session data. The `useSessionContext` hook is a local utility to access your application's session context. For a complete guide on this setup, please refer to the [PaymentProvider documentation](./providers-payment-provider.md).
|
|
66
|
+
|
|
67
|
+
### Default Mode Usage
|
|
68
|
+
|
|
69
|
+
In its default mode, the component renders a dialog that summarizes the overdue payments and prompts the user to pay. This is the quickest way to implement overdue payment handling.
|
|
70
|
+
|
|
71
|
+
#### Handling a Single Subscription's Overdue Invoices
|
|
72
|
+
|
|
73
|
+
Provide the `subscriptionId` to target a specific subscription. A dialog will appear if there are any overdue invoices.
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import { PaymentProvider, OverdueInvoicePayment } from '@blocklet/payment-react';
|
|
77
|
+
// This is a local utility to get session info from your app's context.
|
|
78
|
+
// See the PaymentProvider docs for setup details.
|
|
79
|
+
import { useSessionContext } from 'src/hooks/session';
|
|
80
|
+
|
|
81
|
+
function SubscriptionDetailsPage({ subscriptionId }) {
|
|
82
|
+
const { session, connect: connectApi } = useSessionContext();
|
|
83
|
+
|
|
84
|
+
const handlePaymentSuccess = () => {
|
|
85
|
+
console.log('All overdue invoices for the subscription have been paid.');
|
|
86
|
+
// You can refresh the subscription status here
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
if (!session || !connectApi) {
|
|
90
|
+
return <div>Loading session...</div>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
95
|
+
<OverdueInvoicePayment
|
|
96
|
+
subscriptionId={subscriptionId}
|
|
97
|
+
onPaid={handlePaymentSuccess}
|
|
98
|
+
/>
|
|
99
|
+
</PaymentProvider>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### Handling All of a Customer's Overdue Invoices
|
|
105
|
+
|
|
106
|
+
Provide the `customerId` (which can be the user's DID) to consolidate all overdue invoices from all of their subscriptions into a single payment flow.
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { PaymentProvider, OverdueInvoicePayment } from '@blocklet/payment-react';
|
|
110
|
+
// This is a local utility to get session info from your app's context.
|
|
111
|
+
// See the PaymentProvider docs for setup details.
|
|
112
|
+
import { useSessionContext } from 'src/hooks/session';
|
|
113
|
+
|
|
114
|
+
function CustomerDashboard() {
|
|
115
|
+
const { session, connect: connectApi } = useSessionContext();
|
|
116
|
+
|
|
117
|
+
if (!session?.user?.did || !connectApi) {
|
|
118
|
+
return <div>Loading session...</div>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
123
|
+
<OverdueInvoicePayment
|
|
124
|
+
customerId={session.user.did}
|
|
125
|
+
onPaid={() => {
|
|
126
|
+
console.log("All of the customer's overdue invoices are paid.");
|
|
127
|
+
// Refresh customer data or redirect
|
|
128
|
+
}}
|
|
129
|
+
dialogProps={{
|
|
130
|
+
title: 'Outstanding Payments',
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
</PaymentProvider>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Custom Mode Usage
|
|
139
|
+
|
|
140
|
+
For full control over the user interface, set `mode="custom"`. This allows you to build a completely custom component for handling overdue payments using the `children` render prop.
|
|
141
|
+
|
|
142
|
+
The render prop receives two arguments:
|
|
143
|
+
1. `handlePay`: A function to trigger the payment process. It takes a `SummaryItem` object as an argument.
|
|
144
|
+
2. `data`: An object containing all the necessary information about the overdue invoices.
|
|
145
|
+
|
|
146
|
+
#### Building a Custom UI
|
|
147
|
+
|
|
148
|
+
Here is an example of creating a custom card to display overdue payment information and trigger payments.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import {
|
|
152
|
+
PaymentProvider,
|
|
153
|
+
OverdueInvoicePayment,
|
|
154
|
+
Amount,
|
|
155
|
+
} from '@blocklet/payment-react';
|
|
156
|
+
import { Card, CardContent, Typography, Button, Stack } from '@mui/material';
|
|
157
|
+
// This is a local utility to get session info from your app's context.
|
|
158
|
+
// See the PaymentProvider docs for setup details.
|
|
159
|
+
import { useSessionContext } from 'src/hooks/session';
|
|
160
|
+
|
|
161
|
+
function CustomOverdueUI({ subscriptionId }) {
|
|
162
|
+
const { session, connect: connectApi } = useSessionContext();
|
|
163
|
+
|
|
164
|
+
if (!session || !connectApi) {
|
|
165
|
+
return <div>Loading session...</div>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
170
|
+
<OverdueInvoicePayment
|
|
171
|
+
subscriptionId={subscriptionId}
|
|
172
|
+
mode="custom"
|
|
173
|
+
onPaid={() => console.log('Paid!')}>
|
|
174
|
+
{(handlePay, { summary, invoices, subscription }) => {
|
|
175
|
+
if (!invoices || invoices.length === 0) {
|
|
176
|
+
return <Typography>No overdue payments. All good!</Typography>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<Card variant="outlined">
|
|
181
|
+
<CardContent>
|
|
182
|
+
<Typography variant="h6" gutterBottom>
|
|
183
|
+
Action Required for {subscription?.description}
|
|
184
|
+
</Typography>
|
|
185
|
+
<Typography color="error" gutterBottom>
|
|
186
|
+
You have {invoices.length} overdue invoice(s).
|
|
187
|
+
</Typography>
|
|
188
|
+
<Stack spacing={2} sx={{ mt: 2 }}>
|
|
189
|
+
{Object.values(summary).map((info) => (
|
|
190
|
+
<Stack
|
|
191
|
+
key={info.currency.id}
|
|
192
|
+
direction="row"
|
|
193
|
+
justifyContent="space-between"
|
|
194
|
+
alignItems="center">
|
|
195
|
+
<Typography>
|
|
196
|
+
Total Due: <Amount amount={info.amount} decimal={info.currency.decimal} symbol={info.currency.symbol} />
|
|
197
|
+
</Typography>
|
|
198
|
+
<Button
|
|
199
|
+
onClick={() => handlePay(info)}
|
|
200
|
+
variant="contained"
|
|
201
|
+
color="primary">
|
|
202
|
+
Pay Now
|
|
203
|
+
</Button>
|
|
204
|
+
</Stack>
|
|
205
|
+
))}
|
|
206
|
+
</Stack>
|
|
207
|
+
</CardContent>
|
|
208
|
+
</Card>
|
|
209
|
+
);
|
|
210
|
+
}}
|
|
211
|
+
</OverdueInvoicePayment>
|
|
212
|
+
</PaymentProvider>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Custom Mode `data` Object
|
|
218
|
+
|
|
219
|
+
The `data` object passed to the `children` render prop contains the following fields:
|
|
220
|
+
|
|
221
|
+
| Field | Type | Description |
|
|
222
|
+
| --- | --- | --- |
|
|
223
|
+
| `subscription` | `Subscription` | The full subscription object, if `subscriptionId` was provided. |
|
|
224
|
+
| `summary` | `{ [key: string]: SummaryItem }` | An object summarizing the total amount due, grouped by currency ID. Each `SummaryItem` contains `amount`, `currency`, and `method`. |
|
|
225
|
+
| `invoices` | `Invoice[]` | An array of the raw overdue invoice objects. |
|
|
226
|
+
| `subscriptionCount` | `number` | The number of subscriptions with overdue payments, if `customerId` was provided. |
|
|
227
|
+
| `detailUrl` | `string` | A pre-generated URL to the detailed invoice or subscription page. |
|
|
228
|
+
|
|
229
|
+
### Note on Payment Methods
|
|
230
|
+
|
|
231
|
+
The batch payment flow initiated by this component currently supports wallet-based payments (like ArcBlock, Ethereum). It does not support batch payments via Stripe. If an overdue invoice's payment method is Stripe, the component will guide the user to a page where they can pay manually.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# ResumeSubscription
|
|
2
|
+
|
|
3
|
+
The `ResumeSubscription` component provides a user interface for resuming a canceled subscription. It handles the necessary logic, including prompting the user to re-stake funds if required, and appears as a modal dialog by default.
|
|
4
|
+
|
|
5
|
+
This component must be used within a [`PaymentProvider`](./providers-payment-provider.md) to access the required payment context.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
The component streamlines the subscription recovery process. When rendered, it first checks if the subscription requires a new stake to be resumed. Based on this information, it presents one of two flows:
|
|
10
|
+
|
|
11
|
+
1. **Direct Resume**: If no new stake is needed, the user can confirm to directly reactivate the subscription.
|
|
12
|
+
2. **Resume with Re-Stake**: If a stake is required, the component will initiate a wallet connection flow, asking the user to approve the staking transaction to resume their subscription.
|
|
13
|
+
|
|
14
|
+
```d2
|
|
15
|
+
shape: sequence_diagram
|
|
16
|
+
|
|
17
|
+
User
|
|
18
|
+
"React App"
|
|
19
|
+
"ResumeSubscription"
|
|
20
|
+
"Payment API"
|
|
21
|
+
"DID Wallet"
|
|
22
|
+
|
|
23
|
+
User -> "React App": "Clicks 'Resume Subscription'"
|
|
24
|
+
"React App" -> "ResumeSubscription": "Renders with subscriptionId"
|
|
25
|
+
|
|
26
|
+
"ResumeSubscription" -> "Payment API": "GET /recover-info"
|
|
27
|
+
"Payment API" --> "ResumeSubscription": "{ needStake }"
|
|
28
|
+
|
|
29
|
+
alt "Direct Resume (needStake is false)" {
|
|
30
|
+
"ResumeSubscription" -> "Payment API": "PUT /recover"
|
|
31
|
+
"Payment API" --> "ResumeSubscription": "{ subscription }"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
alt "Re-Stake Required (needStake is true)" {
|
|
35
|
+
"ResumeSubscription" -> "DID Wallet": "Opens connect for 're-stake'"
|
|
36
|
+
User -> "DID Wallet": "Approves transaction"
|
|
37
|
+
"DID Wallet" --> "ResumeSubscription": "onSuccess()"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
"ResumeSubscription" -> "Payment API": "GET /subscriptions/:id (on success)"
|
|
41
|
+
"Payment API" --> "ResumeSubscription": "Updated subscription data"
|
|
42
|
+
"ResumeSubscription" -> "React App": "onResumed(subscription)"
|
|
43
|
+
"React App" -> User: "UI is updated"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Props
|
|
47
|
+
|
|
48
|
+
| Prop | Type | Description |
|
|
49
|
+
| :--------------- | :------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `subscriptionId` | `string` | **Required.** The ID of the subscription to be resumed. |
|
|
51
|
+
| `onResumed` | `(sub: Subscription \| TSubscriptionExpanded) => void` | Optional. A callback function that is executed after the subscription has been successfully resumed. It receives the updated subscription object as an argument. |
|
|
52
|
+
| `dialogProps` | `object` | Optional. Props to customize the underlying Material-UI Dialog component. Default: `{ open: true }`. Key properties include:<br />- `open`: `boolean`, controls visibility.<br />- `onClose`: `() => void`, a callback for when the dialog is closed.<br />- `title`: `string`, overrides the default dialog title. |
|
|
53
|
+
| `successToast` | `boolean` | Optional. If `true`, a success toast notification is shown upon successful resumption. Defaults to `true`. |
|
|
54
|
+
| `authToken` | `string` | Optional. An authentication token to be included in API requests. This is useful for cross-origin requests or when the application manages authentication separately. |
|
|
55
|
+
|
|
56
|
+
## Usage Examples
|
|
57
|
+
|
|
58
|
+
<div class="lead">All examples require the component to be wrapped in a `PaymentProvider`. The `session` and `connect` props are obtained using a custom `useSessionContext` hook, which represents your application's authentication state. For detailed setup instructions, please refer to the <a href="/providers/payment-provider">PaymentProvider documentation</a>.</div>
|
|
59
|
+
|
|
60
|
+
### Basic Usage
|
|
61
|
+
|
|
62
|
+
This example shows the simplest way to use `ResumeSubscription`. The dialog will be open by default, and a success toast will appear upon completion.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import React from 'react';
|
|
66
|
+
import { PaymentProvider, ResumeSubscription } from '@blocklet/payment-react';
|
|
67
|
+
|
|
68
|
+
// Placeholder for your application's session context hook.
|
|
69
|
+
// See the PaymentProvider documentation for setup details.
|
|
70
|
+
import { useSessionContext } from '../hooks/use-session-context';
|
|
71
|
+
|
|
72
|
+
function SubscriptionManagementPage({ subscriptionId, refetchSubscription }) {
|
|
73
|
+
// session and connect are derived from your application's auth service.
|
|
74
|
+
const { session, connect } = useSessionContext();
|
|
75
|
+
|
|
76
|
+
if (!session) {
|
|
77
|
+
return <div>Loading session...</div>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<PaymentProvider session={session} connect={connect}>
|
|
82
|
+
<ResumeSubscription
|
|
83
|
+
subscriptionId={subscriptionId}
|
|
84
|
+
onResumed={(subscription) => {
|
|
85
|
+
console.log('Subscription resumed:', subscription);
|
|
86
|
+
// Update your application's state here.
|
|
87
|
+
refetchSubscription();
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
90
|
+
</PaymentProvider>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Controlling the Dialog
|
|
96
|
+
|
|
97
|
+
You can manage the dialog's visibility from a parent component by passing its state down through `dialogProps`.
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import React, { useState } from 'react';
|
|
101
|
+
import { Button } from '@mui/material';
|
|
102
|
+
import { PaymentProvider, ResumeSubscription } from '@blocklet/payment-react';
|
|
103
|
+
|
|
104
|
+
// Placeholder for your application's session context hook.
|
|
105
|
+
// See the PaymentProvider documentation for setup details.
|
|
106
|
+
import { useSessionContext } from '../hooks/use-session-context';
|
|
107
|
+
|
|
108
|
+
function SubscriptionDetails({ subscriptionId, refetchSubscription }) {
|
|
109
|
+
const [isResumeDialogOpen, setResumeDialogOpen] = useState(false);
|
|
110
|
+
const { session, connect } = useSessionContext();
|
|
111
|
+
|
|
112
|
+
const handleCloseDialog = () => {
|
|
113
|
+
setResumeDialogOpen(false);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (!session) {
|
|
117
|
+
return <div>Loading session...</div>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<PaymentProvider session={session} connect={connect}>
|
|
122
|
+
<Button onClick={() => setResumeDialogOpen(true)}>
|
|
123
|
+
Resume Subscription
|
|
124
|
+
</Button>
|
|
125
|
+
|
|
126
|
+
{isResumeDialogOpen && (
|
|
127
|
+
<ResumeSubscription
|
|
128
|
+
subscriptionId={subscriptionId}
|
|
129
|
+
onResumed={() => {
|
|
130
|
+
console.log('Subscription has been resumed.');
|
|
131
|
+
handleCloseDialog();
|
|
132
|
+
refetchSubscription(); // Refresh subscription data in parent component.
|
|
133
|
+
}}
|
|
134
|
+
dialogProps={{
|
|
135
|
+
open: isResumeDialogOpen,
|
|
136
|
+
onClose: handleCloseDialog,
|
|
137
|
+
title: 'Confirm Subscription Renewal',
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
)}
|
|
141
|
+
</PaymentProvider>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Usage with an Authentication Token
|
|
147
|
+
|
|
148
|
+
If your API requests require an authentication token, provide it using the `authToken` prop. This is useful for secure communication between different services or Blocklets.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import React from 'react';
|
|
152
|
+
import { PaymentProvider, ResumeSubscription } from '@blocklet/payment-react';
|
|
153
|
+
|
|
154
|
+
// Placeholder for your application's session context hook.
|
|
155
|
+
// See the PaymentProvider documentation for setup details.
|
|
156
|
+
import { useSessionContext } from '../hooks/use-session-context';
|
|
157
|
+
|
|
158
|
+
function SecureSubscriptionResume({ subscriptionId, token }) {
|
|
159
|
+
const { session, connect } = useSessionContext();
|
|
160
|
+
|
|
161
|
+
if (!session) {
|
|
162
|
+
return <div>Loading session...</div>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<PaymentProvider session={session} connect={connect}>
|
|
167
|
+
<ResumeSubscription
|
|
168
|
+
subscriptionId={subscriptionId}
|
|
169
|
+
authToken={token}
|
|
170
|
+
onResumed={(subscription) => {
|
|
171
|
+
console.log('Subscription resumed securely:', subscription.id);
|
|
172
|
+
}}
|
|
173
|
+
/>
|
|
174
|
+
</PaymentProvider>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Business Logic Components
|
|
2
|
+
|
|
3
|
+
Business logic components are specialized React components designed to handle complex, high-level user flows related to subscription and invoice management. These components encapsulate API calls, state management, and user interactions for common scenarios, allowing you to integrate sophisticated features with minimal effort.
|
|
4
|
+
|
|
5
|
+
These components are ready to be integrated into your application to address specific business needs, such as recovering revenue from failed payments or improving user retention.
|
|
6
|
+
|
|
7
|
+
```d2
|
|
8
|
+
direction: down
|
|
9
|
+
|
|
10
|
+
"User Application": {
|
|
11
|
+
shape: cloud
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
"Business Logic Components": {
|
|
15
|
+
shape: package
|
|
16
|
+
"OverdueInvoicePayment"
|
|
17
|
+
"ResumeSubscription"
|
|
18
|
+
"Auto-Topup Components"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
"Payment Service API": {
|
|
22
|
+
shape: database
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
"User Application" -> "Business Logic Components": "Integrates"
|
|
26
|
+
"Business Logic Components.OverdueInvoicePayment" -> "Payment Service API": "Pays for overdue invoices"
|
|
27
|
+
"Business Logic Components.ResumeSubscription" -> "Payment Service API": "Reactivates subscription"
|
|
28
|
+
"Business Logic Components.Auto-Topup Components" -> "Payment Service API": "Configures auto-recharge"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This section provides an overview of the available business logic components. For detailed API references and usage examples, select a component below.
|
|
32
|
+
|
|
33
|
+
<x-cards data-columns="3">
|
|
34
|
+
<x-card data-title="OverdueInvoicePayment" data-icon="lucide:alert-circle" data-href="/components/business/overdue-invoice-payment">
|
|
35
|
+
A component that provides a complete UI flow for handling overdue invoices for a subscription or an entire customer account.
|
|
36
|
+
</x-card>
|
|
37
|
+
<x-card data-title="ResumeSubscription" data-icon="lucide:refresh-cw" data-href="/components/business/resume-subscription">
|
|
38
|
+
A component that facilitates resuming a previously canceled subscription, including handling complex scenarios like re-staking.
|
|
39
|
+
</x-card>
|
|
40
|
+
<x-card data-title="Auto-Topup Components" data-icon="lucide:battery-charging" data-href="/components/business/auto-topup">
|
|
41
|
+
A set of components for managing automatic credit top-ups when a user's balance falls below a configured threshold.
|
|
42
|
+
</x-card>
|
|
43
|
+
</x-cards>
|
|
44
|
+
|
|
45
|
+
After handling these business-specific tasks, you may want to display the results to the user. Proceed to the [History Components](./components-history.md) section to learn how to display lists of invoices, payments, and credit transactions.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# CheckoutDonate
|
|
2
|
+
|
|
3
|
+
The `CheckoutDonate` component provides a flexible way to implement donation functionality in your application. It supports several display modes, from a simple pre-built button to a fully custom UI, and handles the entire donation flow, including displaying supporter history.
|
|
4
|
+
|
|
5
|
+
To function correctly, `CheckoutDonate` must be wrapped within both a [`PaymentProvider`](./providers-payment-provider.md) and a [`DonateProvider`](./providers-donate-provider.md).
|
|
6
|
+
|
|
7
|
+
## Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Description |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `settings` | `CheckoutDonateSettings` | **Required.** An object containing the configuration for the donation instance, such as target, title, and beneficiaries. |
|
|
12
|
+
| `onPaid` | `(session: TCheckoutSessionExpanded) => void` | Optional. A callback function that is executed after a donation is successfully paid. |
|
|
13
|
+
| `onError` | `(error: any) => void` | Optional. A callback function that is executed if an error occurs during the payment process. |
|
|
14
|
+
| `livemode` | `boolean` | Optional. Toggles between live and test payment modes. If not set, it inherits the value from `PaymentProvider`. |
|
|
15
|
+
| `timeout` | `number` | Optional. The time in milliseconds to wait before closing the checkout dialog after a successful payment. Defaults to `5000`. |
|
|
16
|
+
| `mode` | `'default' \| 'inline' \| 'custom'` | Optional. Determines the rendering mode of the component. Defaults to `'default'`. |
|
|
17
|
+
| `inlineOptions` | `{ button?: ButtonType }` | Optional. Customization options for the button when `mode` is set to `'inline'`. |
|
|
18
|
+
| `theme` | `'default' \| 'inherit' \| PaymentThemeOptions` | Optional. Controls the component's theme. See the [Theming guide](./guides-theming.md) for more details. Defaults to `'default'`. |
|
|
19
|
+
| `children` | `(openDialog, donateTotalAmount, supporters, loading, donateSettings) => React.ReactNode` | Optional. A render prop function used when `mode` is `'custom'`. See the Custom Mode section for details. |
|
|
20
|
+
|
|
21
|
+
### `CheckoutDonateSettings`
|
|
22
|
+
|
|
23
|
+
This object configures the donation's behavior and appearance.
|
|
24
|
+
|
|
25
|
+
| Property | Type | Description |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `target` | `string` | **Required.** A unique identifier for the donation instance (e.g., a post ID like `"post-123"`). |
|
|
28
|
+
| `title` | `string` | **Required.** The title displayed in the donation modal. |
|
|
29
|
+
| `description` | `string` | **Required.** A description shown in the donation modal. |
|
|
30
|
+
| `reference` | `string` | **Required.** A reference link for the donation, such as the URL of the page where the donation is being made. |
|
|
31
|
+
| `beneficiaries` | `PaymentBeneficiary[]` | **Required.** An array of objects defining who receives the donation and their respective shares. |
|
|
32
|
+
| `amount` | `object` | Optional. Configures donation amounts, including presets, min/max values, and whether custom amounts are allowed. Inherits from `DonateProvider` if not set. |
|
|
33
|
+
| `appearance` | `object` | Optional. Customizes the look and feel of the donation button and supporter history display (`'avatar'` or `'table'`). Inherits from `DonateProvider` if not set. |
|
|
34
|
+
|
|
35
|
+
## Basic Usage
|
|
36
|
+
|
|
37
|
+
Here is a basic example of how to set up `CheckoutDonate`. This will render a default donation button and a list of supporters.
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import {
|
|
41
|
+
PaymentProvider,
|
|
42
|
+
DonateProvider,
|
|
43
|
+
CheckoutDonate
|
|
44
|
+
} from '@blocklet/payment-react';
|
|
45
|
+
|
|
46
|
+
// This is a placeholder for your application's session management.
|
|
47
|
+
// See the documentation for PaymentProvider for details on how to set up this context.
|
|
48
|
+
import { useSessionContext } from '../contexts/session'; // Adjust path as needed
|
|
49
|
+
|
|
50
|
+
function DonationSection() {
|
|
51
|
+
const { session, connectApi } = useSessionContext();
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
55
|
+
<DonateProvider
|
|
56
|
+
mountLocation="unique-page-identifier"
|
|
57
|
+
description="Donations for this page"
|
|
58
|
+
>
|
|
59
|
+
<CheckoutDonate
|
|
60
|
+
settings={{
|
|
61
|
+
target: "post-123", // Unique ID for this donation target
|
|
62
|
+
title: "Support the Author",
|
|
63
|
+
description: "If you find this article helpful, feel free to buy me a coffee.",
|
|
64
|
+
reference: "https://your-site.com/posts/123",
|
|
65
|
+
beneficiaries: [
|
|
66
|
+
{
|
|
67
|
+
address: "did:abt:z123...", // Beneficiary's DID address
|
|
68
|
+
share: "100",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
}}
|
|
72
|
+
onPaid={(session) => console.log('Donation successful:', session.id)}
|
|
73
|
+
/>
|
|
74
|
+
</DonateProvider>
|
|
75
|
+
</PaymentProvider>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage Modes
|
|
81
|
+
|
|
82
|
+
The `CheckoutDonate` component can be rendered in three different modes, controlled by the `mode` prop.
|
|
83
|
+
|
|
84
|
+
### Default Mode
|
|
85
|
+
|
|
86
|
+
When `mode` is `'default'` (or omitted), the component renders a donation button. Below the button, it displays a history of supporters, which can be configured to show as avatars or a table via `settings.appearance.history.variant`.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
<CheckoutDonate
|
|
90
|
+
settings={{
|
|
91
|
+
target: "post-456",
|
|
92
|
+
title: "Support Our Project",
|
|
93
|
+
description: "Every little bit helps!",
|
|
94
|
+
reference: "https://your-site.com/projects/our-project",
|
|
95
|
+
beneficiaries: [{ address: "did:abt:z456...", share: "100" }],
|
|
96
|
+
appearance: {
|
|
97
|
+
button: {
|
|
98
|
+
text: 'Buy me a coffee ☕',
|
|
99
|
+
variant: 'contained',
|
|
100
|
+
},
|
|
101
|
+
history: {
|
|
102
|
+
variant: 'table', // or 'avatar'
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Inline Mode
|
|
110
|
+
|
|
111
|
+
Setting `mode="inline"` renders a button that opens a popover when hovered over. The popover contains the donation button and a summary of supporters. This is useful for more compact UIs.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
<CheckoutDonate
|
|
115
|
+
mode="inline"
|
|
116
|
+
settings={{
|
|
117
|
+
target: "post-789",
|
|
118
|
+
title: "Tip Jar",
|
|
119
|
+
description: "Thanks for your support!",
|
|
120
|
+
reference: "https://your-site.com/posts/789",
|
|
121
|
+
beneficiaries: [{ address: "did:abt:z789...", share: "100" }],
|
|
122
|
+
}}
|
|
123
|
+
inlineOptions={{
|
|
124
|
+
button: {
|
|
125
|
+
text: 'Tip',
|
|
126
|
+
variant: 'outlined',
|
|
127
|
+
}
|
|
128
|
+
}}
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Custom Mode
|
|
133
|
+
|
|
134
|
+
For complete control over the UI, use `mode="custom"`. This mode uses a render prop passed as the `children` of the component. The function provides you with the state and actions needed to build your own interface.
|
|
135
|
+
|
|
136
|
+
The `children` function receives the following arguments:
|
|
137
|
+
|
|
138
|
+
| Argument | Type | Description |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| `openDialog` | `() => void` | A function to call to open the donation payment modal. |
|
|
141
|
+
| `donateTotalAmount` | `string` | A formatted string representing the total amount donated (e.g., `"125.50 USDT"`). |
|
|
142
|
+
| `supporters` | `DonateHistory` | An object containing supporter data, including the list of supporters, currency, and payment method details. |
|
|
143
|
+
| `loading` | `boolean` | A boolean indicating if the supporter data is currently being fetched. |
|
|
144
|
+
| `donateSettings` | `DonationSettings` | The processed donation settings object, including defaults inherited from `DonateProvider`. |
|
|
145
|
+
|
|
146
|
+
Here is an example of a custom donation UI:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { CheckoutDonate, formatAmount } from '@blocklet/payment-react';
|
|
150
|
+
import { Button, CircularProgress, Typography, List, ListItem, ListItemText } from '@mui/material';
|
|
151
|
+
|
|
152
|
+
// Assuming PaymentProvider and DonateProvider are set up in a parent component.
|
|
153
|
+
|
|
154
|
+
function CustomDonationDisplay() {
|
|
155
|
+
return (
|
|
156
|
+
<CheckoutDonate
|
|
157
|
+
mode="custom"
|
|
158
|
+
settings={{
|
|
159
|
+
target: "post-123",
|
|
160
|
+
title: "Support the Author",
|
|
161
|
+
description: "Your support is appreciated!",
|
|
162
|
+
reference: "https://your-site.com/posts/123",
|
|
163
|
+
beneficiaries: [{ address: "did:abt:z123...", share: "100" }],
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{(openDonate, totalAmount, supporters, loading) => (
|
|
167
|
+
<div>
|
|
168
|
+
<Typography variant="h5">Our Supporters</Typography>
|
|
169
|
+
<Button variant="contained" onClick={openDonate} sx={{ my: 2 }}>Support Us</Button>
|
|
170
|
+
{loading ? (
|
|
171
|
+
<CircularProgress />
|
|
172
|
+
) : (
|
|
173
|
+
<div>
|
|
174
|
+
<Typography variant="subtitle1">Total Donations: {totalAmount}</Typography>
|
|
175
|
+
<List>
|
|
176
|
+
{supporters.supporters && supporters.supporters.map(supporter => (
|
|
177
|
+
<ListItem key={supporter.id}>
|
|
178
|
+
<ListItemText
|
|
179
|
+
primary={supporter.customer?.name}
|
|
180
|
+
secondary={`${formatAmount(supporter.amount_total, supporters.currency?.decimal)} ${supporters.currency?.symbol}`}
|
|
181
|
+
/>
|
|
182
|
+
</ListItem>
|
|
183
|
+
))}
|
|
184
|
+
</List>
|
|
185
|
+
</div>
|
|
186
|
+
)}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
</CheckoutDonate>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
This custom setup gives you full control over the presentation of donation information.
|
|
194
|
+
|
|
195
|
+
## Admin Features
|
|
196
|
+
|
|
197
|
+
If the current user session has an `owner` or `admin` role, a settings icon will appear in the title of the donation dialog. Clicking this icon opens the donation configuration interface, allowing administrators to modify donation settings directly from the UI.
|
|
198
|
+
|
|
199
|
+
This feature requires that the `DonateProvider` is properly configured and that the underlying Payment Kit blocklet supports this functionality.
|