@blocklet/payment-react 1.19.22 → 1.20.0
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/payment/form/index.js +15 -1
- package/lib/payment/form/index.js +14 -1
- package/package.json +5 -5
- package/src/payment/form/index.tsx +16 -1
package/docs/overview.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
`@blocklet/payment-react` is a React component library designed for building payment flows, subscriptions, and donation systems within blocklets. It integrates seamlessly with [Payment Kit](https://www.arcblock.io/docs/arcblock-payment-kit) to provide a comprehensive set of pre-built UI components, context providers, and utility functions that accelerate the development of payment-related features.
|
|
4
|
+
|
|
5
|
+
Whether you need a simple checkout form, a complete pricing table, or a view of a customer's invoice history, `@blocklet/payment-react` offers the tools to build it efficiently.
|
|
6
|
+
|
|
7
|
+
## Key Features
|
|
8
|
+
|
|
9
|
+
<x-cards data-columns="3">
|
|
10
|
+
<x-card data-title="Pre-built UI Components" data-icon="lucide:layout-template">
|
|
11
|
+
Includes a rich set of components like checkout forms, pricing tables, and donation widgets to cover common use cases.
|
|
12
|
+
</x-card>
|
|
13
|
+
<x-card data-title="Customizable Themes" data-icon="lucide:palette">
|
|
14
|
+
Gain full control over the look and feel using Material-UI themes, ensuring consistency with your application's design.
|
|
15
|
+
</x-card>
|
|
16
|
+
<x-card data-title="i18n Support" data-icon="lucide:languages">
|
|
17
|
+
Built-in localization capabilities to support a global user base.
|
|
18
|
+
</x-card>
|
|
19
|
+
<x-card data-title="Lazy Loading" data-icon="lucide:package-minus">
|
|
20
|
+
Optimize your application's bundle size by dynamically importing components only when they are needed.
|
|
21
|
+
</x-card>
|
|
22
|
+
<x-card data-title="Payment Operations" data-icon="lucide:credit-card">
|
|
23
|
+
Functionality to manage subscriptions, process refunds, view invoices, and handle metered billing.
|
|
24
|
+
</x-card>
|
|
25
|
+
</x-cards>
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
The library is built around a provider pattern. You wrap your application, or a relevant part of your component tree, with a `PaymentProvider`. This provider handles authentication, API communication, and state management. Components rendered within this provider can then access the payment context to perform actions and display data.
|
|
30
|
+
|
|
31
|
+
This architecture decouples your UI components from the direct handling of API requests, making your code cleaner and easier to maintain.
|
|
32
|
+
|
|
33
|
+
```d2
|
|
34
|
+
direction: down
|
|
35
|
+
|
|
36
|
+
"Your React Application": {
|
|
37
|
+
"PaymentProvider": {
|
|
38
|
+
shape: package
|
|
39
|
+
"CheckoutForm"
|
|
40
|
+
"CheckoutDonate"
|
|
41
|
+
"CustomerInvoiceList"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
"Blocklet Environment": {
|
|
46
|
+
"Payment Service": {
|
|
47
|
+
shape: cloud
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
"Your React Application.PaymentProvider" -> "Blocklet Environment.Payment Service": "Communicates via API"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Here is a basic example of how to integrate the `CheckoutForm`:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';
|
|
58
|
+
|
|
59
|
+
// A custom hook from your application that provides the session context.
|
|
60
|
+
// See the PaymentProvider documentation for setup details.
|
|
61
|
+
import { useSessionContext } from './session-context';
|
|
62
|
+
|
|
63
|
+
function App() {
|
|
64
|
+
const { session, connectApi } = useSessionContext();
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
68
|
+
<CheckoutForm
|
|
69
|
+
id="plink_xxx" // Payment Link ID
|
|
70
|
+
mode="inline" // Embed directly in your UI
|
|
71
|
+
showCheckoutSummary={true}
|
|
72
|
+
onChange={(state) => console.log('Checkout State:', state)}
|
|
73
|
+
/>
|
|
74
|
+
</PaymentProvider>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
In this example, `useSessionContext` is a custom hook within your application responsible for managing user session state. It should provide the `session` object and the `connect` function required by the `PaymentProvider`. For a detailed guide on setting up this context, please refer to the [PaymentProvider](./providers-payment-provider.md) documentation.
|
|
80
|
+
|
|
81
|
+
## Next Steps
|
|
82
|
+
|
|
83
|
+
To begin integrating payments into your application, proceed to the next section for a step-by-step guide.
|
|
84
|
+
|
|
85
|
+
<x-card data-title="Getting Started" data-href="/getting-started" data-icon="lucide:arrow-right">
|
|
86
|
+
Install the library and build your first functional payment form.
|
|
87
|
+
</x-card>
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# DonateProvider
|
|
2
|
+
|
|
3
|
+
The `DonateProvider` is a context provider that manages the state and settings for donation-related components, such as `CheckoutDonate`. It handles fetching donation configurations, updating settings, and providing this data to its children components. To function correctly, `DonateProvider` must be placed within a [`PaymentProvider`](./providers-payment-provider.md).
|
|
4
|
+
|
|
5
|
+
```d2
|
|
6
|
+
direction: down
|
|
7
|
+
|
|
8
|
+
"PaymentProvider": {
|
|
9
|
+
shape: package
|
|
10
|
+
|
|
11
|
+
"DonateProvider": {
|
|
12
|
+
shape: package
|
|
13
|
+
|
|
14
|
+
"CheckoutDonate": {
|
|
15
|
+
shape: document
|
|
16
|
+
label: "CheckoutDonate Component"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
"PaymentProvider" -> "DonateProvider" -> "CheckoutDonate": "Provides Context"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This structure ensures that donation components have access to both the general payment context and the specific donation settings.
|
|
25
|
+
|
|
26
|
+
## Props
|
|
27
|
+
|
|
28
|
+
The `DonateProvider` accepts the following props to configure its behavior:
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Required | Description |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `mountLocation` | `string` | Yes | A unique identifier for this specific donation instance. It's used to fetch and store settings, ensuring that different donation points in your application have their own configurations. |
|
|
33
|
+
| `description` | `string` | Yes | A description to help identify this donation instance in logs or admin interfaces. |
|
|
34
|
+
| `defaultSettings` | `DonateConfigSettings` | No | An object with default settings for the donation component. These settings are used when no configuration has been saved for the given `mountLocation`. |
|
|
35
|
+
| `children` | `any` | Yes | The child components that will be rendered within the provider. Typically, this will include one or more `CheckoutDonate` components. |
|
|
36
|
+
| `active` | `boolean` | No | A flag to control whether the donation functionality is active. Defaults to `true`. |
|
|
37
|
+
| `enableDonate` | `boolean` | No | If set to `true`, it allows administrators to enable a disabled donation instance directly from the UI. Defaults to `false`. |
|
|
38
|
+
|
|
39
|
+
### DonateConfigSettings
|
|
40
|
+
|
|
41
|
+
The `defaultSettings` prop accepts an object with the following structure:
|
|
42
|
+
|
|
43
|
+
| Key | Type | Description |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `amount` | `object` | Configuration for donation amounts. Contains `presets` (array of strings), `preset` (string), `custom` (boolean), `minimum` (string), and `maximum` (string). |
|
|
46
|
+
| `btnText` | `string` | Custom text for the main donation button (e.g., "Like", "Support"). |
|
|
47
|
+
| `historyType` | `'table' \| 'avatar'` | Defines the display style for the donation history. |
|
|
48
|
+
|
|
49
|
+
## Usage Example
|
|
50
|
+
|
|
51
|
+
Here is a complete example of how to set up `DonateProvider` to wrap a `CheckoutDonate` component. This setup ensures that the donation button has access to the necessary context from both providers.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import {
|
|
55
|
+
PaymentProvider,
|
|
56
|
+
DonateProvider,
|
|
57
|
+
CheckoutDonate,
|
|
58
|
+
} from '@blocklet/payment-react';
|
|
59
|
+
// This is a custom hook to get session context from your application.
|
|
60
|
+
// See the PaymentProvider documentation for more on session setup.
|
|
61
|
+
import { useSessionContext } from '../hooks/use-session-context';
|
|
62
|
+
|
|
63
|
+
function DonationSection() {
|
|
64
|
+
const { session, connectApi } = useSessionContext();
|
|
65
|
+
|
|
66
|
+
// Render a loading state or null until the session is available
|
|
67
|
+
if (!session) {
|
|
68
|
+
return <div>Loading session...</div>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
73
|
+
<DonateProvider
|
|
74
|
+
mountLocation="unique-blog-post-123"
|
|
75
|
+
description="Donation button for the blog post about React Hooks"
|
|
76
|
+
defaultSettings={{
|
|
77
|
+
btnText: 'Support the Author',
|
|
78
|
+
amount: {
|
|
79
|
+
presets: ['1', '5', '10'],
|
|
80
|
+
custom: true,
|
|
81
|
+
minimum: '1',
|
|
82
|
+
},
|
|
83
|
+
}}>
|
|
84
|
+
<CheckoutDonate
|
|
85
|
+
settings={{
|
|
86
|
+
target: 'post-123',
|
|
87
|
+
title: 'Support Author',
|
|
88
|
+
description: 'If you find this article helpful, feel free to buy me a coffee',
|
|
89
|
+
reference: 'https://your-site.com/posts/123',
|
|
90
|
+
beneficiaries: [
|
|
91
|
+
{
|
|
92
|
+
address: 'user-did-address',
|
|
93
|
+
share: '100',
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
</DonateProvider>
|
|
99
|
+
</PaymentProvider>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Using the Context
|
|
105
|
+
|
|
106
|
+
You can access the donation context's state and functions using the `useDonateContext` hook. This is useful for building custom UI or logic that interacts with the donation settings.
|
|
107
|
+
|
|
108
|
+
### Context Values
|
|
109
|
+
|
|
110
|
+
The `useDonateContext` hook returns an object with the following properties:
|
|
111
|
+
|
|
112
|
+
| Key | Type | Description |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `settings` | `TSetting` | An object containing the current settings for the donation instance, including its active status and configuration. |
|
|
115
|
+
| `refresh` | `(forceRefresh?: boolean) => void` | A function to manually trigger a refresh of the donation settings from the server. Pass `true` to bypass the cache. |
|
|
116
|
+
| `updateSettings` | `(newSettings: DonateConfigSettings) => Promise<void>` | An async function to update and persist new settings for the donation instance. |
|
|
117
|
+
| `api` | `Axios` | An Axios instance configured for making requests to the payment API. |
|
|
118
|
+
|
|
119
|
+
### Example
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { useDonateContext } from '@blocklet/payment-react';
|
|
123
|
+
import { Button, Typography } from '@mui/material';
|
|
124
|
+
|
|
125
|
+
function CustomDonateUI() {
|
|
126
|
+
const { settings, refresh, updateSettings } = useDonateContext();
|
|
127
|
+
|
|
128
|
+
const handleUpdateBtnText = async () => {
|
|
129
|
+
try {
|
|
130
|
+
await updateSettings({ btnText: 'New Button Text!' });
|
|
131
|
+
// The settings will be automatically refreshed after update.
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('Failed to update settings:', error);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<div>
|
|
139
|
+
<Typography>Current Button Text: {settings.settings?.btnText}</Typography>
|
|
140
|
+
<Button onClick={handleUpdateBtnText}>Change Text</Button>
|
|
141
|
+
<Button onClick={() => refresh(true)}>Force Refresh</Button>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Utility Functions
|
|
148
|
+
|
|
149
|
+
The library also exports utility functions to manage the donation settings cache outside of the React component lifecycle.
|
|
150
|
+
|
|
151
|
+
### clearDonateCache
|
|
152
|
+
|
|
153
|
+
Removes the cached settings for a specific `mountLocation` from `localStorage`.
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { clearDonateCache } from '@blocklet/payment-react';
|
|
157
|
+
|
|
158
|
+
// Call this when you know the settings are stale, for example after a user logs out.
|
|
159
|
+
clearDonateCache('unique-blog-post-123');
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### clearDonateSettings
|
|
163
|
+
|
|
164
|
+
Sends a `DELETE` request to the server to completely remove the settings for a `mountLocation` and also clears the local cache.
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import { clearDonateSettings } from '@blocklet/payment-react';
|
|
168
|
+
|
|
169
|
+
// Use this to reset a donation instance to its default state.
|
|
170
|
+
async function resetDonationSettings() {
|
|
171
|
+
await clearDonateSettings('unique-blog-post-123');
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
After setting up the provider, the next step is to implement the donation UI using the [`CheckoutDonate`](./components-checkout-checkout-donate.md) component to render the donation widget and display donation history.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# PaymentProvider
|
|
2
|
+
|
|
3
|
+
The `PaymentProvider` is the cornerstone of the `@blocklet/payment-react` library. It's a context provider that must wrap your application or the specific sections that utilize payment components. It initializes the payment context, fetches necessary settings from the Payment Kit, and makes payment functions and data available to all its child components.
|
|
4
|
+
|
|
5
|
+
Any component from this library, such as `CheckoutForm` or `CustomerInvoiceList`, must be nested within a `PaymentProvider` to function correctly.
|
|
6
|
+
|
|
7
|
+
```d2
|
|
8
|
+
direction: down
|
|
9
|
+
|
|
10
|
+
"Your React App": {
|
|
11
|
+
"PaymentProvider": {
|
|
12
|
+
shape: package
|
|
13
|
+
|
|
14
|
+
"Payment Components": {
|
|
15
|
+
grid-columns: 3
|
|
16
|
+
|
|
17
|
+
"CheckoutForm": {shape: document}
|
|
18
|
+
"CustomerInvoiceList": {shape: document}
|
|
19
|
+
"Custom Component (usePaymentContext)": {shape: document}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
"PaymentProvider" -> "Payment Components": "Provides context"
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Prerequisite: Setting Up the Session Context
|
|
30
|
+
|
|
31
|
+
The `PaymentProvider` requires `session` and `connect` props, which are typically managed by `@arcblock/did-connect-react`. To streamline their use across your application, it's best practice to create a dedicated session context.
|
|
32
|
+
|
|
33
|
+
Create a file, for example, at `src/contexts/session.tsx`, with the following content. This will create a `SessionProvider` to wrap your app and a `useSessionContext` hook to access session data easily.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
// src/contexts/session.tsx
|
|
37
|
+
import { createAuthServiceSessionContext } from '@arcblock/did-connect-react/lib/Session';
|
|
38
|
+
import { useContext } from 'react';
|
|
39
|
+
|
|
40
|
+
const { SessionProvider, SessionContext, SessionConsumer, withSession } = createAuthServiceSessionContext();
|
|
41
|
+
|
|
42
|
+
function useSessionContext() {
|
|
43
|
+
const info = useContext(SessionContext);
|
|
44
|
+
return info;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export { SessionProvider, SessionContext, SessionConsumer, useSessionContext, withSession };
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Then, wrap your application's root component with the `SessionProvider` you just created:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
// src/App.tsx
|
|
54
|
+
import { SessionProvider } from './contexts/session';
|
|
55
|
+
|
|
56
|
+
function App() {
|
|
57
|
+
return (
|
|
58
|
+
<SessionProvider>
|
|
59
|
+
{/* Your application components */}
|
|
60
|
+
</SessionProvider>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Props
|
|
66
|
+
|
|
67
|
+
The `PaymentProvider` accepts the following props to configure the payment environment.
|
|
68
|
+
|
|
69
|
+
| Prop | Type | Required | Description |
|
|
70
|
+
|---|---|---|---|
|
|
71
|
+
| `session` | `SessionContext['session']` | Yes | The user session object obtained from `useSessionContext()`. It contains essential user data like their DID. |
|
|
72
|
+
| `connect` | `SessionContext['connectApi']` | Yes | The connect API instance from `useSessionContext()`, used for handling DID Connect interactions. |
|
|
73
|
+
| `children`| `React.ReactNode` | Yes | The React components or part of your application tree that needs access to the payment context. |
|
|
74
|
+
| `baseUrl` | `string` | No | The base URL of the Payment Kit blocklet. This is only necessary if your application and the Payment Kit are running on different origins. The provider uses this URL to fetch configuration for cross-origin API requests. |
|
|
75
|
+
| `authToken` | `string` | No | An optional authentication token. If provided, it will be used for API requests, overriding the default token from the session. |
|
|
76
|
+
|
|
77
|
+
## Basic Integration
|
|
78
|
+
|
|
79
|
+
To get started, wrap your main application component or the relevant layout with `PaymentProvider`. The required `session` and `connectApi` props are obtained from the `useSessionContext` hook you created earlier.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';
|
|
83
|
+
import { useSessionContext } from './contexts/session'; // Adjust path as needed
|
|
84
|
+
|
|
85
|
+
function App() {
|
|
86
|
+
const { session, connectApi } = useSessionContext();
|
|
87
|
+
|
|
88
|
+
if (!session.user) {
|
|
89
|
+
// Render a login button or a loading state
|
|
90
|
+
return <button onClick={() => connectApi.open()}>Login</button>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
95
|
+
{/* All child components now have access to the payment context */}
|
|
96
|
+
<h1>My Store</h1>
|
|
97
|
+
<CheckoutForm
|
|
98
|
+
id="plink_xxx" // A valid Payment Link ID
|
|
99
|
+
mode="inline"
|
|
100
|
+
/>
|
|
101
|
+
</PaymentProvider>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Advanced Usage
|
|
107
|
+
|
|
108
|
+
### Cross-Origin Communication with `baseUrl`
|
|
109
|
+
|
|
110
|
+
If your payment blocklet is hosted on a different domain than your main application (e.g., `payments.example.com` vs `app.example.com`), you must provide the `baseUrl` prop. The `PaymentProvider` will use this URL to correctly resolve API endpoints and fetch necessary blocklet information for seamless cross-origin communication.
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
import { PaymentProvider, CustomerInvoiceList } from '@blocklet/payment-react';
|
|
114
|
+
import { useSessionContext } from './contexts/session';
|
|
115
|
+
|
|
116
|
+
function MyAccountPage() {
|
|
117
|
+
const { session, connectApi } = useSessionContext();
|
|
118
|
+
const paymentKitBaseUrl = 'https://your-payment-blocklet-domain.com';
|
|
119
|
+
|
|
120
|
+
if (!session.user) {
|
|
121
|
+
return <button onClick={() => connectApi.open()}>Login</button>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<PaymentProvider
|
|
126
|
+
session={session}
|
|
127
|
+
connect={connectApi}
|
|
128
|
+
baseUrl={paymentKitBaseUrl}
|
|
129
|
+
>
|
|
130
|
+
<h2>My Invoice History</h2>
|
|
131
|
+
<CustomerInvoiceList />
|
|
132
|
+
</PaymentProvider>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Using a Custom `authToken`
|
|
138
|
+
|
|
139
|
+
In scenarios where you need to use a specific API token instead of relying on the user's session—for example, in a backend-for-frontend pattern or when using a service account token—you can pass the `authToken` prop. This token will be used for all subsequent API requests made by the components within the provider.
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { PaymentProvider, ResumeSubscription } from '@blocklet/payment-react';
|
|
143
|
+
import { useSessionContext } from './contexts/session';
|
|
144
|
+
|
|
145
|
+
function SubscriptionManager({ temporaryAuthToken }) {
|
|
146
|
+
const { session, connectApi } = useSessionContext();
|
|
147
|
+
|
|
148
|
+
if (!session.user) {
|
|
149
|
+
return <button onClick={() => connectApi.open()}>Login</button>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<PaymentProvider
|
|
154
|
+
session={session}
|
|
155
|
+
connect={connectApi}
|
|
156
|
+
authToken={temporaryAuthToken}
|
|
157
|
+
>
|
|
158
|
+
<ResumeSubscription subscriptionId="sub_xxx" />
|
|
159
|
+
</PaymentProvider>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Accessing Context Data with `usePaymentContext`
|
|
165
|
+
|
|
166
|
+
Child components can access the data and functions provided by `PaymentProvider` using the `usePaymentContext` hook. This hook provides access to settings, the current operational mode, a pre-configured API client, and more.
|
|
167
|
+
|
|
168
|
+
### Context Values
|
|
169
|
+
|
|
170
|
+
Here are the key values returned by the `usePaymentContext` hook:
|
|
171
|
+
|
|
172
|
+
| Key | Type | Description |
|
|
173
|
+
|---|---|---|
|
|
174
|
+
| `settings` | `object` | An object containing available `paymentMethods` and the `baseCurrency`. |
|
|
175
|
+
| `livemode` | `boolean` | Returns `true` for live mode and `false` for test mode. This state is persisted in local storage. |
|
|
176
|
+
| `setLivemode` | `(livemode: boolean) => void` | A function to toggle between live and test mode. |
|
|
177
|
+
| `api` | `AxiosInstance` | A pre-configured Axios instance for making authenticated requests to the Payment Kit API. |
|
|
178
|
+
| `refresh` | `(forceRefresh?: boolean) => void` | A function to manually trigger a refresh of the settings data. |
|
|
179
|
+
| `getCurrency` | `(id: string) => TPaymentCurrency` | A helper function to find a currency object by its ID from the settings. |
|
|
180
|
+
| `getMethod` | `(id: string) => TPaymentMethodExpanded` | A helper function to find a payment method object by its ID from the settings. |
|
|
181
|
+
| `session` | `object` | The currently active user session object that was passed to the provider. |
|
|
182
|
+
|
|
183
|
+
### Example: Custom Payment Info Component
|
|
184
|
+
|
|
185
|
+
This example shows a component that uses the `usePaymentContext` hook to display the current mode and a list of available payment methods.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { usePaymentContext } from '@blocklet/payment-react';
|
|
189
|
+
import { useSessionContext } from './contexts/session';
|
|
190
|
+
import { Chip, List, ListItem, ListItemText, Typography, Button } from '@mui/material';
|
|
191
|
+
|
|
192
|
+
function PaymentInfo() {
|
|
193
|
+
const { settings, livemode, refresh, setLivemode } = usePaymentContext();
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div>
|
|
197
|
+
<Typography variant="h6" component="h2" gutterBottom>
|
|
198
|
+
Payment Status
|
|
199
|
+
{livemode ?
|
|
200
|
+
<Chip label="Live Mode" color="success" size="small" sx={{ ml: 1 }} /> :
|
|
201
|
+
<Chip label="Test Mode" color="warning" size="small" sx={{ ml: 1 }} />
|
|
202
|
+
}
|
|
203
|
+
</Typography>
|
|
204
|
+
|
|
205
|
+
<Typography>Available Payment Methods:</Typography>
|
|
206
|
+
<List dense>
|
|
207
|
+
{settings.paymentMethods.map(method => (
|
|
208
|
+
<ListItem key={method.id}>
|
|
209
|
+
<ListItemText primary={method.name} />
|
|
210
|
+
</ListItem>
|
|
211
|
+
))}
|
|
212
|
+
</List>
|
|
213
|
+
|
|
214
|
+
<Button variant="outlined" onClick={() => setLivemode(!livemode)} sx={{ mr: 1 }}>
|
|
215
|
+
Toggle Mode
|
|
216
|
+
</Button>
|
|
217
|
+
<Button variant="outlined" onClick={() => refresh(true)}>
|
|
218
|
+
Refresh Settings
|
|
219
|
+
</Button>
|
|
220
|
+
</div>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// This component must be rendered inside a <PaymentProvider>
|
|
225
|
+
function AppWithPaymentInfo() {
|
|
226
|
+
const { session, connectApi } = useSessionContext();
|
|
227
|
+
|
|
228
|
+
if (!session.user) {
|
|
229
|
+
return <button onClick={() => connectApi.open()}>Login</button>;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
234
|
+
<PaymentInfo />
|
|
235
|
+
</PaymentProvider>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Next Steps
|
|
241
|
+
|
|
242
|
+
With `PaymentProvider` set up, you are ready to integrate other components. A good next step is to implement a donation flow or build a checkout page.
|
|
243
|
+
|
|
244
|
+
- **[DonateProvider](./providers-donate-provider.md)**: Learn how to configure the context for donation-related components.
|
|
245
|
+
- **[CheckoutForm](./components-checkout-checkout-form.md)**: Dive into the primary component for handling payments and checkout sessions.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Providers
|
|
2
|
+
|
|
3
|
+
Providers are the foundation of the `@blocklet/payment-react` library. They use React's Context API to manage state and share essential data—like user sessions, payment settings, and API clients—across all payment-related components. Wrapping your application in the appropriate provider is a necessary first step before using any of the library's components.
|
|
4
|
+
|
|
5
|
+
This library offers two primary providers that serve distinct purposes:
|
|
6
|
+
|
|
7
|
+
```d2
|
|
8
|
+
direction: down
|
|
9
|
+
|
|
10
|
+
"Your App" {
|
|
11
|
+
"PaymentProvider": {
|
|
12
|
+
style.fill: "#DDF0FF"
|
|
13
|
+
"CheckoutForm"
|
|
14
|
+
"CustomerInvoiceList"
|
|
15
|
+
|
|
16
|
+
"DonateProvider": {
|
|
17
|
+
style.fill: "#E3F9E5"
|
|
18
|
+
"CheckoutDonate"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
"Your App" -> "PaymentProvider": "Wraps the application"
|
|
24
|
+
"PaymentProvider" -> "CheckoutForm": "Provides context"
|
|
25
|
+
"PaymentProvider" -> "CustomerInvoiceList": "Provides context"
|
|
26
|
+
"PaymentProvider" -> "DonateProvider": "Can be nested inside"
|
|
27
|
+
"DonateProvider" -> "CheckoutDonate": "Provides context for donations"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## PaymentProvider
|
|
31
|
+
|
|
32
|
+
The `PaymentProvider` is the main provider that you will use in almost every integration. It is responsible for handling user authentication, fetching payment method settings, managing test/live modes, and providing a pre-configured API client to all nested components. Any component that deals with payments, subscriptions, or invoices must be a descendant of `PaymentProvider`.
|
|
33
|
+
|
|
34
|
+
It centralizes access to critical data, ensuring a consistent and secure payment environment.
|
|
35
|
+
|
|
36
|
+
[Learn more about PaymentProvider ›](./providers-payment-provider.md)
|
|
37
|
+
|
|
38
|
+
## DonateProvider
|
|
39
|
+
|
|
40
|
+
The `DonateProvider` is designed specifically for donation features. It manages the configuration and state for the `CheckoutDonate` component, such as preset amounts, button text, and donation history display.
|
|
41
|
+
|
|
42
|
+
It is important to note that the `DonateProvider` must be used *within* a `PaymentProvider`, as it relies on the core payment context to process donations.
|
|
43
|
+
|
|
44
|
+
[Learn more about DonateProvider ›](./providers-donate-provider.md)
|
|
45
|
+
|
|
46
|
+
### Basic Setup Example
|
|
47
|
+
|
|
48
|
+
Here is a typical setup showing how to nest the providers. The `useSessionContext` hook is a placeholder for your application's own session management logic, which supplies the `session` and `connectApi` props required by `PaymentProvider`.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import {
|
|
52
|
+
PaymentProvider,
|
|
53
|
+
DonateProvider,
|
|
54
|
+
CheckoutForm,
|
|
55
|
+
CheckoutDonate,
|
|
56
|
+
} from '@blocklet/payment-react';
|
|
57
|
+
// This hook should be implemented in your application to provide session context.
|
|
58
|
+
// See the PaymentProvider documentation for an example implementation.
|
|
59
|
+
import { useSessionContext } from '../path/to/your/session-context';
|
|
60
|
+
|
|
61
|
+
function App() {
|
|
62
|
+
const { session, connectApi } = useSessionContext();
|
|
63
|
+
|
|
64
|
+
// Render only when the session is available.
|
|
65
|
+
if (!session) {
|
|
66
|
+
return <div>Loading Session...</div>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<PaymentProvider session={session} connect={connectApi}>
|
|
71
|
+
{/* General payment components can be placed directly under PaymentProvider */}
|
|
72
|
+
<CheckoutForm id="plink_xxx" />
|
|
73
|
+
|
|
74
|
+
{/* For donation features, wrap the relevant part with DonateProvider */}
|
|
75
|
+
<DonateProvider
|
|
76
|
+
mountLocation="your-unique-instance-id"
|
|
77
|
+
description="Donations for my awesome project"
|
|
78
|
+
>
|
|
79
|
+
<CheckoutDonate
|
|
80
|
+
settings={{
|
|
81
|
+
target: 'project-donate',
|
|
82
|
+
title: 'Support This Project',
|
|
83
|
+
description: 'Your contribution is appreciated!',
|
|
84
|
+
reference: 'https://your-site.com/project',
|
|
85
|
+
beneficiaries: [{
|
|
86
|
+
address: 'user-did-address',
|
|
87
|
+
share: '100'
|
|
88
|
+
}]
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
91
|
+
</DonateProvider>
|
|
92
|
+
</PaymentProvider>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
With an understanding of the providers, you are ready to explore their specific configurations. We recommend starting with the `PaymentProvider` as it is fundamental to the library's operation.
|
|
100
|
+
|
|
101
|
+
**Next:** [PaymentProvider](./providers-payment-provider.md)
|
package/es/payment/form/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
formatError,
|
|
26
26
|
formatQuantityInventory,
|
|
27
27
|
getPrefix,
|
|
28
|
+
getQueryParams,
|
|
28
29
|
getStatementDescriptor,
|
|
29
30
|
getTokenBalanceLink,
|
|
30
31
|
isCrossOrigin
|
|
@@ -138,6 +139,7 @@ export default function PaymentForm({
|
|
|
138
139
|
creditInsufficientInfo: null
|
|
139
140
|
});
|
|
140
141
|
const currencies = flattenPaymentMethods(paymentMethods);
|
|
142
|
+
const searchParams = getQueryParams(window.location.href);
|
|
141
143
|
const onCheckoutComplete = useMemoizedFn(async ({ response }) => {
|
|
142
144
|
if (response.id === checkoutSession.id && state.paid === false) {
|
|
143
145
|
await handleConnected();
|
|
@@ -595,6 +597,18 @@ export default function PaymentForm({
|
|
|
595
597
|
confirm: t("common.confirm")
|
|
596
598
|
}
|
|
597
599
|
);
|
|
600
|
+
const getRedirectUrl = () => {
|
|
601
|
+
if (searchParams.redirect) {
|
|
602
|
+
return decodeURIComponent(searchParams.redirect);
|
|
603
|
+
}
|
|
604
|
+
if (checkoutSession.success_url) {
|
|
605
|
+
return checkoutSession.success_url;
|
|
606
|
+
}
|
|
607
|
+
if (paymentLink?.after_completion?.redirect?.url) {
|
|
608
|
+
return paymentLink.after_completion.redirect.url;
|
|
609
|
+
}
|
|
610
|
+
return void 0;
|
|
611
|
+
};
|
|
598
612
|
if (onlyShowBtn) {
|
|
599
613
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
600
614
|
/* @__PURE__ */ jsx(Box, { className: "cko-payment-submit-btn", children: /* @__PURE__ */ jsxs(
|
|
@@ -708,7 +722,7 @@ export default function PaymentForm({
|
|
|
708
722
|
mode: checkoutSession.mode,
|
|
709
723
|
onConfirm: onStripeConfirm,
|
|
710
724
|
onCancel: onStripeCancel,
|
|
711
|
-
returnUrl:
|
|
725
|
+
returnUrl: getRedirectUrl()
|
|
712
726
|
}
|
|
713
727
|
)
|
|
714
728
|
]
|
|
@@ -161,6 +161,7 @@ function PaymentForm({
|
|
|
161
161
|
creditInsufficientInfo: null
|
|
162
162
|
});
|
|
163
163
|
const currencies = (0, _util2.flattenPaymentMethods)(paymentMethods);
|
|
164
|
+
const searchParams = (0, _util2.getQueryParams)(window.location.href);
|
|
164
165
|
const onCheckoutComplete = (0, _ahooks.useMemoizedFn)(async ({
|
|
165
166
|
response
|
|
166
167
|
}) => {
|
|
@@ -673,6 +674,18 @@ function PaymentForm({
|
|
|
673
674
|
}),
|
|
674
675
|
confirm: t("common.confirm")
|
|
675
676
|
});
|
|
677
|
+
const getRedirectUrl = () => {
|
|
678
|
+
if (searchParams.redirect) {
|
|
679
|
+
return decodeURIComponent(searchParams.redirect);
|
|
680
|
+
}
|
|
681
|
+
if (checkoutSession.success_url) {
|
|
682
|
+
return checkoutSession.success_url;
|
|
683
|
+
}
|
|
684
|
+
if (paymentLink?.after_completion?.redirect?.url) {
|
|
685
|
+
return paymentLink.after_completion.redirect.url;
|
|
686
|
+
}
|
|
687
|
+
return void 0;
|
|
688
|
+
};
|
|
676
689
|
if (onlyShowBtn) {
|
|
677
690
|
return /* @__PURE__ */(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
678
691
|
children: [/* @__PURE__ */(0, _jsxRuntime.jsx)(_material.Box, {
|
|
@@ -780,7 +793,7 @@ function PaymentForm({
|
|
|
780
793
|
mode: checkoutSession.mode,
|
|
781
794
|
onConfirm: onStripeConfirm,
|
|
782
795
|
onCancel: onStripeCancel,
|
|
783
|
-
returnUrl:
|
|
796
|
+
returnUrl: getRedirectUrl()
|
|
784
797
|
})]
|
|
785
798
|
})
|
|
786
799
|
}), showForm && /* @__PURE__ */(0, _jsxRuntime.jsxs)(_material.Stack, {
|