You're Invited: Meet the Socket team at BSidesSF and RSAC - April 27 - May 1.RSVP
Socket
Sign inDemoInstall
Socket

@blocklet/payment-react

Package Overview
Dependencies
Maintainers
2
Versions
332
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blocklet/payment-react

Reusable react components for payment kit v2

1.18.29
latest
Source
npm
Version published
Weekly downloads
784
58.7%
Maintainers
2
Weekly downloads
 
Created
Source

@blocklet/payment-react

npm version

A React component library for building payment flows, subscriptions, and donation systems in Blocklet applications. Seamlessly integrated with Blocklet's payment infrastructure.

Features

  • 🛠️ Pre-built UI Components: Includes checkout forms, pricing tables, donation widgets, and more
  • 🎨 Customizable Themes: Full control over styling via Material-UI themes
  • 🌍 i18n Support: Built-in localization for global audiences
  • 🧩 Lazy Loading: Optimize bundle size with dynamic imports
  • 💳 Payment Operations: Handle subscriptions, refunds, invoices, and metered billing

Installation

npm install @blocklet/payment-react 

Quick Start

Basic Integration

import { PaymentProvider, CheckoutForm } from '@blocklet/payment-react';

function App() {
  return (
    <PaymentProvider session={session} connect={connectApi}>
      <CheckoutForm 
        id="plink_xxx" // Payment Link ID
        mode="inline"  // Embed directly in your UI
        showCheckoutSummary={true}
        onChange={(state) => console.log('Checkout State:', state)}
      />
    </PaymentProvider>
  );
}

Available Components & Utilities

Core Components

  • CheckoutForm - Payment form for checkout sessions and payment links
  • CheckoutTable - Pricing table display
  • CheckoutDonate - Donation widget
  • OverdueInvoicePayment - Handle overdue invoice payments

Form Components

  • FormInput - Base form input component
  • PhoneInput - Phone number input with validation
  • AddressForm - Complete address form
  • StripeForm - Stripe payment form
  • CurrencySelector - Currency selection dropdown
  • CountrySelect - Country selection dropdown

Display Components

  • Status - Status indicator
  • Livemode - Test mode indicator
  • Switch - Toggle switch
  • ConfirmDialog - Confirmation dialog
  • Amount - Amount display with formatting
  • TruncatedText - Text truncation
  • Link - Safe navigation link

UI Components

// Loading Button with state management
import { LoadingButton } from '@blocklet/payment-react';

function PaymentButton() {
  const [loading, setLoading] = useState(false);
  
  const handlePayment = async () => {
    setLoading(true);
    try {
      await processPayment();
    } finally {
      setLoading(false);
    }
  };

  return (
    <LoadingButton
      loading={loading}
      onClick={handlePayment}
      variant="contained"
      color="primary"
    >
      Pay Now
    </LoadingButton>
  );
}

Transaction Components

  • TxLink - Transaction link
  • TxGas - Gas fee display
  • PaymentBeneficiaries - Payment beneficiaries list

History Components

  • CustomerInvoiceList - Invoice history list
  • CustomerPaymentList - Payment history list

Context Providers

  • PaymentProvider - Payment context provider
  • DonateProvider - Donation context provider
  • PaymentThemeProvider - Theme provider

Hooks

  • useSubscription - event socket callback
  • useMobile - Mobile detection

Utilities

API Client

import { api } from '@blocklet/payment-react';

// Basic usage
const response = await api.get('/api/payments');
const data = await api.post('/api/checkout', { amount: 100 });

// With query parameters
const results = await api.get('/api/invoices', { 
  params: { status: 'paid' } 
});

// With request config
const config = { 
  headers: { 'Custom-Header': 'value' }
};
const response = await api.put('/api/subscription', data, config);

Cached Request

import { CachedRequest } from '@blocklet/payment-react';

// Create a cached request
const priceRequest = new CachedRequest(
  'product-prices', 
  () => api.get('/api/prices'),
  {
    strategy: 'session',  // 'session' | 'local' | 'memory'
    ttl: 5 * 60 * 1000   // Cache for 5 minutes
  }
);

// Use the cached request
async function fetchPrices() {
  // Will use cache if available and not expired
  const prices = await priceRequest.fetch();
  
  // Force refresh cache
  const freshPrices = await priceRequest.fetch(true);
  
  return prices;
}

Date Handling

import { dayjs } from '@blocklet/payment-react';

// Format dates
const formatted = dayjs().format('YYYY-MM-DD');

// Parse timestamps
const date = dayjs(timestamp);
const unix = date.unix();

// Relative time
const relative = dayjs().from(date);

i18n Setup

// use your own translator
import { createTranslator } from '@blocklet/payment-react';

const translator = createTranslator({
  en: { 
    checkout: { title: 'Complete Payment' }
  },
  zh: { 
    checkout: { title: '完成支付' }
  }
});

// use payment-react locales
import { translations as extraTranslations } from '@blocklet/payment-react';
import merge from 'lodash/merge';

import en from './en';
import zh from './zh';

export const translations = merge(
  {
    zh,
    en,
  },
  extraTranslations
);

Lazy Loading

import { createLazyComponent } from '@blocklet/payment-react';

const LazyComponent = createLazyComponent(async () => {
  const [{ Component }, { useHook }] = await Promise.all([
    import('./Component'),
    import('./hooks')
  ]);
  
  globalThis.__DEPENDENCIES__ = { useHook };
  return Component;
});

Complete Examples

Donation Page Example

import { 
  DonateProvider, 
  CheckoutDonate,
  PaymentProvider 
} from '@blocklet/payment-react';
import { useEffect, useState } from 'react';

function DonationPage() {
  const [session, setSession] = useState(null);

  useEffect(() => {
    // Get session from your auth system
    const getSession = async () => {
      const userSession = await fetchSession();
      setSession(userSession);
    };
    getSession();
  }, []);

  return (
    <PaymentProvider session={session} connect={connectApi}>
      <DonateProvider 
        mountLocation="your-unique-donate-instance"
        description="Help locate this donation instance"
        defaultSettings={{
          btnText: 'Like',
        }}
      >
        <CheckoutDonate
          settings={{
            target: "post-123", // required, unique identifier for the donation instance
            title: "Support Author", // required, title of the donation modal
            description: "If you find this article helpful, feel free to buy me a coffee", // required, description of the donation 
            reference: "https://your-site.com/posts/123", // required, reference link of the donation 
            beneficiaries: [
              {
                address: "tip user did", // required, address of the beneficiary
                share: "100",  // required, percentage share
              },
            ],
          }}
        />

        {/* Custom donation history display */}
        <CheckoutDonate
          mode="custom"
          settings={{
            target: "post-123", // required, unique identifier for the donation instance
            title: "Support Author", // required, title of the donation modal
            description: "If you find this article helpful, feel free to buy me a coffee", // required, description of the donation 
            reference: "https://your-site.com/posts/123", // required, reference link of the donation 
            beneficiaries: [
              {
                address: "tip user did", // required, address of the beneficiary
                share: "100",  // required, percentage share
              },
            ],
          }}
        >
          {(openDonate, totalAmount, supporters, loading, settings) => (
            <div>
              <h2>Our Supporters</h2>
              {loading ? (
                <CircularProgress />
              ) : (
                <div>
                  <div>
                    Total Donations: {totalAmount} {supporters.currency?.symbol}
                  </div>
                  <div>
                    {supporters.supporters.map(supporter => (
                      <div key={supporter.id}>
                        <span>{supporter.customer?.name}</span>
                        <span>{supporter.amount_total} {supporters.currency?.symbol}</span>
                      </div>
                    ))}
                  </div>
                </div>
              )}
            </div>
          )}
        </CheckoutDonate>
      </DonateProvider>
    </PaymentProvider>
  );
}

Subscription Management Example

  • OverdueInvoicePayment component
    • Display overdue invoices for a subscription, and support batch payment

    • Props:

      • subscriptionId: [Optional] The subscription ID
      • customerId: [Optional] The customer ID or DID
      • onPaid: [Optional] Callback function called after successful payment, receives (id, currencyId, type)
      • mode: [Optional] Component mode, default or custom (default is default)
      • dialogProps: [Optional] Dialog properties, default is { open: true }
      • detailLinkOptions: [Optional] Detail link options, format: { enabled, onClick, title }
      • successToast: [Optional] Whether to show success toast, default is true
      • children: [Optional] Custom rendering function, used only when mode="custom"
    • Custom Mode:

      • children function receives two parameters:
        • handlePay: Function to start the payment process
        • data: Payment data (includes subscription, summary, invoices, subscriptionCount, detailUrl)
import {
  PaymentProvider,
  OverdueInvoicePayment,
  CustomerInvoiceList,
  Amount
} from '@blocklet/payment-react';

function SubscriptionPage({ subscriptionId }) {
  return (
    <PaymentProvider session={session}>
      {/* Handle subscription overdue payments */}
      <OverdueInvoicePayment
        subscriptionId={subscriptionId}
        onPaid={() => {
          // Refresh subscription status
          refetchSubscription();
        }}
      />
      {/* Handle customer overdue payment */}
      <OverdueInvoicePayment
        customerId={session.user.did}
        onPaid={() => {
          // Refresh customer status
          refetch();
        }}
      />

      {/* Custom Overdue Invoice Payment */}
      <OverdueInvoicePayment
        subscriptionId={subscriptionId}
        onPaid={() => {
          refetchSubscription();
        }}
        mode="custom"
      >
        {(handlePay, { subscription, summary, invoices }) => (
          <Card>
            <CardHeader title="Overdue Payments" />
            <CardContent>
              <Stack spacing={2}>
                {Object.entries(summary).map(([currencyId, info]) => (
                  <div key={currencyId}>
                    <Typography>
                      Due Amount: 
                      <Amount
                        amount={info.amount}
                      />
                      {info.currency?.symbol}
                    </Typography>
                    <Button
                      onClick={() => handlePay(info)}
                      variant="contained"
                    >
                      Pay Now
                    </Button>
                  </div>
                ))}
              </Stack>
            </CardContent>
          </Card>
        )}
      </OverdueInvoicePayment>

      {/* Display invoice history */}
      <CustomerInvoiceList
        subscription_id={subscriptionId}
        type="table"
        include_staking
        status="open,paid,uncollectible,void"
      />
    </PaymentProvider>
  );
}

Best Practices

Cache Management

// 1. Choose appropriate cache strategy
const shortLivedCache = new CachedRequest('key', fetchData, {
  strategy: 'memory',
  ttl: 60 * 1000 // 1 minute
});

const persistentCache = new CachedRequest('key', fetchData, {
  strategy: 'local',
  ttl: 24 * 60 * 60 * 1000 // 1 day
});

// 2. Clear cache when data changes
async function updateData() {
  await api.post('/api/data', newData);
  await cache.fetch(true); // Force refresh
}

// 3. Handle cache errors
try {
  const data = await cache.fetch();
} catch (err) {
  console.error('Cache error:', err);
  // Fallback to fresh data
  const fresh = await cache.fetch(true);
}

Bundle Optimization

  • Use lazy loading for non-critical components
  • Import only required components
  • Leverage code splitting with dynamic imports

Theme Consistency

  • Maintain consistent styling across components
  • Use theme provider for global style changes
  • Override styles at component level when needed

Theme Customization

Since version 1.14.22, the component includes a built-in theme provider. If you need to modify the styles of internal components, pass the theme property to override or inherit the external theme.

OptionDescription
defaultWrapped with built-in PaymentThemeProvider
inheritUse the parent component's themeProvider
PaymentThemeOptionsOverride some styles of PaymentThemeProvider
// 1. Use themeOptions
<CheckoutForm
  id="plink_xxx"
  onChange={console.info}
  theme={{
    components: {
      MuiButton: {
        styleOverrides: {
          containedPrimary: {
            backgroundColor: '#1DC1C7',
            color: '#fff',
            '&:hover': {
              backgroundColor: 'rgb(20, 135, 139)',
            },
          },
        },
      },
    },
  }}
/>

// 2. Use theme sx
<CheckoutForm
  id="plink_xxx"
  showCheckoutSummary={false}
  onChange={console.info}
  theme={{
    sx: {
      '.cko-submit-button': {
        backgroundColor: '#1DC1C7',
        color: '#fff',
        '&:hover': {
          backgroundColor: 'rgb(20, 135, 139)',
        },
      },
    },
  }}
/>

Status & Utility Components

import { 
  Status,
  Livemode,
  Switch,
  Link,
  Amount
} from '@blocklet/payment-react';

// Status indicator for payment states
<Status 
  label="active"
  color="success"
  size="small"
  sx={{ margin: 1 }}
/>

// Test mode indicator
<Livemode />

// Custom switch button
<Switch
  checked={true}
  onChange={(checked) => console.log('Switched:', checked)}
/>

// Safe navigation link
<Link to="/demo" />


## License

Apache-2.0

Keywords

react

FAQs

Package last updated on 12 Apr 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts