GamerC0der commited on
Commit
e181b68
·
verified ·
1 Parent(s): 678a59a

Create templates/payment.html

Browse files
Files changed (1) hide show
  1. templates/payment.html +499 -0
templates/payment.html ADDED
@@ -0,0 +1,499 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Payment Link - AstraPay</title>
7
+ <style>
8
+ body {
9
+ margin: 0;
10
+ padding: 0;
11
+ min-height: 100vh;
12
+ background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
13
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
14
+ color: #ffffff;
15
+ line-height: 1.6;
16
+ }
17
+ .top-bar {
18
+ position: fixed;
19
+ top: 0;
20
+ left: 0;
21
+ right: 0;
22
+ background-color: rgba(26, 26, 26, 0.95);
23
+ backdrop-filter: blur(10px);
24
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
25
+ padding: 1rem 2rem;
26
+ display: flex;
27
+ justify-content: center;
28
+ gap: 2rem;
29
+ z-index: 1000;
30
+ }
31
+ .top-bar a {
32
+ color: #ffffff;
33
+ text-decoration: none;
34
+ font-size: 1.2rem;
35
+ font-weight: 600;
36
+ transition: color 0.3s ease;
37
+ }
38
+ .top-bar a:hover {
39
+ color: rgba(255, 255, 255, 0.7);
40
+ }
41
+ .top-bar a.active {
42
+ color: #ffffff;
43
+ border-bottom: 2px solid #ffffff;
44
+ padding-bottom: 0.25rem;
45
+ }
46
+ .main-content {
47
+ margin-top: 80px;
48
+ min-height: calc(100vh - 80px);
49
+ display: flex;
50
+ justify-content: center;
51
+ align-items: center;
52
+ padding: 2rem 0;
53
+ }
54
+ .container {
55
+ text-align: center;
56
+ max-width: 500px;
57
+ padding: 2rem;
58
+ }
59
+ .title {
60
+ font-size: 2.2rem;
61
+ font-weight: 600;
62
+ margin-bottom: 1.5rem;
63
+ letter-spacing: -0.02em;
64
+ }
65
+ .payment-card {
66
+ background: rgba(255, 255, 255, 0.02);
67
+ backdrop-filter: blur(20px);
68
+ border: 1px solid rgba(255, 255, 255, 0.1);
69
+ border-radius: 16px;
70
+ padding: 2.5rem;
71
+ margin-bottom: 2rem;
72
+ position: relative;
73
+ overflow: hidden;
74
+ }
75
+ .payment-card::before {
76
+ content: '';
77
+ position: absolute;
78
+ top: 0;
79
+ left: 0;
80
+ right: 0;
81
+ height: 1px;
82
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
83
+ }
84
+ .amount {
85
+ font-size: 3.2rem;
86
+ font-weight: 700;
87
+ background: linear-gradient(135deg, #ffffff 0%, #e0e0e0 100%);
88
+ -webkit-background-clip: text;
89
+ -webkit-text-fill-color: transparent;
90
+ background-clip: text;
91
+ margin-bottom: 0.5rem;
92
+ letter-spacing: -0.02em;
93
+ }
94
+ .description {
95
+ font-size: 1.1rem;
96
+ color: rgba(255, 255, 255, 0.7);
97
+ margin-bottom: 2rem;
98
+ font-weight: 400;
99
+ }
100
+ .status {
101
+ font-size: 0.95rem;
102
+ padding: 0.5rem 1.2rem;
103
+ border-radius: 20px;
104
+ display: inline-block;
105
+ margin-bottom: 2rem;
106
+ font-weight: 500;
107
+ letter-spacing: 0.01em;
108
+ }
109
+ .status.pending {
110
+ background: rgba(255, 255, 255, 0.1);
111
+ color: rgba(255, 255, 255, 0.8);
112
+ border: 1px solid rgba(255, 255, 255, 0.2);
113
+ }
114
+ .status.paid {
115
+ background: rgba(0, 255, 136, 0.1);
116
+ color: #00ff88;
117
+ border: 1px solid rgba(0, 255, 136, 0.3);
118
+ }
119
+ .pay-button {
120
+ background: linear-gradient(135deg, #ffffff 0%, #f8f8f8 100%);
121
+ color: #000000;
122
+ border: none;
123
+ padding: 1rem 2.5rem;
124
+ font-size: 1rem;
125
+ font-weight: 600;
126
+ border-radius: 12px;
127
+ cursor: pointer;
128
+ transition: all 0.3s ease;
129
+ letter-spacing: 0.01em;
130
+ box-shadow: 0 4px 20px rgba(255, 255, 255, 0.1);
131
+ }
132
+ .pay-button:hover:not(:disabled) {
133
+ transform: translateY(-2px);
134
+ box-shadow: 0 8px 30px rgba(255, 255, 255, 0.2);
135
+ }
136
+ .pay-button:disabled {
137
+ background: rgba(255, 255, 255, 0.3);
138
+ color: rgba(255, 255, 255, 0.5);
139
+ cursor: not-allowed;
140
+ transform: none;
141
+ box-shadow: none;
142
+ }
143
+ .confirmation-text {
144
+ font-size: 1.2rem;
145
+ color: #00ff88;
146
+ font-weight: 500;
147
+ margin-top: 1rem;
148
+ }
149
+ .sender-email {
150
+ font-size: 0.9rem;
151
+ color: rgba(255, 255, 255, 0.6);
152
+ margin-top: 0.5rem;
153
+ font-family: 'Monaco', 'Consolas', monospace;
154
+ }
155
+ .timer {
156
+ font-size: 0.8rem;
157
+ color: rgba(255, 255, 255, 0.5);
158
+ margin-top: 1rem;
159
+ font-family: 'Monaco', 'Consolas', monospace;
160
+ }
161
+ .expired {
162
+ color: #ff6b6b;
163
+ }
164
+ .back-link {
165
+ color: rgba(255, 255, 255, 0.6);
166
+ text-decoration: none;
167
+ font-size: 0.9rem;
168
+ margin-top: 2rem;
169
+ display: inline-block;
170
+ font-weight: 500;
171
+ transition: color 0.3s ease;
172
+ }
173
+ .back-link:hover {
174
+ color: rgba(255, 255, 255, 0.9);
175
+ }
176
+ .banner {
177
+ background: rgba(255, 193, 7, 0.15);
178
+ border: 1px solid rgba(255, 193, 7, 0.3);
179
+ border-radius: 8px;
180
+ padding: 0.75rem 1.5rem;
181
+ margin-bottom: 2rem;
182
+ color: #ffc107;
183
+ font-size: 0.9rem;
184
+ font-weight: 500;
185
+ text-align: center;
186
+ }
187
+ .payment-modal {
188
+ display: none;
189
+ position: fixed;
190
+ z-index: 1;
191
+ left: 0;
192
+ top: 0;
193
+ width: 100%;
194
+ height: 100%;
195
+ background-color: rgba(0, 0, 0, 0.9);
196
+ }
197
+ .payment-modal-content {
198
+ background-color: #1a1a1a;
199
+ margin: 15% auto;
200
+ padding: 2rem;
201
+ border-radius: 8px;
202
+ width: 90%;
203
+ max-width: 500px;
204
+ border: 1px solid #333;
205
+ text-align: center;
206
+ }
207
+ .payment-modal-title {
208
+ color: #ffffff;
209
+ font-size: 1.5rem;
210
+ font-weight: bold;
211
+ margin-bottom: 1.5rem;
212
+ }
213
+ .payment-instruction {
214
+ color: #cccccc;
215
+ font-size: 1.1rem;
216
+ margin-bottom: 2rem;
217
+ line-height: 1.6;
218
+ }
219
+ .email-address {
220
+ background-color: #2a2a2a;
221
+ border: 1px solid #555;
222
+ border-radius: 4px;
223
+ padding: 1rem;
224
+ margin: 1rem 0;
225
+ color: #00ff88;
226
+ font-family: monospace;
227
+ font-size: 1.1rem;
228
+ word-break: break-all;
229
+ display: inline-block;
230
+ }
231
+ .payment-modal-buttons {
232
+ display: flex;
233
+ gap: 1rem;
234
+ justify-content: center;
235
+ margin-top: 2rem;
236
+ }
237
+ </style>
238
+ </head>
239
+ <body>
240
+ <div class="top-bar">
241
+ <a href="/">AstraPay</a>
242
+ <a href="/bank">AstraBank</a>
243
+ </div>
244
+ <div class="main-content">
245
+ <div class="container">
246
+ <h1 class="title">AstraPay</h1>
247
+
248
+ <div class="banner">
249
+ Payments May Reset Daily. Ensure your link works.
250
+ </div>
251
+
252
+ {% if recipient_email %}
253
+ <div class="banner" style="background: rgba(0, 255, 136, 0.15); border: 1px solid rgba(0, 255, 136, 0.3); color: #00ff88;">
254
+ Your astras will go to {{ recipient_email }}
255
+ </div>
256
+ {% endif %}
257
+
258
+ <div class="payment-card">
259
+ <div class="amount">{{ amount }} Astra{{ 's' if amount > 1 else '' }}</div>
260
+ <div class="description">{{ description }}</div>
261
+ <div class="status {{ 'paid' if paid else 'pending' }}">
262
+ {{ 'Paid' if paid else 'Pending Payment' }}
263
+ </div>
264
+
265
+ {% if not paid %}
266
+ <button class="pay-button" onclick="processPayment()">
267
+ Pay {{ amount }} Astra{{ 's' if amount > 1 else '' }}
268
+ </button>
269
+ {% else %}
270
+ <div style="font-size: 1.2rem; color: #00ff88;">✓ Payment Completed</div>
271
+ {% endif %}
272
+ </div>
273
+
274
+ <a href="/" class="back-link">← Back to AstraPay</a>
275
+ </div>
276
+
277
+ <div id="paymentModal" class="payment-modal">
278
+ <div class="payment-modal-content">
279
+ <div class="payment-modal-title">Complete Payment</div>
280
+ <div class="payment-instruction">
281
+ Please send {{ amount }} Astra{{ 's' if amount > 1 else '' }} to the following address:
282
+ </div>
283
+ <div class="email-address">astratrader@astranova.org</div>
284
+
285
+ <div id="payment-status" class="payment-instruction">
286
+ <div id="waiting-message">
287
+ Waiting for payment confirmation...
288
+ <div id="timer" class="timer">5:00</div>
289
+ </div>
290
+ <div id="payment-received" style="display: none;">
291
+ ✓ Payment of {{ amount }} Astra{{ 's' if amount > 1 else '' }} received!
292
+ <br><br>
293
+ Please enter your email to confirm:
294
+ <br>
295
+ <input type="email" id="user-email" class="form-input" placeholder="Enter your email" style="margin-top: 1rem; width: 100%; max-width: 300px;">
296
+ </div>
297
+ <div id="payment-expired" style="display: none;">
298
+ Payment window expired.
299
+ <br><br>
300
+ Please create a new payment link.
301
+ </div>
302
+ <div id="confirmation-complete" style="display: none;">
303
+ <div class="confirmation-text">Payment Confirmed ✓</div>
304
+ <div class="sender-email" id="sender-email-display"></div>
305
+ </div>
306
+ </div>
307
+
308
+ <div class="payment-modal-buttons">
309
+ <button class="btn-secondary" onclick="closePaymentModal()">Cancel</button>
310
+ <button id="confirm-btn" class="pay-button" onclick="confirmPayment()" style="display: none;">Confirm Payment</button>
311
+ <button id="verify-btn" class="pay-button" onclick="verifyEmail()" style="display: none;">Verify Email</button>
312
+ </div>
313
+ </div>
314
+ </div>
315
+
316
+ <script>
317
+ let paymentCheckInterval;
318
+ let timerInterval;
319
+ let existingTransactionIds = [];
320
+ let timeLeft = 300;
321
+ let paymentTransaction = null;
322
+
323
+ function processPayment() {
324
+ document.getElementById('paymentModal').style.display = 'block';
325
+ timeLeft = 300;
326
+ paymentTransaction = null;
327
+ initPaymentCheck();
328
+ startTimer();
329
+ }
330
+
331
+ function closePaymentModal() {
332
+ document.getElementById('paymentModal').style.display = 'none';
333
+ stopPaymentCheck();
334
+ stopTimer();
335
+ document.getElementById('waiting-message').style.display = 'block';
336
+ document.getElementById('payment-received').style.display = 'none';
337
+ document.getElementById('payment-expired').style.display = 'none';
338
+ document.getElementById('confirmation-complete').style.display = 'none';
339
+ document.getElementById('confirm-btn').style.display = 'none';
340
+ document.getElementById('verify-btn').style.display = 'none';
341
+ document.getElementById('user-email').value = '';
342
+ document.getElementById('timer').classList.remove('expired');
343
+ existingTransactionIds = [];
344
+ }
345
+
346
+ async function initPaymentCheck() {
347
+ try {
348
+ const response = await fetch('/init-payment-check/{{ payment_id }}');
349
+ const data = await response.json();
350
+
351
+ if (data.existing_transaction_ids) {
352
+ existingTransactionIds = data.existing_transaction_ids;
353
+ startPaymentCheck();
354
+ } else {
355
+ console.error('Failed to initialize payment check');
356
+ }
357
+ } catch (error) {
358
+ console.error('Error initializing payment check:', error);
359
+ }
360
+ }
361
+
362
+ function startPaymentCheck() {
363
+ paymentCheckInterval = setInterval(async () => {
364
+ if (timeLeft <= 0) return;
365
+
366
+ try {
367
+ const existingIdsParam = existingTransactionIds.join(',');
368
+ const response = await fetch(`/check-payment/{{ payment_id }}?existing_ids=${existingIdsParam}`);
369
+ const data = await response.json();
370
+
371
+ if (data.payment_received) {
372
+ paymentTransaction = data.transaction;
373
+ document.getElementById('waiting-message').style.display = 'none';
374
+ document.getElementById('payment-received').style.display = 'block';
375
+ document.getElementById('verify-btn').style.display = 'inline-block';
376
+ stopPaymentCheck();
377
+ }
378
+ } catch (error) {
379
+ console.log('Error checking payment status:', error);
380
+ }
381
+ }, 2000);
382
+ }
383
+
384
+ function stopPaymentCheck() {
385
+ if (paymentCheckInterval) {
386
+ clearInterval(paymentCheckInterval);
387
+ paymentCheckInterval = null;
388
+ }
389
+ }
390
+
391
+ function startTimer() {
392
+ timerInterval = setInterval(() => {
393
+ timeLeft--;
394
+ updateTimerDisplay();
395
+
396
+ if (timeLeft <= 0) {
397
+ stopTimer();
398
+ stopPaymentCheck();
399
+ document.getElementById('waiting-message').style.display = 'none';
400
+ document.getElementById('payment-expired').style.display = 'block';
401
+ document.getElementById('confirm-btn').style.display = 'none';
402
+ document.getElementById('verify-btn').style.display = 'none';
403
+ }
404
+ }, 1000);
405
+ }
406
+
407
+ function stopTimer() {
408
+ if (timerInterval) {
409
+ clearInterval(timerInterval);
410
+ timerInterval = null;
411
+ }
412
+ }
413
+
414
+ function updateTimerDisplay() {
415
+ const minutes = Math.floor(timeLeft / 60);
416
+ const seconds = timeLeft % 60;
417
+ const timerElement = document.getElementById('timer');
418
+
419
+ timerElement.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
420
+
421
+ if (timeLeft <= 60) {
422
+ timerElement.classList.add('expired');
423
+ }
424
+ }
425
+
426
+ function verifyEmail() {
427
+ const userEmail = document.getElementById('user-email').value.trim();
428
+ const senderEmail = paymentTransaction ? paymentTransaction.from_email : '';
429
+
430
+ if (!userEmail) {
431
+ alert('Please enter your email address');
432
+ return;
433
+ }
434
+
435
+ if (userEmail.toLowerCase() === senderEmail.toLowerCase()) {
436
+ document.getElementById('verify-btn').style.display = 'none';
437
+ document.getElementById('confirm-btn').style.display = 'inline-block';
438
+ } else {
439
+ alert('Email address does not match the payment sender. Please use the email you sent the payment from.');
440
+ document.getElementById('user-email').focus();
441
+ }
442
+ }
443
+
444
+ async function confirmPayment() {
445
+ const confirmButton = document.getElementById('confirm-btn');
446
+ confirmButton.disabled = true;
447
+ confirmButton.textContent = 'Confirming...';
448
+
449
+ try {
450
+ const response = await fetch('/pay/{{ payment_id }}', {
451
+ method: 'POST',
452
+ headers: {
453
+ 'Content-Type': 'application/json',
454
+ }
455
+ });
456
+
457
+ const data = await response.json();
458
+
459
+ if (response.ok) {
460
+ document.getElementById('payment-received').style.display = 'none';
461
+ document.getElementById('confirm-btn').style.display = 'none';
462
+ document.getElementById('confirmation-complete').style.display = 'block';
463
+
464
+ if (paymentTransaction && paymentTransaction.from_email) {
465
+ document.getElementById('sender-email-display').textContent = `From: ${paymentTransaction.from_email}`;
466
+ }
467
+
468
+ stopTimer();
469
+ setTimeout(() => {
470
+ location.reload();
471
+ }, 3000);
472
+ } else {
473
+ alert('Payment confirmation failed: ' + data.error);
474
+ confirmButton.disabled = false;
475
+ confirmButton.textContent = 'Confirm Payment';
476
+ }
477
+ } catch (error) {
478
+ alert('Payment confirmation failed: ' + error.message);
479
+ confirmButton.disabled = false;
480
+ confirmButton.textContent = 'Confirm Payment';
481
+ }
482
+ }
483
+
484
+ window.onclick = function(event) {
485
+ const modal = document.getElementById('paymentModal');
486
+ if (event.target == modal) {
487
+ closePaymentModal();
488
+ }
489
+ }
490
+
491
+ window.onbeforeunload = function() {
492
+ stopPaymentCheck();
493
+ stopTimer();
494
+ };
495
+ </script>
496
+ </div>
497
+ </body>
498
+ </html>
499
+