@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.
Files changed (43) hide show
  1. package/.aigne/doc-smith/config.yaml +114 -0
  2. package/.aigne/doc-smith/output/structure-plan.json +361 -0
  3. package/.aigne/doc-smith/preferences.yml +55 -0
  4. package/.aigne/doc-smith/upload-cache.yaml +264 -0
  5. package/README.md +2 -3
  6. package/docs/_sidebar.md +33 -0
  7. package/docs/components-business-auto-topup.md +238 -0
  8. package/docs/components-business-overdue-invoice-payment.md +231 -0
  9. package/docs/components-business-resume-subscription.md +177 -0
  10. package/docs/components-business.md +45 -0
  11. package/docs/components-checkout-checkout-donate.md +199 -0
  12. package/docs/components-checkout-checkout-form.md +185 -0
  13. package/docs/components-checkout-checkout-table.md +228 -0
  14. package/docs/components-checkout.md +131 -0
  15. package/docs/components-history-credit-grants-list.md +98 -0
  16. package/docs/components-history-credit-transactions-list.md +116 -0
  17. package/docs/components-history-invoice-list.md +104 -0
  18. package/docs/components-history-payment-list.md +65 -0
  19. package/docs/components-history.md +92 -0
  20. package/docs/components-ui-form-elements-address-form.md +150 -0
  21. package/docs/components-ui-form-elements-country-select.md +105 -0
  22. package/docs/components-ui-form-elements-currency-selector.md +124 -0
  23. package/docs/components-ui-form-elements-phone-input.md +160 -0
  24. package/docs/components-ui-form-elements.md +125 -0
  25. package/docs/components-ui-payment-summary.md +157 -0
  26. package/docs/components-ui-pricing-table.md +227 -0
  27. package/docs/components-ui.md +44 -0
  28. package/docs/components.md +95 -0
  29. package/docs/getting-started.md +111 -0
  30. package/docs/guides-theming.md +175 -0
  31. package/docs/guides-utilities.md +235 -0
  32. package/docs/guides.md +95 -0
  33. package/docs/hooks-use-mobile.md +70 -0
  34. package/docs/hooks-use-subscription.md +129 -0
  35. package/docs/hooks.md +84 -0
  36. package/docs/overview.md +87 -0
  37. package/docs/providers-donate-provider.md +175 -0
  38. package/docs/providers-payment-provider.md +245 -0
  39. package/docs/providers.md +101 -0
  40. package/es/payment/form/index.js +15 -1
  41. package/lib/payment/form/index.js +14 -1
  42. package/package.json +5 -5
  43. package/src/payment/form/index.tsx +16 -1
@@ -0,0 +1,124 @@
1
+ # CurrencySelector
2
+
3
+ The `CurrencySelector` component renders an interactive list of available payment currencies. Each currency is displayed as a distinct card, showing its logo, symbol, and the associated payment network, allowing users to easily choose their preferred option.
4
+
5
+ This component is a form element designed to be integrated into broader payment flows, such as within a `CheckoutForm` or a custom payment UI.
6
+
7
+ ## Props
8
+
9
+ The `CurrencySelector` component accepts the following props:
10
+
11
+ | Prop | Type | Description | Required |
12
+ | :----------- | :----------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- | :------- |
13
+ | `value` | `string` | The `id` of the currently selected currency. This prop controls which currency card is highlighted with a checked radio button. | Yes |
14
+ | `currencies` | `TPaymentCurrency[]` | An array of currency objects to display as selectable options. See the `TPaymentCurrency` interface below for the required object structure. | Yes |
15
+ | `onChange` | `(currencyId: string, methodId?: string) => void` | A callback function that fires when the user selects a currency. It receives the `id` of the chosen currency and its associated method. | Yes |
16
+
17
+ ### `TPaymentCurrency` Interface
18
+
19
+ The `currencies` prop requires an array of objects, where each object represents a selectable currency and must conform to the following structure:
20
+
21
+ ```typescript
22
+ interface TPaymentCurrency {
23
+ id: string; // Unique identifier for the currency option
24
+ logo: string; // URL to the currency or payment method logo
25
+ name: string; // The display name of the currency
26
+ symbol: string; // The currency symbol or ticker (e.g., "USDT", "BTC")
27
+ method: {
28
+ id: string; // ID of the associated payment method or network
29
+ name: string; // Display name of the associated payment method or network (e.g., "TRON Network")
30
+ };
31
+ }
32
+ ```
33
+
34
+ ## Example Usage
35
+
36
+ Below is an example of how to implement the `CurrencySelector`. It uses the `useState` hook to manage the user's selection and updates the UI accordingly.
37
+
38
+ Note that while `CurrencySelector` is a UI component, it's designed to function within a payment context. Therefore, it must be wrapped in `PaymentProvider`. For details on how to set up your session context, please refer to the [PaymentProvider documentation](./providers-payment-provider.md).
39
+
40
+ ```tsx
41
+ import React, { useState } from 'react';
42
+ import { CurrencySelector, PaymentProvider } from '@blocklet/payment-react';
43
+ import { useSessionContext } from '../hooks/session'; // Assuming a local session context hook
44
+ import type { TPaymentCurrency } from '@blocklet/payment-types';
45
+ import { Box, Typography, CircularProgress } from '@mui/material';
46
+
47
+ // Mock data representing available currencies
48
+ const mockCurrencies: TPaymentCurrency[] = [
49
+ {
50
+ id: 'usdt_tron',
51
+ logo: 'https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a63530be6e374711a8554f31b17e4cb92c25661/svg/color/usdt.svg',
52
+ name: 'Tether',
53
+ symbol: 'USDT',
54
+ method: {
55
+ id: 'tron_network',
56
+ name: 'TRON Network',
57
+ },
58
+ },
59
+ {
60
+ id: 'btc_native',
61
+ logo: 'https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a63530be6e374711a8554f31b17e4cb92c25661/svg/color/btc.svg',
62
+ name: 'Bitcoin',
63
+ symbol: 'BTC',
64
+ method: {
65
+ id: 'bitcoin_network',
66
+ name: 'Bitcoin Network',
67
+ },
68
+ },
69
+ {
70
+ id: 'eth_native',
71
+ logo: 'https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a63530be6e374711a8554f31b17e4cb92c25661/svg/color/eth.svg',
72
+ name: 'Ethereum',
73
+ symbol: 'ETH',
74
+ method: {
75
+ id: 'ethereum_network',
76
+ name: 'Ethereum Network',
77
+ },
78
+ },
79
+ ];
80
+
81
+ function CurrencySelectorExample() {
82
+ const [selectedCurrencyId, setSelectedCurrencyId] = useState<string>('usdt_tron');
83
+
84
+ const handleCurrencyChange = (currencyId: string, methodId?: string) => {
85
+ console.log(`Selected Currency ID: ${currencyId}, Method ID: ${methodId}`);
86
+ setSelectedCurrencyId(currencyId);
87
+ };
88
+
89
+ return (
90
+ <Box sx={{ padding: 2, border: '1px solid #ddd', borderRadius: '4px' }}>
91
+ <Typography variant="h6" gutterBottom>
92
+ Select Your Payment Currency
93
+ </Typography>
94
+ <CurrencySelector
95
+ value={selectedCurrencyId}
96
+ currencies={mockCurrencies}
97
+ onChange={handleCurrencyChange}
98
+ />
99
+ <Typography sx={{ marginTop: '20px' }}>
100
+ Current Selection: <strong>{selectedCurrencyId}</strong>
101
+ </Typography>
102
+ </Box>
103
+ );
104
+ }
105
+
106
+ // Most components from this library must be wrapped in PaymentProvider.
107
+ export default function MyPaymentPage() {
108
+ const { session, connectApi } = useSessionContext();
109
+
110
+ // PaymentProvider requires session and connectApi.
111
+ // Ensure these are available before rendering.
112
+ if (!session || !connectApi) {
113
+ return <CircularProgress />;
114
+ }
115
+
116
+ return (
117
+ <PaymentProvider session={session} connectApi={connectApi}>
118
+ <CurrencySelectorExample />
119
+ </PaymentProvider>
120
+ );
121
+ }
122
+ ```
123
+
124
+ In this example, `selectedCurrencyId` holds the state for the chosen currency. When a user clicks a currency card, the `handleCurrencyChange` function is triggered, which updates the state. The `CurrencySelector` re-renders to visually reflect the new selection.
@@ -0,0 +1,160 @@
1
+ # PhoneInput
2
+
3
+ The `PhoneInput` component provides a user-friendly field for entering international phone numbers. It integrates seamlessly with `react-hook-form` and includes a built-in, searchable country selector. It is designed to work in tandem with a country selection field, ensuring data consistency across your form.
4
+
5
+ ### Features
6
+
7
+ - **React Hook Form Integration**: Built to work directly with `useFormContext` for easy state management and validation.
8
+ - **Interactive Country Selector**: Includes the `CountrySelect` component as a prefix, offering country flags, names, and a search field.
9
+ - **Two-Way Country Synchronization**: Automatically syncs the selected country with another form field (e.g., a billing address country field).
10
+ - **Asynchronous Validation**: Leverages `google-libphonenumber` for robust validation without blocking the main thread on initial load.
11
+ - **Responsive Design**: The country selector adapts to the viewport, using a dropdown on desktop and a dialog on mobile devices.
12
+
13
+ ## Props
14
+
15
+ The `PhoneInput` component accepts all standard props from Material-UI's `TextField` in addition to its own specific props.
16
+
17
+ | Prop | Type | Description | Default |
18
+ | --- | --- | --- | --- |
19
+ | `name` | `string` | **Required.** The name of the field to be registered with `react-hook-form`. | - |
20
+ | `countryFieldName` | `string` | The name of the form field that stores the selected country's ISO 3166-1 alpha-2 code. The component synchronizes with this field. | `'billing_address.country'` |
21
+ | `...rest` | `TextFieldProps` | Any other props accepted by the Material-UI `TextField` component, such as `label`, `placeholder`, `required`, `helperText`, and `error`. | - |
22
+
23
+ ## Usage
24
+
25
+ The `PhoneInput` must be wrapped in a `FormProvider` from `react-hook-form`. While it is often used within payment forms that require `PaymentProvider`, the component itself does not need it. For details on setting up the payment context, please refer to the [PaymentProvider documentation](./providers-payment-provider.md).
26
+
27
+ ### Basic Example
28
+
29
+ This example demonstrates a complete form with a `PhoneInput` and a separate `CountrySelect` for the billing address. The two are synchronized via the `countryFieldName` prop.
30
+
31
+ ```tsx
32
+ import { FormProvider, useForm } from 'react-hook-form';
33
+ import { Button, Stack } from '@mui/material';
34
+ import PhoneInput from '@blocklet/payment-react/components/ui/form-elements/phone-input';
35
+ import CountrySelect from '@blocklet/payment-react/components/ui/form-elements/country-select';
36
+ import { validatePhoneNumber } from '@blocklet/payment-react/libs/phone-validator';
37
+
38
+ export default function PhoneForm() {
39
+ const methods = useForm({
40
+ mode: 'onBlur', // Validate on blur
41
+ defaultValues: {
42
+ phone: '',
43
+ 'billing_address.country': 'us', // Default country
44
+ },
45
+ });
46
+
47
+ const { handleSubmit, formState: { errors }, watch, setValue, register } = methods;
48
+
49
+ const onSubmit = (data) => {
50
+ alert(JSON.stringify(data, null, 2));
51
+ };
52
+
53
+ return (
54
+ <FormProvider {...methods}>
55
+ <form onSubmit={handleSubmit(onSubmit)}>
56
+ <Stack spacing={2}>
57
+ <CountrySelect
58
+ name="billing_address.country"
59
+ value={watch('billing_address.country')}
60
+ onChange={(country) => setValue('billing_address.country', country, { shouldValidate: true })}
61
+ />
62
+ <PhoneInput
63
+ label="Phone Number"
64
+ name="phone"
65
+ required
66
+ {...register('phone', {
67
+ required: 'Phone number is required.',
68
+ validate: async (value) => {
69
+ const isValid = await validatePhoneNumber(value);
70
+ return isValid || 'Please enter a valid phone number';
71
+ },
72
+ })}
73
+ error={!!errors.phone}
74
+ helperText={errors.phone?.message?.toString()}
75
+ />
76
+ <Button type="submit" variant="contained">
77
+ Submit
78
+ </Button>
79
+ </Stack>
80
+ </form>
81
+ </FormProvider>
82
+ );
83
+ }
84
+ ```
85
+
86
+ ## Country Synchronization
87
+
88
+ The key feature of `PhoneInput` is its ability to synchronize with an external country field. This is particularly useful in forms like an [AddressForm](./components-ui-form-elements-address-form.md) where the phone number's country should match the billing address country.
89
+
90
+ - **Default Behavior**: By default, it listens to and updates a form field named `billing_address.country`.
91
+ - **Customization**: You can specify a different field name by passing the `countryFieldName` prop.
92
+
93
+ This two-way synchronization works as follows:
94
+ 1. When the user selects a country in an external `CountrySelect` component, the flag and dial code inside the `PhoneInput` update automatically.
95
+ 2. When the user changes the country from the dropdown within the `PhoneInput`, the value of the `countryFieldName` field is also updated, ensuring the entire form state remains consistent.
96
+
97
+ The following diagram illustrates this interaction:
98
+
99
+ ```d2
100
+ direction: down
101
+
102
+ User: "User"
103
+
104
+ UI: {
105
+ shape: package
106
+ "PhoneInput": {
107
+ "Internal CountrySelect": "Country selector inside phone input"
108
+ }
109
+ "External CountrySelect": "Separate country selector for address"
110
+ }
111
+
112
+ FormState: "react-hook-form State" {
113
+ shape: cylinder
114
+ phone: "Phone number value"
115
+ "billing_address.country": "Country ISO code"
116
+ }
117
+
118
+ User -> UI."External CountrySelect": "Selects 'Canada'"
119
+ UI."External CountrySelect" -> FormState."billing_address.country": "Updates state to 'ca'"
120
+ FormState."billing_address.country" -> UI."PhoneInput"."Internal CountrySelect": "Syncs flag and dial code to Canada"
121
+
122
+ User -> UI."PhoneInput"."Internal CountrySelect": "Selects 'UK'"
123
+ UI."PhoneInput"."Internal CountrySelect" -> FormState."billing_address.country": "Updates state to 'gb'"
124
+ FormState."billing_address.country" -> UI."External CountrySelect": "Syncs selection to UK"
125
+ ```
126
+
127
+ ## Validation
128
+
129
+ Phone number validation is handled by the `validatePhoneNumber` utility. This function asynchronously loads the `google-libphonenumber` library to perform validation without impacting your application's initial load time. If the library fails to load, it falls back to a basic regex pattern for validation.
130
+
131
+ To apply validation, use the `validate` function in the rules object when registering the field with `react-hook-form`, as shown in the example above.
132
+
133
+ ## Helper Utilities
134
+
135
+ ### `formatPhone`
136
+
137
+ The library also exports a `formatPhone` utility function that can be used to standardize a phone number into the E.164 international format (e.g., `+12125552368`). This is useful for normalizing data before sending it to your backend.
138
+
139
+ **Parameters**
140
+
141
+ | Parameter | Type | Description | Default |
142
+ | --- | --- | --- | --- |
143
+ | `phoneNumber` | `string` | The original phone number string. | - |
144
+ | `defaultCountry` | `string` | The default country code (ISO 3166-1 alpha-2) to use if the number is ambiguous. | `'US'` |
145
+
146
+ **Example**
147
+
148
+ ```javascript
149
+ import { formatPhone } from '@blocklet/payment-react/libs/phone-validator';
150
+
151
+ const rawNumber = '(541) 754-3010';
152
+ const formattedNumber = formatPhone(rawNumber, 'US');
153
+ // formattedNumber will be '+15417543010'
154
+
155
+ const rawUkNumber = '07700 900077';
156
+ const formattedUkNumber = formatPhone(rawUkNumber, 'GB');
157
+ // formattedUkNumber will be '+447700900077'
158
+ ```
159
+
160
+ This utility is particularly helpful for normalizing phone numbers before submitting them to a backend service.
@@ -0,0 +1,125 @@
1
+ # Form Elements
2
+
3
+ The `@blocklet/payment-react` library provides a collection of granular input components for building custom payment and contact information forms. These components come with built-in validation, internationalization support, and a responsive UI, simplifying the process of collecting user data.
4
+
5
+ This section provides an overview of the key form elements. For detailed props and advanced usage, please refer to the specific documentation for each component linked below.
6
+
7
+ <x-cards data-columns="2">
8
+ <x-card data-title="AddressForm" data-icon="lucide:map-pin" data-href="/components/ui/form-elements/address-form">
9
+ A pre-built form for collecting billing address details, with validation that adapts to the selected country.
10
+ </x-card>
11
+ <x-card data-title="PhoneInput" data-icon="lucide:phone" data-href="/components/ui/form-elements/phone-input">
12
+ An international phone number input with an integrated country selector, dial code display, and validation.
13
+ </x-card>
14
+ <x-card data-title="CountrySelect" data-icon="lucide:globe" data-href="/components/ui/form-elements/country-select">
15
+ A searchable dropdown for selecting a country, complete with flags and a responsive design for mobile and desktop.
16
+ </x-card>
17
+ <x-card data-title="CurrencySelector" data-icon="lucide:circle-dollar-sign" data-href="/components/ui/form-elements/currency-selector">
18
+ A component that allows users to select their preferred payment currency from a list of available options.
19
+ </x-card>
20
+ </x-cards>
21
+
22
+ ## Usage Patterns
23
+
24
+ Most form elements are designed to work within a `react-hook-form` context, while others can be used as standalone components.
25
+
26
+ ### Form-Based Components
27
+
28
+ Components like `AddressForm` and `PhoneInput` should be wrapped in a `FormProvider` from `react-hook-form`. This allows them to share form state, validation, and submission logic seamlessly.
29
+
30
+ Here is an example of how to combine them into a single form:
31
+
32
+ ```jsx
33
+ import { FormProvider, useForm } from 'react-hook-form';
34
+ import { AddressForm, PhoneInput } from '@blocklet/payment-react';
35
+ import { Button } from '@mui/material';
36
+ import { getPhoneUtil } from '@blocklet/payment-react/libs/phone-validator';
37
+
38
+ function MyContactForm() {
39
+ const methods = useForm({
40
+ defaultValues: {
41
+ phone: '',
42
+ billing_address: {
43
+ line1: '',
44
+ city: '',
45
+ state: '',
46
+ postal_code: '',
47
+ country: 'us',
48
+ },
49
+ },
50
+ });
51
+
52
+ const validatePhoneNumber = async (phone) => {
53
+ const phoneUtil = await getPhoneUtil();
54
+ return phoneUtil.isValid(phone) || 'Invalid phone number';
55
+ };
56
+
57
+ const onSubmit = (data) => {
58
+ console.log('Form data:', data);
59
+ };
60
+
61
+ return (
62
+ <FormProvider {...methods}>
63
+ <form onSubmit={methods.handleSubmit(onSubmit)}>
64
+ <AddressForm mode="required" stripe={false} />
65
+ <PhoneInput
66
+ name="phone"
67
+ label="Phone Number"
68
+ rules={{ validate: validatePhoneNumber }}
69
+ />
70
+ <Button type="submit" variant="contained" sx={{ mt: 2 }}>
71
+ Submit
72
+ </Button>
73
+ </form>
74
+ </FormProvider>
75
+ );
76
+ }
77
+ ```
78
+
79
+ ### Standalone Components
80
+
81
+ Components like `CurrencySelector` are self-contained and manage their state via props and callbacks, so they don't need to be inside a `FormProvider`.
82
+
83
+ ```jsx
84
+ import { CurrencySelector } from '@blocklet/payment-react';
85
+ import { useState } from 'react';
86
+
87
+ // Example currency data structure
88
+ const sampleCurrencies = [
89
+ {
90
+ id: 'usd_credit_card',
91
+ name: 'USD',
92
+ symbol: '$',
93
+ logo: 'https://example.com/usd-logo.png',
94
+ method: { id: 'card', name: 'Credit Card' },
95
+ },
96
+ {
97
+ id: 'eth_mainnet',
98
+ name: 'Ethereum',
99
+ symbol: 'ETH',
100
+ logo: 'https://example.com/eth-logo.png',
101
+ method: { id: 'crypto', name: 'Ethereum Network' },
102
+ },
103
+ ];
104
+
105
+ function MyCurrencyComponent() {
106
+ const [selectedCurrency, setSelectedCurrency] = useState('usd_credit_card');
107
+
108
+ const handleChange = (currencyId, methodId) => {
109
+ setSelectedCurrency(currencyId);
110
+ console.log('Selected payment method:', methodId);
111
+ };
112
+
113
+ return (
114
+ <CurrencySelector
115
+ currencies={sampleCurrencies}
116
+ value={selectedCurrency}
117
+ onChange={handleChange}
118
+ />
119
+ );
120
+ }
121
+ ```
122
+
123
+ ## Next Steps
124
+
125
+ Now that you have an overview of the individual form elements, you can explore their detailed documentation for advanced configurations. For building a complete payment experience, consider using higher-level components like [`CheckoutForm`](./components-checkout-checkout-form.md), which integrate these elements into a complete and managed flow.
@@ -0,0 +1,157 @@
1
+ # PaymentSummary
2
+
3
+ The `PaymentSummary` component displays a detailed overview of an order within the checkout flow. It lists all line items, shows any applicable trial periods or staking requirements, and calculates the total amount due. It is designed to give customers a clear and transparent breakdown of their purchase before they complete the payment.
4
+
5
+ This component works in conjunction with `ProductItem` to render individual items and can adapt its display for various scenarios, including cross-sells, upsells, and donations.
6
+
7
+ ## Props
8
+
9
+ The `PaymentSummary` component accepts the following props to customize its behavior and the information it displays.
10
+
11
+ | Prop | Type | Description |
12
+ |---|---|---|
13
+ | `items` | `TLineItemExpanded[]` | **Required.** An array of line item objects to be displayed in the summary. |
14
+ | `currency` | `TPaymentCurrency` | **Required.** The currency object used for formatting amounts. |
15
+ | `trialInDays` | `number` | The number of days for a trial period. Defaults to `0`. |
16
+ | `trialEnd` | `number` | A Unix timestamp indicating when the trial ends. |
17
+ | `billingThreshold` | `number` | The billing threshold for staking calculations. |
18
+ | `showStaking` | `boolean` | If `true`, staking information will be calculated and displayed. Defaults to `false`. |
19
+ | `onUpsell` | `(from: string, to: string) => void` | Callback function triggered when a user accepts an upsell offer. |
20
+ | `onDownsell` | `(from: string) => void` | Callback function triggered when a user reverts an upsell offer. |
21
+ | `onQuantityChange` | `(itemId: string, quantity: number) => void` | Callback function for when the quantity of an item is changed. |
22
+ | `onChangeAmount` | `(amount: number) => void` | Callback function for when a custom donation amount is changed. |
23
+ | `onApplyCrossSell` | `(crossSellId: string) => void` | Callback function to add a cross-sell item to the cart. |
24
+ | `onCancelCrossSell` | `() => void` | Callback function to remove a cross-sell item from the cart. |
25
+ | `checkoutSessionId` | `string` | The ID of the current checkout session, used to fetch available cross-sell offers. |
26
+ | `crossSellBehavior` | `'required' \| 'optional'` | Defines the behavior of the cross-sell offer. Defaults to `''` (optional). |
27
+ | `donationSettings` | `DonationSettings` | Configuration object for donation items. |
28
+ | `action` | `string` | A custom title to display at the top of the summary box (e.g., "Renew Subscription"). Defaults to "Order Summary". |
29
+ | `completed` | `boolean` | If `true`, disables interactive elements like quantity adjustments, as the checkout is complete. Defaults to `false`. |
30
+
31
+ ## Usage
32
+
33
+ The `PaymentSummary` component is typically placed within a checkout page to provide a persistent view of the order details. It must be wrapped by a `PaymentProvider` to access necessary context.
34
+
35
+ For details on setting up the provider, please see the [PaymentProvider documentation](./providers-payment-provider.md).
36
+
37
+ ### Basic Order Summary
38
+
39
+ Here is a basic example of rendering a payment summary. The component automatically calculates totals and displays item details based on the `items` and `currency` props.
40
+
41
+ ```jsx
42
+ // Note: Ensure this component is rendered within a PaymentProvider.
43
+ import React from 'react';
44
+ import { PaymentSummary } from '@blocklet/payment-react';
45
+
46
+ const items = [
47
+ {
48
+ price_id: 'price_123',
49
+ quantity: 2,
50
+ price: {
51
+ product: { name: 'Standard Plan', images: ['/logo.png'] },
52
+ type: 'recurring',
53
+ recurring: { interval: 'month', interval_count: 1 },
54
+ unit_amount: '10.00',
55
+ },
56
+ // other TLineItemExpanded properties...
57
+ },
58
+ ];
59
+
60
+ const currency = {
61
+ id: 'usd',
62
+ symbol: '$',
63
+ decimal: 2,
64
+ // other TPaymentCurrency properties...
65
+ };
66
+
67
+ function MyCheckoutPage() {
68
+ return (
69
+ <PaymentSummary
70
+ items={items}
71
+ currency={currency}
72
+ trialInDays={14}
73
+ />
74
+ );
75
+ }
76
+ ```
77
+
78
+ ### Displaying Staking and Totals
79
+
80
+ When `showStaking` is set to `true`, the component calculates and displays the required staking amount separately from the payment amount. The final total combines both values.
81
+
82
+ ```jsx
83
+ // Note: Ensure this component is rendered within a PaymentProvider.
84
+ import React from 'react';
85
+ import { PaymentSummary } from '@blocklet/payment-react';
86
+
87
+ const recurringItems = [
88
+ {
89
+ price_id: 'price_456',
90
+ quantity: 1,
91
+ price: {
92
+ product: { name: 'Pro Plan' },
93
+ type: 'recurring',
94
+ recurring: { interval: 'year', interval_count: 1, usage_type: 'licensed' },
95
+ unit_amount: '100.00',
96
+ },
97
+ },
98
+ ];
99
+ const currency = { id: 'usd', symbol: '$', decimal: 2 };
100
+
101
+ function StakingCheckoutPage() {
102
+ return (
103
+ <PaymentSummary
104
+ items={recurringItems}
105
+ currency={currency}
106
+ showStaking={true}
107
+ billingThreshold={50} // Optional: Sets a fixed staking amount
108
+ />
109
+ );
110
+ }
111
+ ```
112
+
113
+ ### Handling Cross-Sells
114
+
115
+ By providing a `checkoutSessionId`, the component can fetch and display cross-sell offers. The `crossSellBehavior` prop determines if the offer is optional or required. User interactions are handled via the `onApplyCrossSell` and `onCancelCrossSell` callbacks.
116
+
117
+ ```jsx
118
+ // Note: Ensure this component is rendered within a PaymentProvider.
119
+ import React from 'react';
120
+ import { PaymentSummary } from '@blocklet/payment-react';
121
+
122
+ const items = [
123
+ {
124
+ price_id: 'price_123',
125
+ quantity: 1,
126
+ price: { product: { name: 'Main Product' }, unit_amount: '25.00' },
127
+ },
128
+ ];
129
+ const currency = { id: 'usd', symbol: '$', decimal: 2 };
130
+
131
+ function CrossSellCheckoutPage() {
132
+ const handleApplyCrossSell = async (crossSellId) => {
133
+ console.log('Applying cross-sell:', crossSellId);
134
+ // Add logic to update the checkout session via API call
135
+ };
136
+
137
+ const handleCancelCrossSell = async () => {
138
+ console.log('Canceling cross-sell');
139
+ // Add logic to update the checkout session via API call
140
+ };
141
+
142
+ return (
143
+ <PaymentSummary
144
+ items={items}
145
+ currency={currency}
146
+ checkoutSessionId="cs_12345"
147
+ crossSellBehavior="required"
148
+ onApplyCrossSell={handleApplyCrossSell}
149
+ onCancelCrossSell={handleCancelCrossSell}
150
+ />
151
+ );
152
+ }
153
+ ```
154
+
155
+ ### Mobile Responsiveness
156
+
157
+ On mobile devices, the component automatically renders a collapsible section for the product list to save screen space. The list is initially collapsed if it contains three or more items. This behavior is handled internally using the `useMobile` hook and requires no extra configuration.