UNPKG

@blocklet/payment-react

Version:

Reusable react components for payment kit v2

259 lines (217 loc) 10 kB
# CheckoutDonate The `CheckoutDonate` component provides a flexible and easy-to-integrate solution for adding donation functionality to your application. It supports various display modes, from a simple button that opens a checkout dialog to a fully custom UI that you control. This component must be wrapped within both a `PaymentProvider` and a `DonateProvider` to function correctly. The `DonateProvider` manages the settings and state for donation instances within a specific scope of your application. ## How It Works The donation flow is orchestrated by a combination of `DonateProvider` and `CheckoutDonate`. Here's a high-level overview: ```d2 How It Works icon=graph-ql:diagram direction: down user: { shape: c4-person } app: { label: "Your React App" checkout-donate: { label: "CheckoutDonate" } checkout-form: { label: "CheckoutForm (in Dialog)" } } payment-api: { label: "Payment Backend API" shape: cylinder } # Initial Load app.checkout-donate -> payment-api: "Fetches settings & supporters" # Donation Flow user -> app.checkout-donate: "1. Clicks Donate" app.checkout-donate -> app.checkout-form: "2. Opens Dialog with CheckoutForm" app.checkout-form -> payment-api: "3. Processes Payment" payment-api -> app.checkout-form: "4. Returns Success" app.checkout-form -> app.checkout-donate: "5. Triggers onPaid callback" app.checkout-donate -> payment-api: "6. Refetches supporters list" payment-api -> app.checkout-donate: "7. Returns updated supporters" ``` 1. **Initialization**: `DonateProvider` fetches and caches donation settings (like preset amounts, button text) from the backend, identified by a unique `mountLocation`. 2. **Rendering**: `CheckoutDonate` renders a button or custom UI based on the retrieved settings and its props. 3. **Interaction**: When a user initiates a donation, `CheckoutDonate` opens a dialog containing a `CheckoutForm` pre-configured for the donation. 4. **Payment**: The user completes the payment through the `CheckoutForm`. 5. **Confirmation**: After a successful payment, the `onPaid` callback is triggered, and the component automatically refreshes the list of supporters. ## Provider Setup Before using `CheckoutDonate`, you must wrap your component tree with `PaymentProvider` and `DonateProvider`. ```tsx Provider Setup Example icon=logos:react import { PaymentProvider, DonateProvider, CheckoutDonate, } from '@blocklet/payment-react'; import { useSessionContext } from '../hooks/session-context'; // Your session context hook function DonationPage() { const { session, connect } = useSessionContext(); // Ensure session is loaded before rendering providers if (!session) { return <div>Loading...</div>; } return ( <PaymentProvider session={session} connect={connect}> <DonateProvider mountLocation="unique-page-identifier" // A unique key for this donation context description="Donation for my awesome blog post" defaultSettings={{ btnText: 'Support Me', }}> {/* Your CheckoutDonate component goes here */} <CheckoutDonate settings={{ target: "post-123", title: "Support the Author", description: "If you find this article helpful, feel free to buy me a coffee", reference: "https://your-site.com/posts/123", beneficiaries: [ { address: "z2qa...", share: "100", }, ], }} /> </DonateProvider> </PaymentProvider> ); } ``` For more details, see the [`DonateProvider`](./providers-donate-provider.md) documentation. ## Component Props ### `DonateProps` | Prop | Type | Description | | --- | --- | --- | | `settings` | `CheckoutDonateSettings` | **Required.** Configuration for this specific donation instance. | | `onPaid` | `(session) => void` | Optional. Callback function executed after a successful payment. | | `onError` | `(error) => void` | Optional. Callback function executed if an error occurs. | | `mode` | `'default' \| 'inline' \| 'custom'` | Optional. The rendering mode. Defaults to `'default'`. | | `livemode` | `boolean` | Optional. Overrides the `livemode` from `PaymentProvider`. | | `timeout` | `number` | Optional. Milliseconds to wait before closing the dialog after payment. Defaults to `5000`. | | `theme` | `'default' \| 'inherit' \| object` | Optional. Theme customization options. See the [Theming](./guides-theming.md) guide. | | `children` | `(openDialog, donateTotalAmount, supporters, loading, donateSettings) => React.ReactNode` | Optional. A render prop function used only when `mode="custom"`. | ### `CheckoutDonateSettings` This object is passed to the `settings` prop and defines the core details of the donation. | Property | Type | Description | | --- | --- | --- | | `target` | `string` | **Required.** A unique identifier for the donation target (e.g., a post ID, a project name). | | `title` | `string` | **Required.** The title displayed at the top of the donation dialog. | | `description` | `string` | **Required.** A short description displayed in the donation dialog. | | `reference` | `string` | **Required.** A URL related to the donation, used for reference. | | `beneficiaries` | `PaymentBeneficiary[]` | **Required.** An array of objects defining who receives the funds. Each object needs an `address` (recipient's DID) and `share` (percentage). | | `amount` | `object` | Optional. Configures donation amounts, including `presets` (e.g., `['1', '5', '10']`), a default `preset`, `minimum`, `maximum`, and whether `custom` amounts are allowed. | | `appearance` | `object` | Optional. Customizes the look and feel, including `button` (text, icon, variant) and `history` display (`'avatar'` or `'table'`). | ## Usage Examples ### Default Mode This is the simplest way to use `CheckoutDonate`. It renders a button that opens a donation dialog, along with a summary of recent supporters. ```tsx Default Donation Button icon=logos:react import { PaymentProvider, DonateProvider, CheckoutDonate, } from '@blocklet/payment-react'; import { useSessionContext } from '../hooks/session-context'; function App() { const { session, connect } = useSessionContext(); if (!session) { return <div>Loading session...</div>; } return ( <PaymentProvider session={session} connect={connect}> <DonateProvider mountLocation="blog-post-123" description="Donations for Blog Post 123" defaultSettings={{ btnText: 'Buy me a coffee', historyType: 'avatar', }}> <CheckoutDonate settings={{ target: 'post-123', title: 'Support the Author', description: 'If you found this article helpful, consider a small donation.', reference: 'https://example.com/posts/123', beneficiaries: [ { address: 'z2qa...gCLd', // Author's DID address share: '100', }, ], }} onPaid={() => { console.log('Donation successful!'); }} /> </DonateProvider> </PaymentProvider> ); } ``` ### Custom UI Mode For full control over the user interface, use `mode="custom"` and provide a render prop as the `children`. This function gives you access to the donation state, including the total amount raised and a list of supporters, allowing you to build a completely custom display. ```tsx Custom Donation UI icon=logos:react import { PaymentProvider, DonateProvider, CheckoutDonate, } from '@blocklet/payment-react'; import { useSessionContext } from '../hooks/session-context'; import { CircularProgress, Button } from '@mui/material'; function CustomDonationDisplay() { const { session, connect } = useSessionContext(); if (!session) { return <div>Loading session...</div>; } const donateSettings = { target: 'post-123', title: 'Support the Author', description: 'If you found this article helpful, consider a small donation.', reference: 'https://example.com/posts/123', beneficiaries: [ { address: 'z2qa...gCLd', // Author's DID address share: '100', }, ], }; return ( <PaymentProvider session={session} connect={connect}> <DonateProvider mountLocation="blog-post-123" description="Donations for Blog Post 123"> <CheckoutDonate mode="custom" settings={donateSettings}> {(openDonate, totalAmount, supporters, loading, settings) => ( <div style={{ border: '1px solid #ccc', padding: '16px', borderRadius: '8px' }}> <h2>Our Supporters</h2> <p>Total Donations: <strong>{totalAmount}</strong></p> <Button variant="contained" onClick={openDonate}> {settings?.appearance?.button?.text || 'Donate Now'} </Button> {loading ? ( <CircularProgress style={{ marginTop: '16px' }} /> ) : ( <ul style={{ listStyle: 'none', padding: 0, marginTop: '16px' }}> {(supporters.supporters || []).map((supporter) => ( <li key={supporter.id}> <span>{supporter.customer?.name}</span> </li> ))} </ul> )} </div> )} </CheckoutDonate> </DonateProvider> </PaymentProvider> ); } ``` The `children` function receives the following arguments: - `openDonate`: A function to manually trigger the donation dialog. - `totalAmount`: A formatted string of the total amount donated (e.g., `"125.00 T"`). - `supporters`: A `DonateHistory` object containing the `supporters` array and currency info. - `loading`: A boolean indicating if the supporter data is being fetched. - `settings`: The resolved donation settings, merged from `DonateProvider` and props.