bison-web-components 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/LICENSE +21 -0
- package/README.md +749 -0
- package/api.js +659 -0
- package/bison-operator-payments.js +1913 -0
- package/bison_logo.png +0 -0
- package/bison_logo_green.png +0 -0
- package/bison_logo_green.svg +103 -0
- package/bison_logo_white.svg +68 -0
- package/component.js +48 -0
- package/demo-payments.html +275 -0
- package/index.html +199 -0
- package/operator-bank-account.js +1193 -0
- package/operator-management.js +823 -0
- package/operator-onboarding.js +3750 -0
- package/operator-payment.js +2404 -0
- package/operator-underwriting.js +1473 -0
- package/package.json +14 -0
- package/test.js +3 -0
- package/test.mjs +3 -0
- package/theme.css +312 -0
- package/wio-bank-account.js +536 -0
- package/wio-onboarding.js +3981 -0
- package/wio-payment-linking.js +2054 -0
- package/wio-payment.js +579 -0
package/README.md
ADDED
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
# Operator Onboarding Web Component
|
|
2
|
+
|
|
3
|
+
A complete, self-contained web component for operator onboarding with 4-step stepper form, file uploads, validations, and success page.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<script src="https://cdn.jsdelivr.net/npm/web-components-moov@1.0.17/component.js"></script>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
### Minimal Setup (No Callbacks)
|
|
14
|
+
The simplest way to use the component:
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<script src="https://cdn.jsdelivr.net/npm/web-components-moov@1.0.17/component.js"></script>
|
|
18
|
+
<operator-onboarding></operator-onboarding>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
When submitted, form data is automatically logged to console and success page is shown.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
The component can be configured with optional attributes for API integration:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<operator-onboarding
|
|
31
|
+
api-base-url="https://your-api-domain.com"
|
|
32
|
+
embeddable-key="your-embeddable-key">
|
|
33
|
+
</operator-onboarding>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Attributes
|
|
37
|
+
|
|
38
|
+
| Attribute | Type | Default | Description |
|
|
39
|
+
|-----------|------|---------|-------------|
|
|
40
|
+
| `api-base-url` | `String` | `https://bison-jib-development.azurewebsites.net` | Base URL for API endpoints |
|
|
41
|
+
| `embeddable-key` | `String` | Default key provided | Authentication key for API requests |
|
|
42
|
+
| `on-success` | `String` | - | Name of global function to call on success |
|
|
43
|
+
| `on-error` | `String` | - | Name of global function to call on error |
|
|
44
|
+
| `on-load` | `String` | - | JSON string or global variable name for initial data |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Form Flow
|
|
49
|
+
|
|
50
|
+
The onboarding process consists of a 4-step stepper form:
|
|
51
|
+
|
|
52
|
+
1. **Business Details** - Company information and address
|
|
53
|
+
2. **Representatives** (Optional) - Add business representatives
|
|
54
|
+
3. **Bank Account** - Link bank account details
|
|
55
|
+
4. **Underwriting** - Upload required documents
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Form Steps in Detail
|
|
60
|
+
|
|
61
|
+
### Step 1: Business Details
|
|
62
|
+
- Business name *
|
|
63
|
+
- Doing Business As (DBA) *
|
|
64
|
+
- EIN (Employer Identification Number) * (auto-formatted as XX-XXXXXXX)
|
|
65
|
+
- Business website (auto-normalized to include https://)
|
|
66
|
+
- Business phone * (auto-formatted as (555) 123-4567)
|
|
67
|
+
- Business email *
|
|
68
|
+
- Full address * (street, city, state, ZIP)
|
|
69
|
+
|
|
70
|
+
### Step 2: Representatives (Optional)
|
|
71
|
+
- Add/remove multiple representatives
|
|
72
|
+
- Full CRUD interface
|
|
73
|
+
- Each representative requires:
|
|
74
|
+
- First name, last name *
|
|
75
|
+
- Job title *
|
|
76
|
+
- Phone * (auto-formatted)
|
|
77
|
+
- Email *
|
|
78
|
+
- Date of birth *
|
|
79
|
+
- Full address * (street, city, state, ZIP)
|
|
80
|
+
- Can skip entire step if no representatives to add
|
|
81
|
+
|
|
82
|
+
### Step 3: Bank Account
|
|
83
|
+
- Account holder name *
|
|
84
|
+
- Account type * (checking/savings)
|
|
85
|
+
- Routing number * (9 digits)
|
|
86
|
+
- Account number * (4-17 digits)
|
|
87
|
+
|
|
88
|
+
### Step 4: Underwriting
|
|
89
|
+
- Upload supporting documents * (required)
|
|
90
|
+
- Drag-and-drop or browse file selection
|
|
91
|
+
- Maximum 10 files
|
|
92
|
+
- Maximum 10MB per file
|
|
93
|
+
- Accepted formats: PDF, JPG, JPEG, PNG, DOC, DOCX
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Pre-populating Form Data
|
|
98
|
+
|
|
99
|
+
### Method 1: Direct Property Assignment (Recommended)
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
const component = document.querySelector('operator-onboarding');
|
|
103
|
+
|
|
104
|
+
// Pre-populate with existing data
|
|
105
|
+
component.onLoad = {
|
|
106
|
+
businessDetails: {
|
|
107
|
+
businessName: 'Acme Corp',
|
|
108
|
+
doingBusinessAs: 'Acme',
|
|
109
|
+
ein: '12-3456789',
|
|
110
|
+
businessWebsite: 'https://acme.com',
|
|
111
|
+
businessPhoneNumber: '5551234567',
|
|
112
|
+
businessEmail: 'contact@acme.com',
|
|
113
|
+
BusinessAddress1: '123 Main St',
|
|
114
|
+
businessCity: 'San Francisco',
|
|
115
|
+
businessState: 'CA',
|
|
116
|
+
businessPostalCode: '94105'
|
|
117
|
+
},
|
|
118
|
+
representatives: [
|
|
119
|
+
{
|
|
120
|
+
representativeFirstName: 'John',
|
|
121
|
+
representativeLastName: 'Doe',
|
|
122
|
+
representativeJobTitle: 'CEO',
|
|
123
|
+
representativePhone: '5559876543',
|
|
124
|
+
representativeEmail: 'john@company.com',
|
|
125
|
+
representativeDateOfBirth: '1980-01-15',
|
|
126
|
+
representativeAddress: '456 Oak Ave',
|
|
127
|
+
representativeCity: 'San Francisco',
|
|
128
|
+
representativeState: 'CA',
|
|
129
|
+
representativeZip: '94105'
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
underwriting: {
|
|
133
|
+
underwritingDocuments: [] // Can be pre-populated with File objects
|
|
134
|
+
},
|
|
135
|
+
bankDetails: {
|
|
136
|
+
bankAccountHolderName: 'Acme Corp',
|
|
137
|
+
bankAccountType: 'checking',
|
|
138
|
+
bankRoutingNumber: '123456789',
|
|
139
|
+
bankAccountNumber: '987654321'
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Method 2: HTML Attribute with JSON
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<operator-onboarding on-load='{"businessDetails":{"businessName":"Acme Corp"}}'></operator-onboarding>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Method 3: HTML Attribute with Global Variable
|
|
151
|
+
|
|
152
|
+
```html
|
|
153
|
+
<script>
|
|
154
|
+
const initialData = {
|
|
155
|
+
businessDetails: {
|
|
156
|
+
businessName: 'Acme Corp',
|
|
157
|
+
businessEmail: 'test@company.com'
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
</script>
|
|
161
|
+
|
|
162
|
+
<operator-onboarding on-load="initialData"></operator-onboarding>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Advanced Usage with Callbacks
|
|
168
|
+
|
|
169
|
+
### Method 1: Direct Property Assignment (Recommended for Frameworks)
|
|
170
|
+
|
|
171
|
+
**Perfect for React, Vue, Angular, and vanilla JavaScript:**
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
const component = document.querySelector('operator-onboarding');
|
|
175
|
+
|
|
176
|
+
// Success callback
|
|
177
|
+
component.onSuccess = (formData) => {
|
|
178
|
+
console.log('Onboarding complete!', formData);
|
|
179
|
+
|
|
180
|
+
// Send to your backend
|
|
181
|
+
fetch('/api/operators/onboard', {
|
|
182
|
+
method: 'POST',
|
|
183
|
+
headers: { 'Content-Type': 'application/json' },
|
|
184
|
+
body: JSON.stringify(formData)
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Close your modal
|
|
188
|
+
closeModal();
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// Error callback
|
|
192
|
+
component.onError = (errorData) => {
|
|
193
|
+
console.error('Onboarding error:', errorData);
|
|
194
|
+
|
|
195
|
+
if (errorData.action === 'resubmit') {
|
|
196
|
+
// User clicked resubmit button
|
|
197
|
+
console.log('User wants to retry submission');
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Method 2: HTML Attribute
|
|
203
|
+
|
|
204
|
+
Good for simple cases with global functions:
|
|
205
|
+
|
|
206
|
+
```html
|
|
207
|
+
<operator-onboarding
|
|
208
|
+
on-success="handleSuccess"
|
|
209
|
+
on-error="handleError">
|
|
210
|
+
</operator-onboarding>
|
|
211
|
+
|
|
212
|
+
<script>
|
|
213
|
+
function handleSuccess(data) {
|
|
214
|
+
console.log('Success!', data);
|
|
215
|
+
closeModal();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function handleError(errorData) {
|
|
219
|
+
console.error('Error:', errorData);
|
|
220
|
+
}
|
|
221
|
+
</script>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Method 3: Event Listeners
|
|
225
|
+
|
|
226
|
+
Listen to custom events:
|
|
227
|
+
|
|
228
|
+
```javascript
|
|
229
|
+
// Success event
|
|
230
|
+
component.addEventListener('formComplete', (event) => {
|
|
231
|
+
const formData = event.detail;
|
|
232
|
+
console.log('Form completed!', formData);
|
|
233
|
+
closeModal();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Submission failure event
|
|
237
|
+
component.addEventListener('submissionFailed', (event) => {
|
|
238
|
+
const errorData = event.detail;
|
|
239
|
+
console.error('Submission failed:', errorData);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## React Integration
|
|
246
|
+
|
|
247
|
+
### Recommended Pattern (Using useRef)
|
|
248
|
+
|
|
249
|
+
```jsx
|
|
250
|
+
import { useEffect, useRef } from 'react';
|
|
251
|
+
|
|
252
|
+
function OnboardingModal({ isOpen, onClose }) {
|
|
253
|
+
const componentRef = useRef(null);
|
|
254
|
+
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (componentRef.current) {
|
|
257
|
+
// Success handler
|
|
258
|
+
componentRef.current.onSuccess = (data) => {
|
|
259
|
+
console.log('Onboarding complete:', data);
|
|
260
|
+
|
|
261
|
+
// Send to API
|
|
262
|
+
fetch('/api/onboard', {
|
|
263
|
+
method: 'POST',
|
|
264
|
+
body: JSON.stringify(data)
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
onClose();
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// Error handler
|
|
271
|
+
componentRef.current.onError = (errorData) => {
|
|
272
|
+
console.error('Error:', errorData);
|
|
273
|
+
// Handle errors appropriately
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}, [onClose]);
|
|
277
|
+
|
|
278
|
+
if (!isOpen) return null;
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<div className="modal">
|
|
282
|
+
<operator-onboarding
|
|
283
|
+
ref={componentRef}
|
|
284
|
+
api-base-url="https://your-api.com"
|
|
285
|
+
embeddable-key="your-key">
|
|
286
|
+
</operator-onboarding>
|
|
287
|
+
</div>
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### With Pre-populated Data
|
|
293
|
+
|
|
294
|
+
```jsx
|
|
295
|
+
function EditOperatorModal({ operatorId, isOpen, onClose }) {
|
|
296
|
+
const componentRef = useRef(null);
|
|
297
|
+
const [initialData, setInitialData] = useState(null);
|
|
298
|
+
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (isOpen && operatorId) {
|
|
301
|
+
// Fetch existing operator data
|
|
302
|
+
fetch(`/api/operators/${operatorId}`)
|
|
303
|
+
.then(res => res.json())
|
|
304
|
+
.then(data => setInitialData(data));
|
|
305
|
+
}
|
|
306
|
+
}, [isOpen, operatorId]);
|
|
307
|
+
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
if (componentRef.current) {
|
|
310
|
+
// Pre-populate form
|
|
311
|
+
if (initialData) {
|
|
312
|
+
componentRef.current.onLoad = initialData;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Set success handler
|
|
316
|
+
componentRef.current.onSuccess = (updatedData) => {
|
|
317
|
+
fetch(`/api/operators/${operatorId}`, {
|
|
318
|
+
method: 'PUT',
|
|
319
|
+
body: JSON.stringify(updatedData)
|
|
320
|
+
});
|
|
321
|
+
onClose();
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
}, [initialData, operatorId, onClose]);
|
|
325
|
+
|
|
326
|
+
if (!isOpen) return null;
|
|
327
|
+
|
|
328
|
+
return (
|
|
329
|
+
<div className="modal">
|
|
330
|
+
<operator-onboarding ref={componentRef} />
|
|
331
|
+
</div>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## Data Structure
|
|
339
|
+
|
|
340
|
+
The component returns a complete data object:
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
{
|
|
344
|
+
"businessDetails": {
|
|
345
|
+
"businessName": "Acme Corp",
|
|
346
|
+
"doingBusinessAs": "Acme",
|
|
347
|
+
"ein": "12-3456789",
|
|
348
|
+
"businessWebsite": "https://acme.com",
|
|
349
|
+
"businessPhoneNumber": "(555) 123-4567",
|
|
350
|
+
"businessEmail": "contact@acme.com",
|
|
351
|
+
"BusinessAddress1": "123 Main St",
|
|
352
|
+
"businessCity": "San Francisco",
|
|
353
|
+
"businessState": "CA",
|
|
354
|
+
"businessPostalCode": "94105"
|
|
355
|
+
},
|
|
356
|
+
"representatives": [
|
|
357
|
+
{
|
|
358
|
+
"id": "uuid-here",
|
|
359
|
+
"representativeFirstName": "John",
|
|
360
|
+
"representativeLastName": "Doe",
|
|
361
|
+
"representativeJobTitle": "CEO",
|
|
362
|
+
"representativePhone": "(555) 987-6543",
|
|
363
|
+
"representativeEmail": "john@company.com",
|
|
364
|
+
"representativeDateOfBirth": "1980-01-15",
|
|
365
|
+
"representativeAddress": "456 Oak Ave",
|
|
366
|
+
"representativeCity": "San Francisco",
|
|
367
|
+
"representativeState": "CA",
|
|
368
|
+
"representativeZip": "94105"
|
|
369
|
+
}
|
|
370
|
+
],
|
|
371
|
+
"underwriting": {
|
|
372
|
+
"underwritingDocuments": [
|
|
373
|
+
// Array of File objects
|
|
374
|
+
File { name: "document.pdf", size: 1234567, type: "application/pdf" }
|
|
375
|
+
]
|
|
376
|
+
},
|
|
377
|
+
"bankDetails": {
|
|
378
|
+
"bankAccountHolderName": "Acme Corp",
|
|
379
|
+
"bankAccountType": "checking",
|
|
380
|
+
"bankRoutingNumber": "123456789",
|
|
381
|
+
"bankAccountNumber": "987654321"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## Features
|
|
389
|
+
|
|
390
|
+
✅ **4-Step Stepper Form** - Visual progress indicator
|
|
391
|
+
✅ **Field Validation** - Real-time validation on blur
|
|
392
|
+
✅ **Auto-Formatting** - Phone numbers, EIN, URLs
|
|
393
|
+
✅ **File Upload** - Drag-and-drop with validation
|
|
394
|
+
✅ **CRUD Representatives** - Add/remove multiple reps
|
|
395
|
+
✅ **Error Handling** - Verification and submission failures
|
|
396
|
+
✅ **Success Page** - Animated completion screen
|
|
397
|
+
✅ **Framework Friendly** - Easy integration with React, Vue, etc.
|
|
398
|
+
✅ **Shadow DOM** - Fully encapsulated styles
|
|
399
|
+
✅ **Zero Dependencies** - Pure vanilla JavaScript
|
|
400
|
+
✅ **API Integration** - Ready for backend integration
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## API Reference
|
|
405
|
+
|
|
406
|
+
### Properties
|
|
407
|
+
|
|
408
|
+
| Property | Type | Description |
|
|
409
|
+
|----------|------|-------------|
|
|
410
|
+
| `onSuccess` | `Function` | Callback function called when form is successfully submitted. Receives complete form data as parameter. |
|
|
411
|
+
| `onError` | `Function` | Callback function called when submission fails. Receives error data as parameter. |
|
|
412
|
+
| `onLoad` | `Object` | Pre-populate form fields with initial data. Accepts partial or complete form data object. |
|
|
413
|
+
| `apiBaseURL` | `String` | Base URL for API endpoints. |
|
|
414
|
+
| `embeddableKey` | `String` | Authentication key for API requests. |
|
|
415
|
+
|
|
416
|
+
### Events
|
|
417
|
+
|
|
418
|
+
| Event | Detail | Description |
|
|
419
|
+
|-------|--------|-------------|
|
|
420
|
+
| `formComplete` | `Object` | Emitted when form is successfully submitted. `event.detail` contains complete form data. |
|
|
421
|
+
| `submissionFailed` | `Object` | Emitted when form submission fails. `event.detail` contains error information. |
|
|
422
|
+
|
|
423
|
+
### Global Functions
|
|
424
|
+
|
|
425
|
+
| Function | Parameters | Returns | Description |
|
|
426
|
+
|----------|------------|---------|-------------|
|
|
427
|
+
| `verifyOperator(operatorEmail, mockResult)` | `operatorEmail: string`, `mockResult: boolean` | `boolean` | Verify if an operator email exists. |
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Operator Verification
|
|
432
|
+
|
|
433
|
+
You can verify operator emails:
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
// Check if operator exists
|
|
437
|
+
const exists = verifyOperator('operator@company.com', true);
|
|
438
|
+
|
|
439
|
+
if (exists) {
|
|
440
|
+
// Proceed with operation
|
|
441
|
+
console.log('Operator verified');
|
|
442
|
+
} else {
|
|
443
|
+
// Show error
|
|
444
|
+
console.error('Operator not found');
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## Error Handling
|
|
451
|
+
|
|
452
|
+
The component provides comprehensive error handling:
|
|
453
|
+
|
|
454
|
+
### Submission Failures
|
|
455
|
+
|
|
456
|
+
When form submission fails:
|
|
457
|
+
|
|
458
|
+
```javascript
|
|
459
|
+
component.addEventListener('submissionFailed', (event) => {
|
|
460
|
+
const { formData, message, timestamp } = event.detail;
|
|
461
|
+
console.error('Submission failed:', message);
|
|
462
|
+
// Retry or show error
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Or use callback
|
|
466
|
+
component.onError = (errorData) => {
|
|
467
|
+
if (errorData.action === 'resubmit') {
|
|
468
|
+
// User clicked resubmit button
|
|
469
|
+
// Your retry logic here
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Modal Integration Example
|
|
477
|
+
|
|
478
|
+
```html
|
|
479
|
+
<div id="onboardingModal" class="modal">
|
|
480
|
+
<div class="modal-content">
|
|
481
|
+
<operator-onboarding
|
|
482
|
+
on-success="closeOnboardingModal"
|
|
483
|
+
on-error="handleOnboardingError">
|
|
484
|
+
</operator-onboarding>
|
|
485
|
+
</div>
|
|
486
|
+
</div>
|
|
487
|
+
|
|
488
|
+
<script>
|
|
489
|
+
function closeOnboardingModal(data) {
|
|
490
|
+
console.log('Onboarding complete for:', data.businessDetails.businessName);
|
|
491
|
+
|
|
492
|
+
// Close modal
|
|
493
|
+
document.getElementById('onboardingModal').style.display = 'none';
|
|
494
|
+
|
|
495
|
+
// Send data to backend
|
|
496
|
+
fetch('/api/onboarding', {
|
|
497
|
+
method: 'POST',
|
|
498
|
+
headers: { 'Content-Type': 'application/json' },
|
|
499
|
+
body: JSON.stringify(data)
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function handleOnboardingError(errorData) {
|
|
504
|
+
console.error('Onboarding error:', errorData);
|
|
505
|
+
// Show error notification
|
|
506
|
+
}
|
|
507
|
+
</script>
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## File Upload Validation
|
|
513
|
+
|
|
514
|
+
The underwriting step includes file upload with the following restrictions:
|
|
515
|
+
|
|
516
|
+
- **Maximum files:** 10
|
|
517
|
+
- **Maximum size per file:** 10MB
|
|
518
|
+
- **Allowed formats:** PDF, JPG, JPEG, PNG, DOC, DOCX
|
|
519
|
+
- **Validation:** Real-time with error messages
|
|
520
|
+
|
|
521
|
+
Files are validated on both drag-and-drop and browse selection. Invalid files are rejected with clear error messages.
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## Browser Support
|
|
526
|
+
|
|
527
|
+
- Chrome/Edge (latest)
|
|
528
|
+
- Firefox (latest)
|
|
529
|
+
- Safari (latest)
|
|
530
|
+
- Any browser supporting Custom Elements V1 and Shadow DOM
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## BisonJibPayAPI - Direct API Access
|
|
535
|
+
|
|
536
|
+
In addition to the web component, you can use the `BisonJibPayAPI` class directly for API integration without the UI. This is useful when you need to interact with the BisonJibPay API programmatically.
|
|
537
|
+
|
|
538
|
+
### Installation & Import
|
|
539
|
+
|
|
540
|
+
The API class is automatically exported when you load the component:
|
|
541
|
+
|
|
542
|
+
```javascript
|
|
543
|
+
// ES Module
|
|
544
|
+
import { BisonJibPayAPI } from './component.js';
|
|
545
|
+
|
|
546
|
+
// Or access from window (script tag)
|
|
547
|
+
const BisonJibPayAPI = window.BisonJibPayAPI;
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Basic Usage
|
|
551
|
+
|
|
552
|
+
```javascript
|
|
553
|
+
// Create API instance
|
|
554
|
+
const api = new BisonJibPayAPI(
|
|
555
|
+
'https://bison-jib-development.azurewebsites.net',
|
|
556
|
+
'YOUR_EMBEDDABLE_KEY'
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
// Validate operator email
|
|
560
|
+
try {
|
|
561
|
+
const result = await api.validateOperatorEmail(
|
|
562
|
+
'operator@example.com',
|
|
563
|
+
'OP123456'
|
|
564
|
+
);
|
|
565
|
+
console.log('Operator email is valid:', result);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
console.error('Validation failed:', error);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Register operator
|
|
571
|
+
const formData = new FormData();
|
|
572
|
+
formData.append('businessName', 'Acme Corp');
|
|
573
|
+
formData.append('businessEmail', 'contact@acme.com');
|
|
574
|
+
// ... add more fields
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
const result = await api.registerOperator(formData);
|
|
578
|
+
console.log('Operator registered successfully:', result);
|
|
579
|
+
} catch (error) {
|
|
580
|
+
console.error('Registration failed:', error);
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### API Methods
|
|
585
|
+
|
|
586
|
+
#### `validateOperatorEmail(email, operatorId)`
|
|
587
|
+
Validates an operator email address.
|
|
588
|
+
|
|
589
|
+
**Parameters:**
|
|
590
|
+
- `email` (string) - The operator email address to validate
|
|
591
|
+
- `operatorId` (string) - The operator ID to validate
|
|
592
|
+
|
|
593
|
+
**Returns:**
|
|
594
|
+
- Promise resolving to the API response
|
|
595
|
+
|
|
596
|
+
**Example:**
|
|
597
|
+
```javascript
|
|
598
|
+
const result = await api.validateOperatorEmail('operator@company.com', 'OP123456');
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
#### `registerOperator(formData)`
|
|
602
|
+
Registers a new operator with complete form data.
|
|
603
|
+
|
|
604
|
+
**Parameters:**
|
|
605
|
+
- `formData` (FormData) - FormData object containing all operator information
|
|
606
|
+
|
|
607
|
+
**Returns:**
|
|
608
|
+
- Promise resolving to the API response
|
|
609
|
+
|
|
610
|
+
**Example:**
|
|
611
|
+
```javascript
|
|
612
|
+
const formData = new FormData();
|
|
613
|
+
formData.append('businessName', 'Acme Corp');
|
|
614
|
+
formData.append('businessEmail', 'contact@acme.com');
|
|
615
|
+
formData.append('ein', '12-3456789');
|
|
616
|
+
// ... add all required fields
|
|
617
|
+
|
|
618
|
+
const result = await api.registerOperator(formData);
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### React Integration Example
|
|
622
|
+
|
|
623
|
+
```jsx
|
|
624
|
+
import { useEffect, useState } from 'react';
|
|
625
|
+
import { BisonJibPayAPI } from './component.js';
|
|
626
|
+
|
|
627
|
+
function EmailValidator() {
|
|
628
|
+
const [api] = useState(() => new BisonJibPayAPI(
|
|
629
|
+
'https://bison-jib-development.azurewebsites.net',
|
|
630
|
+
'YOUR_KEY'
|
|
631
|
+
));
|
|
632
|
+
const [email, setEmail] = useState('');
|
|
633
|
+
const [operatorId, setOperatorId] = useState('');
|
|
634
|
+
const [isValid, setIsValid] = useState(null);
|
|
635
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
636
|
+
|
|
637
|
+
const validateEmail = async () => {
|
|
638
|
+
setIsLoading(true);
|
|
639
|
+
try {
|
|
640
|
+
await api.validateOperatorEmail(email, operatorId);
|
|
641
|
+
setIsValid(true);
|
|
642
|
+
} catch (error) {
|
|
643
|
+
setIsValid(false);
|
|
644
|
+
console.error('Validation failed:', error);
|
|
645
|
+
} finally {
|
|
646
|
+
setIsLoading(false);
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
return (
|
|
651
|
+
<div>
|
|
652
|
+
<input
|
|
653
|
+
type="text"
|
|
654
|
+
value={operatorId}
|
|
655
|
+
onChange={(e) => setOperatorId(e.target.value)}
|
|
656
|
+
placeholder="Enter operator ID"
|
|
657
|
+
/>
|
|
658
|
+
<input
|
|
659
|
+
type="email"
|
|
660
|
+
value={email}
|
|
661
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
662
|
+
placeholder="Enter operator email"
|
|
663
|
+
/>
|
|
664
|
+
<button onClick={validateEmail} disabled={isLoading}>
|
|
665
|
+
{isLoading ? 'Validating...' : 'Validate'}
|
|
666
|
+
</button>
|
|
667
|
+
{isValid !== null && (
|
|
668
|
+
<p>{isValid ? '✓ Valid' : '✗ Invalid'}</p>
|
|
669
|
+
)}
|
|
670
|
+
</div>
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Error Handling
|
|
676
|
+
|
|
677
|
+
The API methods throw structured errors that you can catch:
|
|
678
|
+
|
|
679
|
+
```javascript
|
|
680
|
+
try {
|
|
681
|
+
await api.validateOperatorEmail('invalid@email.com', 'OP123456');
|
|
682
|
+
} catch (error) {
|
|
683
|
+
console.error('Status:', error.status);
|
|
684
|
+
console.error('Message:', error.data.message);
|
|
685
|
+
console.error('Errors:', error.data.errors);
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
Error structure:
|
|
690
|
+
```javascript
|
|
691
|
+
{
|
|
692
|
+
status: 400, // HTTP status code
|
|
693
|
+
data: {
|
|
694
|
+
success: false,
|
|
695
|
+
message: "Validation failed",
|
|
696
|
+
errors: ["Email does not exist in our system"]
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
### Using with Different Environments
|
|
702
|
+
|
|
703
|
+
```javascript
|
|
704
|
+
// Development
|
|
705
|
+
const devApi = new BisonJibPayAPI(
|
|
706
|
+
'https://bison-jib-development.azurewebsites.net',
|
|
707
|
+
'DEV_KEY'
|
|
708
|
+
);
|
|
709
|
+
|
|
710
|
+
// Production
|
|
711
|
+
const prodApi = new BisonJibPayAPI(
|
|
712
|
+
'https://bison-jib-production.azurewebsites.net',
|
|
713
|
+
'PROD_KEY'
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
// Use environment variables
|
|
717
|
+
const api = new BisonJibPayAPI(
|
|
718
|
+
process.env.REACT_APP_API_URL,
|
|
719
|
+
process.env.REACT_APP_EMBEDDABLE_KEY
|
|
720
|
+
);
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
---
|
|
724
|
+
|
|
725
|
+
## API Integration
|
|
726
|
+
|
|
727
|
+
The component is designed to work with the BisonJibPay API. Configure your endpoints:
|
|
728
|
+
|
|
729
|
+
```html
|
|
730
|
+
<operator-onboarding
|
|
731
|
+
api-base-url="https://your-api-domain.com"
|
|
732
|
+
embeddable-key="your-embeddable-key">
|
|
733
|
+
</operator-onboarding>
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
### API Endpoints Used
|
|
737
|
+
|
|
738
|
+
- `POST /api/embeddable/validate/operator-email` - Validate operator email
|
|
739
|
+
- `POST /api/embeddable/operator-registration` - Register operator with form data
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
## License
|
|
744
|
+
|
|
745
|
+
MIT
|
|
746
|
+
|
|
747
|
+
## Author
|
|
748
|
+
|
|
749
|
+
@kfajardo
|