payment-skill 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 +62 -0
- package/README.md +545 -0
- package/SKILL.md +99 -0
- package/SUPPORT.md +153 -0
- package/bin/payment-skill.js +2 -0
- package/dashboard.html +669 -0
- package/dist/api/bunq.d.ts +35 -0
- package/dist/api/bunq.d.ts.map +1 -0
- package/dist/api/bunq.js +164 -0
- package/dist/api/bunq.js.map +1 -0
- package/dist/api/wise.d.ts +32 -0
- package/dist/api/wise.d.ts.map +1 -0
- package/dist/api/wise.js +155 -0
- package/dist/api/wise.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/bunq.d.ts +8 -0
- package/dist/commands/bunq.d.ts.map +1 -0
- package/dist/commands/bunq.js +193 -0
- package/dist/commands/bunq.js.map +1 -0
- package/dist/commands/config.d.ts +8 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +70 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/emergency.d.ts +8 -0
- package/dist/commands/emergency.d.ts.map +1 -0
- package/dist/commands/emergency.js +85 -0
- package/dist/commands/emergency.js.map +1 -0
- package/dist/commands/limits.d.ts +6 -0
- package/dist/commands/limits.d.ts.map +1 -0
- package/dist/commands/limits.js +125 -0
- package/dist/commands/limits.js.map +1 -0
- package/dist/commands/merchant.d.ts +6 -0
- package/dist/commands/merchant.d.ts.map +1 -0
- package/dist/commands/merchant.js +41 -0
- package/dist/commands/merchant.js.map +1 -0
- package/dist/commands/pay.d.ts +10 -0
- package/dist/commands/pay.d.ts.map +1 -0
- package/dist/commands/pay.js +112 -0
- package/dist/commands/pay.js.map +1 -0
- package/dist/commands/provider.d.ts +6 -0
- package/dist/commands/provider.d.ts.map +1 -0
- package/dist/commands/provider.js +74 -0
- package/dist/commands/provider.js.map +1 -0
- package/dist/commands/server.d.ts +8 -0
- package/dist/commands/server.d.ts.map +1 -0
- package/dist/commands/server.js +92 -0
- package/dist/commands/server.js.map +1 -0
- package/dist/commands/template.d.ts +8 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +161 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/transaction.d.ts +6 -0
- package/dist/commands/transaction.d.ts.map +1 -0
- package/dist/commands/transaction.js +72 -0
- package/dist/commands/transaction.js.map +1 -0
- package/dist/commands/wise.d.ts +8 -0
- package/dist/commands/wise.d.ts.map +1 -0
- package/dist/commands/wise.js +240 -0
- package/dist/commands/wise.js.map +1 -0
- package/dist/core/config.d.ts +40 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +201 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/template-engine.d.ts +27 -0
- package/dist/core/template-engine.d.ts.map +1 -0
- package/dist/core/template-engine.js +410 -0
- package/dist/core/template-engine.js.map +1 -0
- package/dist/core/transaction.d.ts +31 -0
- package/dist/core/transaction.d.ts.map +1 -0
- package/dist/core/transaction.js +214 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/server/server.d.ts +14 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +120 -0
- package/dist/server/server.js.map +1 -0
- package/dist/types/index.d.ts +141 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/logo.png +0 -0
- package/package.json +78 -0
- package/src/api/bunq.ts +257 -0
- package/src/api/wise.ts +204 -0
- package/src/cli.ts +67 -0
- package/src/commands/bunq.ts +223 -0
- package/src/commands/config.ts +72 -0
- package/src/commands/emergency.ts +94 -0
- package/src/commands/limits.ts +126 -0
- package/src/commands/merchant.ts +39 -0
- package/src/commands/pay.ts +109 -0
- package/src/commands/provider.ts +75 -0
- package/src/commands/server.ts +59 -0
- package/src/commands/template.ts +172 -0
- package/src/commands/transaction.ts +66 -0
- package/src/commands/wise.ts +279 -0
- package/src/core/config.ts +202 -0
- package/src/core/template-engine.ts +454 -0
- package/src/core/transaction.ts +228 -0
- package/src/index.ts +14 -0
- package/src/server/server.ts +131 -0
- package/src/types/index.ts +178 -0
- package/tsconfig.json +23 -0
- package/verified-merchants.json +63 -0
package/dashboard.html
ADDED
|
@@ -0,0 +1,669 @@
|
|
|
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>PaymentControl Dashboard</title>
|
|
7
|
+
<style>
|
|
8
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
--bg-primary: #0f1419; --bg-secondary: #1a1f2e; --bg-tertiary: #252b3d;
|
|
12
|
+
--border-color: #2a3142; --text-primary: #e6e6e6; --text-secondary: #9ca3af;
|
|
13
|
+
--text-muted: #6b7280; --accent-green: #22c55e; --accent-red: #dc2626;
|
|
14
|
+
--button-bg: #ffffff; --button-text: #0f1419;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body.light-theme {
|
|
18
|
+
--bg-primary: #f5f5f5; --bg-secondary: #ffffff; --bg-tertiary: #e8e8e8;
|
|
19
|
+
--border-color: #d1d5db; --text-primary: #1a1a1a; --text-secondary: #4b5563;
|
|
20
|
+
--button-bg: #1a1a1a; --button-text: #ffffff;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
body {
|
|
24
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
25
|
+
background: var(--bg-primary); color: var(--text-primary); min-height: 100vh;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.header {
|
|
29
|
+
background: #0a0d12; padding: 4px 16px;
|
|
30
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
31
|
+
border-bottom: 1px solid var(--border-color);
|
|
32
|
+
min-height: 40px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.header-logo {
|
|
36
|
+
height: 87px;
|
|
37
|
+
width: auto;
|
|
38
|
+
margin-left: auto;
|
|
39
|
+
margin-right: 16px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.emergency-btn {
|
|
43
|
+
background: #dc2626; color: white; border: none; padding: 6px 12px;
|
|
44
|
+
border-radius: 5px; font-size: 11px; font-weight: 600; cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.theme-toggle {
|
|
48
|
+
background: var(--bg-tertiary); border: 1px solid var(--border-color);
|
|
49
|
+
color: var(--text-primary); padding: 5px 10px; border-radius: 5px;
|
|
50
|
+
cursor: pointer; font-size: 12px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.container { display: flex; min-height: calc(100vh - 50px); }
|
|
54
|
+
|
|
55
|
+
.sidebar {
|
|
56
|
+
width: 180px; background: var(--bg-secondary);
|
|
57
|
+
border-right: 1px solid var(--border-color); padding: 10px 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.nav-header {
|
|
61
|
+
padding: 5px 14px; font-size: 8px; font-weight: 600;
|
|
62
|
+
color: var(--text-muted); text-transform: uppercase;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.nav-item {
|
|
66
|
+
padding: 7px 14px; display: flex; align-items: center; gap: 8px;
|
|
67
|
+
cursor: pointer; font-size: 11px; color: var(--text-secondary);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.nav-item:hover, .nav-item.active {
|
|
71
|
+
background: var(--bg-tertiary); color: var(--text-primary);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.nav-item.active { border-left: 2px solid var(--accent-green); }
|
|
75
|
+
|
|
76
|
+
.main { flex: 1; padding: 16px; overflow-y: auto; }
|
|
77
|
+
|
|
78
|
+
.page { display: none; }
|
|
79
|
+
.page.active { display: block; }
|
|
80
|
+
|
|
81
|
+
/* Provider Selection */
|
|
82
|
+
.provider-selection {
|
|
83
|
+
display: flex; gap: 12px; margin-bottom: 16px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.provider-btn {
|
|
87
|
+
flex: 1; padding: 12px; background: var(--bg-secondary);
|
|
88
|
+
border: 2px solid var(--border-color); border-radius: 8px;
|
|
89
|
+
cursor: pointer; text-align: center;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.provider-btn.active {
|
|
93
|
+
border-color: var(--accent-green);
|
|
94
|
+
background: rgba(34, 197, 94, 0.1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.provider-btn .icon { font-size: 24px; margin-bottom: 6px; }
|
|
98
|
+
.provider-btn .name { font-size: 12px; font-weight: 600; }
|
|
99
|
+
|
|
100
|
+
/* API Section */
|
|
101
|
+
.api-section-card {
|
|
102
|
+
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
103
|
+
border-radius: 8px; padding: 14px; margin-bottom: 14px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.api-section-title { font-size: 12px; font-weight: 600; margin-bottom: 10px; }
|
|
107
|
+
|
|
108
|
+
.api-input-row { display: flex; gap: 8px; }
|
|
109
|
+
|
|
110
|
+
.api-input {
|
|
111
|
+
flex: 1; background: var(--bg-primary); border: 1px solid var(--border-color);
|
|
112
|
+
color: var(--text-primary); padding: 7px 10px; border-radius: 5px; font-size: 11px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.btn {
|
|
116
|
+
background: var(--button-bg); color: var(--button-text); border: none;
|
|
117
|
+
padding: 7px 14px; border-radius: 5px; font-size: 11px; font-weight: 600; cursor: pointer;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Section Cards */
|
|
121
|
+
.section-card {
|
|
122
|
+
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
123
|
+
border-radius: 8px; margin-bottom: 14px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.section-header {
|
|
127
|
+
padding: 12px; border-bottom: 1px solid var(--border-color);
|
|
128
|
+
display: flex; align-items: center; gap: 8px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.section-icon {
|
|
132
|
+
width: 28px; height: 28px; border-radius: 5px;
|
|
133
|
+
display: flex; align-items: center; justify-content: center; font-size: 14px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.section-icon.yellow { background: rgba(234, 179, 8, 0.2); }
|
|
137
|
+
.section-icon.purple { background: rgba(168, 85, 247, 0.2); }
|
|
138
|
+
.section-icon.green { background: rgba(34, 197, 94, 0.2); }
|
|
139
|
+
.section-icon.blue { background: rgba(59, 130, 246, 0.2); }
|
|
140
|
+
|
|
141
|
+
.section-title { flex: 1; }
|
|
142
|
+
.section-title h3 { font-size: 12px; font-weight: 600; margin-bottom: 2px; }
|
|
143
|
+
.section-title p { font-size: 10px; color: var(--text-muted); }
|
|
144
|
+
|
|
145
|
+
.badge {
|
|
146
|
+
background: var(--accent-green); color: white; padding: 2px 6px;
|
|
147
|
+
border-radius: 3px; font-size: 8px; font-weight: 600;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.toggle-card-btn {
|
|
151
|
+
background: var(--bg-tertiary);
|
|
152
|
+
border: 1px solid var(--border-color);
|
|
153
|
+
color: var(--text-secondary);
|
|
154
|
+
padding: 4px 10px;
|
|
155
|
+
border-radius: 4px;
|
|
156
|
+
font-size: 10px;
|
|
157
|
+
cursor: pointer;
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 4px;
|
|
161
|
+
transition: all 0.2s;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.toggle-card-btn:hover {
|
|
165
|
+
background: var(--border-color);
|
|
166
|
+
color: var(--text-primary);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.toggle-card-btn .arrow {
|
|
170
|
+
transition: transform 0.2s;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.toggle-card-btn.collapsed .arrow {
|
|
174
|
+
transform: rotate(-90deg);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.section-body {
|
|
178
|
+
padding: 12px;
|
|
179
|
+
transition: all 0.3s ease;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.section-body.collapsed {
|
|
183
|
+
display: none;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.section-body { padding: 12px; }
|
|
187
|
+
|
|
188
|
+
.form-row {
|
|
189
|
+
display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-bottom: 10px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.form-group { display: flex; flex-direction: column; gap: 3px; }
|
|
193
|
+
.form-group label { font-size: 9px; color: var(--text-secondary); }
|
|
194
|
+
.form-group input, .form-group select {
|
|
195
|
+
background: var(--bg-primary); border: 1px solid var(--border-color);
|
|
196
|
+
color: var(--text-primary); padding: 5px 8px; border-radius: 4px; font-size: 10px;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.save-section-btn {
|
|
200
|
+
background: var(--button-bg); color: var(--button-text); border: none;
|
|
201
|
+
padding: 7px 14px; border-radius: 5px; font-size: 11px; font-weight: 600;
|
|
202
|
+
float: right; margin-top: 8px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.clearfix::after { content: ""; clear: both; display: table; }
|
|
206
|
+
|
|
207
|
+
/* Logs */
|
|
208
|
+
.logs-container {
|
|
209
|
+
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
210
|
+
border-radius: 8px; overflow: hidden;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.logs-header {
|
|
214
|
+
display: flex; gap: 10px; padding: 10px;
|
|
215
|
+
border-bottom: 1px solid var(--border-color); background: var(--bg-tertiary);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.log-filter {
|
|
219
|
+
padding: 5px 10px; border-radius: 4px; font-size: 10px; cursor: pointer;
|
|
220
|
+
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
221
|
+
color: var(--text-secondary);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.log-filter.active { background: var(--accent-green); color: white; }
|
|
225
|
+
|
|
226
|
+
.log-entry {
|
|
227
|
+
padding: 10px 12px; border-bottom: 1px solid var(--border-color);
|
|
228
|
+
font-size: 11px; display: flex; gap: 10px;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.log-time { color: var(--text-muted); font-size: 9px; min-width: 60px; }
|
|
232
|
+
|
|
233
|
+
.log-level {
|
|
234
|
+
padding: 2px 6px; border-radius: 3px; font-size: 8px; font-weight: 600;
|
|
235
|
+
min-width: 50px; text-align: center;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.log-level.success { background: rgba(34, 197, 94, 0.2); color: #22c55e; }
|
|
239
|
+
.log-level.info { background: rgba(59, 130, 246, 0.2); color: #3b82f6; }
|
|
240
|
+
.log-level.warning { background: rgba(234, 179, 8, 0.2); color: #eab308; }
|
|
241
|
+
.log-level.error { background: rgba(220, 38, 38, 0.2); color: #dc2626; }
|
|
242
|
+
|
|
243
|
+
.log-message { flex: 1; }
|
|
244
|
+
|
|
245
|
+
/* Transactions */
|
|
246
|
+
.transactions-table {
|
|
247
|
+
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
248
|
+
border-radius: 8px; overflow: hidden;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.table-header {
|
|
252
|
+
display: grid; grid-template-columns: 100px 1fr 100px 80px 80px;
|
|
253
|
+
gap: 10px; padding: 10px 12px; background: var(--bg-tertiary);
|
|
254
|
+
border-bottom: 1px solid var(--border-color);
|
|
255
|
+
font-size: 10px; font-weight: 600; color: var(--text-secondary);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.table-row {
|
|
259
|
+
display: grid; grid-template-columns: 100px 1fr 100px 80px 80px;
|
|
260
|
+
gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--border-color);
|
|
261
|
+
font-size: 11px; align-items: center;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.tx-date { color: var(--text-muted); font-size: 10px; }
|
|
265
|
+
.tx-merchant { color: var(--text-primary); font-weight: 500; }
|
|
266
|
+
.tx-category { font-size: 9px; }
|
|
267
|
+
.tx-amount { font-weight: 600; }
|
|
268
|
+
|
|
269
|
+
.tx-status {
|
|
270
|
+
padding: 2px 6px; border-radius: 3px; font-size: 9px; font-weight: 600; text-align: center;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.tx-status.completed { background: rgba(34, 197, 94, 0.2); color: #22c55e; }
|
|
274
|
+
.tx-status.pending { background: rgba(234, 179, 8, 0.2); color: #eab308; }
|
|
275
|
+
|
|
276
|
+
/* Monitoring */
|
|
277
|
+
.monitoring-grid {
|
|
278
|
+
display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 20px;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.monitor-card {
|
|
282
|
+
background: var(--bg-secondary); border: 1px solid var(--border-color);
|
|
283
|
+
border-radius: 8px; padding: 14px; text-align: center;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.monitor-icon { font-size: 28px; margin-bottom: 8px; }
|
|
287
|
+
.monitor-value { font-size: 24px; font-weight: 700; margin-bottom: 4px; }
|
|
288
|
+
.monitor-label { font-size: 10px; color: var(--text-muted); }
|
|
289
|
+
</style>
|
|
290
|
+
</head>
|
|
291
|
+
<body>
|
|
292
|
+
<div class="header">
|
|
293
|
+
<button class="emergency-btn">🔴 Emergency Stop</button>
|
|
294
|
+
<img src="logo.png" alt="Logo" class="header-logo">
|
|
295
|
+
</div>
|
|
296
|
+
|
|
297
|
+
<div class="container">
|
|
298
|
+
<div class="sidebar">
|
|
299
|
+
<div class="nav-header">Account Centre</div>
|
|
300
|
+
<div class="nav-item active" onclick="showPage('configuration')">⚙️ Configuration</div>
|
|
301
|
+
<div class="nav-item" onclick="showPage('monitoring')">📊 Monitoring</div>
|
|
302
|
+
<div class="nav-item" onclick="showPage('logs')">📋 Logs</div>
|
|
303
|
+
|
|
304
|
+
<div class="nav-header">Analytics</div>
|
|
305
|
+
<div class="nav-item" onclick="showPage('transactions')">💳 Transactions</div>
|
|
306
|
+
|
|
307
|
+
<div class="nav-header">Theme</div>
|
|
308
|
+
<div class="nav-item" onclick="toggleTheme()">☀️/🌙 Toggle</div>
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
<div class="main">
|
|
312
|
+
<!-- Configuration Page -->
|
|
313
|
+
<div id="configuration" class="page active">
|
|
314
|
+
<div class="api-section-card">
|
|
315
|
+
<div class="api-section-title">🏦 Select Payment Provider</div>
|
|
316
|
+
<div class="provider-selection">
|
|
317
|
+
<div class="provider-btn active" onclick="selectProvider('wise', this)">
|
|
318
|
+
<div class="icon">💚</div>
|
|
319
|
+
<div class="name">Wise</div>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="provider-btn" onclick="selectProvider('bunq', this)">
|
|
322
|
+
<div class="icon">💜</div>
|
|
323
|
+
<div class="name">Bunq</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<div class="api-section-card">
|
|
329
|
+
<div class="api-section-title" id="api-title">🔑 API Configuration</div>
|
|
330
|
+
<div class="api-input-row">
|
|
331
|
+
<input type="text" class="api-input" id="api-key-input" placeholder="Enter API Key">
|
|
332
|
+
<button class="btn">Save</button>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
<!-- PSD2 Notice -->
|
|
337
|
+
<div class="api-section-card" style="background: rgba(59, 130, 246, 0.1); border-color: #3b82f6;">
|
|
338
|
+
<div style="font-size: 11px; color: var(--text-secondary);">
|
|
339
|
+
🇪🇺 users should install Wise/Bunq mobile app for confirming transactions (under PSD2 law)
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
<div class="section-card">
|
|
344
|
+
<div class="section-header">
|
|
345
|
+
<div class="section-icon yellow">💵</div>
|
|
346
|
+
<div class="section-title">
|
|
347
|
+
<h3>Account Limits</h3>
|
|
348
|
+
<p>Set transaction limits for your account</p>
|
|
349
|
+
</div>
|
|
350
|
+
<button class="toggle-card-btn" onclick="toggleCard(this)">
|
|
351
|
+
|
|
352
|
+
<span class="arrow">▼</span>
|
|
353
|
+
</button>
|
|
354
|
+
</div>
|
|
355
|
+
<div class="section-body">
|
|
356
|
+
<div class="form-row">
|
|
357
|
+
<div class="form-group"><label>Per Transaction</label><input type="text" value="5.0"></div>
|
|
358
|
+
<div class="form-group"><label>Per Hour</label><input type="text" value="50.0"></div>
|
|
359
|
+
<div class="form-group"><label>Per Day</label><input type="text" value="500.0"></div>
|
|
360
|
+
<div class="form-group"><label>Per Week</label><input type="text" value="2,500.0"></div>
|
|
361
|
+
</div>
|
|
362
|
+
<div class="form-row">
|
|
363
|
+
<div class="form-group"><label>Per Month</label><input type="text" value="10,000.0"></div>
|
|
364
|
+
<div class="form-group"><label>Per Year</label><input type="text" value="100,000.0"></div>
|
|
365
|
+
<div class="form-group"><label>Currency</label><select><option>USD</option><option>EUR</option></select></div>
|
|
366
|
+
<div class="form-group"><label>Max Tx/Hour</label><input type="text" value="20"></div>
|
|
367
|
+
</div>
|
|
368
|
+
<button class="save-section-btn">Save Account Limits</button>
|
|
369
|
+
<div class="clearfix"></div>
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
|
|
373
|
+
<!-- Cumulative Budgets -->
|
|
374
|
+
<div class="section-card">
|
|
375
|
+
<div class="section-header">
|
|
376
|
+
<div class="section-icon purple">📊</div>
|
|
377
|
+
<div class="section-title">
|
|
378
|
+
<h3>Cumulative Budgets</h3>
|
|
379
|
+
<p>Manage rolling budgets with automatic reset</p>
|
|
380
|
+
</div>
|
|
381
|
+
<button class="toggle-card-btn" onclick="toggleCard(this)">
|
|
382
|
+
|
|
383
|
+
<span class="arrow">▼</span>
|
|
384
|
+
</button>
|
|
385
|
+
</div>
|
|
386
|
+
<div class="section-body">
|
|
387
|
+
<div class="form-row">
|
|
388
|
+
<div class="form-group"><label>Budget Name</label><input type="text" value="Monthly Budget"></div>
|
|
389
|
+
<div class="form-group"><label>Amount</label><input type="text" value="1000"></div>
|
|
390
|
+
<div class="form-group"><label>Period</label><select><option>Monthly</option><option>Weekly</option><option>Daily</option></select></div>
|
|
391
|
+
<div class="form-group"><label>Currency</label><select><option>USD</option><option>EUR</option></select></div>
|
|
392
|
+
</div>
|
|
393
|
+
<button class="save-section-btn">Save Budgets</button>
|
|
394
|
+
<div class="clearfix"></div>
|
|
395
|
+
</div>
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<!-- Domain Controls -->
|
|
399
|
+
<div class="section-card">
|
|
400
|
+
<div class="section-header">
|
|
401
|
+
<div class="section-icon orange">🌐</div>
|
|
402
|
+
<div class="section-title">
|
|
403
|
+
<h3>Domain Controls</h3>
|
|
404
|
+
<p>Whitelist or blacklist merchant domains</p>
|
|
405
|
+
</div>
|
|
406
|
+
<button class="toggle-card-btn" onclick="toggleCard(this)">
|
|
407
|
+
|
|
408
|
+
<span class="arrow">▼</span>
|
|
409
|
+
</button>
|
|
410
|
+
</div>
|
|
411
|
+
<div class="section-body">
|
|
412
|
+
<div style="margin-bottom: 15px;">
|
|
413
|
+
<div style="font-size: 10px; color: var(--text-secondary); margin-bottom: 6px;">Allowed Domains</div>
|
|
414
|
+
<div style="display: flex; gap: 6px; margin-bottom: 8px;">
|
|
415
|
+
<input type="text" style="flex: 1; background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 5px 8px; border-radius: 4px; font-size: 10px;" placeholder="e.g., amazon.com">
|
|
416
|
+
<button class="btn" style="padding: 5px 10px; font-size: 10px;">+ Add</button>
|
|
417
|
+
</div>
|
|
418
|
+
<div style="display: flex; flex-wrap: wrap; gap: 5px;">
|
|
419
|
+
<span style="background: rgba(34, 197, 94, 0.2); color: #22c55e; padding: 3px 6px; border-radius: 3px; font-size: 9px;">amazon.com ✕</span>
|
|
420
|
+
<span style="background: rgba(34, 197, 94, 0.2); color: #22c55e; padding: 3px 6px; border-radius: 3px; font-size: 9px;">google.com ✕</span>
|
|
421
|
+
</div>
|
|
422
|
+
</div>
|
|
423
|
+
<div>
|
|
424
|
+
<div style="font-size: 10px; color: var(--text-secondary); margin-bottom: 6px;">Blocked Domains</div>
|
|
425
|
+
<div style="display: flex; gap: 6px; margin-bottom: 8px;">
|
|
426
|
+
<input type="text" style="flex: 1; background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 5px 8px; border-radius: 4px; font-size: 10px;" placeholder="e.g., gambling.com">
|
|
427
|
+
<button class="btn" style="padding: 5px 10px; font-size: 10px; background: #dc2626;">+ Add</button>
|
|
428
|
+
</div>
|
|
429
|
+
<div style="display: flex; flex-wrap: wrap; gap: 5px;">
|
|
430
|
+
<span style="background: rgba(220, 38, 38, 0.2); color: #ef4444; padding: 3px 6px; border-radius: 3px; font-size: 9px;">gambling.com ✕</span>
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
<button class="save-section-btn">Save Domain Controls</button>
|
|
434
|
+
<div class="clearfix"></div>
|
|
435
|
+
</div>
|
|
436
|
+
</div>
|
|
437
|
+
|
|
438
|
+
<!-- Time Window Controls -->
|
|
439
|
+
<div class="section-card">
|
|
440
|
+
<div class="section-header">
|
|
441
|
+
<div class="section-icon green">🕐</div>
|
|
442
|
+
<div class="section-title">
|
|
443
|
+
<h3>Time Window Controls</h3>
|
|
444
|
+
<p>Restrict transactions by time and day</p>
|
|
445
|
+
</div>
|
|
446
|
+
<button class="toggle-card-btn" onclick="toggleCard(this)">
|
|
447
|
+
|
|
448
|
+
<span class="arrow">▼</span>
|
|
449
|
+
</button>
|
|
450
|
+
</div>
|
|
451
|
+
<div class="section-body">
|
|
452
|
+
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 12px;">
|
|
453
|
+
<div style="width: 36px; height: 18px; background: var(--accent-green); border-radius: 9px; position: relative; cursor: pointer;">
|
|
454
|
+
<div style="position: absolute; width: 14px; height: 14px; background: white; border-radius: 50%; top: 2px; right: 2px;"></div>
|
|
455
|
+
</div>
|
|
456
|
+
<span style="font-size: 11px;">Enable time window enforcement</span>
|
|
457
|
+
</div>
|
|
458
|
+
<div class="form-row">
|
|
459
|
+
<div class="form-group"><label>Start Time</label><input type="time" value="08:00"></div>
|
|
460
|
+
<div class="form-group"><label>End Time</label><input type="time" value="22:00"></div>
|
|
461
|
+
<div class="form-group"><label>Timezone</label><select><option>Europe/Bucharest</option><option>UTC</option></select></div>
|
|
462
|
+
<div class="form-group"><label>Blocked Days</label><select><option>None</option><option>Weekends</option></select></div>
|
|
463
|
+
</div>
|
|
464
|
+
<button class="save-section-btn">Save Time Policy</button>
|
|
465
|
+
<div class="clearfix"></div>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
|
|
469
|
+
<!-- Geography Controls -->
|
|
470
|
+
<div class="section-card">
|
|
471
|
+
<div class="section-header">
|
|
472
|
+
<div class="section-icon red">📍</div>
|
|
473
|
+
<div class="section-title">
|
|
474
|
+
<h3>Geography Controls</h3>
|
|
475
|
+
<p>Allow or block transactions by country</p>
|
|
476
|
+
</div>
|
|
477
|
+
<button class="toggle-card-btn" onclick="toggleCard(this)">
|
|
478
|
+
|
|
479
|
+
<span class="arrow">▼</span>
|
|
480
|
+
</button>
|
|
481
|
+
</div>
|
|
482
|
+
<div class="section-body">
|
|
483
|
+
<div style="margin-bottom: 15px;">
|
|
484
|
+
<div style="font-size: 10px; color: var(--text-secondary); margin-bottom: 6px;">Allowed Countries</div>
|
|
485
|
+
<div style="display: flex; gap: 6px; margin-bottom: 8px;">
|
|
486
|
+
<input type="text" style="flex: 1; background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 5px 8px; border-radius: 4px; font-size: 10px;" placeholder="e.g., Romania">
|
|
487
|
+
<button class="btn" style="padding: 5px 10px; font-size: 10px;">+ Add</button>
|
|
488
|
+
</div>
|
|
489
|
+
<div style="display: flex; flex-wrap: wrap; gap: 5px;">
|
|
490
|
+
<span style="background: rgba(34, 197, 94, 0.2); color: #22c55e; padding: 3px 6px; border-radius: 3px; font-size: 9px;">Romania ✕</span>
|
|
491
|
+
<span style="background: rgba(34, 197, 94, 0.2); color: #22c55e; padding: 3px 6px; border-radius: 3px; font-size: 9px;">Germany ✕</span>
|
|
492
|
+
<span style="background: rgba(34, 197, 94, 0.2); color: #22c55e; padding: 3px 6px; border-radius: 3px; font-size: 9px;">UK ✕</span>
|
|
493
|
+
</div>
|
|
494
|
+
</div>
|
|
495
|
+
<div>
|
|
496
|
+
<div style="font-size: 10px; color: var(--text-secondary); margin-bottom: 6px;">Blocked Countries</div>
|
|
497
|
+
<div style="display: flex; gap: 6px; margin-bottom: 8px;">
|
|
498
|
+
<input type="text" style="flex: 1; background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-primary); padding: 5px 8px; border-radius: 4px; font-size: 10px;" placeholder="e.g., North Korea">
|
|
499
|
+
<button class="btn" style="padding: 5px 10px; font-size: 10px; background: #dc2626;">+ Add</button>
|
|
500
|
+
</div>
|
|
501
|
+
</div>
|
|
502
|
+
<button class="save-section-btn">Save Geography</button>
|
|
503
|
+
<div class="clearfix"></div>
|
|
504
|
+
</div>
|
|
505
|
+
</div>
|
|
506
|
+
|
|
507
|
+
<!-- Category Controls -->
|
|
508
|
+
<div class="section-card">
|
|
509
|
+
<div class="section-header">
|
|
510
|
+
<div class="section-icon purple">🏷️</div>
|
|
511
|
+
<div class="section-title">
|
|
512
|
+
<h3>Category Controls</h3>
|
|
513
|
+
<p>Block or allow spending categories</p>
|
|
514
|
+
</div>
|
|
515
|
+
<button class="toggle-card-btn" onclick="toggleCard(this)">
|
|
516
|
+
|
|
517
|
+
<span class="arrow">▼</span>
|
|
518
|
+
</button>
|
|
519
|
+
</div>
|
|
520
|
+
<div class="section-body">
|
|
521
|
+
<div style="margin-bottom: 15px;">
|
|
522
|
+
<div style="font-size: 10px; color: var(--text-secondary); margin-bottom: 8px;">Allowed Categories</div>
|
|
523
|
+
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
|
|
524
|
+
<div style="background: rgba(34, 197, 94, 0.2); border: 1px solid #22c55e; color: #22c55e; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Groceries</div>
|
|
525
|
+
<div style="background: rgba(34, 197, 94, 0.2); border: 1px solid #22c55e; color: #22c55e; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Transport</div>
|
|
526
|
+
<div style="background: rgba(34, 197, 94, 0.2); border: 1px solid #22c55e; color: #22c55e; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Utilities</div>
|
|
527
|
+
<div style="background: var(--bg-tertiary); border: 1px solid var(--border-color); color: var(--text-secondary); padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Shopping</div>
|
|
528
|
+
<div style="background: rgba(34, 197, 94, 0.2); border: 1px solid #22c55e; color: #22c55e; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Dining</div>
|
|
529
|
+
<div style="background: var(--bg-tertiary); border: 1px solid var(--border-color); color: var(--text-secondary); padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Healthcare</div>
|
|
530
|
+
<div style="background: rgba(34, 197, 94, 0.2); border: 1px solid #22c55e; color: #22c55e; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Education</div>
|
|
531
|
+
<div style="background: var(--bg-tertiary); border: 1px solid var(--border-color); color: var(--text-secondary); padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Entertainment</div>
|
|
532
|
+
</div>
|
|
533
|
+
</div>
|
|
534
|
+
<div>
|
|
535
|
+
<div style="font-size: 10px; color: var(--text-secondary); margin-bottom: 8px;">Blocked Categories</div>
|
|
536
|
+
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
|
|
537
|
+
<div style="background: rgba(220, 38, 38, 0.2); border: 1px solid #dc2626; color: #ef4444; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Gambling</div>
|
|
538
|
+
<div style="background: rgba(220, 38, 38, 0.2); border: 1px solid #dc2626; color: #ef4444; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Crypto</div>
|
|
539
|
+
<div style="background: rgba(220, 38, 38, 0.2); border: 1px solid #dc2626; color: #ef4444; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Adult</div>
|
|
540
|
+
<div style="background: rgba(220, 38, 38, 0.2); border: 1px solid #dc2626; color: #ef4444; padding: 7px; border-radius: 4px; font-size: 10px; text-align: center;">Drugs</div>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
<button class="save-section-btn">Save Categories</button>
|
|
544
|
+
<div class="clearfix"></div>
|
|
545
|
+
</div>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
548
|
+
|
|
549
|
+
<!-- Monitoring Page -->
|
|
550
|
+
<div id="monitoring" class="page">
|
|
551
|
+
<div class="monitoring-grid">
|
|
552
|
+
<div class="monitor-card">
|
|
553
|
+
<div class="monitor-icon">💰</div>
|
|
554
|
+
<div class="monitor-value">$12,450</div>
|
|
555
|
+
<div class="monitor-label">Total Balance</div>
|
|
556
|
+
</div>
|
|
557
|
+
<div class="monitor-card">
|
|
558
|
+
<div class="monitor-icon">📈</div>
|
|
559
|
+
<div class="monitor-value">$1,230</div>
|
|
560
|
+
<div class="monitor-label">Spent Today</div>
|
|
561
|
+
</div>
|
|
562
|
+
<div class="monitor-card">
|
|
563
|
+
<div class="monitor-icon">🔄</div>
|
|
564
|
+
<div class="monitor-value">47</div>
|
|
565
|
+
<div class="monitor-label">Transactions</div>
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
<!-- Logs Page -->
|
|
571
|
+
<div id="logs" class="page">
|
|
572
|
+
<div class="logs-container">
|
|
573
|
+
<div class="logs-header">
|
|
574
|
+
<div class="log-filter active">All</div>
|
|
575
|
+
<div class="log-filter">API</div>
|
|
576
|
+
<div class="log-filter">Connection</div>
|
|
577
|
+
<div class="log-filter">Transaction</div>
|
|
578
|
+
<div class="log-filter">Errors</div>
|
|
579
|
+
</div>
|
|
580
|
+
<div class="logs-list">
|
|
581
|
+
<div class="log-entry">
|
|
582
|
+
<span class="log-time">15:23:45</span>
|
|
583
|
+
<span class="log-level success">SUCCESS</span>
|
|
584
|
+
<span class="log-message">Connected to API</span>
|
|
585
|
+
</div>
|
|
586
|
+
<div class="log-entry">
|
|
587
|
+
<span class="log-time">15:20:33</span>
|
|
588
|
+
<span class="log-level success">SUCCESS</span>
|
|
589
|
+
<span class="log-message">Transaction: $250.00 to Amazon</span>
|
|
590
|
+
</div>
|
|
591
|
+
<div class="log-entry">
|
|
592
|
+
<span class="log-time">15:18:12</span>
|
|
593
|
+
<span class="log-level warning">WARNING</span>
|
|
594
|
+
<span class="log-message">Rate limit approaching</span>
|
|
595
|
+
</div>
|
|
596
|
+
<div class="log-entry">
|
|
597
|
+
<span class="log-time">15:10:22</span>
|
|
598
|
+
<span class="log-level error">ERROR</span>
|
|
599
|
+
<span class="log-message">Connection timeout</span>
|
|
600
|
+
</div>
|
|
601
|
+
</div>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
|
|
605
|
+
<!-- Transactions Page -->
|
|
606
|
+
<div id="transactions" class="page">
|
|
607
|
+
<div class="transactions-table">
|
|
608
|
+
<div class="table-header">
|
|
609
|
+
<div>Date</div>
|
|
610
|
+
<div>Merchant</div>
|
|
611
|
+
<div>Category</div>
|
|
612
|
+
<div>Amount</div>
|
|
613
|
+
<div>Status</div>
|
|
614
|
+
</div>
|
|
615
|
+
<div class="table-row">
|
|
616
|
+
<div class="tx-date">Mar 9, 15:20</div>
|
|
617
|
+
<div class="tx-merchant">Amazon</div>
|
|
618
|
+
<div class="tx-category">Shopping</div>
|
|
619
|
+
<div class="tx-amount">$250.00</div>
|
|
620
|
+
<div class="tx-status completed">Completed</div>
|
|
621
|
+
</div>
|
|
622
|
+
<div class="table-row">
|
|
623
|
+
<div class="tx-date">Mar 9, 14:15</div>
|
|
624
|
+
<div class="tx-merchant">Uber</div>
|
|
625
|
+
<div class="tx-category">Transport</div>
|
|
626
|
+
<div class="tx-amount">$24.50</div>
|
|
627
|
+
<div class="tx-status completed">Completed</div>
|
|
628
|
+
</div>
|
|
629
|
+
</div>
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
632
|
+
</div>
|
|
633
|
+
|
|
634
|
+
<script>
|
|
635
|
+
function toggleTheme() {
|
|
636
|
+
document.body.classList.toggle('light-theme');
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function showPage(pageId) {
|
|
640
|
+
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
|
641
|
+
document.querySelectorAll('.nav-item').forEach(n => n.classList.remove('active'));
|
|
642
|
+
document.getElementById(pageId).classList.add('active');
|
|
643
|
+
event.target.classList.add('active');
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function selectProvider(provider, btn) {
|
|
647
|
+
document.querySelectorAll('.provider-btn').forEach(b => b.classList.remove('active'));
|
|
648
|
+
btn.classList.add('active');
|
|
649
|
+
const title = document.getElementById('api-title');
|
|
650
|
+
const input = document.getElementById('api-key-input');
|
|
651
|
+
if (provider === 'wise') {
|
|
652
|
+
title.textContent = '🔑 Wise API Configuration';
|
|
653
|
+
input.placeholder = 'Enter Wise API Key';
|
|
654
|
+
} else {
|
|
655
|
+
title.textContent = '🔑 Bunq API Configuration';
|
|
656
|
+
input.placeholder = 'Enter Bunq API Key';
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function toggleCard(btn) {
|
|
661
|
+
btn.classList.toggle('collapsed');
|
|
662
|
+
const body = btn.closest('.section-card').querySelector('.section-body');
|
|
663
|
+
body.classList.toggle('collapsed');
|
|
664
|
+
const arrow = btn.querySelector('.arrow');
|
|
665
|
+
arrow.textContent = body.classList.contains('collapsed') ? '▶' : '▼';
|
|
666
|
+
}
|
|
667
|
+
</script>
|
|
668
|
+
</body>
|
|
669
|
+
</html>
|