source: interfejs/store-employee.html@ 2d1ec46

main
Last change on this file since 2d1ec46 was 79fff4f, checked in by Klimentina Efremova <klimentina08642@…>, 7 months ago

Improved employee logging in and changing password

  • Property mode set to 100644
File size: 19.8 KB
Line 
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>Employee Dashboard - Handcraft Marketplace</title>
7 <link rel="stylesheet" href="style.css">
8</head>
9<body>
10<header>
11 <div class="logo-container">
12 <img src="../images/administrative/logo.jpg" alt="Handcraft Marketplace Logo" onerror="this.style.display='none'">
13 <h1>🎨 Handcraft Marketplace</h1>
14 </div>
15 <nav>
16 <ul>
17 <li><a href="index.html">Home</a></li>
18 <li><a href="products.html">Products</a></li>
19 <li><a href="#" id="dashboard-link" class="active">Employee</a></li>
20 <li><a href="change-password.html" class="change-password-btn">🔑 Change Password</a></li>
21 <li><a href="#" id="logout-link">Logout</a></li>
22 </ul>
23 </nav>
24</header>
25
26<main>
27 <div class="dashboard-header">
28 <h2>Employee Dashboard</h2>
29 <p>Welcome, <span id="employee-name">Employee</span>!</p>
30 </div>
31
32 <div class="form-group">
33 <label for="store-select">Select Store:</label>
34 <select id="store-select" class="store-selector">
35 <option value="">Loading stores...</option>
36 </select>
37 </div>
38
39 <div id="store-dashboard" style="display: none;">
40 <div class="dashboard-stats">
41 <div class="stat-card pink">
42 <h3>Pending Orders</h3>
43 <div class="stat-number" id="pending-orders">0</div>
44 </div>
45 <div class="stat-card blue">
46 <h3>Pending Requests</h3>
47 <div class="stat-number" id="pending-requests">0</div>
48 </div>
49 <div class="stat-card">
50 <h3>Pending Refunds</h3>
51 <div class="stat-number" id="pending-refunds">0</div>
52 </div>
53 <div class="stat-card pink">
54 <h3>My Tasks</h3>
55 <div class="stat-number" id="my-tasks">0</div>
56 </div>
57 </div>
58
59 <div class="tabs">
60 <button class="tab-btn active" data-tab="orders">Orders</button>
61 <button class="tab-btn" data-tab="requests">Customer Requests</button>
62 <button class="tab-btn" data-tab="refunds">Refunds</button>
63 <button class="tab-btn" data-tab="products">Products</button>
64 <button class="tab-btn" data-tab="tasks">My Tasks</button>
65 </div>
66
67 <!-- Orders Tab -->
68 <div id="orders-tab" class="tab-content active">
69 <div class="dashboard-section">
70 <h3>Manage Orders</h3>
71 <div class="table-responsive">
72 <table id="orders-table">
73 <thead>
74 <tr>
75 <th>Order #</th>
76 <th>Client</th>
77 <th>Date</th>
78 <th>Status</th>
79 <th>Total</th>
80 <th>Actions</th>
81 </tr>
82 </thead>
83 <tbody id="orders-list">
84 <tr><td colspan="6" class="loading">Loading orders...</td></tr>
85 </tbody>
86 </table>
87 </div>
88 </div>
89 </div>
90
91 <!-- Requests Tab -->
92 <div id="requests-tab" class="tab-content">
93 <div class="dashboard-section">
94 <h3>Customer Requests</h3>
95 <div class="table-responsive">
96 <table id="requests-table">
97 <thead>
98 <tr>
99 <th>Request #</th>
100 <th>Client</th>
101 <th>Date</th>
102 <th>Problem</th>
103 <th>Status</th>
104 <th>Actions</th>
105 </tr>
106 </thead>
107 <tbody id="requests-list">
108 <tr><td colspan="6" class="loading">Loading requests...</td></tr>
109 </tbody>
110 </table>
111 </div>
112 </div>
113 </div>
114
115 <!-- Refunds Tab -->
116 <div id="refunds-tab" class="tab-content">
117 <div class="dashboard-section">
118 <h3>Refund Requests</h3>
119 <div class="table-responsive">
120 <table id="refunds-table">
121 <thead>
122 <tr>
123 <th>Refund ID</th>
124 <th>Order #</th>
125 <th>Amount</th>
126 <th>Reason</th>
127 <th>Status</th>
128 <th>Actions</th>
129 </tr>
130 </thead>
131 <tbody id="refunds-list">
132 <tr><td colspan="6" class="loading">Loading refunds...</td></tr>
133 </tbody>
134 </table>
135 </div>
136 </div>
137 </div>
138
139 <!-- Products Tab -->
140 <div id="products-tab" class="tab-content">
141 <div class="dashboard-section">
142 <h3>Store Products</h3>
143 <div class="table-responsive">
144 <table id="products-table">
145 <thead>
146 <tr>
147 <th>Code</th>
148 <th>Description</th>
149 <th>Price</th>
150 <th>Available</th>
151 <th>Actions</th>
152 </tr>
153 </thead>
154 <tbody id="products-list">
155 <tr><td colspan="5" class="loading">Loading products...</td></tr>
156 </tbody>
157 </table>
158 </div>
159 </div>
160 </div>
161
162 <!-- Tasks Tab -->
163 <div id="tasks-tab" class="tab-content">
164 <div class="dashboard-section">
165 <h3>My Assigned Tasks</h3>
166 <div id="tasks-list" class="task-list">
167 <div class="loading">Loading tasks...</div>
168 </div>
169 </div>
170 </div>
171 </div>
172</main>
173
174<!-- Respond to Request Modal -->
175<div id="respond-request-modal" class="modal" style="display: none;">
176 <div class="modal-content">
177 <span class="close">&times;</span>
178 <h2>Respond to Request</h2>
179 <form id="respond-request-form" class="form">
180 <input type="hidden" id="respond-request-num">
181 <div class="form-group">
182 <label for="request-response">Your Response</label>
183 <textarea id="request-response" rows="4" required></textarea>
184 </div>
185 <div class="form-group">
186 <label for="request-status">Update Status</label>
187 <select id="request-status">
188 <option value="in_progress">In Progress</option>
189 <option value="resolved">Resolved</option>
190 <option value="closed">Closed</option>
191 </select>
192 </div>
193 <button type="submit" class="btn-primary">Submit Response</button>
194 </form>
195 </div>
196</div>
197
198<!-- Process Refund Modal -->
199<div id="process-refund-modal" class="modal" style="display: none;">
200 <div class="modal-content">
201 <span class="close">&times;</span>
202 <h2>Process Refund</h2>
203 <form id="process-refund-form" class="form">
204 <input type="hidden" id="process-refund-id">
205 <div class="form-group">
206 <label for="refund-action">Action</label>
207 <select id="refund-action" required>
208 <option value="approved">Approve Refund</option>
209 <option value="rejected">Reject Refund</option>
210 </select>
211 </div>
212 <div class="form-group">
213 <label for="refund-notes">Notes</label>
214 <textarea id="refund-notes" rows="3"></textarea>
215 </div>
216 <button type="submit" class="btn-primary">Process Refund</button>
217 </form>
218 </div>
219</div>
220
221<footer>
222 <div class="footer-content">
223 <div class="footer-section">
224 <h3>Handcraft Marketplace</h3>
225 <p>Employee Portal</p>
226 </div>
227 <div class="footer-section">
228 <h3>Quick Links</h3>
229 <ul>
230 <li><a href="index.html">Home</a></li>
231 <li><a href="products.html">Products</a></li>
232 </ul>
233 </div>
234 </div>
235 <div class="footer-bottom">
236 <p>&copy; 2025 Handcraft Marketplace. All rights reserved.</p>
237 </div>
238</footer>
239
240<script src="script.js"></script>
241<script>
242 document.addEventListener('DOMContentLoaded', async () => {
243 const user = await loadUserData();
244
245 if (!user || user.userType !== 'store_employee') {
246 window.location.href = 'index.html';
247 return;
248 }
249
250 document.getElementById('employee-name').textContent = `${user.firstName} ${user.lastName || ''}`;
251
252 // Logout functionality
253 document.getElementById('logout-link').addEventListener('click', async (e) => {
254 e.preventDefault();
255 await logout();
256 });
257
258 // Load stores
259 const stores = user.stores || [];
260 const storeSelect = document.getElementById('store-select');
261
262 if (stores.length === 0) {
263 storeSelect.innerHTML = '<option value="">No stores assigned</option>';
264 } else {
265 storeSelect.innerHTML = stores.map(store =>
266 `<option value="${store.store_id}">${store.name} (${store.store_id})</option>`
267 ).join('');
268
269 // Load first store by default
270 loadStoreData(stores[0].store_id);
271 }
272
273 storeSelect.addEventListener('change', (e) => {
274 if (e.target.value) {
275 loadStoreData(e.target.value);
276 }
277 });
278
279 // Tab switching
280 document.querySelectorAll('.tab-btn').forEach(btn => {
281 btn.addEventListener('click', () => {
282 document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
283 document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
284
285 btn.classList.add('active');
286 document.getElementById(`${btn.dataset.tab}-tab`).classList.add('active');
287 });
288 });
289 });
290
291 async function loadStoreData(storeId) {
292 document.getElementById('store-dashboard').style.display = 'block';
293
294 // Load tasks and stats
295 await loadEmployeeTasks(storeId);
296
297 // Load orders
298 await loadStoreOrders(storeId);
299
300 // Load requests
301 await loadStoreRequests(storeId);
302
303 // Load refunds
304 await loadStoreRefunds(storeId);
305
306 // Load products
307 await loadStoreProducts(storeId);
308 }
309
310 async function loadEmployeeTasks(storeId) {
311 try {
312 const response = await fetch(`/api/employee-tasks?storeId=${storeId}`);
313 const data = await response.json();
314
315 if (data.success) {
316 document.getElementById('pending-orders').textContent = data.tasks.pending_orders.length;
317 document.getElementById('pending-requests').textContent = data.tasks.pending_requests.length;
318 document.getElementById('pending-refunds').textContent = data.tasks.pending_refunds.length;
319 document.getElementById('my-tasks').textContent =
320 data.tasks.pending_orders.length + data.tasks.pending_requests.length + data.tasks.pending_refunds.length;
321
322 // Display tasks
323 const tasksList = document.getElementById('tasks-list');
324
325 if (data.tasks.pending_orders.length > 0 || data.tasks.pending_requests.length > 0 || data.tasks.pending_refunds.length > 0) {
326 let tasksHtml = '<div class="task-items">';
327
328 if (data.tasks.pending_orders.length > 0) {
329 tasksHtml += '<h4>Pending Orders</h4>';
330 data.tasks.pending_orders.forEach(order => {
331 tasksHtml += `
332 <div class="task-item">
333 <p><strong>Order #${order.order_num}</strong> - ${order.first_name} ${order.last_name}</p>
334 <button class="btn-small" onclick="updateOrderStatus('${order.order_num}')">Update Status</button>
335 </div>
336 `;
337 });
338 }
339
340 if (data.tasks.pending_requests.length > 0) {
341 tasksHtml += '<h4>Pending Requests</h4>';
342 data.tasks.pending_requests.forEach(request => {
343 tasksHtml += `
344 <div class="task-item">
345 <p><strong>Request #${request.request_num}</strong> - ${request.first_name} ${request.last_name}</p>
346 <p>${request.problem.substring(0, 50)}${request.problem.length > 50 ? '...' : ''}</p>
347 <button class="btn-small" onclick="respondToRequest('${request.request_num}')">Respond</button>
348 </div>
349 `;
350 });
351 }
352
353 if (data.tasks.pending_refunds.length > 0) {
354 tasksHtml += '<h4>Pending Refunds</h4>';
355 data.tasks.pending_refunds.forEach(refund => {
356 tasksHtml += `
357 <div class="task-item">
358 <p><strong>Refund #${refund.refund_id}</strong> - Order #${refund.order_num}</p>
359 <p>Amount: $${parseFloat(refund.amount).toFixed(2)}</p>
360 <button class="btn-small" onclick="processRefund('${refund.refund_id}')">Process</button>
361 </div>
362 `;
363 });
364 }
365
366 tasksHtml += '</div>';
367 tasksList.innerHTML = tasksHtml;
368 } else {
369 tasksList.innerHTML = '<p>No pending tasks</p>';
370 }
371 }
372 } catch (error) {
373 console.error('Error loading tasks:', error);
374 }
375 }
376
377 async function loadStoreOrders(storeId) {
378 try {
379 const response = await fetch(`/api/store-orders?storeId=${storeId}`);
380 const data = await response.json();
381
382 const tbody = document.getElementById('orders-list');
383
384 if (data.success && data.orders.length > 0) {
385 tbody.innerHTML = data.orders.map(order => {
386 const total = order.items ? order.items.reduce((sum, item) =>
387 sum + (item.price * item.quantity), 0) : 0;
388
389 return `
390 <tr>
391 <td>${order.order_num}</td>
392 <td>${order.first_name} ${order.last_name}</td>
393 <td>${new Date(order.order_date).toLocaleDateString()}</td>
394 <td><span class="status-badge status-${order.status}">${order.status}</span></td>
395 <td>$${total.toFixed(2)}</td>
396 <td>
397 <button class="btn-small" onclick="updateOrderStatus('${order.order_num}')">Update</button>
398 <button class="btn-small" onclick="viewOrderDetails('${order.order_num}')">View</button>
399 </td>
400 </tr>
401 `;
402 }).join('');
403 } else {
404 tbody.innerHTML = '<tr><td colspan="6">No orders found</td></tr>';
405 }
406 } catch (error) {
407 console.error('Error loading orders:', error);
408 document.getElementById('orders-list').innerHTML = '<tr><td colspan="6">Error loading orders</td></tr>';
409 }
410 }
411
412 async function loadStoreRequests(storeId) {
413 // This would need a separate API endpoint
414 document.getElementById('requests-list').innerHTML = '<tr><td colspan="6">Requests feature coming soon</td></tr>';
415 }
416
417 async function loadStoreRefunds(storeId) {
418 // This would need a separate API endpoint
419 document.getElementById('refunds-list').innerHTML = '<tr><td colspan="6">Refunds feature coming soon</td></tr>';
420 }
421
422 async function loadStoreProducts(storeId) {
423 try {
424 const response = await fetch(`/api/store-products?storeId=${storeId}`);
425 const data = await response.json();
426
427 const tbody = document.getElementById('products-list');
428
429 if (data.success && data.products.length > 0) {
430 tbody.innerHTML = data.products.map(product => `
431 <tr>
432 <td>${product.code}</td>
433 <td>${product.description.substring(0, 30)}${product.description.length > 30 ? '...' : ''}</td>
434 <td>$${parseFloat(product.price).toFixed(2)}</td>
435 <td>${product.availability}</td>
436 <td>
437 <button class="btn-small" onclick="viewProduct('${product.code}')">View</button>
438 </td>
439 </tr>
440 `).join('');
441 } else {
442 tbody.innerHTML = '<tr><td colspan="5">No products found</td></tr>';
443 }
444 } catch (error) {
445 console.error('Error loading products:', error);
446 document.getElementById('products-list').innerHTML = '<tr><td colspan="5">Error loading products</td></tr>';
447 }
448 }
449
450 window.updateOrderStatus = (orderNum) => {
451 const newStatus = prompt('Enter new status (pending, processing, shipping, delivered, canceled):');
452 if (newStatus) {
453 alert(`Order ${orderNum} status updated to ${newStatus} - Feature coming soon`);
454 }
455 };
456
457 window.respondToRequest = (requestNum) => {
458 document.getElementById('respond-request-num').value = requestNum;
459 document.getElementById('respond-request-modal').style.display = 'block';
460 };
461
462 window.processRefund = (refundId) => {
463 document.getElementById('process-refund-id').value = refundId;
464 document.getElementById('process-refund-modal').style.display = 'block';
465 };
466
467 window.viewOrderDetails = (orderNum) => {
468 alert(`View order ${orderNum} details - Feature coming soon`);
469 };
470
471 window.viewProduct = (productCode) => {
472 window.location.href = `product-detail.html?code=${productCode}`;
473 };
474
475 // Form submissions
476 document.getElementById('respond-request-form').addEventListener('submit', (e) => {
477 e.preventDefault();
478 alert('Response submitted - Feature coming soon');
479 document.getElementById('respond-request-modal').style.display = 'none';
480 });
481
482 document.getElementById('process-refund-form').addEventListener('submit', (e) => {
483 e.preventDefault();
484 alert('Refund processed - Feature coming soon');
485 document.getElementById('process-refund-modal').style.display = 'none';
486 });
487
488 // Close modal functionality
489 document.querySelectorAll('.modal .close').forEach(closeBtn => {
490 closeBtn.addEventListener('click', () => {
491 closeBtn.closest('.modal').style.display = 'none';
492 });
493 });
494
495 window.addEventListener('click', (event) => {
496 if (event.target.classList.contains('modal')) {
497 event.target.style.display = 'none';
498 }
499 });
500</script>
501</body>
502</html>
Note: See TracBrowser for help on using the repository browser.