source: interfejs/client-dashboard.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: 15.7 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>My 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">My Dashboard</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>My Dashboard</h2>
29 <p>Welcome back, <span id="client-name">Client</span>!</p>
30 </div>
31
32 <div class="dashboard-stats">
33 <div class="stat-card pink">
34 <h3>Total Orders</h3>
35 <div class="stat-number" id="total-orders">0</div>
36 </div>
37 <div class="stat-card blue">
38 <h3>Total Spent</h3>
39 <div class="stat-number" id="total-spent">$0</div>
40 </div>
41 <div class="stat-card">
42 <h3>Pending Orders</h3>
43 <div class="stat-number" id="pending-orders">0</div>
44 </div>
45 <div class="stat-card pink">
46 <h3>Delivered</h3>
47 <div class="stat-number" id="delivered-orders">0</div>
48 </div>
49 </div>
50
51 <div class="tabs">
52 <button class="tab-btn active" data-tab="orders">My Orders</button>
53 <button class="tab-btn" data-tab="addresses">Delivery Addresses</button>
54 <button class="tab-btn" data-tab="requests">My Requests</button>
55 <button class="tab-btn" data-tab="reviews">My Reviews</button>
56 <button class="tab-btn" data-tab="profile">Profile Settings</button>
57 </div>
58
59 <!-- Orders Tab -->
60 <div id="orders-tab" class="tab-content active">
61 <div class="dashboard-section">
62 <h3>My Orders</h3>
63 <div class="table-responsive">
64 <table id="orders-table">
65 <thead>
66 <tr>
67 <th>Order #</th>
68 <th>Store</th>
69 <th>Date</th>
70 <th>Status</th>
71 <th>Total</th>
72 <th>Actions</th>
73 </tr>
74 </thead>
75 <tbody id="orders-list">
76 <tr><td colspan="6" class="loading">Loading orders...</td></tr>
77 </tbody>
78 </table>
79 </div>
80 </div>
81 </div>
82
83 <!-- Addresses Tab -->
84 <div id="addresses-tab" class="tab-content">
85 <div class="dashboard-section">
86 <h3>Delivery Addresses</h3>
87 <button id="add-address-btn" class="btn-primary" style="margin-bottom: 1rem;">Add New Address</button>
88
89 <div id="addresses-list">
90 <div class="loading">Loading addresses...</div>
91 </div>
92
93 <div id="add-address-form" style="display: none;">
94 <h4>Add New Address</h4>
95 <form class="form">
96 <div class="form-group">
97 <label for="new-address">Street Address *</label>
98 <input type="text" id="new-address" required>
99 </div>
100 <div class="form-row">
101 <div class="form-group">
102 <label for="new-city">City *</label>
103 <input type="text" id="new-city" required>
104 </div>
105 <div class="form-group">
106 <label for="new-postcode">Postcode *</label>
107 <input type="text" id="new-postcode" required>
108 </div>
109 </div>
110 <div class="form-group">
111 <label for="new-country">Country *</label>
112 <input type="text" id="new-country" required>
113 </div>
114 <div class="form-group checkbox">
115 <input type="checkbox" id="new-is-default">
116 <label for="new-is-default">Set as default address</label>
117 </div>
118 <button type="submit" class="btn-primary">Save Address</button>
119 <button type="button" class="btn-secondary" id="cancel-add-address">Cancel</button>
120 </form>
121 </div>
122 </div>
123 </div>
124
125 <!-- Requests Tab -->
126 <div id="requests-tab" class="tab-content">
127 <div class="dashboard-section">
128 <h3>My Requests</h3>
129 <button id="new-request-btn" class="btn-primary" style="margin-bottom: 1rem;">New Request</button>
130
131 <div class="table-responsive">
132 <table id="requests-table">
133 <thead>
134 <tr>
135 <th>Request #</th>
136 <th>Store</th>
137 <th>Date</th>
138 <th>Problem</th>
139 <th>Status</th>
140 <th>Actions</th>
141 </tr>
142 </thead>
143 <tbody id="requests-list">
144 <tr><td colspan="6" class="loading">Loading requests...</td></tr>
145 </tbody>
146 </table>
147 </div>
148
149 <div id="new-request-form" style="display: none; margin-top: 2rem;">
150 <h4>New Request</h4>
151 <form class="form">
152 <div class="form-group">
153 <label for="request-store">Store *</label>
154 <select id="request-store" required>
155 <option value="">Select Store</option>
156 </select>
157 </div>
158 <div class="form-group">
159 <label for="request-problem">Problem Description *</label>
160 <textarea id="request-problem" rows="4" required></textarea>
161 </div>
162 <button type="submit" class="btn-primary">Submit Request</button>
163 <button type="button" class="btn-secondary" id="cancel-new-request">Cancel</button>
164 </form>
165 </div>
166 </div>
167 </div>
168
169 <!-- Reviews Tab -->
170 <div id="reviews-tab" class="tab-content">
171 <div class="dashboard-section">
172 <h3>My Reviews</h3>
173 <div class="table-responsive">
174 <table id="reviews-table">
175 <thead>
176 <tr>
177 <th>Product</th>
178 <th>Rating</th>
179 <th>Comment</th>
180 <th>Date</th>
181 <th>Actions</th>
182 </tr>
183 </thead>
184 <tbody id="reviews-list">
185 <tr><td colspan="5" class="loading">Loading reviews...</td></tr>
186 </tbody>
187 </table>
188 </div>
189 </div>
190 </div>
191
192 <!-- Profile Tab -->
193 <div id="profile-tab" class="tab-content">
194 <div class="dashboard-section">
195 <h3>Profile Settings</h3>
196 <form id="profile-form" class="form">
197 <div class="form-row">
198 <div class="form-group">
199 <label for="profile-first-name">First Name</label>
200 <input type="text" id="profile-first-name">
201 </div>
202 <div class="form-group">
203 <label for="profile-last-name">Last Name</label>
204 <input type="text" id="profile-last-name">
205 </div>
206 </div>
207
208 <div class="form-group">
209 <label for="profile-email">Email</label>
210 <input type="email" id="profile-email" readonly>
211 <small>Email cannot be changed</small>
212 </div>
213
214 <h4>Change Password</h4>
215 <div class="form-group">
216 <label for="current-password">Current Password</label>
217 <input type="password" id="current-password">
218 </div>
219
220 <div class="form-group">
221 <label for="new-password">New Password</label>
222 <input type="password" id="new-password">
223 <small class="password-hint">Leave blank to keep current password</small>
224 </div>
225
226 <div class="form-group">
227 <label for="confirm-new-password">Confirm New Password</label>
228 <input type="password" id="confirm-new-password">
229 </div>
230
231 <button type="submit" class="btn-primary">Update Profile</button>
232 </form>
233 </div>
234 </div>
235</main>
236
237<footer>
238 <div class="footer-content">
239 <div class="footer-section">
240 <h3>Handcraft Marketplace</h3>
241 <p>Your personal shopping dashboard</p>
242 </div>
243 <div class="footer-section">
244 <h3>Quick Links</h3>
245 <ul>
246 <li><a href="index.html">Home</a></li>
247 <li><a href="products.html">Products</a></li>
248 </ul>
249 </div>
250 </div>
251 <div class="footer-bottom">
252 <p>&copy; 2025 Handcraft Marketplace. All rights reserved.</p>
253 </div>
254</footer>
255
256<script src="script.js"></script>
257<script>
258 document.addEventListener('DOMContentLoaded', async () => {
259 const user = await loadUserData();
260
261 if (!user || user.userType !== 'client') {
262 window.location.href = 'index.html';
263 return;
264 }
265
266 document.getElementById('client-name').textContent = `${user.firstName} ${user.lastName || ''}`;
267
268 // Logout functionality
269 document.getElementById('logout-link').addEventListener('click', async (e) => {
270 e.preventDefault();
271 await logout();
272 });
273
274 // Load profile data
275 document.getElementById('profile-first-name').value = user.firstName || '';
276 document.getElementById('profile-last-name').value = user.lastName || '';
277 document.getElementById('profile-email').value = user.email || '';
278
279 // Load client stats
280 await loadClientStats(user.id);
281
282 // Load orders
283 await loadClientOrders(user.id);
284
285 // Load addresses
286 await loadClientAddresses(user.id);
287
288 // Load requests
289 await loadClientRequests(user.id);
290
291 // Load reviews
292 await loadClientReviews(user.id);
293
294 // Load stores for request form
295 await loadStores();
296
297 // Tab switching
298 document.querySelectorAll('.tab-btn').forEach(btn => {
299 btn.addEventListener('click', () => {
300 document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
301 document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
302
303 btn.classList.add('active');
304 document.getElementById(`${btn.dataset.tab}-tab`).classList.add('active');
305 });
306 });
307
308 // Address form toggle
309 document.getElementById('add-address-btn').addEventListener('click', () => {
310 document.getElementById('add-address-form').style.display = 'block';
311 document.getElementById('add-address-btn').style.display = 'none';
312 });
313
314 document.getElementById('cancel-add-address').addEventListener('click', () => {
315 document.getElementById('add-address-form').style.display = 'none';
316 document.getElementById('add-address-btn').style.display = 'inline-block';
317 });
318
319 // Request form toggle
320 document.getElementById('new-request-btn').addEventListener('click', () => {
321 document.getElementById('new-request-form').style.display = 'block';
322 document.getElementById('new-request-btn').style.display = 'none';
323 });
324
325 document.getElementById('cancel-new-request').addEventListener('click', () => {
326 document.getElementById('new-request-form').style.display = 'none';
327 document.getElementById('new-request-btn').style.display = 'inline-block';
328 });
329
330 // Form submissions
331 document.getElementById('add-address-form').addEventListener('submit', addAddress);
332 document.getElementById('new-request-form').addEventListener('submit', submitRequest);
333 document.getElementById('profile-form').addEventListener('submit', updateProfile);
334 });
335
336 async function loadClientStats(clientId) {
337 try {
338 const response = await fetch(`/api/client-stats`);
339 const data = await response.json();
340
341 if (data.success) {
342 document.getElementById('total-orders').textContent = data.stats.total_orders || 0;
343 document.getElementById('total-spent').textContent = `$${parseFloat(data.stats.total_spent || 0).toFixed(2)}`;
344 document.getElementById('pending-orders').textContent = data.stats.pending_orders || 0;
345 document.getElementById('delivered-orders').textContent = data.stats.delivered_orders || 0;
346 }
347 } catch (error) {
348 console.error('Error loading stats:', error);
349 }
350 }
351
352 async function loadClientOrders(clientId) {
353 try {
354 const response = await fetch('/api/user-orders');
355 const data = await response.json();
356
357 const tbody = document.getElementById('orders-list');
358
359 if (data.success && data.orders.length > 0) {
360 tbody.innerHTML = data.orders.map(order => {
361 const total = order.items ? order.items.reduce((sum, item) =>
362 sum + (item.price * item.quantity), 0) : 0;
363
364 return `
365 <tr>
366 <td>${order.order_num}</td>
367 <td>${order.store_name || 'Unknown'}</td>
368 <td>${new Date(order.order_date).toLocaleDateString()}</td>
369 <td><span class="status-badge status-${order.status}">${order.status}</span></td>
370 <td>$${total.toFixed(2)}</td>
371 <td>
372 <button class="btn-small" onclick="viewOrder('${order.order_num}')">View</button>
373 ${order.status === 'delivered' ?
374 `<button class="btn-small" onclick="reviewOrder('${order.order_num}')">Review</button>` : ''}
375 </td>
376 </tr>
377 `;
378 }).join('');
379 } else {
380 tbody.innerHTML = '<tr><td colspan="6">No orders found</td></tr>';
381 }
382 } catch (error) {
383 console.error('Error loading orders:', error);
384 document.getElementById('orders-list').innerHTML = '<tr><td colspan="6">Error loading orders</td></tr>';
385 }
386 }
387
388 async function loadClientAddresses(clientId) {
389 // This would need a separate API endpoint
390 document.getElementById('addresses-list').innerHTML = `
391 <div class="address-card">
392 <p><strong>Default Address:</strong></p>
393 <p>st. Center num.10, Skopje 1000, North Macedonia</p>
394 <button class="btn-small">Edit</button>
395 <button class="btn-small" style="background: var(--danger);">Delete</button>
396 </div>
397 `;
398 }
399
400 async function loadClientRequests(clientId) {
401 // This would need a separate API endpoint
402 document.getElementById('requests-list').innerHTML = '<tr><td colspan="6">No requests found</td></tr>';
403 }
404
405 async function loadClientReviews(clientId) {
406 // This would need a separate API endpoint
407 document.getElementById('reviews-list').innerHTML = '<tr><td colspan="5">No reviews yet</td></tr>';
408 }
409
410 async function loadStores() {
411 try {
412 const response = await fetch('/api/stores');
413 const data = await response.json();
414
415 if (data.success) {
416 const select = document.getElementById('request-store');
417 select.innerHTML = '<option value="">Select Store</option>' +
418 data.stores.map(store =>
419 `<option value="${store.store_id}">${store.name}</option>`
420 ).join('');
421 }
422 } catch (error) {
423 console.error('Error loading stores:', error);
424 }
425 }
426
427 function addAddress(e) {
428 e.preventDefault();
429 alert('Address added - Feature coming soon');
430 document.getElementById('add-address-form').style.display = 'none';
431 document.getElementById('add-address-btn').style.display = 'inline-block';
432 }
433
434 function submitRequest(e) {
435 e.preventDefault();
436 alert('Request submitted - Feature coming soon');
437 document.getElementById('new-request-form').style.display = 'none';
438 document.getElementById('new-request-btn').style.display = 'inline-block';
439 }
440
441 function updateProfile(e) {
442 e.preventDefault();
443
444 const newPassword = document.getElementById('new-password').value;
445 const confirmPassword = document.getElementById('confirm-new-password').value;
446
447 if (newPassword && newPassword !== confirmPassword) {
448 alert('New passwords do not match');
449 return;
450 }
451
452 alert('Profile updated - Feature coming soon');
453 }
454
455 window.viewOrder = (orderNum) => {
456 alert(`View order ${orderNum} details - Feature coming soon`);
457 };
458
459 window.reviewOrder = (orderNum) => {
460 window.location.href = `reviews.html?order=${orderNum}`;
461 };
462</script>
463</body>
464</html>
Note: See TracBrowser for help on using the repository browser.