source: interfejs/client-dashboard.html@ 591278c

finki-main main
Last change on this file since 591278c was 69f2a41, checked in by Klimentina Efremova <klimentina08642@…>, 7 months ago

Initial commit

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