File History: src/main/resources/templates/admin.html

← View file content

File Content at Commit 188fc92

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>Admin Panel - Payment Link Service</title>
7 <link rel="stylesheet" th:href="@{/css/styles.css}">
8 <style>
9 .admin-container {
10 max-width: 1400px;
11 margin: 2rem auto;
12 }
13 .admin-tabs {
14 display: flex;
15 gap: 1rem;
16 margin-bottom: 2rem;
17 border-bottom: 2px solid var(--border-color);
18 }
19 .admin-tab {
20 padding: 1rem 2rem;
21 background: none;
22 border: none;
23 border-bottom: 3px solid transparent;
24 cursor: pointer;
25 font-size: 1rem;
26 font-weight: 600;
27 color: #666;
28 transition: all 0.3s ease;
29 }
30 .admin-tab.active {
31 color: var(--primary-color);
32 border-bottom-color: var(--primary-color);
33 }
34 .admin-tab:hover {
35 color: var(--primary-color);
36 }
37 .admin-content {
38 display: none;
39 }
40 .admin-content.active {
41 display: block;
42 }
43 .admin-header {
44 display: flex;
45 justify-content: space-between;
46 align-items: center;
47 margin-bottom: 2rem;
48 }
49 .admin-table {
50 width: 100%;
51 background: var(--card-bg);
52 border-radius: 12px;
53 overflow: hidden;
54 box-shadow: var(--shadow);
55 }
56 .admin-table table {
57 width: 100%;
58 border-collapse: collapse;
59 }
60 .admin-table th {
61 background: var(--bg-color);
62 padding: 1rem;
63 text-align: left;
64 font-weight: 600;
65 border-bottom: 2px solid var(--border-color);
66 }
67 .admin-table td {
68 padding: 1rem;
69 border-bottom: 1px solid var(--border-color);
70 }
71 .admin-table tr:hover {
72 background: #f8f9fa;
73 }
74 .admin-form {
75 background: var(--card-bg);
76 padding: 2rem;
77 border-radius: 12px;
78 box-shadow: var(--shadow);
79 margin-bottom: 2rem;
80 }
81 .form-row {
82 display: grid;
83 grid-template-columns: 1fr 1fr;
84 gap: 1rem;
85 margin-bottom: 1rem;
86 }
87 .form-full {
88 grid-column: 1 / -1;
89 }
90 .image-preview {
91 width: 200px;
92 height: 200px;
93 object-fit: cover;
94 border-radius: 8px;
95 margin-top: 0.5rem;
96 border: 2px solid var(--border-color);
97 }
98 .btn-small {
99 padding: 0.5rem 1rem;
100 font-size: 0.9rem;
101 }
102 .btn-danger {
103 background: #e74c3c;
104 }
105 .btn-danger:hover {
106 background: #c0392b;
107 }
108 .status-badge {
109 display: inline-block;
110 padding: 0.25rem 0.75rem;
111 border-radius: 12px;
112 font-size: 0.85rem;
113 font-weight: 600;
114 }
115 .status-pending {
116 background: #fff3cd;
117 color: #856404;
118 }
119 .status-paid {
120 background: #d4edda;
121 color: #155724;
122 }
123 .status-cancelled {
124 background: #f8d7da;
125 color: #721c24;
126 }
127 .status-processing {
128 background: #d1ecf1;
129 color: #0c5460;
130 }
131 .status-completed {
132 background: #d4edda;
133 color: #155724;
134 }
135 .status-enabled {
136 background: #d4edda;
137 color: #155724;
138 }
139 .status-disabled {
140 background: #f8d7da;
141 color: #721c24;
142 }
143 .loading {
144 padding: 2rem;
145 text-align: center;
146 color: #666;
147 }
148 .error {
149 padding: 2rem;
150 text-align: center;
151 color: #e74c3c;
152 background: #fee;
153 border-radius: 8px;
154 margin: 1rem 0;
155 }
156 @media (max-width: 968px) {
157 .admin-container {
158 margin: 1rem auto;
159 }
160 .admin-tabs {
161 flex-wrap: wrap;
162 gap: 0.5rem;
163 }
164 .admin-tab {
165 padding: 0.75rem 1rem;
166 font-size: 0.9rem;
167 }
168 .admin-header {
169 flex-direction: column;
170 align-items: flex-start;
171 gap: 1rem;
172 }
173 .admin-table {
174 overflow-x: auto;
175 }
176 .admin-table table {
177 min-width: 600px;
178 }
179 .form-row {
180 grid-template-columns: 1fr;
181 }
182 .image-preview {
183 width: 150px;
184 height: 150px;
185 }
186 }
187 </style>
188 </head>
189 <body>
190 <header>
191 <nav class="navbar container">
192 <a th:href="@{/}" class="navbar-brand">
193 <h1>Webshop</h1>
194 </a>
195 <div class="navbar-actions">
196 <a th:href="@{/}" class="cart-button" style="background: #6c757d;">View Shop</a>
197 <a th:href="@{/admin}" class="cart-button">Admin Panel</a>
198 </div>
199 </nav>
200 </header>
201
202 <main class="container">
203 <div class="admin-container">
204 <div class="page-header">
205 <h2>Admin Panel</h2>
206 <p>Manage products and view orders</p>
207 </div>
208
209 <div class="admin-tabs">
210 <button class="admin-tab active" onclick="switchTab('products')">Products</button>
211 <button class="admin-tab" onclick="switchTab('orders')">Orders</button>
212 <button class="admin-tab" onclick="switchTab('regions')">Regions</button>
213 <button class="admin-tab" onclick="switchTab('translations')">Translations</button>
214 <button class="admin-tab" onclick="switchTab('currency')">Currency</button>
215 </div>
216
217 <!-- Products Tab -->
218 <div id="productsTab" class="admin-content active">
219 <div class="admin-header">
220 <h3>Product Management</h3>
221 <button class="btn btn-success" onclick="openProductForm()">Add New Product</button>
222 </div>
223
224 <div id="productForm" class="admin-form" style="display: none;">
225 <h4 id="formTitle">Add Product</h4>
226 <form id="productFormElement" onsubmit="handleProductSubmit(event)">
227 <input type="hidden" id="productId" name="id">
228
229 <div class="form-row">
230 <div class="form-group">
231 <label>Product Name *</label>
232 <input type="text" id="productName" name="name" required>
233 </div>
234 <div class="form-group">
235 <label>Category *</label>
236 <input type="text" id="productCategory" name="category" required placeholder="e.g., electronics, clothing">
237 </div>
238 </div>
239
240 <div class="form-group form-full">
241 <label>Description</label>
242 <textarea id="productDescription" name="description" rows="3"></textarea>
243 </div>
244
245 <div class="form-row">
246 <div class="form-group">
247 <label>Price *</label>
248 <input type="number" id="productPrice" name="price" step="0.01" min="0" required placeholder="e.g., 99.99">
249 <small>Enter price in dollars (will be converted to cents)</small>
250 </div>
251 <div class="form-group">
252 <label>Currency *</label>
253 <select id="productCurrency" name="currency" required>
254 <option value="USD">USD</option>
255 <option value="EUR">EUR</option>
256 <option value="GBP">GBP</option>
257 <option value="CAD">CAD</option>
258 <option value="AUD">AUD</option>
259 </select>
260 </div>
261 </div>
262
263 <div class="form-row">
264 <div class="form-group">
265 <label>Stock Quantity</label>
266 <input type="number" id="productStock" name="stock" min="0" placeholder="Leave empty for unlimited">
267 </div>
268 <div class="form-group">
269 <label>Image URL</label>
270 <input type="url" id="productImage" name="image" placeholder="https://example.com/image.jpg">
271 <small>Enter full URL to product image</small>
272 </div>
273 </div>
274
275 <div class="form-group form-full">
276 <label>Tax Handling</label>
277 <select id="productTaxIncluded" name="taxIncluded">
278 <option value="false">Tax Excluded (price shown is before tax)</option>
279 <option value="true">Tax Included (price shown includes tax)</option>
280 </select>
281 <small>Choose whether the product price includes tax or not</small>
282 </div>
283
284 <div class="form-group form-full" id="imagePreviewContainer" style="display: none;">
285 <label>Image Preview</label>
286 <img id="imagePreview" class="image-preview" src="" alt="Preview">
287 </div>
288
289 <div style="display: flex; gap: 1rem; margin-top: 1.5rem;">
290 <button type="submit" class="btn btn-success">Save Product</button>
291 <button type="button" class="btn" onclick="closeProductForm()">Cancel</button>
292 </div>
293 </form>
294 </div>
295
296 <div id="productsList" class="admin-table">
297 <div class="loading">Loading products...</div>
298 </div>
299 </div>
300
301 <!-- Orders Tab -->
302 <div id="ordersTab" class="admin-content">
303 <div class="admin-header">
304 <h3>Order Management</h3>
305 </div>
306
307 <div id="ordersList" class="admin-table">
308 <div class="loading">Loading orders...</div>
309 </div>
310 </div>
311
312 <!-- Regions Tab -->
313 <div id="regionsTab" class="admin-content">
314 <div class="admin-header">
315 <h3>Region Management</h3>
316 <div style="display: flex; gap: 1rem;">
317 <button class="btn btn-success" onclick="loadRegions()">Refresh</button>
318 <div id="regionStats" style="background: var(--card-bg); padding: 0.5rem 1rem; border-radius: 8px; font-size: 0.9rem;">
319 <strong>Loading stats...</strong>
320 </div>
321 </div>
322 </div>
323
324 <div style="margin-bottom: 1rem; display: flex; gap: 1rem;">
325 <button class="btn btn-small" onclick="filterRegions('all')">All</button>
326 <button class="btn btn-small" onclick="filterRegions('enabled')">Enabled Only</button>
327 <button class="btn btn-small" onclick="filterRegions('disabled')">Disabled Only</button>
328 </div>
329
330 <div id="regionsList" class="admin-table">
331 <div class="loading">Loading regions...</div>
332 </div>
333 </div>
334
335 <!-- Translations Tab -->
336 <div id="translationsTab" class="admin-content">
337 <div class="admin-header">
338 <h3>Translation Management</h3>
339 <button class="btn btn-success" onclick="openTranslationForm()">Add Translation</button>
340 </div>
341
342 <div id="translationForm" class="admin-form" style="display: none;">
343 <h4>Add/Edit Translation</h4>
344 <form id="translationFormElement" onsubmit="handleTranslationSubmit(event)">
345 <div class="form-row">
346 <div class="form-group">
347 <label>Entity Type *</label>
348 <select id="translationEntityType" name="entityType" required onchange="loadEntitiesForTranslation()">
349 <option value="">Select type...</option>
350 <option value="product">Product</option>
351 <option value="category">Category</option>
352 <option value="ui">UI Text</option>
353 </select>
354 </div>
355 <div class="form-group">
356 <label>Entity ID *</label>
357 <input type="text" id="translationEntityId" name="entityId" required placeholder="e.g., 1, electronics, welcome_message">
358 </div>
359 </div>
360
361 <div class="form-row">
362 <div class="form-group">
363 <label>Field Name *</label>
364 <select id="translationFieldName" name="fieldName" required>
365 <option value="">Select field...</option>
366 <option value="name">Name</option>
367 <option value="description">Description</option>
368 </select>
369 </div>
370 <div class="form-group">
371 <label>Language *</label>
372 <select id="translationLanguageCode" name="languageCode" required>
373 <option value="">Select language...</option>
374 <option value="es">Spanish (es)</option>
375 <option value="fr">French (fr)</option>
376 <option value="de">German (de)</option>
377 <option value="zh">Chinese (zh)</option>
378 </select>
379 </div>
380 </div>
381
382 <div class="form-group form-full">
383 <label>Translated Text *</label>
384 <textarea id="translationText" name="translatedText" rows="3" required></textarea>
385 </div>
386
387 <div style="display: flex; gap: 1rem; margin-top: 1.5rem;">
388 <button type="submit" class="btn btn-success">Save Translation</button>
389 <button type="button" class="btn" onclick="closeTranslationForm()">Cancel</button>
390 </div>
391 </form>
392 </div>
393
394 <div id="translationsList" class="admin-table">
395 <div class="loading">Select a product to view translations</div>
396 </div>
397 </div>
398
399 <!-- Currency Tab -->
400 <div id="currencyTab" class="admin-content">
401 <div class="admin-header">
402 <h3>Currency Management</h3>
403 <div style="display: flex; gap: 1rem;">
404 <button class="btn btn-success" onclick="refreshExchangeRates()">Refresh Rates Now</button>
405 <button class="btn" onclick="loadCurrencyRates()">Reload</button>
406 </div>
407 </div>
408
409 <div style="background: var(--card-bg); padding: 1.5rem; border-radius: 12px; margin-bottom: 1.5rem; box-shadow: var(--shadow);">
410 <h4 style="margin-bottom: 1rem;">Exchange Rate Information</h4>
411 <div id="currencyInfo" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem;">
412 <div>
413 <strong>Base Currency:</strong>
414 <p style="font-size: 1.2rem; margin: 0.5rem 0;">USD</p>
415 </div>
416 <div>
417 <strong>Last Updated:</strong>
418 <p id="lastUpdated" style="font-size: 0.9rem; margin: 0.5rem 0; color: #666;">Loading...</p>
419 </div>
420 <div>
421 <strong>Total Rates:</strong>
422 <p id="totalRates" style="font-size: 1.2rem; margin: 0.5rem 0;">-</p>
423 </div>
424 <div>
425 <strong>Supported Currencies:</strong>
426 <p id="supportedCount" style="font-size: 1.2rem; margin: 0.5rem 0;">20+</p>
427 </div>
428 </div>
429 </div>
430
431 <div id="currencyRatesList" class="admin-table">
432 <div class="loading">Loading exchange rates...</div>
433 </div>
434 </div>
435 </div>
436 </main>
437
438 <!-- Notification Container -->
439 <div id="notificationContainer" class="notification-container"></div>
440
441 <script th:src="@{/js/notifications.js}"></script>
442 <script th:src="@{/js/csrf.js}"></script>
443 <script th:src="@{/js/admin.js}"></script>
444 </body>
445 </html>
446
447
448

Commits

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