@bloque/payments-react 0.0.2

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 ADDED
@@ -0,0 +1,319 @@
1
+ # @bloque/payments-react
2
+
3
+ React wrapper for `@bloque/payments-elements` web components.
4
+
5
+ ## Installation
6
+
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
+ }
64
+ ```
65
+
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
+ server: '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
88
+
89
+ ```tsx
90
+ import { BloqueCheckout } from '@bloque/payments-react';
91
+ import type {
92
+ CheckoutConfig,
93
+ AppearanceConfig,
94
+ PaymentSubmitPayload,
95
+ } from '@bloque/payments-react';
96
+
97
+ 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
+ return (
134
+ <BloqueCheckout
135
+ config={config}
136
+ appearance={appearance}
137
+ onSubmit={handleSubmit}
138
+ onSuccess={handleSuccess}
139
+ onError={handleError}
140
+ />
141
+ );
142
+ }
143
+ ```
144
+
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
+ server: '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
+ ```
310
+
311
+ ## Payment Methods
312
+
313
+ - **Card** - Credit and debit card payments
314
+ - **PSE** - Colombian online banking system
315
+ - **Cash** - Generate receipt for cash payment at physical locations
316
+
317
+ ## License
318
+
319
+ [MIT](../../LICENSE)
@@ -0,0 +1,25 @@
1
+ import '@bloque/payments-elements';
2
+ import type { AppearanceConfig, CheckoutConfig, PaymentMethodType, PaymentSubmitPayload } from '@bloque/payments-elements';
3
+ declare global {
4
+ namespace JSX {
5
+ interface IntrinsicElements {
6
+ 'bloque-checkout': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
7
+ }
8
+ }
9
+ }
10
+ export interface BloqueCheckoutProps {
11
+ config?: CheckoutConfig;
12
+ appearance?: AppearanceConfig;
13
+ amount?: number;
14
+ availableMethods?: PaymentMethodType[];
15
+ requireEmail?: boolean;
16
+ showMethodSelector?: boolean;
17
+ onSubmit?: (payload: PaymentSubmitPayload) => Promise<void>;
18
+ onSuccess?: (event: CustomEvent<PaymentSubmitPayload>) => void;
19
+ onError?: (event: CustomEvent<PaymentSubmitPayload & {
20
+ error: string;
21
+ }>) => void;
22
+ className?: string;
23
+ style?: React.CSSProperties;
24
+ }
25
+ export declare function BloqueCheckout({ config, appearance, amount, availableMethods, requireEmail, showMethodSelector, onSubmit, onSuccess, onError, className, style, }: BloqueCheckoutProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,50 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import "@bloque/payments-elements";
3
+ import { useEffect, useRef } from "react";
4
+ function BloqueCheckout({ config, appearance, amount, availableMethods, requireEmail = true, showMethodSelector = true, onSubmit, onSuccess, onError, className, style }) {
5
+ const checkoutRef = useRef(null);
6
+ useEffect(()=>{
7
+ const element = checkoutRef.current;
8
+ if (!element) return;
9
+ if (config) element.config = config;
10
+ if (appearance) element.appearance = appearance;
11
+ if (void 0 !== amount) element.amount = amount;
12
+ if (availableMethods) element.availableMethods = availableMethods;
13
+ element.requireEmail = requireEmail;
14
+ element.showMethodSelector = showMethodSelector;
15
+ if (onSubmit) element.onSubmit = onSubmit;
16
+ }, [
17
+ config,
18
+ appearance,
19
+ amount,
20
+ availableMethods,
21
+ requireEmail,
22
+ showMethodSelector,
23
+ onSubmit
24
+ ]);
25
+ useEffect(()=>{
26
+ const element = checkoutRef.current;
27
+ if (!element) return;
28
+ const handleSuccess = (event)=>{
29
+ if (onSuccess) onSuccess(event);
30
+ };
31
+ const handleError = (event)=>{
32
+ if (onError) onError(event);
33
+ };
34
+ element.addEventListener('payment-success', handleSuccess);
35
+ element.addEventListener('payment-error', handleError);
36
+ return ()=>{
37
+ element.removeEventListener('payment-success', handleSuccess);
38
+ element.removeEventListener('payment-error', handleError);
39
+ };
40
+ }, [
41
+ onSuccess,
42
+ onError
43
+ ]);
44
+ return /*#__PURE__*/ jsx("bloque-checkout", {
45
+ ref: checkoutRef,
46
+ className: className,
47
+ style: style
48
+ });
49
+ }
50
+ export { BloqueCheckout };
@@ -0,0 +1,3 @@
1
+ export type { AppearanceConfig, CheckoutConfig, PaymentSubmitPayload, } from '@bloque/payments-elements';
2
+ export type { BloqueCheckoutProps } from './bloque-checkout';
3
+ export { BloqueCheckout } from './bloque-checkout';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { BloqueCheckout } from "./bloque-checkout.js";
2
+ export { BloqueCheckout };
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@bloque/payments-react",
3
+ "version": "0.0.2",
4
+ "description": "React wrapper for Bloque payments web components",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "keywords": [
21
+ "react",
22
+ "payments",
23
+ "checkout",
24
+ "bloque",
25
+ "colombia",
26
+ "pse",
27
+ "card",
28
+ "cash"
29
+ ],
30
+ "author": "Nestor Cortina <nexckycort@gmail.com>",
31
+ "license": "MIT",
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "provenance": true
35
+ },
36
+ "scripts": {
37
+ "build": "rslib build",
38
+ "clean": "rm -rf node_modules && rm -rf dist",
39
+ "check": "biome check --write",
40
+ "dev": "rslib build --watch",
41
+ "storybook": "storybook dev",
42
+ "typecheck": "tsgo --noEmit"
43
+ },
44
+ "dependencies": {
45
+ "@bloque/payments-elements": "workspace:*"
46
+ },
47
+ "devDependencies": {
48
+ "@rsbuild/core": "catalog:",
49
+ "@rsbuild/plugin-react": "^1.4.2",
50
+ "@rslib/core": "catalog:",
51
+ "@storybook/addon-docs": "^10.1.4",
52
+ "@storybook/addon-onboarding": "^10.1.4",
53
+ "@storybook/react": "^10.1.4",
54
+ "@types/react": "^19.2.7",
55
+ "@typescript/native-preview": "catalog:",
56
+ "react": "^19.2.1",
57
+ "storybook": "^10.1.4",
58
+ "storybook-addon-rslib": "^3.1.0",
59
+ "storybook-react-rsbuild": "^3.1.0",
60
+ "typescript": "catalog:"
61
+ },
62
+ "peerDependencies": {
63
+ "react": ">=16.9.0",
64
+ "react-dom": ">=16.9.0"
65
+ },
66
+ "homepage": "git+https://github.com/bloque-app/payments.git#readme",
67
+ "repository": {
68
+ "type": "git",
69
+ "url": "git+https://github.com/bloque-app/payments.git",
70
+ "directory": "packages/payments-react"
71
+ }
72
+ }