File History: src/main/resources/templates/order-confirmation.html

← View file content

File Content at Commit e6d1548

1 <!DOCTYPE html>
2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Order Confirmation - Payment Link Service</title>
7 <link rel="stylesheet" th:href="@{/css/styles.css}">
8 <style>
9 * {
10 box-sizing: border-box;
11 }
12 html, body {
13 margin: 0;
14 padding: 0;
15 width: 100%;
16 height: 100%;
17 overflow-x: hidden;
18 }
19 header {
20 display: none;
21 }
22 main {
23 padding: 0 !important;
24 margin: 0;
25 width: 100%;
26 height: 100vh;
27 display: flex;
28 align-items: center;
29 justify-content: center;
30 overflow-y: auto;
31 overflow-x: hidden;
32 }
33 .confirmation-container {
34 max-width: 500px;
35 width: 100%;
36 margin: 0 auto;
37 /* background: var(--card-bg); */
38 padding: 1.25rem;
39 border-radius: 8px;
40 /* box-shadow: var(--shadow); */
41 text-align: center;
42 overflow: hidden;
43 }
44 .success-icon {
45 font-size: 2.5rem;
46 margin-bottom: 0.5rem;
47 line-height: 1;
48 }
49 .order-details {
50 text-align: left;
51 background: var(--bg-color);
52 padding: 1rem;
53 border-radius: 6px;
54 margin: 1rem 0;
55 }
56 .order-details h3 {
57 font-size: 0.95rem;
58 margin-bottom: 0.5rem;
59 font-weight: 600;
60 }
61 .order-details h4 {
62 font-size: 0.85rem;
63 margin-bottom: 0.375rem;
64 font-weight: 600;
65 }
66 .detail-row {
67 display: flex;
68 justify-content: space-between;
69 margin-bottom: 0.375rem;
70 font-size: 0.85rem;
71 gap: 0.5rem;
72 }
73 .detail-row strong {
74 font-weight: 600;
75 }
76 .detail-row span:last-child {
77 text-align: right;
78 word-break: break-word;
79 }
80 .email-verification {
81 background: var(--bg-color);
82 padding: 1rem;
83 border-radius: 6px;
84 margin: 1rem 0;
85 text-align: left;
86 }
87 .email-verification h3 {
88 font-size: 0.9rem;
89 margin-bottom: 0.375rem;
90 font-weight: 600;
91 }
92 .email-verification p {
93 font-size: 0.8rem;
94 color: var(--text-light);
95 margin-bottom: 0.5rem;
96 }
97 .email-form {
98 display: flex;
99 gap: 0.75rem;
100 margin-top: 0.5rem;
101 }
102 .email-form input {
103 flex: 2;
104 padding: 0.875rem;
105 border: 2px solid var(--border-color);
106 border-radius: 6px;
107 font-size: 1rem;
108 min-width: 0;
109 }
110 .email-form input:focus {
111 outline: none;
112 border-color: var(--primary-color);
113 box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
114 }
115 .email-form .btn {
116 flex: 1;
117 padding: 0.875rem 1.5rem;
118 font-size: 0.9rem;
119 white-space: nowrap;
120 min-width: 120px;
121 }
122 .tracking-section {
123 background: #e8f5e9;
124 border: 2px solid var(--secondary-color);
125 padding: 1rem;
126 border-radius: 6px;
127 margin-top: 1rem;
128 }
129 .tracking-section h3 {
130 font-size: 0.9rem;
131 margin-bottom: 0.5rem;
132 color: var(--secondary-color);
133 font-weight: 600;
134 }
135 .tracking-info {
136 display: flex;
137 flex-direction: column;
138 gap: 0.5rem;
139 }
140 .tracking-item {
141 display: flex;
142 justify-content: space-between;
143 align-items: center;
144 padding: 0.5rem;
145 background: white;
146 border-radius: 6px;
147 font-size: 0.85rem;
148 gap: 0.5rem;
149 }
150 .tracking-label {
151 font-weight: 600;
152 color: var(--text-color);
153 }
154 .tracking-value {
155 color: var(--primary-color);
156 font-weight: 600;
157 word-break: break-word;
158 text-align: right;
159 }
160 .confirmation-container h2 {
161 font-size: 1.25rem;
162 margin-bottom: 0.375rem;
163 font-weight: 600;
164 }
165 .confirmation-container > p {
166 font-size: 0.85rem;
167 color: var(--text-light);
168 margin-bottom: 1rem;
169 }
170 .confirmation-container .btn {
171 padding: 0.625rem 1.25rem;
172 font-size: 0.85rem;
173 }
174 #confirmationContent {
175 max-width: 100%;
176 overflow: hidden;
177 }
178 @media (max-width: 768px) {
179 main {
180 padding: 1rem;
181 align-items: flex-start;
182 }
183 .confirmation-container {
184 max-width: 100%;
185 padding: 1rem;
186 margin: 0;
187 }
188 .success-icon {
189 font-size: 2rem;
190 }
191 .confirmation-container h2 {
192 font-size: 1.1rem;
193 }
194 .confirmation-container > p {
195 font-size: 0.8rem;
196 margin-bottom: 0.75rem;
197 }
198 .order-details {
199 padding: 0.75rem;
200 margin: 0.75rem 0;
201 }
202 .order-details h3 {
203 font-size: 0.9rem;
204 }
205 .detail-row {
206 font-size: 0.8rem;
207 flex-wrap: wrap;
208 }
209 .email-verification {
210 padding: 0.75rem;
211 margin: 0.75rem 0;
212 }
213 .email-verification h3 {
214 font-size: 0.85rem;
215 }
216 .email-verification p {
217 font-size: 0.75rem;
218 }
219 .email-form {
220 flex-direction: column;
221 gap: 0.5rem;
222 }
223 .email-form input {
224 width: 100%;
225 padding: 0.75rem;
226 font-size: 0.9rem;
227 }
228 .email-form .btn {
229 width: 100%;
230 padding: 0.5rem;
231 }
232 .tracking-section {
233 padding: 0.75rem;
234 margin-top: 0.75rem;
235 }
236 .tracking-section h3 {
237 font-size: 0.85rem;
238 }
239 .tracking-item {
240 flex-direction: column;
241 align-items: flex-start;
242 gap: 0.25rem;
243 padding: 0.5rem;
244 font-size: 0.8rem;
245 }
246 .tracking-value {
247 text-align: left;
248 word-break: break-word;
249 }
250 .confirmation-container .btn {
251 width: 100%;
252 padding: 0.625rem;
253 }
254 }
255 #error {
256 text-align: center;
257 }
258 #error .success-icon {
259 color: #ef4444;
260 font-size: 3rem;
261 margin-bottom: 0.5rem;
262 line-height: 1;
263 }
264 #error h2 {
265 font-size: 1.25rem;
266 margin-bottom: 0.5rem;
267 font-weight: 600;
268 }
269 #error > p {
270 font-size: 0.9rem;
271 color: #666;
272 margin-bottom: 1.5rem;
273 }
274 @media (max-width: 480px) {
275 main {
276 padding: 0.5rem;
277 }
278 .confirmation-container {
279 padding: 0.75rem;
280 }
281 .success-icon {
282 font-size: 1.75rem;
283 }
284 .error-icon {
285 font-size: 2rem;
286 }
287 .confirmation-container h2 {
288 font-size: 1rem;
289 }
290 #error h2 {
291 font-size: 1rem;
292 }
293 .order-details {
294 padding: 0.625rem;
295 }
296 .detail-row {
297 font-size: 0.75rem;
298 }
299 }
300 </style>
301 </head>
302 <body>
303 <header>
304 <nav class="navbar container">
305 <a th:href="@{/}" class="navbar-brand">
306 <h1>Webshop</h1>
307 </a>
308 </nav>
309 </header>
310
311 <main>
312 <div class="confirmation-container">
313 <div id="loading" class="loading">Loading order details...</div>
314 <div id="error" class="error" style="display: none;"></div>
315 <div id="confirmationContent" style="display: none;"></div>
316 </div>
317 </main>
318
319 <!-- Notification Container -->
320 <div id="notificationContainer" class="notification-container"></div>
321
322 <script th:src="@{/js/notifications.js}"></script>
323 <script th:src="@{/js/csrf.js}"></script>
324 <script>
325 const orderId = window.location.pathname.split('/').pop();
326 const API_BASE = '/api';
327 let order = null;
328 let emailVerified = false;
329
330 document.addEventListener('DOMContentLoaded', async () => {
331 await loadOrder();
332 });
333
334 async function loadOrder() {
335 const loading = document.getElementById('loading');
336 const error = document.getElementById('error');
337 const content = document.getElementById('confirmationContent');
338
339 try {
340 const response = await fetch(`${API_BASE}/orders/${orderId}`);
341 const data = await response.json();
342
343 if (!data.success) {
344 throw new Error(data.error || 'Order not found');
345 }
346
347 order = data.order;
348 loading.style.display = 'none';
349 content.style.display = 'block';
350 content.innerHTML = createConfirmationContent(order, false);
351 } catch (err) {
352 loading.style.display = 'none';
353 error.style.display = 'block';
354 error.innerHTML = createErrorContent(err.message);
355 }
356 }
357
358 function createErrorContent(errorMessage) {
359 return `
360 <div class="success-icon" style="color: #ef4444; font-size: 3rem;"></div>
361 <h2>Order Not Found</h2>
362 <p style="color: #666; margin-bottom: 2rem;">${escapeHtml(errorMessage || 'The order you are looking for could not be found. Please check your order ID and try again.')}</p>
363 `;
364 }
365
366 async function verifyEmail() {
367 const emailInput = document.getElementById('verifyEmailInput');
368 const email = emailInput?.value?.trim();
369 const verifyBtn = document.getElementById('verifyEmailBtn');
370 const content = document.getElementById('confirmationContent');
371
372 if (!email) {
373 if (window.showNotification) {
374 showNotification('Please enter your email address', 'error');
375 } else {
376 console.error('Please enter your email address');
377 }
378 return;
379 }
380
381 verifyBtn.disabled = true;
382 verifyBtn.textContent = 'Verifying...';
383
384 try {
385 // Ensure fetchWithCsrf is available
386 const fetchFn = window.fetchWithCsrf || fetch;
387 const response = await fetchFn(`${API_BASE}/orders/${orderId}/verify-email`, {
388 method: 'POST',
389 headers: {
390 'Content-Type': 'application/json'
391 },
392 body: JSON.stringify({ email })
393 });
394
395 const data = await response.json();
396
397 if (!data.success) {
398 throw new Error(data.error || 'Email verification failed');
399 }
400
401 // Email verified - update order with tracking details
402 order = data.order;
403 emailVerified = true;
404 content.innerHTML = createConfirmationContent(order, true);
405 if (window.showNotification) {
406 showNotification('Email verified! Tracking details are now visible.', 'success');
407 }
408 } catch (err) {
409 if (window.showNotification) {
410 showNotification(`Error: ${err.message}`, 'error');
411 } else {
412 console.error('Error:', err.message);
413 }
414 verifyBtn.disabled = false;
415 verifyBtn.textContent = 'Verify Email';
416 }
417 }
418
419 function createConfirmationContent(order, verified) {
420 const itemsHtml = order.items.map(item => `
421 <div class="detail-row">
422 <span>${escapeHtml(item.productName)} x${item.quantity}</span>
423 <span>${order.currency} ${(item.price / 100).toFixed(2)}</span>
424 </div>
425 `).join('');
426
427 const trackingSection = verified && (order.trackingId || order.carrier) ? `
428 <div class="tracking-section">
429 <h3 style="margin-bottom: 1rem; color: var(--secondary-color);">Tracking Information</h3>
430 <div class="tracking-info">
431 ${order.trackingId ? `
432 <div class="tracking-item">
433 <span class="tracking-label">Tracking ID:</span>
434 <span class="tracking-value">${escapeHtml(order.trackingId)}</span>
435 </div>
436 ` : ''}
437 ${order.carrier ? `
438 <div class="tracking-item">
439 <span class="tracking-label">Carrier:</span>
440 <span class="tracking-value">${escapeHtml(order.carrier)}</span>
441 </div>
442 ` : ''}
443 ${order.trackingId && order.carrier ? `
444 <div style="margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--border-color);">
445 <a href="https://www.google.com/search?q=${encodeURIComponent(order.carrier + ' ' + order.trackingId)}"
446 target="_blank"
447 class="btn"
448 style="display: inline-block; text-decoration: none;">
449 Track Package
450 </a>
451 </div>
452 ` : ''}
453 </div>
454 </div>
455 ` : '';
456
457 const emailVerificationSection = !verified ? `
458 <div class="email-verification">
459 <h3 style="margin-bottom: 0.5rem;">View Tracking Details</h3>
460 <p style="color: #666; margin-bottom: 1rem;">Enter your email address to view tracking information for this order.</p>
461 <div class="email-form">
462 <input
463 type="email"
464 id="verifyEmailInput"
465 placeholder="Enter your email address"
466 onkeypress="if(event.key === 'Enter') verifyEmail()">
467 <button class="btn" id="verifyEmailBtn" onclick="verifyEmail()">Verify Email</button>
468 </div>
469 </div>
470 ` : '';
471
472 return `
473 <div class="success-icon" style="color: #28a745; font-size: 3rem;"></div>
474 <h2>Order Confirmed!</h2>
475 <p style="color: #666; margin-bottom: 2rem;">Thank you for your purchase. Your order has been successfully processed.</p>
476
477 <div class="order-details">
478 <h3 style="margin-bottom: 1rem;">Order Details</h3>
479 <div class="detail-row">
480 <span><strong>Order ID:</strong></span>
481 <span>${order.orderId}</span>
482 </div>
483 <div class="detail-row">
484 <span><strong>Status:</strong></span>
485 <span>${order.status}</span>
486 </div>
487 <div class="detail-row">
488 <span><strong>Date:</strong></span>
489 <span>${new Date(order.createdAt).toLocaleString()}</span>
490 </div>
491 <div style="border-top: 1px solid var(--border-color); margin: 1rem 0; padding-top: 1rem;">
492 <h4 style="margin-bottom: 0.5rem;">Items:</h4>
493 ${itemsHtml}
494 </div>
495 <div style="border-top: 2px solid var(--border-color); margin-top: 1rem; padding-top: 1rem;">
496 <div class="detail-row">
497 <span><strong>Subtotal:</strong></span>
498 <span>${order.currency} ${(order.subtotal / 100).toFixed(2)}</span>
499 </div>
500 ${order.shippingInfo?.cost > 0 ? `
501 <div class="detail-row">
502 <span><strong>Shipping:</strong></span>
503 <span>${order.currency} ${(order.shippingInfo.cost / 100).toFixed(2)}</span>
504 </div>
505 ` : ''}
506 ${order.shippingInfo?.tax > 0 ? `
507 <div class="detail-row">
508 <span><strong>Tax:</strong></span>
509 <span>${order.currency} ${(order.shippingInfo.tax / 100).toFixed(2)}</span>
510 </div>
511 ` : ''}
512 <div class="detail-row" style="font-size: 1.2rem; font-weight: 700; margin-top: 0.5rem;">
513 <span><strong>Total:</strong></span>
514 <span>${order.currency} ${(order.total / 100).toFixed(2)}</span>
515 </div>
516 </div>
517 </div>
518
519 ${emailVerificationSection}
520 ${trackingSection}
521 `;
522 }
523 // <div style="margin-top: 2rem;">
524 // <a th:href="@{/}" class="btn">Continue Shopping</a>
525 // </div>
526
527 function escapeHtml(text) {
528 if (!text) return '';
529 const div = document.createElement('div');
530 div.textContent = text;
531 return div.innerHTML;
532 }
533
534 // Make verifyEmail globally available
535 window.verifyEmail = verifyEmail;
536 </script>
537 </body>
538 </html>
539

Commits

Commit Author Date Message File SHA Actions
f0438c2 <f69e50@finnacloud.com> 1766443042 +0300 12/22/2025, 10:37:22 PM increment once more 1b32856 View
188fc92 <f69e50@finnacloud.com> 1766442998 +0300 12/22/2025, 10:36:38 PM increment 1b32856 View
4617f76 <f69e50@finnacloud.com> 1766442953 +0300 12/22/2025, 10:35:53 PM rename branch from main to master oops 1b32856 View
e6d1548 <f69e50@finnacloud.com> 1766442769 +0300 12/22/2025, 10:32:49 PM add initial test workflow file 1b32856 Hide
9c24ca4 <f69e50@finnacloud.com> 1766442705 +0300 12/22/2025, 10:31:45 PM add CI configuration and test script for Jenkins build 1b32856 View
690c1f6 <f69e50@finnacloud.com> 1766368110 +0300 12/22/2025, 1:48:30 AM initialize backend structure with controllers, DTOs, and configuration files 1b32856 View