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.
@@ -0,0 +1,275 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Bison Operator Payments - Demo</title>
7
+ <link
8
+ rel="stylesheet"
9
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
10
+ />
11
+ <style>
12
+ /* ── Reset ──────────────────────────────────────── */
13
+ * {
14
+ margin: 0;
15
+ padding: 0;
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ /* ── Layout ─────────────────────────────────────── */
20
+ body {
21
+ font-family: "Inter", system-ui, sans-serif;
22
+ background: #f0f2f5;
23
+ min-height: 100vh;
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ justify-content: center;
28
+ gap: 24px;
29
+ padding: 40px 20px;
30
+ }
31
+
32
+ /* ── Demo Card ──────────────────────────────────── */
33
+ .demo-card {
34
+ background: #fff;
35
+ border-radius: 12px;
36
+ padding: 24px 32px;
37
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
38
+ text-align: center;
39
+ max-width: 480px;
40
+ width: 100%;
41
+ }
42
+
43
+ .demo-card h1 {
44
+ font-size: 1.25rem;
45
+ font-weight: 700;
46
+ color: #0f2a39;
47
+ margin-bottom: 4px;
48
+ }
49
+
50
+ .demo-card p {
51
+ font-size: 0.875rem;
52
+ color: #5f6e78;
53
+ margin-bottom: 20px;
54
+ line-height: 1.5;
55
+ }
56
+
57
+ /* ── Attribute Controls ─────────────────────────── */
58
+ .demo-controls {
59
+ display: flex;
60
+ flex-direction: column;
61
+ gap: 10px;
62
+ margin-bottom: 20px;
63
+ text-align: left;
64
+ }
65
+
66
+ .demo-controls label {
67
+ font-size: 0.75rem;
68
+ font-weight: 600;
69
+ color: #5f6e78;
70
+ text-transform: uppercase;
71
+ letter-spacing: 0.05em;
72
+ }
73
+
74
+ .demo-controls input {
75
+ width: 100%;
76
+ padding: 8px 12px;
77
+ border: 1.5px solid #e8e8e8;
78
+ border-radius: 8px;
79
+ font-size: 0.875rem;
80
+ font-family: ui-monospace, "SF Mono", Menlo, monospace;
81
+ color: #0f2a39;
82
+ outline: none;
83
+ transition:
84
+ border-color 0.15s ease,
85
+ box-shadow 0.15s ease;
86
+ }
87
+
88
+ .demo-controls input:focus {
89
+ border-color: #4c7b63;
90
+ box-shadow: 0 0 0 3px rgba(76, 123, 99, 0.15);
91
+ }
92
+
93
+ .demo-controls input::placeholder {
94
+ color: #b0b8c0;
95
+ }
96
+
97
+ .demo-field-row {
98
+ display: flex;
99
+ gap: 10px;
100
+ }
101
+
102
+ .demo-field-row > div {
103
+ flex: 1;
104
+ }
105
+
106
+ .demo-prio-tag {
107
+ font-size: 0.65rem;
108
+ font-weight: 700;
109
+ background: #e8f0eb;
110
+ color: #4c7b63;
111
+ padding: 1px 6px;
112
+ border-radius: 4px;
113
+ margin-left: 6px;
114
+ vertical-align: middle;
115
+ }
116
+
117
+ /* ── Event Log ──────────────────────────────────── */
118
+ .event-log {
119
+ max-width: 480px;
120
+ width: 100%;
121
+ background: #1e1e2e;
122
+ color: #cdd6f4;
123
+ border-radius: 12px;
124
+ padding: 16px 20px;
125
+ font-family: ui-monospace, "SF Mono", Menlo, monospace;
126
+ font-size: 0.72rem;
127
+ line-height: 1.8;
128
+ max-height: 260px;
129
+ overflow-y: auto;
130
+ }
131
+
132
+ .event-log h3 {
133
+ color: #a6e3a1;
134
+ font-size: 0.8rem;
135
+ margin-bottom: 8px;
136
+ }
137
+
138
+ .event-log .entry { opacity: 0.85; }
139
+ .event-log .entry.success { color: #a6e3a1; }
140
+ .event-log .entry.close { color: #f9e2af; }
141
+ .event-log .entry.lookup { color: #89b4fa; }
142
+ .event-log .entry.error { color: #f38ba8; }
143
+ .event-log .entry.disabled { color: #9399b2; }
144
+ </style>
145
+ </head>
146
+
147
+ <body>
148
+ <!-- ── Demo Card ────────────────────────────────── -->
149
+ <div class="demo-card">
150
+ <h1>Operator Bank Account Mgt.</h1>
151
+ <p>
152
+ Set the operator attributes below, then click the button to open the
153
+ Bank Management modal. Both fields empty = component disabled.
154
+ </p>
155
+
156
+ <!-- Attribute controls -->
157
+ <div class="demo-controls">
158
+ <div>
159
+ <label for="input-embeddableKey">
160
+ x-embeddable-key <span class="demo-prio-tag" style="background:#fce7f3;color:#9d174d">REQUIRED</span>
161
+ </label>
162
+ <input id="input-embeddableKey" type="text" placeholder="Paste embeddable key…" />
163
+ </div>
164
+ <div class="demo-field-row">
165
+ <div>
166
+ <label for="input-opOrgId">
167
+ op-org-id <span class="demo-prio-tag">PRIORITY 1</span>
168
+ </label>
169
+ <input id="input-opOrgId" type="text" placeholder="e.g. 12345" />
170
+ </div>
171
+ <div>
172
+ <label for="input-orgNumber">
173
+ org-number
174
+ <span
175
+ class="demo-prio-tag"
176
+ style="background: #fef3c7; color: #92400e"
177
+ >PRIORITY 2</span
178
+ >
179
+ </label>
180
+ <input id="input-orgNumber" type="text" placeholder="e.g. ORG-001" />
181
+ </div>
182
+ </div>
183
+ </div>
184
+
185
+ <bison-operator-payments></bison-operator-payments>
186
+ </div>
187
+
188
+ <!-- ── Event Log ────────────────────────────────── -->
189
+ <div class="event-log" id="log">
190
+ <h3>Event Log</h3>
191
+ </div>
192
+
193
+ <!-- ── Scripts ──────────────────────────────────── -->
194
+ <script src="api.js" type="module"></script>
195
+ <script src="bison-operator-payments.js"></script>
196
+ <script type="module">
197
+ import { BisonJibPayAPI } from "./api.js";
198
+
199
+ // ── API Bootstrap ─────────────────────────────
200
+ const API_BASE =
201
+ "https://bison-backend-development-hhgrdbhcbwhahdfk.southeastasia-01.azurewebsites.net";
202
+ const API_KEY = "BwVEfJ2u5y2JPsX8qGxtXlIhHyhu3qU2VW2y6Nf9Qc6KTsETvr";
203
+
204
+ const api = new BisonJibPayAPI(API_BASE, API_KEY);
205
+ window.__bisonApi = api;
206
+
207
+ // ── DOM References ────────────────────────────
208
+ const comp = document.querySelector("bison-operator-payments");
209
+ const logEl = document.getElementById("log");
210
+ const inputEmbeddableKey = document.getElementById("input-embeddableKey");
211
+ const inputOpOrgId = document.getElementById("input-opOrgId");
212
+ const inputOrgNumber = document.getElementById("input-orgNumber");
213
+
214
+ // ── Helpers ────────────────────────────────────
215
+ function addLog(text, cls = "") {
216
+ const entry = document.createElement("div");
217
+ entry.className = `entry ${cls}`;
218
+ entry.textContent = `[${new Date().toLocaleTimeString()}] ${text}`;
219
+ logEl.appendChild(entry);
220
+ logEl.scrollTop = logEl.scrollHeight;
221
+ }
222
+
223
+ // ── Attribute Binding ─────────────────────────
224
+ function bindAttributeInput(inputEl, attrName) {
225
+ inputEl.addEventListener("input", (e) => {
226
+ const val = e.target.value.trim();
227
+ if (val) {
228
+ comp.setAttribute(attrName, val);
229
+ addLog(`SET ${attrName}="${val}"`, "lookup");
230
+ } else {
231
+ comp.removeAttribute(attrName);
232
+ addLog(`REMOVED ${attrName}`, "disabled");
233
+ }
234
+ });
235
+ }
236
+
237
+ bindAttributeInput(inputEmbeddableKey, "x-embeddable-key");
238
+ bindAttributeInput(inputOpOrgId, "op-org-id");
239
+ bindAttributeInput(inputOrgNumber, "org-number");
240
+
241
+ // ── Component Events ──────────────────────────
242
+ comp.addEventListener("bop-close", () => {
243
+ addLog("bop-close fired", "close");
244
+ });
245
+
246
+ comp.addEventListener("bop-success", (e) => {
247
+ const { bankName, accountType, lastFour } = e.detail;
248
+ addLog(
249
+ `bop-success → ${bankName} · ${accountType} · ••••${lastFour}`,
250
+ "success"
251
+ );
252
+ });
253
+
254
+ comp.addEventListener("bop-operator-lookup", (e) => {
255
+ const { status, data, error, reason } = e.detail;
256
+
257
+ switch (status) {
258
+ case "success":
259
+ addLog("bop-operator-lookup → SUCCESS", "success");
260
+ addLog(` Data: ${JSON.stringify(data)}`, "success");
261
+ break;
262
+ case "error":
263
+ addLog("bop-operator-lookup → ERROR", "error");
264
+ addLog(` ${JSON.stringify(error)}`, "error");
265
+ break;
266
+ case "disabled":
267
+ addLog(`bop-operator-lookup → DISABLED: ${reason}`, "disabled");
268
+ break;
269
+ }
270
+ });
271
+
272
+ addLog("Component ready. Set x-embeddable-key first, then op-org-id or org-number.");
273
+ </script>
274
+ </body>
275
+ </html>
package/index.html ADDED
@@ -0,0 +1,199 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Operator Onboarding - Test</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
16
+ "Helvetica Neue", Arial, sans-serif;
17
+ background: #f5f5f5;
18
+ padding: 20px;
19
+ }
20
+
21
+ .page-header {
22
+ text-align: center;
23
+ margin-bottom: 40px;
24
+ padding: 20px;
25
+ background: white;
26
+ border-radius: 8px;
27
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
28
+ }
29
+
30
+ .page-header h1 {
31
+ color: #333;
32
+ margin-bottom: 10px;
33
+ }
34
+
35
+ .page-header p {
36
+ color: #666;
37
+ font-size: 14px;
38
+ }
39
+
40
+ .component-wrapper {
41
+ max-width: 900px;
42
+ margin: 0 auto;
43
+ }
44
+
45
+ .console-output {
46
+ max-width: 900px;
47
+ margin: 40px auto;
48
+ padding: 20px;
49
+ background: #1e1e1e;
50
+ color: #d4d4d4;
51
+ border-radius: 8px;
52
+ font-family: "Courier New", monospace;
53
+ font-size: 12px;
54
+ display: none;
55
+ }
56
+
57
+ .console-output.visible {
58
+ display: block;
59
+ }
60
+
61
+ .console-output h3 {
62
+ color: #4ec9b0;
63
+ margin-bottom: 15px;
64
+ font-size: 14px;
65
+ }
66
+
67
+ .console-output pre {
68
+ white-space: pre-wrap;
69
+ word-wrap: break-word;
70
+ line-height: 1.6;
71
+ }
72
+
73
+ .success-badge {
74
+ display: inline-block;
75
+ background: #28a745;
76
+ color: white;
77
+ padding: 4px 12px;
78
+ border-radius: 12px;
79
+ font-size: 12px;
80
+ margin-left: 10px;
81
+ }
82
+ </style>
83
+ </head>
84
+ <body>
85
+ <div class="page-header">
86
+ <h1>Operator Onboarding Component</h1>
87
+ <p>Complete the 4-step onboarding process with validation</p>
88
+ </div>
89
+
90
+ <!-- Demo: Operator Verification -->
91
+ <div style="max-width: 900px; margin: 0 auto 20px; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
92
+ <h3 style="margin-bottom: 10px;">Demo: Operator Verification</h3>
93
+ <p style="margin-bottom: 15px; color: #666; font-size: 14px;">
94
+ Try the <code>verifyOperator()</code> function to conditionally show the form:
95
+ </p>
96
+ <div style="display: flex; gap: 10px; margin-bottom: 10px;">
97
+ <input
98
+ type="text"
99
+ id="operatorIdInput"
100
+ placeholder="Enter Operator ID"
101
+ value="OP123456"
102
+ style="flex: 1; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;"
103
+ />
104
+ <button
105
+ onclick="checkOperator(true)"
106
+ style="padding: 10px 20px; background: #28a745; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: 500;"
107
+ >
108
+ ✓ Verify (Success)
109
+ </button>
110
+ <button
111
+ onclick="checkOperator(false)"
112
+ style="padding: 10px 20px; background: #dc3545; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: 500;"
113
+ >
114
+ ✗ Verify (Fail)
115
+ </button>
116
+ </div>
117
+ <div id="verificationResult" style="padding: 10px; border-radius: 4px; font-size: 14px; display: none;"></div>
118
+ </div>
119
+
120
+ <div class="component-wrapper" id="onboardingContainer">
121
+ <!-- onSuccess callback can be set via attribute -->
122
+ <operator-onboarding on-success="handleOnboardingSuccess"></operator-onboarding>
123
+ </div>
124
+
125
+ <!-- Load the component -->
126
+ <script src="component.js"></script>
127
+
128
+ <script>
129
+ // Demo function to test verifyOperator
130
+ function checkOperator(shouldPass) {
131
+ const operatorId = document.getElementById('operatorIdInput').value;
132
+ const resultDiv = document.getElementById('verificationResult');
133
+ const container = document.getElementById('onboardingContainer');
134
+
135
+ if (!operatorId) {
136
+ resultDiv.style.display = 'block';
137
+ resultDiv.style.background = '#fff3cd';
138
+ resultDiv.style.color = '#856404';
139
+ resultDiv.style.border = '1px solid #ffeeba';
140
+ resultDiv.innerHTML = '⚠️ Please enter an Operator ID';
141
+ return;
142
+ }
143
+
144
+ // Call the verifyOperator function
145
+ const isVerified = verifyOperator(operatorId, shouldPass);
146
+
147
+ // Show result
148
+ resultDiv.style.display = 'block';
149
+
150
+ if (isVerified) {
151
+ resultDiv.style.background = '#d4edda';
152
+ resultDiv.style.color = '#155724';
153
+ resultDiv.style.border = '1px solid #c3e6cb';
154
+ resultDiv.innerHTML = `✅ Operator <strong>${operatorId}</strong> is verified! Showing onboarding form below.`;
155
+
156
+ // Show the onboarding form
157
+ container.style.display = 'block';
158
+ } else {
159
+ resultDiv.style.background = '#f8d7da';
160
+ resultDiv.style.color = '#721c24';
161
+ resultDiv.style.border = '1px solid #f5c6cb';
162
+ resultDiv.innerHTML = `❌ Operator <strong>${operatorId}</strong> is not verified. Onboarding form is hidden.`;
163
+
164
+ // Hide the onboarding form
165
+ container.style.display = 'none';
166
+ }
167
+ }
168
+
169
+ // Define the onSuccess callback in global scope
170
+ function handleOnboardingSuccess(data) {
171
+ console.log("✅ onSuccess callback received:", data);
172
+ alert(`Onboarding complete for ${data.businessDetails.businessName}!\n\nIn a real application, you would close the modal here.`);
173
+ }
174
+
175
+ // Wait for DOM to be ready
176
+ document.addEventListener("DOMContentLoaded", () => {
177
+ const form = document.querySelector("operator-onboarding");
178
+
179
+ // Option 1: Set callback via attribute (function name as string)
180
+ // Already set in HTML: on-success="handleOnboardingSuccess"
181
+
182
+ // Option 2: Set callback programmatically (alternative approach)
183
+ // Uncomment to use programmatic approach instead:
184
+ // form.setOnSuccess((data) => {
185
+ // console.log("Programmatic callback:", data);
186
+ // alert(`Success! ${data.businessDetails.businessName} is onboarded.`);
187
+ // });
188
+
189
+ // Also listen for the formComplete event (optional)
190
+ form.addEventListener("formComplete", (event) => {
191
+ console.log("Form Complete Event Received:", event.detail);
192
+ });
193
+
194
+ console.log("✅ Operator Onboarding Component Initialized");
195
+ console.log("📝 Complete the form to see the success page!");
196
+ });
197
+ </script>
198
+ </body>
199
+ </html>