@payconductor-sdk-web/library-rsc 1.0.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/README.md +293 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# @payconductor-sdk-web/library-rsc
|
|
2
|
+
|
|
3
|
+
React Server Components SDK for integrating with PayConductor Payment Gateway. Optimized for Next.js App Router.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @payconductor-sdk-web/library-rsc
|
|
9
|
+
# or
|
|
10
|
+
yarn add @payconductor-sdk-web/library-rsc
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @payconductor-sdk-web/library-rsc
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Basic Usage with Next.js App Router
|
|
16
|
+
|
|
17
|
+
### 1. Create a client component for checkout
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
// components/CheckoutForm.tsx
|
|
21
|
+
"use client";
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
useElement,
|
|
25
|
+
usePayConductor,
|
|
26
|
+
type PaymentResult,
|
|
27
|
+
} from "@payconductor-sdk-web/library-rsc";
|
|
28
|
+
import { useState, useEffect } from "react";
|
|
29
|
+
|
|
30
|
+
export function CheckoutForm() {
|
|
31
|
+
const { isReady, error } = usePayConductor();
|
|
32
|
+
const { submit, confirmPayment, update } = useElement();
|
|
33
|
+
|
|
34
|
+
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
35
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
36
|
+
const [clientName, setClientName] = useState("");
|
|
37
|
+
const [clientEmail, setClientEmail] = useState("");
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
update({
|
|
41
|
+
billingDetails: {
|
|
42
|
+
name: clientName,
|
|
43
|
+
email: clientEmail,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}, [clientName, clientEmail, update]);
|
|
47
|
+
|
|
48
|
+
const handleSubmit = async (event: React.FormEvent) => {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
|
|
51
|
+
if (!isReady) return;
|
|
52
|
+
|
|
53
|
+
setIsProcessing(true);
|
|
54
|
+
setErrorMessage(null);
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
const { error: submitError } = await submit();
|
|
58
|
+
|
|
59
|
+
if (submitError) {
|
|
60
|
+
setErrorMessage(submitError.message || "Validation failed");
|
|
61
|
+
setIsProcessing(false);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const result: PaymentResult = await confirmPayment({
|
|
66
|
+
intentToken: "pi_xxx_intent_token_xxx",
|
|
67
|
+
returnUrl: window.location.href,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (result.status === "succeeded") {
|
|
71
|
+
alert("Payment successful!");
|
|
72
|
+
}
|
|
73
|
+
} catch (err: any) {
|
|
74
|
+
setErrorMessage(err.message || "Payment failed");
|
|
75
|
+
} finally {
|
|
76
|
+
setIsProcessing(false);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<form onSubmit={handleSubmit}>
|
|
82
|
+
<input
|
|
83
|
+
type="text"
|
|
84
|
+
placeholder="Full name"
|
|
85
|
+
value={clientName}
|
|
86
|
+
onChange={(e) => setClientName(e.target.value)}
|
|
87
|
+
/>
|
|
88
|
+
<input
|
|
89
|
+
type="email"
|
|
90
|
+
placeholder="Email"
|
|
91
|
+
value={clientEmail}
|
|
92
|
+
onChange={(e) => setClientEmail(e.target.value)}
|
|
93
|
+
/>
|
|
94
|
+
<button type="submit" disabled={!isReady || isProcessing}>
|
|
95
|
+
{isProcessing ? "Processing..." : "Pay now"}
|
|
96
|
+
</button>
|
|
97
|
+
{errorMessage && <div>{errorMessage}</div>}
|
|
98
|
+
{error && <div>Error: {error}</div>}
|
|
99
|
+
</form>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2. Use in a Server Component page
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// app/checkout/page.tsx
|
|
108
|
+
import { PayConductor } from "@payconductor-sdk-web/library-rsc";
|
|
109
|
+
import { CheckoutForm } from "@/components/CheckoutForm";
|
|
110
|
+
|
|
111
|
+
export default function CheckoutPage() {
|
|
112
|
+
return (
|
|
113
|
+
<main>
|
|
114
|
+
<h1>Checkout</h1>
|
|
115
|
+
<PayConductor
|
|
116
|
+
publicKey="pk_test_123"
|
|
117
|
+
intentToken="pi_test_abc123"
|
|
118
|
+
theme={{ primaryColor: "#0066ff" }}
|
|
119
|
+
locale="en-US"
|
|
120
|
+
height="500px"
|
|
121
|
+
onReady={() => console.log("Ready")}
|
|
122
|
+
onError={(err) => console.error(err)}
|
|
123
|
+
onPaymentComplete={(result) => console.log(result)}
|
|
124
|
+
>
|
|
125
|
+
<CheckoutForm />
|
|
126
|
+
</PayConductor>
|
|
127
|
+
</main>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 3. Passing server-side data
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
// app/checkout/page.tsx
|
|
136
|
+
import { PayConductor } from "@payconductor-sdk-web/library-rsc";
|
|
137
|
+
import { CheckoutForm } from "@/components/CheckoutForm";
|
|
138
|
+
import { getPaymentIntent } from "@/lib/payconductor";
|
|
139
|
+
|
|
140
|
+
export default async function CheckoutPage() {
|
|
141
|
+
// Fetch payment intent from your backend
|
|
142
|
+
const { intentToken, amount, currency } = await getPaymentIntent();
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<main>
|
|
146
|
+
<h1>Checkout - {amount} {currency}</h1>
|
|
147
|
+
<PayConductor
|
|
148
|
+
publicKey={process.env.NEXT_PUBLIC_PAYCONDUCTOR_PUBLIC_KEY!}
|
|
149
|
+
intentToken={intentToken}
|
|
150
|
+
theme={{ primaryColor: "#0066ff" }}
|
|
151
|
+
locale="en-US"
|
|
152
|
+
>
|
|
153
|
+
<CheckoutForm />
|
|
154
|
+
</PayConductor>
|
|
155
|
+
</main>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## API Reference
|
|
161
|
+
|
|
162
|
+
### `<PayConductor />`
|
|
163
|
+
|
|
164
|
+
Client-side component that initializes the payment iframe. Marked with `"use client"` for RSC compatibility.
|
|
165
|
+
|
|
166
|
+
| Prop | Type | Description |
|
|
167
|
+
|------|------|-------------|
|
|
168
|
+
| `publicKey` | `string` | Your PayConductor public key |
|
|
169
|
+
| `intentToken` | `string` | Payment intent token |
|
|
170
|
+
| `theme` | `PayConductorTheme` | Theme configuration |
|
|
171
|
+
| `locale` | `string` | Locale (e.g., 'en-US', 'pt-BR') |
|
|
172
|
+
| `height` | `string` | Iframe height (default: '500px') |
|
|
173
|
+
| `onReady` | `() => void` | Callback when iframe is ready |
|
|
174
|
+
| `onError` | `(error: Error) => void` | Error callback |
|
|
175
|
+
| `onPaymentComplete` | `(result: PaymentResult) => void` | Payment complete callback |
|
|
176
|
+
|
|
177
|
+
### `usePayConductor()`
|
|
178
|
+
|
|
179
|
+
Hook that returns frame state and configuration. Use only in Client Components.
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
"use client";
|
|
183
|
+
|
|
184
|
+
const { isReady, error, publicKey, intentToken, theme, locale } = usePayConductor();
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Property | Type | Description |
|
|
188
|
+
|----------|------|-------------|
|
|
189
|
+
| `isReady` | `boolean` | Whether iframe is ready |
|
|
190
|
+
| `error` | `string \| null` | Error message if any |
|
|
191
|
+
| `publicKey` | `string` | Public key from config |
|
|
192
|
+
| `intentToken` | `string` | Intent token from config |
|
|
193
|
+
| `theme` | `PayConductorTheme` | Theme from config |
|
|
194
|
+
| `locale` | `string` | Locale from config |
|
|
195
|
+
|
|
196
|
+
### `useElement()`
|
|
197
|
+
|
|
198
|
+
Hook that provides payment methods. Use only in Client Components.
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
"use client";
|
|
202
|
+
|
|
203
|
+
const {
|
|
204
|
+
submit,
|
|
205
|
+
confirmPayment,
|
|
206
|
+
update,
|
|
207
|
+
validate,
|
|
208
|
+
reset,
|
|
209
|
+
updateConfig,
|
|
210
|
+
updateIntentToken
|
|
211
|
+
} = useElement();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
| Method | Description |
|
|
215
|
+
|--------|-------------|
|
|
216
|
+
| `submit()` | Submits the form, returns `{ error?, paymentMethod? }` |
|
|
217
|
+
| `confirmPayment(options)` | Confirms payment with `{ intentToken, returnUrl? }` |
|
|
218
|
+
| `update(options)` | Updates billing details `{ billingDetails?: { name, email, phone, address } }` |
|
|
219
|
+
| `validate(data)` | Validates payment data |
|
|
220
|
+
| `reset()` | Resets the payment form |
|
|
221
|
+
| `updateConfig(config)` | Updates theme, locale, or paymentMethods config |
|
|
222
|
+
| `updateIntentToken(token)` | Updates the intent token |
|
|
223
|
+
|
|
224
|
+
## Theming
|
|
225
|
+
|
|
226
|
+
```tsx
|
|
227
|
+
const theme: PayConductorTheme = {
|
|
228
|
+
primaryColor: "#0066ff",
|
|
229
|
+
secondaryColor: "#5a6b7c",
|
|
230
|
+
backgroundColor: "transparent",
|
|
231
|
+
surfaceColor: "#f8fafc",
|
|
232
|
+
textColor: "#0f172a",
|
|
233
|
+
textSecondaryColor: "#64748b",
|
|
234
|
+
errorColor: "#ef4444",
|
|
235
|
+
successColor: "#22c55e",
|
|
236
|
+
warningColor: "#f59e0b",
|
|
237
|
+
borderColor: "#e2e8f0",
|
|
238
|
+
disabledColor: "#cbd5e1",
|
|
239
|
+
fontFamily: '"Poppins", sans-serif',
|
|
240
|
+
fontSize: { xs: "0.75rem", sm: "0.875rem", md: "1rem", lg: "1.125rem", xl: "1.25rem" },
|
|
241
|
+
fontWeight: { normal: 400, medium: 500, bold: 600 },
|
|
242
|
+
lineHeight: "1.5",
|
|
243
|
+
spacing: { xs: "4px", sm: "8px", md: "16px", lg: "24px", xl: "32px" },
|
|
244
|
+
borderRadius: "8px",
|
|
245
|
+
borderWidth: "1px",
|
|
246
|
+
boxShadow: "0 1px 3px 0 rgb(0 0 0 / 0.1)",
|
|
247
|
+
inputBackground: "#ffffff",
|
|
248
|
+
inputBorderColor: "#cbd5e1",
|
|
249
|
+
inputBorderRadius: "8px",
|
|
250
|
+
inputHeight: "44px",
|
|
251
|
+
inputPadding: "12px 16px",
|
|
252
|
+
buttonHeight: "48px",
|
|
253
|
+
buttonPadding: "16px 24px",
|
|
254
|
+
buttonBorderRadius: "8px",
|
|
255
|
+
transitionDuration: "0.2s",
|
|
256
|
+
};
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Types
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
type PaymentResult = {
|
|
263
|
+
paymentIntentId: string;
|
|
264
|
+
status: "succeeded" | "pending" | "failed";
|
|
265
|
+
amount: number;
|
|
266
|
+
currency: string;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
type BillingDetails = {
|
|
270
|
+
name: string;
|
|
271
|
+
email?: string;
|
|
272
|
+
phone?: string;
|
|
273
|
+
address?: {
|
|
274
|
+
line1: string;
|
|
275
|
+
line2?: string;
|
|
276
|
+
city: string;
|
|
277
|
+
state: string;
|
|
278
|
+
postalCode: string;
|
|
279
|
+
country: string;
|
|
280
|
+
};
|
|
281
|
+
};
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Differences from @payconductor-sdk-web/library-react
|
|
285
|
+
|
|
286
|
+
- Optimized for Server Components and Next.js App Router
|
|
287
|
+
- `PayConductor` component marked with `"use client"`
|
|
288
|
+
- Hooks must only be used in Client Components
|
|
289
|
+
- Allows passing server-side data (intentToken, config) directly to the component
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@payconductor-sdk-web/library-rsc",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "React Server Components SDK for PayConductor (Next.js)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "http://github.com/payconductor-ai/payconductor-sdk-web"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/payconductor-ai/payconductor-sdk-web/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/payconductor-ai/payconductor-sdk-web#readme",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "PayConductor",
|
|
22
|
+
"keywords": [
|
|
23
|
+
"payconductor",
|
|
24
|
+
"payment",
|
|
25
|
+
"gateway",
|
|
26
|
+
"react",
|
|
27
|
+
"nextjs",
|
|
28
|
+
"rsc",
|
|
29
|
+
"server-components",
|
|
30
|
+
"sdk",
|
|
31
|
+
"checkout"
|
|
32
|
+
],
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"import": "./dist/index.js",
|
|
36
|
+
"require": "./dist/index.js",
|
|
37
|
+
"types": "./dist/index.d.ts"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"react": ">=16.8.0",
|
|
45
|
+
"react-dom": ">=16.8.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/react": "^18.0.0",
|
|
49
|
+
"@types/react-dom": "^18.0.0",
|
|
50
|
+
"react": "^18.0.0",
|
|
51
|
+
"react-dom": "^18.0.0",
|
|
52
|
+
"typescript": "^5.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|