@bloque/payments-react 0.0.7 → 0.0.8

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 CHANGED
@@ -1,318 +1,38 @@
1
1
  # @bloque/payments-react
2
2
 
3
- React component that embeds the Bloque hosted checkout.
3
+ React components for integrating Bloque hosted checkout into your React application.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- # Using bun
9
- bun add @bloque/payments-react
10
-
11
- # Using pnpm
12
- pnpm add @bloque/payments-react
13
-
14
- # Using npm
15
- npm install @bloque/payments-react
16
-
17
- # Using yarn
18
- yarn add @bloque/payments-react
19
- ```
20
-
21
- ## Usage
22
-
23
- ### How it Works
24
-
25
- ```
26
- ┌─────────────────┐ ┌─────────────────┐ ┌──────────────┐
27
- │ React Component │─────▶│ Your Backend │─────▶│ Bloque API │
28
- │ (Frontend) │ │ (SDK Usage) │ │ │
29
- └─────────────────┘ └─────────────────┘ └──────────────┘
30
- ```
31
-
32
- 1. **React Component** captures payment data from user
33
- 2. **`onSubmit`** sends complete `PaymentSubmitPayload` to your backend
34
- 3. **Your Backend** uses `@bloque/payments` to process the payment
35
-
36
- ### Basic Example
37
-
38
- ```tsx
39
- import { BloqueCheckout } from '@bloque/payments-react';
40
- import type { PaymentSubmitPayload } from '@bloque/payments-react';
41
-
42
- function App() {
43
- const handleSubmit = async (payload: PaymentSubmitPayload) => {
44
- const response = await fetch('/api/payments', {
45
- method: 'POST',
46
- headers: { 'Content-Type': 'application/json' },
47
- body: JSON.stringify(payload),
48
- });
49
-
50
- if (!response.ok) {
51
- throw new Error('Payment failed');
52
- }
53
-
54
- return response.json();
55
- };
56
-
57
- return (
58
- <BloqueCheckout
59
- onSubmit={handleSubmit}
60
- requireEmail={true}
61
- />
62
- );
63
- }
8
+ pnpm install @bloque/payments-react
64
9
  ```
65
10
 
66
- **Your Backend (using `@bloque/payments`):**
67
-
68
- ```typescript
69
- import { Bloque } from '@bloque/payments';
70
-
71
- const bloque = new Bloque({
72
- apiKey: process.env.BLOQUE_API_KEY!,
73
- mode: 'production',
74
- });
75
-
76
- app.post('/api/payments', async (req, res) => {
77
- const payload = req.body;
78
-
79
- const payment = await bloque.payments.create({
80
- payment: payload,
81
- });
82
-
83
- res.json(payment);
84
- });
85
- ```
86
-
87
- ### With Configuration and Appearance
11
+ ## Quick Start
88
12
 
89
13
  ```tsx
90
14
  import { BloqueCheckout } from '@bloque/payments-react';
91
- import type {
92
- CheckoutConfig,
93
- AppearanceConfig,
94
- PaymentSubmitPayload,
95
- } from '@bloque/payments-react';
96
15
 
97
16
  function CheckoutPage() {
98
- const config: CheckoutConfig = {
99
- payment_methods: ['card', 'pse'],
100
- amount: 120_000,
101
- currency: 'COP',
102
- };
103
-
104
- const appearance: AppearanceConfig = {
105
- primaryColor: '#10b981',
106
- borderRadius: '12px',
107
- fontFamily: 'Inter, system-ui, sans-serif',
108
- };
109
-
110
- const handleSubmit = async (payload: PaymentSubmitPayload) => {
111
- const response = await fetch('/api/payments', {
112
- method: 'POST',
113
- headers: { 'Content-Type': 'application/json' },
114
- body: JSON.stringify(payload),
115
- });
116
-
117
- if (!response.ok) {
118
- throw new Error('Payment failed');
119
- }
120
-
121
- return response.json();
122
- };
123
-
124
- const handleSuccess = (event: CustomEvent<PaymentSubmitPayload>) => {
125
- console.log('Payment successful!', event.detail);
126
- window.location.href = '/success';
127
- };
128
-
129
- const handleError = (event: CustomEvent<PaymentSubmitPayload & { error: string }>) => {
130
- console.error('Payment failed:', event.detail.error);
131
- };
132
-
133
17
  return (
134
18
  <BloqueCheckout
135
- config={config}
136
- appearance={appearance}
137
- onSubmit={handleSubmit}
138
- onSuccess={handleSuccess}
139
- onError={handleError}
19
+ checkoutId="checkout_123abc"
20
+ onSuccess={(data) => {
21
+ console.log('Payment successful!', data);
22
+ }}
23
+ onError={(error) => {
24
+ console.error('Payment failed:', error);
25
+ }}
140
26
  />
141
27
  );
142
28
  }
143
29
  ```
144
30
 
145
- ### With Custom Styling
146
-
147
- ```tsx
148
- import { BloqueCheckout } from '@bloque/payments-react';
149
-
150
- function App() {
151
- return (
152
- <div className="checkout-container">
153
- <BloqueCheckout
154
- onSubmit={handleSubmit}
155
- className="custom-checkout"
156
- style={{ maxWidth: '600px', margin: '0 auto' }}
157
- />
158
- </div>
159
- );
160
- }
161
- ```
162
-
163
- ## Props
164
-
165
- ### `BloqueCheckout`
166
-
167
- | Prop | Type | Default | Description |
168
- |------|------|---------|-------------|
169
- | `config` | `CheckoutConfig` | `undefined` | Configuration object from backend SDK |
170
- | `appearance` | `AppearanceConfig` | `undefined` | Appearance customization |
171
- | `amount` | `number` | `undefined` | Payment amount (can also be set via `config.amount`) |
172
- | `availableMethods` | `PaymentMethodType[]` | `['card', 'pse', 'cash']` | Available payment methods |
173
- | `requireEmail` | `boolean` | `true` | Whether email is required for card payments |
174
- | `showMethodSelector` | `boolean` | `true` | Whether to show the payment method selector |
175
- | `onSubmit` | `function` | `undefined` | Function called when user submits payment |
176
- | `onSuccess` | `function` | `undefined` | Event handler for successful payment |
177
- | `onError` | `function` | `undefined` | Event handler for payment errors |
178
- | `className` | `string` | `undefined` | CSS class name |
179
- | `style` | `React.CSSProperties` | `undefined` | Inline styles |
180
-
181
- ### `CheckoutConfig`
182
-
183
- ```typescript
184
- interface CheckoutConfig {
185
- payment_methods?: PaymentMethodType[];
186
- amount?: number;
187
- currency?: string;
188
- }
189
- ```
190
-
191
- ### `AppearanceConfig`
192
-
193
- ```typescript
194
- interface AppearanceConfig {
195
- primaryColor?: string;
196
- borderRadius?: string;
197
- fontFamily?: string;
198
- }
199
- ```
200
-
201
- ## TypeScript
202
-
203
- The package includes full TypeScript definitions with discriminated union types for type safety:
204
-
205
- ```typescript
206
- import type {
207
- BloqueCheckoutProps,
208
- PaymentSubmitPayload,
209
- CheckoutConfig,
210
- AppearanceConfig,
211
- } from '@bloque/payments-react';
212
-
213
- // PaymentSubmitPayload is a discriminated union type
214
- // TypeScript automatically narrows the type based on the 'type' field
215
- const handleSubmit = async (payload: PaymentSubmitPayload) => {
216
- // Type narrowing example
217
- switch (payload.type) {
218
- case 'card':
219
- // payload.data is CardPaymentFormData
220
- console.log('Card ending in:', payload.data.cardNumber.slice(-4));
221
- break;
222
- case 'pse':
223
- // payload.data is PSEPaymentFormData
224
- console.log('Bank:', payload.data.bankCode);
225
- break;
226
- case 'cash':
227
- // payload.data is CashPaymentFormData
228
- console.log('Name:', payload.data.fullName);
229
- break;
230
- }
231
-
232
- // Send complete payload to your backend
233
- const response = await fetch('/api/payments', {
234
- method: 'POST',
235
- headers: { 'Content-Type': 'application/json' },
236
- body: JSON.stringify(payload),
237
- });
238
-
239
- return response.json();
240
- };
241
- ```
242
-
243
- ## Events
244
-
245
- ### `onSubmit`
246
-
247
- Called when the user submits a payment form. Send the complete payload to your backend, which will use `@bloque/payments` to process the payment.
248
-
249
- ```typescript
250
- onSubmit?: (payload: PaymentSubmitPayload) => Promise<void>;
251
- ```
252
-
253
- **Example:**
254
- ```typescript
255
- const handleSubmit = async (payload: PaymentSubmitPayload) => {
256
- const response = await fetch('/api/payments', {
257
- method: 'POST',
258
- headers: { 'Content-Type': 'application/json' },
259
- body: JSON.stringify(payload),
260
- });
261
-
262
- if (!response.ok) throw new Error('Payment failed');
263
- return response.json();
264
- };
265
- ```
266
-
267
- **Type definition:**
268
- ```typescript
269
- type PaymentSubmitPayload =
270
- | { type: 'card'; data: CardPaymentFormData }
271
- | { type: 'pse'; data: PSEPaymentFormData }
272
- | { type: 'cash'; data: CashPaymentFormData };
273
- ```
274
-
275
- **Your backend should:**
276
- ```typescript
277
- import { Bloque } from '@bloque/payments';
278
-
279
- const bloque = new Bloque({
280
- apiKey: process.env.BLOQUE_API_KEY!,
281
- mode: 'production',
282
- });
283
-
284
- app.post('/api/payments', async (req, res) => {
285
- const payload = req.body;
286
-
287
- const payment = await bloque.payments.create({
288
- payment: payload,
289
- });
290
-
291
- res.json(payment);
292
- });
293
- ```
294
-
295
- ### `onSuccess`
296
-
297
- Fired when the payment is successfully processed.
298
-
299
- ```typescript
300
- onSuccess?: (event: CustomEvent<PaymentSubmitPayload>) => void;
301
- ```
302
-
303
- ### `onError`
304
-
305
- Fired when payment processing fails.
306
-
307
- ```typescript
308
- onError?: (event: CustomEvent<PaymentSubmitPayload & { error: string }>) => void;
309
- ```
31
+ ## Documentation
310
32
 
311
- ## Payment Methods
33
+ For complete documentation, examples, and API reference, visit:
312
34
 
313
- - **Card** - Credit and debit card payments
314
- - **PSE** - Colombian online banking system
315
- - **Cash** - Generate receipt for cash payment at physical locations
35
+ **[https://docs.bloque.app/pay](https://docs.bloque.app/pay)**
316
36
 
317
37
  ## License
318
38
 
@@ -1,123 +1,42 @@
1
- export type CheckoutMode = 'sandbox' | 'production';
2
- export type CheckoutLang = 'es' | 'en';
3
- export interface SDKInitOptions {
1
+ import { type BloqueCheckoutOptions } from '@bloque/payments-core';
2
+ export interface BloqueCheckoutProps extends Omit<BloqueCheckoutOptions, 'checkoutId'> {
4
3
  /**
5
- * Your Bloque public API key
4
+ * The checkout ID returned from your backend after creating a checkout session
6
5
  */
7
- publicApiKey: string;
6
+ checkoutId: string;
8
7
  /**
9
- * Operation mode: 'sandbox' or 'production'. Default: 'production'
8
+ * Additional CSS class name for the container div
10
9
  */
11
- mode?: CheckoutMode;
10
+ className?: string;
12
11
  /**
13
- * Default language for all components
12
+ * Additional inline styles for the container div
14
13
  */
15
- lang?: CheckoutLang;
14
+ style?: React.CSSProperties;
16
15
  }
17
16
  /**
18
- * Initialize the Bloque Payments SDK with global configuration.
19
- * This allows you to set the publicApiKey and mode once, instead of
20
- * passing them to every component.
17
+ * BloqueCheckout React component
18
+ *
19
+ * This component renders an iframe with the Bloque hosted checkout page.
21
20
  *
22
21
  * @example
23
22
  * ```tsx
24
- * import { init } from '@bloque/payments-react';
23
+ * import { BloqueCheckout } from '@bloque/payments-react';
25
24
  *
26
- * init({
27
- * publicApiKey: 'pk_test_xxx',
28
- * mode: 'sandbox',
29
- * });
25
+ * function MyCheckout() {
26
+ * return (
27
+ * <BloqueCheckout
28
+ * checkoutId="checkout_123abc"
29
+ * onSuccess={(data) => {
30
+ * console.log('Payment successful!', data);
31
+ * }}
32
+ * onError={(error) => {
33
+ * console.error('Payment failed:', error);
34
+ * }}
35
+ * />
36
+ * );
37
+ * }
30
38
  * ```
31
39
  */
32
- export declare function init(options: SDKInitOptions): void;
33
- /**
34
- * Get the current global configuration.
35
- * Returns null if init() has not been called.
36
- */
37
- export declare function getConfig(): SDKInitOptions | null;
38
- export interface PaymentResult {
39
- payment_id: string;
40
- status: 'approved' | 'pending' | 'rejected';
41
- message: string;
42
- amount: number;
43
- currency: string;
44
- reference: string;
45
- created_at: string;
46
- }
47
- export interface PaymentError {
48
- message: string;
49
- data?: unknown;
50
- type: string;
51
- }
52
- export interface AppearanceConfig {
53
- /**
54
- * Primary color (hex). Example: '#4f46e5'
55
- */
56
- primaryColor?: string;
57
- /**
58
- * Border radius. Example: '8px'
59
- */
60
- borderRadius?: string;
61
- /**
62
- * Font family. Example: 'Inter, system-ui, sans-serif'
63
- */
64
- fontFamily?: string;
65
- }
66
- export interface CheckoutConfig {
67
- /**
68
- * The payment amount in USD (required)
69
- */
70
- amount: number;
71
- webhookUrl?: string;
72
- /**
73
- * Require email in the card form. Default: true
74
- */
75
- requireEmail?: boolean;
76
- }
77
- export interface BloqueCheckoutProps {
78
- /**
79
- * Checkout configuration with amount and optional settings
80
- */
81
- config: CheckoutConfig;
82
- /**
83
- * Appearance customization (colors, fonts, etc.)
84
- */
85
- appearance?: AppearanceConfig;
86
- /**
87
- * Your Bloque public API key. Optional if init() was called.
88
- */
89
- publicApiKey?: string;
90
- /**
91
- * Language: 'es' (Spanish) or 'en' (English). Default: 'es'
92
- */
93
- lang?: CheckoutLang;
94
- /**
95
- * Operation mode: 'sandbox' or 'production'. Default: 'production'
96
- */
97
- mode?: CheckoutMode;
98
- /**
99
- * Callback when payment is successful
100
- */
101
- onSuccess?: (result: PaymentResult) => void;
102
- /**
103
- * Callback when payment fails
104
- */
105
- onError?: (error: PaymentError) => void;
106
- /**
107
- * Additional CSS class name
108
- */
109
- className?: string;
110
- /**
111
- * Additional inline styles
112
- */
113
- style?: React.CSSProperties;
114
- /**
115
- * iframe width. Default: '100%'
116
- */
117
- width?: string | number;
118
- /**
119
- * iframe height. Default: '600px'
120
- */
121
- height?: string | number;
122
- }
123
- export declare function BloqueCheckout({ config, appearance, publicApiKey, lang, mode, onSuccess, onError, className, style, width, height, }: BloqueCheckoutProps): import("react/jsx-runtime").JSX.Element;
40
+ export declare function BloqueCheckout({ checkoutId, publicApiKey, mode, checkoutUrl, appearance, onReady, onSuccess, onError, onPending, iframeStyles, className, style, }: BloqueCheckoutProps): import("react/jsx-runtime").JSX.Element;
41
+ export type { AppearanceConfig, BloqueCheckoutOptions, BloqueInitOptions, PaymentResult, } from '@bloque/payments-core';
42
+ export { BloqueCheckout as BloqueCheckoutCore, init, } from '@bloque/payments-core';
@@ -1,84 +1,45 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef } from "react";
3
- const CHECKOUT_BASE_URL = 'https://payments.bloque.app';
4
- let globalConfig = null;
5
- function init(options) {
6
- globalConfig = options;
7
- }
8
- function getConfig() {
9
- return globalConfig;
10
- }
11
- function buildCheckoutUrl(props) {
12
- const params = new URLSearchParams();
13
- params.set('amount', props.amount.toString());
14
- params.set('publicApiKey', props.publicApiKey);
15
- params.set('lang', props.lang);
16
- params.set('mode', props.mode);
17
- params.set('requireEmail', props.requireEmail.toString());
18
- if (props.webhookUrl) params.set('webhookUrl', props.webhookUrl);
19
- if (props.appearance?.primaryColor) params.set('primaryColor', props.appearance.primaryColor);
20
- if (props.appearance?.borderRadius) params.set('borderRadius', props.appearance.borderRadius);
21
- if (props.appearance?.fontFamily) params.set('fontFamily', props.appearance.fontFamily);
22
- return `${CHECKOUT_BASE_URL}/?${params.toString()}`;
23
- }
24
- function BloqueCheckout({ config, appearance, publicApiKey, lang, mode, onSuccess, onError, className, style, width = '100%', height = '600px' }) {
25
- const iframeRef = useRef(null);
26
- const onSuccessRef = useRef(onSuccess);
27
- const onErrorRef = useRef(onError);
28
- const resolvedPublicApiKey = publicApiKey ?? globalConfig?.publicApiKey;
29
- const resolvedMode = mode ?? globalConfig?.mode ?? 'production';
30
- const resolvedLang = lang ?? globalConfig?.lang ?? 'es';
31
- if (!resolvedPublicApiKey) throw new Error('BloqueCheckout: publicApiKey is required. Either pass it as a prop or call init() first.');
2
+ import { BloqueCheckout, init } from "@bloque/payments-core";
3
+ import { useEffect, useRef } from "react";
4
+ function bloque_checkout_BloqueCheckout({ checkoutId, publicApiKey, mode, checkoutUrl, appearance, onReady, onSuccess, onError, onPending, iframeStyles, className, style }) {
5
+ const containerRef = useRef(null);
6
+ const checkoutRef = useRef(null);
32
7
  useEffect(()=>{
33
- onSuccessRef.current = onSuccess;
34
- onErrorRef.current = onError;
35
- }, [
36
- onSuccess,
37
- onError
38
- ]);
39
- const checkoutUrl = useMemo(()=>buildCheckoutUrl({
40
- amount: config.amount,
41
- publicApiKey: resolvedPublicApiKey,
42
- lang: resolvedLang,
43
- mode: resolvedMode,
44
- requireEmail: config.requireEmail ?? true,
45
- webhookUrl: config.webhookUrl,
46
- appearance
47
- }), [
48
- config.amount,
49
- config.requireEmail,
50
- config.webhookUrl,
51
- resolvedPublicApiKey,
52
- resolvedLang,
53
- resolvedMode,
54
- appearance
55
- ]);
56
- const handleMessage = useCallback((event)=>{
57
- if (event.origin !== CHECKOUT_BASE_URL) return;
58
- const { type, data, error } = event.data || {};
59
- if ('payment-result' === type && onSuccessRef.current) onSuccessRef.current(data);
60
- if ('payment-error' === type && onErrorRef.current) onErrorRef.current(error);
61
- }, []);
62
- useEffect(()=>{
63
- window.addEventListener('message', handleMessage);
8
+ if (!containerRef.current) return;
9
+ const checkout = new BloqueCheckout({
10
+ checkoutId,
11
+ publicApiKey,
12
+ mode,
13
+ checkoutUrl,
14
+ appearance,
15
+ onReady,
16
+ onSuccess,
17
+ onError,
18
+ onPending,
19
+ iframeStyles
20
+ });
21
+ const iframe = checkout.createIframe();
22
+ containerRef.current.appendChild(iframe);
23
+ checkoutRef.current = checkout;
64
24
  return ()=>{
65
- window.removeEventListener('message', handleMessage);
25
+ checkout.destroy();
66
26
  };
67
27
  }, [
68
- handleMessage
28
+ checkoutId,
29
+ publicApiKey,
30
+ mode,
31
+ checkoutUrl,
32
+ appearance,
33
+ onReady,
34
+ onSuccess,
35
+ onError,
36
+ onPending,
37
+ iframeStyles
69
38
  ]);
70
- return /*#__PURE__*/ jsx("iframe", {
71
- ref: iframeRef,
72
- src: checkoutUrl,
73
- width: width,
74
- height: height,
39
+ return /*#__PURE__*/ jsx("div", {
40
+ ref: containerRef,
75
41
  className: className,
76
- style: {
77
- border: 'none',
78
- ...style
79
- },
80
- title: "Bloque Checkout",
81
- allow: "payment"
42
+ style: style
82
43
  });
83
44
  }
84
- export { BloqueCheckout, getConfig, init };
45
+ export { bloque_checkout_BloqueCheckout as BloqueCheckout, BloqueCheckout as BloqueCheckoutCore, init };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export type { AppearanceConfig, BloqueCheckoutProps, CheckoutConfig, CheckoutLang, CheckoutMode, PaymentError, PaymentResult, SDKInitOptions, } from './bloque-checkout';
2
- export { BloqueCheckout, getConfig, init } from './bloque-checkout';
1
+ export type { AppearanceConfig, BloqueCheckoutOptions, BloqueCheckoutProps, BloqueInitOptions, PaymentResult, } from './bloque-checkout';
2
+ export { BloqueCheckout, BloqueCheckoutCore, init, } from './bloque-checkout';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { BloqueCheckout, getConfig, init } from "./bloque-checkout.js";
2
- export { BloqueCheckout, getConfig, init };
1
+ import { BloqueCheckout, BloqueCheckoutCore, init } from "./bloque-checkout.js";
2
+ export { BloqueCheckout, BloqueCheckoutCore, init };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloque/payments-react",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "React wrapper for Bloque payments web components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -33,6 +33,9 @@
33
33
  "access": "public",
34
34
  "provenance": true
35
35
  },
36
+ "dependencies": {
37
+ "@bloque/payments-core": "0.0.8"
38
+ },
36
39
  "peerDependencies": {
37
40
  "react": ">=16.9.0",
38
41
  "react-dom": ">=16.9.0"