- Timestamp:
- 02/22/26 22:32:07 (7 months ago)
- Branches:
- finki-main, main
- Children:
- 6fea37e, 81bc7da
- Parents:
- 4dff800
- Location:
- interfejs
- Files:
-
- 5 edited
-
admin.html (modified) (8 diffs)
-
change-password.html (modified) (5 diffs)
-
client-dashboard.html (modified) (9 diffs)
-
store-employee.html (modified) (16 diffs)
-
store-owner.html (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
interfejs/admin.html
r4dff800 r79fff4f 18 18 <li><a href="products.html">Products</a></li> 19 19 <li><a href="#" id="dashboard-link" class="active">Admin</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> 20 22 </ul> 21 23 </nav> … … 201 203 document.addEventListener('DOMContentLoaded', async () => { 202 204 const user = await loadUserData(); 205 203 206 if (!user || user.userType !== 'admin') { 204 207 window.location.href = 'index.html'; … … 207 210 208 211 document.getElementById('admin-name').textContent = user.username || 'Administrator'; 212 213 // Logout functionality 214 document.getElementById('logout-link').addEventListener('click', async (e) => { 215 e.preventDefault(); 216 await logout(); 217 }); 209 218 210 219 // Tab switching … … 213 222 document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); 214 223 document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); 224 215 225 btn.classList.add('active'); 216 226 document.getElementById(`${btn.dataset.tab}-tab`).classList.add('active'); … … 271 281 272 282 const tbody = document.getElementById('users-list'); 283 273 284 if (data.success && data.users.length > 0) { 274 285 tbody.innerHTML = data.users.map(user => ` 275 <tr>276 <td>${user.id || user.client_id || 'N/A'}</td>277 <td>${user.firstName || user.first_name || user.username || 'N/A'} ${user.lastName || user.last_name || ''}</td>278 <td>${user.email || 'N/A'}</td>279 <td><span class="status-badge status-${user.user_type || user.userType || 'unknown'}">${user.user_type || user.userType || 'unknown'}</span></td>280 <td>281 <button class="btn-small" onclick="viewUser('${user.id || user.client_id}')">View</button>282 </td>283 </tr>284 `).join('');286 <tr> 287 <td>${user.id || user.client_id || 'N/A'}</td> 288 <td>${user.firstName || user.first_name || user.username || 'N/A'} ${user.lastName || user.last_name || ''}</td> 289 <td>${user.email || 'N/A'}</td> 290 <td><span class="status-badge status-${user.user_type || user.userType || 'unknown'}">${user.user_type || user.userType || 'unknown'}</span></td> 291 <td> 292 <button class="btn-small" onclick="viewUser('${user.id || user.client_id}')">View</button> 293 </td> 294 </tr> 295 `).join(''); 285 296 } else { 286 297 tbody.innerHTML = '<tr><td colspan="5">No users found</td></tr>'; … … 298 309 299 310 const tbody = document.getElementById('stores-list'); 311 300 312 if (data.success && data.stores.length > 0) { 301 313 tbody.innerHTML = data.stores.map(store => ` 302 <tr>303 <td>${store.store_id}</td>304 <td>${store.name}</td>305 <td>${store.store_email}</td>306 <td>${store.rating || '0.0'}</td>307 <td>308 <button class="btn-small" onclick="viewStore('${store.store_id}')">View</button>309 </td>310 </tr>311 `).join('');314 <tr> 315 <td>${store.store_id}</td> 316 <td>${store.name}</td> 317 <td>${store.store_email}</td> 318 <td>${store.rating || '0.0'}</td> 319 <td> 320 <button class="btn-small" onclick="viewStore('${store.store_id}')">View</button> 321 </td> 322 </tr> 323 `).join(''); 312 324 } else { 313 325 tbody.innerHTML = '<tr><td colspan="5">No stores found</td></tr>'; … … 325 337 326 338 const tbody = document.getElementById('orders-list'); 339 327 340 if (data.success && data.orders.length > 0) { 328 341 tbody.innerHTML = data.orders.map(order => ` 329 <tr>330 <td>${order.order_num}</td>331 <td>${order.first_name} ${order.last_name}</td>332 <td>${order.store_name}</td>333 <td>${new Date(order.order_date).toLocaleDateString()}</td>334 <td><span class="status-badge status-${order.status}">${order.status}</span></td>335 <td>$${parseFloat(order.total || 0).toFixed(2)}</td>336 </tr>337 `).join('');342 <tr> 343 <td>${order.order_num}</td> 344 <td>${order.first_name} ${order.last_name}</td> 345 <td>${order.store_name}</td> 346 <td>${new Date(order.order_date).toLocaleDateString()}</td> 347 <td><span class="status-badge status-${order.status}">${order.status}</span></td> 348 <td>$${parseFloat(order.total || 0).toFixed(2)}</td> 349 </tr> 350 `).join(''); 338 351 } else { 339 352 tbody.innerHTML = '<tr><td colspan="6">No orders found</td></tr>'; … … 362 375 // Mock report generation 363 376 document.getElementById('report-results').innerHTML = ` 364 <div class="dashboard-section">365 <h4>Generated Report: ${type}</h4>366 <p>Period: ${start} to ${end}</p>367 <div class="loading">Generating report...</div>368 </div>369 `;377 <div class="dashboard-section"> 378 <h4>Generated Report: ${type}</h4> 379 <p>Period: ${start} to ${end}</p> 380 <div class="loading">Generating report...</div> 381 </div> 382 `; 370 383 371 384 // Simulate report generation 372 385 setTimeout(() => { 373 386 document.getElementById('report-results').innerHTML = ` 374 <div class="dashboard-section">375 <h4>Report Results</h4>376 <p><strong>Total Records:</strong> 42</p>377 <p><strong>Summary:</strong> Sample report data for demonstration</p>378 <button class="btn-small" onclick="downloadReport()">Download Report</button>379 </div>380 `;387 <div class="dashboard-section"> 388 <h4>Report Results</h4> 389 <p><strong>Total Records:</strong> 42</p> 390 <p><strong>Summary:</strong> Sample report data for demonstration</p> 391 <button class="btn-small" onclick="downloadReport()">Download Report</button> 392 </div> 393 `; 381 394 }, 1500); 382 395 } -
interfejs/change-password.html
r4dff800 r79fff4f 17 17 <li><a href="index.html">Home</a></li> 18 18 <li><a href="products.html">Products</a></li> 19 <li><a href=" login.html">Login</a></li>19 <li><a href="#" id="dashboard-link">Dashboard</a></li> 20 20 </ul> 21 21 </nav> … … 23 23 24 24 <main> 25 <div class=" form-container">25 <div class="auth-container"> 26 26 <h2>Change Password</h2> 27 <p class="form-subtitle" id="password-message">Please set a new password</p> 28 29 <div id="error-message" class="error-message" style="display: none; color: red; margin-bottom: 1rem; padding: 10px; background-color: #ffeeee; border-radius: 5px;"></div> 30 <div id="success-message" class="success-message" style="display: none; color: green; margin-bottom: 1rem; padding: 10px; background-color: #eeffee; border-radius: 5px;"></div> 27 <div id="password-message" class="message"></div> 31 28 32 29 <form id="change-password-form" class="form"> 33 30 <div class="form-group"> 34 31 <label for="new-password">New Password</label> 35 <input type="password" id="new-password" name="new-password"required>32 <input type="password" id="new-password" required> 36 33 <small class="password-hint">At least 8 characters with uppercase, lowercase, number, and special character</small> 37 34 </div> … … 39 36 <div class="form-group"> 40 37 <label for="confirm-password">Confirm New Password</label> 41 <input type="password" id="confirm-password" name="confirm-password"required>38 <input type="password" id="confirm-password" required> 42 39 </div> 43 40 44 <div class="form-group"> 45 <button type="submit" class="btn-primary btn-full" id="submit-btn">Change Password</button> 46 </div> 41 <button type="submit" class="btn-primary">Change Password</button> 47 42 </form> 48 43 </div> … … 62 57 </ul> 63 58 </div> 59 <div class="footer-section"> 60 <h3>Contact</h3> 61 <p>Email: support@handcraft.com</p> 62 </div> 64 63 </div> 65 64 <div class="footer-bottom"> … … 70 69 <script src="script.js"></script> 71 70 <script> 72 document.addEventListener('DOMContentLoaded', () =>{71 document.addEventListener('DOMContentLoaded', async function() { 73 72 const urlParams = new URLSearchParams(window.location.search); 74 const isForced = urlParams.get('forced') === 'true';75 let userType = 'admin'; // Default73 const forced = urlParams.get('forced'); 74 const redirect = urlParams.get('redirect'); 76 75 77 if (isForced) { 78 document.getElementById('password-message').textContent = 79 'You must change your password before continuing.'; 76 // Check if user is authenticated for password change 77 try { 78 const user = await loadUserData(); 79 if (!user) { 80 window.location.href = 'login.html'; 81 return; 82 } 83 } catch (error) { 84 console.error('Error loading user:', error); 85 window.location.href = 'login.html'; 86 return; 80 87 } 81 88 82 const form = document.getElementById('change-password-form'); 83 const submitBtn = document.getElementById('submit-btn'); 84 const errorDiv = document.getElementById('error-message'); 85 const successDiv = document.getElementById('success-message'); 89 if (forced === 'true') { 90 const messageDiv = document.getElementById('password-message'); 91 messageDiv.className = 'message warning'; 92 messageDiv.innerHTML = '⚠️ You are required to change your password before continuing.'; 93 } 86 94 87 // Check if user is authenticated for password change and get user type 88 checkAuthStatus(); 95 // Store redirect URL in session storage 96 if (redirect) { 97 sessionStorage.setItem('passwordChangeRedirect', redirect); 98 } 89 99 90 form.addEventListener('submit', async (e) => { 100 // Handle form submission 101 document.getElementById('change-password-form').addEventListener('submit', async function(e) { 91 102 e.preventDefault(); 92 93 // Clear previous messages94 errorDiv.style.display = 'none';95 successDiv.style.display = 'none';96 97 // Disable submit button to prevent double submission98 submitBtn.disabled = true;99 submitBtn.textContent = 'Changing Password...';100 103 101 104 const newPassword = document.getElementById('new-password').value; 102 105 const confirmPassword = document.getElementById('confirm-password').value; 103 106 104 // Client-side validation 105 if (!newPassword || !confirmPassword) { 106 showError('All fields are required'); 107 submitBtn.disabled = false; 108 submitBtn.textContent = 'Change Password'; 107 if (newPassword !== confirmPassword) { 108 showMessage('Passwords do not match', 'error'); 109 109 return; 110 110 } 111 111 112 if (newPassword !== confirmPassword) {113 showError('New passwords do not match');114 submitBtn.disabled = false;115 s ubmitBtn.textContent = 'Change Password';112 // Password validation 113 const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; 114 if (!passwordRegex.test(newPassword)) { 115 showMessage('Password must have at least 8 characters, including uppercase, lowercase, number and special character', 'error'); 116 116 return; 117 117 } 118 118 119 // Validate password strength 120 const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/; 121 if (!passwordRegex.test(newPassword)) { 122 showError('Password must have at least 8 characters, including uppercase, lowercase, number and special character'); 123 submitBtn.disabled = false; 124 submitBtn.textContent = 'Change Password'; 125 return; 126 } 127 128 const formData = { 129 newPassword: newPassword, 130 confirmPassword: confirmPassword 131 }; 119 // Get redirect from session storage or URL 120 const redirectTo = sessionStorage.getItem('passwordChangeRedirect') || ''; 132 121 133 122 try { 134 console.log('Sending password change request...');135 123 const response = await fetch('/api/force-change-password', { 136 124 method: 'POST', 137 headers: { 138 'Content-Type': 'application/json' 139 }, 140 body: JSON.stringify(formData), 141 credentials: 'include' // Important: include cookies 125 headers: { 'Content-Type': 'application/json' }, 126 body: JSON.stringify({ 127 newPassword, 128 confirmPassword, 129 redirectTo: redirectTo 130 }) 142 131 }); 143 132 144 133 const data = await response.json(); 145 console.log('Response:', data);146 134 147 135 if (data.success) { 148 showSuccess('Password changed successfully! Redirecting...'); 136 showMessage('Password changed successfully! Redirecting...', 'success'); 137 sessionStorage.removeItem('passwordChangeRedirect'); 149 138 150 // Clear form 151 form.reset(); 152 153 // Redirect after short delay 139 // Redirect to appropriate dashboard 154 140 setTimeout(() => { 155 141 window.location.href = data.redirectTo || 'dashboard.html'; 156 142 }, 1500); 157 143 } else { 158 showError(data.message || 'Failed to change password'); 159 submitBtn.disabled = false; 160 submitBtn.textContent = 'Change Password'; 144 showMessage(data.message || 'Failed to change password', 'error'); 161 145 } 162 146 } catch (error) { 163 console.error('Password change error:', error); 164 showError('Network error: ' + error.message); 165 submitBtn.disabled = false; 166 submitBtn.textContent = 'Change Password'; 147 console.error('Error changing password:', error); 148 showMessage('An error occurred. Please try again.', 'error'); 167 149 } 168 150 }); 169 151 170 async function checkAuthStatus() { 171 try { 172 const response = await fetch('/api/user', { 173 credentials: 'include' 174 }); 175 const data = await response.json(); 176 177 if (!data.success) { 178 // Not authenticated, redirect to login 179 window.location.href = 'login.html'; 180 } else if (data.isTempSession) { 181 console.log('Valid temporary session for password change'); 182 if (data.user && data.user.userType) { 183 userType = data.user.userType; 184 } 185 } else { 186 // Already have full session, redirect to appropriate dashboard 187 if (data.user && data.user.userType) { 188 switch(data.user.userType) { 189 case 'admin': 190 window.location.href = 'admin.html'; 191 break; 192 case 'store_owner': 193 window.location.href = 'store-owner.html'; 194 break; 195 case 'store_employee': 196 window.location.href = 'store-employee.html'; 197 break; 198 case 'client': 199 window.location.href = 'client-dashboard.html'; 200 break; 201 default: 202 window.location.href = 'dashboard.html'; 203 } 204 } 205 } 206 } catch (error) { 207 console.error('Auth check error:', error); 208 } 209 } 210 211 function showError(message) { 212 errorDiv.textContent = message; 213 errorDiv.style.display = 'block'; 214 setTimeout(() => { 215 errorDiv.style.display = 'none'; 216 }, 5000); 217 } 218 219 function showSuccess(message) { 220 successDiv.textContent = message; 221 successDiv.style.display = 'block'; 152 function showMessage(msg, type) { 153 const messageDiv = document.getElementById('password-message'); 154 messageDiv.className = 'message ' + type; 155 messageDiv.textContent = msg; 222 156 } 223 157 }); -
interfejs/client-dashboard.html
r4dff800 r79fff4f 18 18 <li><a href="products.html">Products</a></li> 19 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> 20 22 </ul> 21 23 </nav> … … 96 98 <input type="text" id="new-address" required> 97 99 </div> 98 99 100 <div class="form-row"> 100 101 <div class="form-group"> … … 107 108 </div> 108 109 </div> 109 110 110 <div class="form-group"> 111 111 <label for="new-country">Country *</label> 112 112 <input type="text" id="new-country" required> 113 113 </div> 114 115 114 <div class="form-group checkbox"> 116 115 <input type="checkbox" id="new-is-default"> 117 116 <label for="new-is-default">Set as default address</label> 118 117 </div> 119 120 118 <button type="submit" class="btn-primary">Save Address</button> 121 119 <button type="button" class="btn-secondary" id="cancel-add-address">Cancel</button> … … 158 156 </select> 159 157 </div> 160 161 158 <div class="form-group"> 162 159 <label for="request-problem">Problem Description *</label> 163 160 <textarea id="request-problem" rows="4" required></textarea> 164 161 </div> 165 166 162 <button type="submit" class="btn-primary">Submit Request</button> 167 163 <button type="button" class="btn-secondary" id="cancel-new-request">Cancel</button> … … 262 258 document.addEventListener('DOMContentLoaded', async () => { 263 259 const user = await loadUserData(); 260 264 261 if (!user || user.userType !== 'client') { 265 262 window.location.href = 'index.html'; … … 268 265 269 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 }); 270 273 271 274 // Load profile data … … 297 300 document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); 298 301 document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); 302 299 303 btn.classList.add('active'); 300 304 document.getElementById(`${btn.dataset.tab}-tab`).classList.add('active'); … … 352 356 353 357 const tbody = document.getElementById('orders-list'); 358 354 359 if (data.success && data.orders.length > 0) { 355 360 tbody.innerHTML = data.orders.map(order => { 356 361 const total = order.items ? order.items.reduce((sum, item) => 357 362 sum + (item.price * item.quantity), 0) : 0; 363 358 364 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' ?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' ? 368 374 `<button class="btn-small" onclick="reviewOrder('${order.order_num}')">Review</button>` : ''} 369 </td>370 </tr>371 `;375 </td> 376 </tr> 377 `; 372 378 }).join(''); 373 379 } else { … … 383 389 // This would need a separate API endpoint 384 390 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 `;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 `; 392 398 } 393 399 -
interfejs/store-employee.html
r4dff800 r79fff4f 18 18 <li><a href="products.html">Products</a></li> 19 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> 20 22 </ul> 21 23 </nav> … … 170 172 </main> 171 173 174 <!-- Respond to Request Modal --> 172 175 <div id="respond-request-modal" class="modal" style="display: none;"> 173 176 <div class="modal-content"> … … 176 179 <form id="respond-request-form" class="form"> 177 180 <input type="hidden" id="respond-request-num"> 178 179 181 <div class="form-group"> 180 182 <label for="request-response">Your Response</label> 181 183 <textarea id="request-response" rows="4" required></textarea> 182 184 </div> 183 184 185 <div class="form-group"> 185 186 <label for="request-status">Update Status</label> … … 190 191 </select> 191 192 </div> 192 193 193 <button type="submit" class="btn-primary">Submit Response</button> 194 194 </form> … … 196 196 </div> 197 197 198 <!-- Process Refund Modal --> 198 199 <div id="process-refund-modal" class="modal" style="display: none;"> 199 200 <div class="modal-content"> … … 202 203 <form id="process-refund-form" class="form"> 203 204 <input type="hidden" id="process-refund-id"> 204 205 205 <div class="form-group"> 206 206 <label for="refund-action">Action</label> … … 210 210 </select> 211 211 </div> 212 213 212 <div class="form-group"> 214 213 <label for="refund-notes">Notes</label> 215 214 <textarea id="refund-notes" rows="3"></textarea> 216 215 </div> 217 218 216 <button type="submit" class="btn-primary">Process Refund</button> 219 217 </form> … … 244 242 document.addEventListener('DOMContentLoaded', async () => { 245 243 const user = await loadUserData(); 244 246 245 if (!user || user.userType !== 'store_employee') { 247 246 window.location.href = 'index.html'; … … 250 249 251 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 }); 252 257 253 258 // Load stores … … 277 282 document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); 278 283 document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); 284 279 285 btn.classList.add('active'); 280 286 document.getElementById(`${btn.dataset.tab}-tab`).classList.add('active'); … … 316 322 // Display tasks 317 323 const tasksList = document.getElementById('tasks-list'); 324 318 325 if (data.tasks.pending_orders.length > 0 || data.tasks.pending_requests.length > 0 || data.tasks.pending_refunds.length > 0) { 319 326 let tasksHtml = '<div class="task-items">'; … … 323 330 data.tasks.pending_orders.forEach(order => { 324 331 tasksHtml += ` 325 <div class="task-item">326 <p><strong>Order #${order.order_num}</strong> - ${order.first_name} ${order.last_name}</p>327 <button class="btn-small" onclick="updateOrderStatus('${order.order_num}')">Update Status</button>328 </div>329 `;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 `; 330 337 }); 331 338 } … … 335 342 data.tasks.pending_requests.forEach(request => { 336 343 tasksHtml += ` 337 <div class="task-item">338 <p><strong>Request #${request.request_num}</strong> - ${request.first_name} ${request.last_name}</p>339 <p>${request.problem.substring(0, 50)}${request.problem.length > 50 ? '...' : ''}</p>340 <button class="btn-small" onclick="respondToRequest('${request.request_num}')">Respond</button>341 </div>342 `;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 `; 343 350 }); 344 351 } … … 348 355 data.tasks.pending_refunds.forEach(refund => { 349 356 tasksHtml += ` 350 <div class="task-item">351 <p><strong>Refund #${refund.refund_id}</strong> - Order #${refund.order_num}</p>352 <p>Amount: $${parseFloat(refund.amount).toFixed(2)}</p>353 <button class="btn-small" onclick="processRefund('${refund.refund_id}')">Process</button>354 </div>355 `;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 `; 356 363 }); 357 364 } … … 374 381 375 382 const tbody = document.getElementById('orders-list'); 383 376 384 if (data.success && data.orders.length > 0) { 377 385 tbody.innerHTML = data.orders.map(order => { 378 386 const total = order.items ? order.items.reduce((sum, item) => 379 387 sum + (item.price * item.quantity), 0) : 0; 388 380 389 return ` 381 <tr>382 <td>${order.order_num}</td>383 <td>${order.first_name} ${order.last_name}</td>384 <td>${new Date(order.order_date).toLocaleDateString()}</td>385 <td><span class="status-badge status-${order.status}">${order.status}</span></td>386 <td>$${total.toFixed(2)}</td>387 <td>388 <button class="btn-small" onclick="updateOrderStatus('${order.order_num}')">Update</button>389 <button class="btn-small" onclick="viewOrderDetails('${order.order_num}')">View</button>390 </td>391 </tr>392 `;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 `; 393 402 }).join(''); 394 403 } else { … … 417 426 418 427 const tbody = document.getElementById('products-list'); 428 419 429 if (data.success && data.products.length > 0) { 420 430 tbody.innerHTML = data.products.map(product => ` 421 <tr>422 <td>${product.code}</td>423 <td>${product.description.substring(0, 30)}${product.description.length > 30 ? '...' : ''}</td>424 <td>$${parseFloat(product.price).toFixed(2)}</td>425 <td>${product.availability}</td>426 <td>427 <button class="btn-small" onclick="viewProduct('${product.code}')">View</button>428 </td>429 </tr>430 `).join('');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(''); 431 441 } else { 432 442 tbody.innerHTML = '<tr><td colspan="5">No products found</td></tr>'; -
interfejs/store-owner.html
r4dff800 r79fff4f 18 18 <li><a href="products.html">Products</a></li> 19 19 <li><a href="#" id="dashboard-link" class="active">Store Owner</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> 20 22 </ul> 21 23 </nav> … … 457 459 document.getElementById('owner-name').textContent = `${user.firstName} ${user.lastName || ''}`; 458 460 461 // Logout functionality 462 document.getElementById('logout-link').addEventListener('click', async (e) => { 463 e.preventDefault(); 464 await logout(); 465 }); 466 459 467 // Load stores 460 468 const stores = user.stores || []; … … 484 492 document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); 485 493 document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); 494 486 495 btn.classList.add('active'); 487 496 document.getElementById(`${btn.dataset.tab}-tab`).classList.add('active'); … … 558 567 const response = await fetch(`/api/store-products?storeId=${storeId}`); 559 568 const data = await response.json(); 569 560 570 const tbody = document.getElementById('products-list'); 561 571 562 572 if (data.success && data.products.length > 0) { 563 573 tbody.innerHTML = data.products.map(product => ` 564 <tr>565 <td>${product.code}</td>566 <td>${product.description.substring(0, 30)}${product.description.length > 30 ? '...' : ''}</td>567 <td>$${parseFloat(product.price).toFixed(2)}</td>568 <td>${product.availability}</td>569 <td>${product.category_name || 'General'}</td>570 <td>571 <button class="btn-small" onclick="editProduct('${product.code}')">Edit</button>572 <button class="btn-small" style="background: var(--danger);" onclick="deleteProduct('${product.code}', '${storeId}')">Delete</button>573 </td>574 </tr>575 `).join('');574 <tr> 575 <td>${product.code}</td> 576 <td>${product.description.substring(0, 30)}${product.description.length > 30 ? '...' : ''}</td> 577 <td>$${parseFloat(product.price).toFixed(2)}</td> 578 <td>${product.availability}</td> 579 <td>${product.category_name || 'General'}</td> 580 <td> 581 <button class="btn-small" onclick="editProduct('${product.code}')">Edit</button> 582 <button class="btn-small" style="background: var(--danger);" onclick="deleteProduct('${product.code}', '${storeId}')">Delete</button> 583 </td> 584 </tr> 585 `).join(''); 576 586 } else { 577 587 tbody.innerHTML = '<tr><td colspan="6">No products found</td></tr>'; … … 587 597 const response = await fetch(`/api/store-orders?storeId=${storeId}`); 588 598 const data = await response.json(); 599 589 600 const tbody = document.getElementById('orders-list'); 590 601 … … 593 604 const total = order.items ? order.items.reduce((sum, item) => 594 605 sum + (item.price * item.quantity), 0) : 0; 606 595 607 return ` 596 <tr>597 <td>${order.order_num}</td>598 <td>${order.first_name} ${order.last_name}</td>599 <td>${new Date(order.order_date).toLocaleDateString()}</td>600 <td><span class="status-badge status-${order.status}">${order.status}</span></td>601 <td>$${total.toFixed(2)}</td>602 <td>603 <button class="btn-small" onclick="viewOrder('${order.order_num}')">View</button>604 </td>605 </tr>606 `;608 <tr> 609 <td>${order.order_num}</td> 610 <td>${order.first_name} ${order.last_name}</td> 611 <td>${new Date(order.order_date).toLocaleDateString()}</td> 612 <td><span class="status-badge status-${order.status}">${order.status}</span></td> 613 <td>$${total.toFixed(2)}</td> 614 <td> 615 <button class="btn-small" onclick="viewOrder('${order.order_num}')">View</button> 616 </td> 617 </tr> 618 `; 607 619 }).join(''); 608 620 } else { … … 619 631 const response = await fetch(`/api/store-employees?storeId=${storeId}`); 620 632 const data = await response.json(); 633 621 634 const tbody = document.getElementById('employees-list'); 622 635 623 636 if (data.success && data.employees.length > 0) { 624 637 tbody.innerHTML = data.employees.map(emp => ` 625 <tr>626 <td>${emp.id}</td>627 <td>${emp.first_name} ${emp.last_name}</td>628 <td>${emp.email}</td>629 <td>${emp.date_of_hire || 'N/A'}</td>630 <td><span class="status-badge">${emp.permission_type || 'EMPLOYEE'}</span></td>631 <td>632 <button class="btn-small" onclick="editEmployee('${emp.id}')">Edit</button>633 <button class="btn-small" style="background: var(--danger);" onclick="deleteEmployee('${emp.id}', '${storeId}')">Delete</button>634 </td>635 </tr>636 `).join('');638 <tr> 639 <td>${emp.id}</td> 640 <td>${emp.first_name} ${emp.last_name}</td> 641 <td>${emp.email}</td> 642 <td>${emp.date_of_hire || 'N/A'}</td> 643 <td><span class="status-badge">${emp.permission_type || 'EMPLOYEE'}</span></td> 644 <td> 645 <button class="btn-small" onclick="editEmployee('${emp.id}')">Edit</button> 646 <button class="btn-small" style="background: var(--danger);" onclick="deleteEmployee('${emp.id}', '${storeId}')">Delete</button> 647 </td> 648 </tr> 649 `).join(''); 637 650 } else { 638 651 tbody.innerHTML = '<tr><td colspan="6">No employees found</td></tr>'; … … 661 674 `<option value="${cat.category_id}">${cat.name}</option>` 662 675 ).join(''); 676 663 677 document.getElementById('category-parent').innerHTML = '<option value="">None (Top Level Category)</option>' + parentOptions; 664 678 } … … 787 801 document.getElementById('add-product-form').reset(); 788 802 loadProducts(storeId); 803 789 804 // Switch to products tab 790 805 document.querySelector('[data-tab="products"]').click(); … … 839 854 document.getElementById('add-employee-form').reset(); 840 855 loadEmployees(storeId); 856 841 857 // Switch to employees tab 842 858 document.querySelector('[data-tab="employees"]').click(); … … 1061 1077 1062 1078 document.getElementById('report-results').innerHTML = ` 1063 <div class="dashboard-section">1064 <h4>Generating Report...</h4>1065 <div class="loading">Please wait</div>1066 </div>1067 `;1079 <div class="dashboard-section"> 1080 <h4>Generating Report...</h4> 1081 <div class="loading">Please wait</div> 1082 </div> 1083 `; 1068 1084 1069 1085 try { … … 1084 1100 if (data.success) { 1085 1101 document.getElementById('report-results').innerHTML = ` 1086 <div class="dashboard-section">1087 <h4>Report Generated Successfully</h4>1088 <p><strong>Report ID:</strong> ${data.reportId}</p>1089 <p><strong>Period:</strong> ${data.report.period}</p>1090 <p><strong>Date Range:</strong> ${data.report.startDate} to ${data.report.endDate}</p>1091 <p><strong>Type:</strong> ${data.report.type}</p>1092 <p><strong>Generated:</strong> ${new Date(data.report.generatedAt).toLocaleString()}</p>1093 <button class="btn-small" onclick="downloadReport('${data.reportId}')">Download Report</button>1094 </div>1095 `;1102 <div class="dashboard-section"> 1103 <h4>Report Generated Successfully</h4> 1104 <p><strong>Report ID:</strong> ${data.reportId}</p> 1105 <p><strong>Period:</strong> ${data.report.period}</p> 1106 <p><strong>Date Range:</strong> ${data.report.startDate} to ${data.report.endDate}</p> 1107 <p><strong>Type:</strong> ${data.report.type}</p> 1108 <p><strong>Generated:</strong> ${new Date(data.report.generatedAt).toLocaleString()}</p> 1109 <button class="btn-small" onclick="downloadReport('${data.reportId}')">Download Report</button> 1110 </div> 1111 `; 1096 1112 } else { 1097 1113 document.getElementById('report-results').innerHTML = ` 1098 <div class="dashboard-section">1099 <p class="error">Failed to generate report: ${data.message}</p>1100 </div>1101 `;1114 <div class="dashboard-section"> 1115 <p class="error">Failed to generate report: ${data.message}</p> 1116 </div> 1117 `; 1102 1118 } 1103 1119 } catch (error) { 1104 1120 console.error('Error generating report:', error); 1105 1121 document.getElementById('report-results').innerHTML = ` 1106 <div class="dashboard-section">1107 <p class="error">An error occurred while generating the report</p>1108 </div>1109 `;1122 <div class="dashboard-section"> 1123 <p class="error">An error occurred while generating the report</p> 1124 </div> 1125 `; 1110 1126 } 1111 1127 }
Note:
See TracChangeset
for help on using the changeset viewer.
