Skip to content
171 changes: 171 additions & 0 deletions content/docs/components/payment-processing/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
---
title: Payment Processing
description: A full-screen payment processing state component that displays a loading spinner with secure transaction indicators and customizable messaging.
---

<Tabs items={['Preview', 'Code']} className="bg-transparent border-none">
<Tab value="Preview" className="border-none bg-transparent p-0 mt-3">
<PreviewComponents registryName="payment-processing">
<PaymentProcessingDemo />
</PreviewComponents>
</Tab>

<Tab value="Code" className="mt-3">
<include cwd lang="tsx" meta='title="src/components/payment-processing-demo.tsx"'>
src/components/payment-processing-demo.tsx
</include>
</Tab>
</Tabs>

## Installation

<Tabs
items={["shadcn", "billingSDK"]}
defaultValue="shadcn"
className="border-none bg-transparent"
>
<Tab value="shadcn" className="mt-3 border-none bg-transparent p-0">
<Tabs
items={["npx", "pnpm", "yarn", "bun"]}
defaultValue="npx"
groupId="installation-tabs"
>
<Tab value="npx">
```bash
npx shadcn@latest add @billingsdk/payment-processing
```
</Tab>
<Tab value="pnpm">
```bash
pnpm dlx shadcn@latest add @billingsdk/payment-processing
```
</Tab>
<Tab value="yarn">
```bash
yarn dlx shadcn@latest add @billingsdk/payment-processing
```
</Tab>
<Tab value="bun">
```bash
bunx shadcn@latest add @billingsdk/payment-processing
```
</Tab>
</Tabs>
</Tab>
<Tab value="billingSDK" className="mt-3 border-none bg-transparent p-0">
<Tabs
items={["npx", "pnpm", "yarn", "bun"]}
defaultValue="npx"
groupId="billingsdk-cli-tabs"
>
<Tab value="npx">
```bash
npx @billingsdk/cli add payment-processing
```
</Tab>
<Tab value="pnpm">
```bash
pnpm dlx @billingsdk/cli add payment-processing
```
</Tab>
<Tab value="yarn">
```bash
yarn dlx @billingsdk/cli add payment-processing
```
</Tab>
<Tab value="bun">
```bash
bunx @billingsdk/cli add payment-processing
```
</Tab>
</Tabs>
</Tab>
</Tabs>

## Usage

```tsx
import PaymentProcessing from "@/components/billingsdk/payment-processing";
```

```tsx
// Basic usage with state control
const [isProcessing, setIsProcessing] = useState(false);

async function handlePayment() {
setIsProcessing(true);

try {
// Process payment
await processPaymentAPI();
// Navigate to success page
} catch (error) {
// Handle error
} finally {
setIsProcessing(false);
}
}

<PaymentProcessing status={isProcessing} />
```

## Customization

```tsx
import { CreditCard } from "lucide-react";

<PaymentProcessing
status={true}
title="Processing Your Payment"
description="Securely connecting to payment gateway"
icon={CreditCard}
processLabel="256-bit Encryption Active"
warning="Do not refresh or close this tab"
/>
```

## Props

| Prop | Type | Required | Description |
| -------------- | ------------- | -------- | -------------------------------------------------------------------- |
| `status` | `boolean` | ❌ | Controls visibility of the processing screen (default: `true`) |
| `title` | `string` | ❌ | Main heading text (default: `"Processing Payment"`) |
| `description` | `string` | ❌ | Subtitle text below the spinner (default: `"This may take a few moments"`) |
| `icon` | `LucideIcon` | ❌ | Icon component to display with the process label (default: `Shield`) |
| `processLabel` | `string` | ❌ | Security/process indicator text (default: `"Secure Transaction"`) |
| `warning` | `string` | ❌ | Warning message at the bottom (default: `"Please do not close this window"`) |

## Features

- **Full-Screen Overlay**: Takes over the entire viewport to prevent user interaction during processing
- **Animated Spinner**: Rotating loader provides visual feedback that processing is ongoing
- **Security Indicators**: Displays trust signals like "Secure Transaction" with shield icon
- **Customizable Text**: All text elements can be customized to match your brand and context
- **Custom Icons**: Support for any Lucide React icon to match your payment provider or security messaging
- **Responsive Design**: Adapts gracefully to all screen sizes with proper spacing and typography

## Use Cases

- **Payment Submission**: Display while processing credit card transactions
- **Subscription Activation**: Show during subscription setup or plan changes
- **Payment Method Verification**: Display while validating payment information
- **Refund Processing**: Use when processing refund requests
- **Checkout Flow**: Integrate as the final step after user confirms payment

## Best Practices

1. **Always Control State**: Use a state variable to control the `status` prop
2. **Set Appropriate Timeouts**: Implement timeout handling for long-running processes
3. **Error Handling**: Always have a fallback to hide the processing screen on errors
4. **User Communication**: Update the description to reflect the current processing step
5. **Accessibility**: Ensure the processing screen is announced to screen readers

## Example

<include cwd lang="tsx" meta='title="src/components/payment-processing-demo.tsx"'>
src/components/payment-processing-demo.tsx
</include>

## Theming

The payment processing component uses standard shadcn/ui theming with CSS variables. It adapts automatically to your configured light/dark modes and respects your custom color schemes.
1 change: 1 addition & 0 deletions content/docs/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"components/payment-details-two/index",
"components/payment-success-dialog/index",
"components/payment-failure/index",
"components/payment-processing/index",
"components/payment-method-selector/index",
"components/payment-card/index",
"---Configuration---",
Expand Down
1 change: 1 addition & 0 deletions public/r/all.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@billingsdk/billing-settings",
"@billingsdk/proration-preview",
"@billingsdk/upcoming-charges",
"@billingsdk/payment-processing",
"@billingsdk/coupon",
"@billingsdk/limited-offer-dialog",
"@billingsdk/payment-failure",
Expand Down
23 changes: 23 additions & 0 deletions public/r/payment-processing.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "payment-processing",
"title": "Payment Processing",
"description": "A payment processing state card with spinner and security messaging.",
"dependencies": ["lucide-react"],
"registryDependencies": ["card", "separator", "utils"],
"files": [
{
"path": "src/registry/billingsdk/payment-processing.tsx",
"content": "import { Loader2, Shield, LucideIcon } from \"lucide-react\";\nimport { Separator } from \"@/components/ui/separator\";\n\ntype PaymentProcessingTypes = {\n status?: boolean;\n title?: string;\n description?: string;\n icon?: LucideIcon;\n processLabel?: string;\n warning?: string;\n};\n\nexport default function PaymentProcessing({\n status = true,\n title = \"Processing Payment\",\n description = \"This may take a few moments\",\n icon: Icon = Shield,\n processLabel = \"Secure Transaction\",\n warning = \"Please do not close this window\",\n}: PaymentProcessingTypes) {\n return (\n <>\n {status && (\n <div className=\"bg-background flex min-h-screen items-center justify-center p-4\">\n <div className=\"bg-card w-full max-w-sm space-y-6 rounded-xl border px-8 py-6 text-center md:p-8 lg:p-10\">\n <div className=\"space-y-4\">\n <div className=\"flex justify-center\">\n <Loader2 className=\"text-primary h-12 w-12 animate-spin\" />\n </div>\n <div className=\"space-y-2\">\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n {title}\n </h1>\n <p className=\"text-muted-foreground text-sm\">{description}</p>\n </div>\n </div>\n\n <Separator />\n\n <div className=\"space-y-2\">\n <div className=\"flex items-center justify-center gap-2 text-sm\">\n <Icon className=\"text-muted-foreground h-4 w-4\" />\n <span className=\"text-muted-foreground\">{processLabel}</span>\n </div>\n </div>\n\n <Separator />\n\n <p className=\"text-muted-foreground text-xs\">{warning}</p>\n </div>\n </div>\n )}\n </>\n );\n}\n",
"type": "registry:component",
"target": "components/billingsdk/payment-processing.tsx"
},
{
"path": "src/registry/billingsdk/demo/payment-processing-demo.tsx",
"content": "\"use client\";\n\nimport { useState } from \"react\";\nimport PaymentProcessing from \"@/registry/billingsdk/payment-processing\";\nimport { setTimeout } from \"timers\";\nimport { Button } from \"@/components/ui/button\";\n\nexport function PaymentProcessingDemo() {\n const [loading, setLoading] = useState(false);\n const handleProcessing = async () => {\n setTimeout(() => {\n setLoading(false);\n }, 8000);\n };\n\n const onClickHandler = async () => {\n setLoading(true);\n await handleProcessing();\n };\n\n return (\n <div className=\"bg-background flex min-h-screen items-center justify-center p-4\">\n <Button\n onClick={async () => await onClickHandler()}\n className={`${loading ? \"hidden\" : \"block\"}`}\n >\n Pay now!\n </Button>\n <PaymentProcessing status={loading} />\n </div>\n );\n}\n",
"type": "registry:component",
"target": "components/payment-processing-demo.tsx"
}
],
"type": "registry:block"
}
21 changes: 21 additions & 0 deletions public/r/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@billingsdk/billing-settings",
"@billingsdk/proration-preview",
"@billingsdk/upcoming-charges",
"@billingsdk/payment-processing",
"@billingsdk/coupon",
"@billingsdk/limited-offer-dialog",
"@billingsdk/payment-failure",
Expand Down Expand Up @@ -900,6 +901,26 @@
],
"dependencies": ["lucide-react", "motion"],
"registryDependencies": ["button", "utils"]
},
{
"name": "payment-processing",
"type": "registry:block",
"title": "Payment Processing",
"description": "A payment processing state card with spinner and security messaging.",
"files": [
{
"path": "src/registry/billingsdk/payment-processing.tsx",
"type": "registry:component",
"target": "components/billingsdk/payment-processing.tsx"
},
{
"path": "src/registry/billingsdk/demo/payment-processing-demo.tsx",
"type": "registry:component",
"target": "components/payment-processing-demo.tsx"
}
],
"dependencies": ["lucide-react"],
"registryDependencies": ["card", "separator", "utils"]
}
]
}
21 changes: 21 additions & 0 deletions registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@billingsdk/billing-settings",
"@billingsdk/proration-preview",
"@billingsdk/upcoming-charges",
"@billingsdk/payment-processing",
"@billingsdk/coupon",
"@billingsdk/limited-offer-dialog",
"@billingsdk/payment-failure",
Expand Down Expand Up @@ -900,6 +901,26 @@
],
"dependencies": ["lucide-react", "motion"],
"registryDependencies": ["button", "utils"]
},
{
"name": "payment-processing",
"type": "registry:block",
"title": "Payment Processing",
"description": "A payment processing state card with spinner and security messaging.",
"files": [
{
"path": "src/registry/billingsdk/payment-processing.tsx",
"type": "registry:component",
"target": "components/billingsdk/payment-processing.tsx"
},
{
"path": "src/registry/billingsdk/demo/payment-processing-demo.tsx",
"type": "registry:component",
"target": "components/payment-processing-demo.tsx"
}
],
"dependencies": ["lucide-react"],
"registryDependencies": ["card", "separator", "utils"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this component is not using card, can you remove it from registryDependencies?

}
]
}
32 changes: 32 additions & 0 deletions src/components/payment-processing-demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";

import { useState } from "react";
import PaymentProcessing from "@/registry/billingsdk/payment-processing";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally create the same component in the registry and simply export it from that file.

Please refer to the other demo files in /components and see how the main component is being imported.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright, sorry i didnt check it. i have fixed it now, can you review it again?

import { setTimeout } from "timers";
import { Button } from "@/components/ui/button";

export function PaymentProcessingDemo() {
const [loading, setLoading] = useState(false);
const handleProcessing = async () => {
setTimeout(() => {
setLoading(false);
}, 8000);
};

const onClickHandler = async () => {
setLoading(true);
await handleProcessing();
};

return (
<div className="bg-background flex min-h-screen items-center justify-center p-4">
<Button
onClick={async () => await onClickHandler()}
className={`${loading ? "hidden" : "block"}`}
>
Pay now!
</Button>
<PaymentProcessing status={loading} />
</div>
);
}
2 changes: 2 additions & 0 deletions src/mdx-components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { PricingTableEightDemo } from "@/registry/billingsdk/demo/pricing-table-
import TrialExpiryCardDemo from "@/components/trial-expiry-card-demo";
import { BillingScreenDemo } from "@/components/billing-screen-demo";
import { PaymentFailureDemo } from "./components/payment-failure-demo";
import { PaymentProcessingDemo } from "@/components/payment-processing-demo";

// use this function to get MDX components, you will need it for rendering MDX
export function getMDXComponents(components?: MDXComponents): MDXComponents {
Expand Down Expand Up @@ -104,5 +105,6 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
TrialExpiryCardDemo,
BillingScreenDemo,
PaymentFailureDemo,
PaymentProcessingDemo,
};
}
32 changes: 32 additions & 0 deletions src/registry/billingsdk/demo/payment-processing-demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use client";

import { useState } from "react";
import PaymentProcessing from "@/registry/billingsdk/payment-processing";
import { setTimeout } from "timers";
import { Button } from "@/components/ui/button";

export function PaymentProcessingDemo() {
const [loading, setLoading] = useState(false);
const handleProcessing = async () => {
setTimeout(() => {
setLoading(false);
}, 8000);
};

const onClickHandler = async () => {
setLoading(true);
await handleProcessing();
};

return (
<div className="bg-background flex min-h-screen items-center justify-center p-4">
<Button
onClick={async () => await onClickHandler()}
className={`${loading ? "hidden" : "block"}`}
>
Pay now!
</Button>
<PaymentProcessing status={loading} />
</div>
);
}
Loading
Loading