Updated dashboard, Added payroll API
This commit is contained in:
parent
4d757daf97
commit
870d81e2ca
|
|
@ -1310,3 +1310,336 @@ tr[data-vaid]:hover {
|
||||||
.modal-actions a {
|
.modal-actions a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.profile-container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-header {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 1px solid #e1e5e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-title {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2d3748;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-sections {
|
||||||
|
display: grid;
|
||||||
|
gap: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-section {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 30px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
border: 1px solid #e1e5e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
border-bottom: 1px solid #e1e5e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: #4299e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2d3748;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4a5568;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #e1e5e9;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
background: #f7fafc;
|
||||||
|
color: #4a5568;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-field {
|
||||||
|
color: #a0aec0;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password-section {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change-password-btn {
|
||||||
|
background: #4299e1;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change-password-btn:hover {
|
||||||
|
background: #3182ce;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal Styles */
|
||||||
|
.modal-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 500px;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
border-bottom: 1px solid #e1e5e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2d3748;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #718096;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close:hover {
|
||||||
|
background: #f7fafc;
|
||||||
|
color: #2d3748;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form .form-group {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form .form-label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #4a5568;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form .form-input {
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #cbd5e0;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1rem;
|
||||||
|
background: white;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form .form-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #4299e1;
|
||||||
|
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-form .form-input.error {
|
||||||
|
border-color: #e53e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: #e53e3e;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-message {
|
||||||
|
color: #38a169;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 30px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #e1e5e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
background: #48bb78;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn:hover {
|
||||||
|
background: #38a169;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn:disabled {
|
||||||
|
background: #a0aec0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
background: #e53e3e;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn:hover {
|
||||||
|
background: #c53030;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Logout Confirmation Modal Styles */
|
||||||
|
.logout-modal-body {
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
color: #e53e3e;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #2d3748;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-message {
|
||||||
|
color: #718096;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-confirm-btn {
|
||||||
|
background: #e53e3e;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-confirm-btn:hover {
|
||||||
|
background: #c53030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-cancel-btn {
|
||||||
|
background: #718096;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-cancel-btn:hover {
|
||||||
|
background: #4a5568;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.form-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-actions {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
async function va_payslip_data_function(req, res) {
|
||||||
|
try {
|
||||||
|
// Assuming we have a service function to get payroll schedule
|
||||||
|
const payrollSchedule = await getPayrollScheduleForVA(req.user.id);
|
||||||
|
return res.status(200).json({ success: true, data: payrollSchedule });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching payroll schedule:", error);
|
||||||
|
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { va_payslip_data_function };
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
async function va_payroll_schedule_function(req, res) {
|
||||||
|
try {
|
||||||
|
const salesforceUrl = `${process.env.SF_DOCTRACKER_API_URL}services/apexrest/docva/api/payroll-schedule`;
|
||||||
|
|
||||||
|
const response = await fetch(salesforceUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
// Add any required headers for Salesforce authentication
|
||||||
|
// 'Authorization': 'Bearer ' + process.env.SF_ACCESS_TOKEN
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorText = await response.text();
|
||||||
|
throw new Error(`Salesforce API responded with status ${response.status}: ${errorText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
// console.log("✅ Successfully synced VA data to Salesforce:", result);
|
||||||
|
|
||||||
|
res.status(201).json({
|
||||||
|
success: true,
|
||||||
|
result
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to sync with Salesforce:", error.message);
|
||||||
|
console.log(error)
|
||||||
|
|
||||||
|
// Create a custom error to distinguish Salesforce errors
|
||||||
|
const salesforceError = new Error(`Salesforce sync failed: ${error.message}`);
|
||||||
|
salesforceError.isSalesforceError = true;
|
||||||
|
throw salesforceError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { va_payroll_schedule_function };
|
||||||
|
|
@ -27,6 +27,8 @@ import { va_leave_apply_function } from "../../controllers/va/vaLeaves/vaLeavesA
|
||||||
import { va_leave_list_function } from "../../controllers/va/vaLeaves/vaLeaveList.controller.js"
|
import { va_leave_list_function } from "../../controllers/va/vaLeaves/vaLeaveList.controller.js"
|
||||||
import { va_leave_manage_function } from "../../controllers/va/vaLeaves/vaLeaveManage.controller.js";
|
import { va_leave_manage_function } from "../../controllers/va/vaLeaves/vaLeaveManage.controller.js";
|
||||||
import { va_remove_function } from "../../controllers/va/vaProfile/vaDelete.controller.js";
|
import { va_remove_function } from "../../controllers/va/vaProfile/vaDelete.controller.js";
|
||||||
|
import { va_payroll_schedule_function } from "../../controllers/va/vaPayroll/vaPayrollSchedule.controller.js";
|
||||||
|
// import { va_payslip_data_function } from "../../controllers/va/vaPayroll/vaPaySlip.controller.js";
|
||||||
|
|
||||||
vaRoutes.get("/", va_callback); // VA Callback for getting active VA
|
vaRoutes.get("/", va_callback); // VA Callback for getting active VA
|
||||||
|
|
||||||
|
|
@ -40,9 +42,6 @@ vaRoutes.post("/verify-va-email", va_verify_email);
|
||||||
vaRoutes.get("/profile", authValidator, va_profile_callback); // Get VA Profile
|
vaRoutes.get("/profile", authValidator, va_profile_callback); // Get VA Profile
|
||||||
vaRoutes.patch("/profile", authValidator, va_profile_update_callback); // Update VA Profile
|
vaRoutes.patch("/profile", authValidator, va_profile_update_callback); // Update VA Profile
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vaRoutes.get("/:userName", va_username_callback); // VA Username Callback
|
|
||||||
vaRoutes.delete("/:id", va_remove_function); // VA Username Callback
|
vaRoutes.delete("/:id", va_remove_function); // VA Username Callback
|
||||||
|
|
||||||
// timesheet adjustment routes
|
// timesheet adjustment routes
|
||||||
|
|
@ -81,6 +80,14 @@ vaRoutes.get("/log/project/:projectId/:from?/:to?", authValidator, va_log_callba
|
||||||
// VA filter search: supports query params `name`, `email`, `from`, `to`
|
// VA filter search: supports query params `name`, `email`, `from`, `to`
|
||||||
|
|
||||||
|
|
||||||
|
// Payroll routes
|
||||||
|
vaRoutes.get("/payrollSchedule", authValidator, va_payroll_schedule_function); // VA Payroll Schedule
|
||||||
|
// vaRoutes.get("/paySlip/:vaId", authValidator, va_payslip_data_function); // VA Payslip
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vaRoutes.get("/:userName", va_username_callback); // VA Username Callback
|
||||||
|
|
||||||
|
|
||||||
export default vaRoutes;
|
export default vaRoutes;
|
||||||
|
|
@ -46,6 +46,12 @@
|
||||||
<aside class="dashboard-sidebar">
|
<aside class="dashboard-sidebar">
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="sidebar-list">
|
<ul class="sidebar-list">
|
||||||
|
<li class="sidebar-item">
|
||||||
|
<a href="/client/profile" class="sidebar-link">
|
||||||
|
<i class="fas fa-user sidebar-icon"></i>
|
||||||
|
<span>Profile</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="/client/dashboard" class="sidebar-link active">
|
<a href="/client/dashboard" class="sidebar-link active">
|
||||||
<i class="fas fa-chart-bar sidebar-icon"></i>
|
<i class="fas fa-chart-bar sidebar-icon"></i>
|
||||||
|
|
@ -64,12 +70,6 @@
|
||||||
<span>Projects</span>
|
<span>Projects</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar-item">
|
|
||||||
<a href="/client/profile" class="sidebar-link">
|
|
||||||
<i class="fas fa-user sidebar-icon"></i>
|
|
||||||
<span>Profile</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
||||||
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
||||||
|
|
@ -203,6 +203,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="logoutModal" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="modal-title">Confirm Logout</h2>
|
||||||
|
<button class="modal-close" onclick="closeLogoutModal()">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="logout-modal-body">
|
||||||
|
<div class="logout-icon">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="logout-title">Are you sure you want to logout?</h3>
|
||||||
|
<p class="logout-message">You will be logged out of your account and redirected to the login page.</p>
|
||||||
|
<div class="logout-actions">
|
||||||
|
<button class="logout-cancel-btn" onclick="closeLogoutModal()">Cancel</button>
|
||||||
|
<button class="logout-confirm-btn" id="confirmLogoutBtn">Yes, Logout</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
// Theme management
|
// Theme management
|
||||||
|
|
@ -486,6 +508,19 @@
|
||||||
// Optional: Auto-refresh data every 30 seconds
|
// Optional: Auto-refresh data every 30 seconds
|
||||||
setInterval(loadDashboardData, 30000);
|
setInterval(loadDashboardData, 30000);
|
||||||
|
|
||||||
|
// Logout Modal Functions
|
||||||
|
function openLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'none';
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Load dashboard data
|
// Load dashboard data
|
||||||
loadDashboardData();
|
loadDashboardData();
|
||||||
|
|
@ -497,13 +532,24 @@
|
||||||
sidebar.classList.toggle('active');
|
sidebar.classList.toggle('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logout button
|
// Close modal with escape key
|
||||||
const logoutButton = document.getElementById('logoutButton');
|
document.addEventListener('keydown', function(e) {
|
||||||
logoutButton.addEventListener('click', () => {
|
if (e.key === 'Escape') {
|
||||||
if (confirm('Are you sure you want to logout?')) {
|
closeLogoutModal();
|
||||||
handleLogout();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('logoutModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeLogoutModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logout button - opens confirmation modal instead of directly logging out
|
||||||
|
document.getElementById('logoutButton').addEventListener('click', openLogoutModal);
|
||||||
|
|
||||||
|
// Confirm logout button
|
||||||
|
document.getElementById('confirmLogoutBtn').addEventListener('click', handleLogout);
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -6,272 +6,7 @@
|
||||||
<title>DocVA Client | Profile</title>
|
<title>DocVA Client | Profile</title>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
<link rel="stylesheet" href="/public/css/dashboard.css">
|
<link rel="stylesheet" href="/public/css/dashboard.css">
|
||||||
<style>
|
|
||||||
.profile-container {
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-header {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
padding-bottom: 20px;
|
|
||||||
border-bottom: 1px solid #e1e5e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-title {
|
|
||||||
font-size: 2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2d3748;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-sections {
|
|
||||||
display: grid;
|
|
||||||
gap: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-section {
|
|
||||||
background: white;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 30px;
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
||||||
border: 1px solid #e1e5e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
border-bottom: 1px solid #e1e5e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-icon {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
color: #4299e1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2d3748;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #4a5568;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input {
|
|
||||||
padding: 12px;
|
|
||||||
border: 1px solid #e1e5e9;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 1rem;
|
|
||||||
background: #f7fafc;
|
|
||||||
color: #4a5568;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-field {
|
|
||||||
color: #a0aec0;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-section {
|
|
||||||
text-align: center;
|
|
||||||
padding: 40px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-password-btn {
|
|
||||||
background: #4299e1;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1rem;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.change-password-btn:hover {
|
|
||||||
background: #3182ce;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Modal Styles */
|
|
||||||
.modal-overlay {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 1000;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
background: white;
|
|
||||||
border-radius: 12px;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 500px;
|
|
||||||
max-height: 90vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 24px;
|
|
||||||
border-bottom: 1px solid #e1e5e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2d3748;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #718096;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-close:hover {
|
|
||||||
background: #f7fafc;
|
|
||||||
color: #2d3748;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
padding: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form .form-group {
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form .form-label {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #4a5568;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form .form-input {
|
|
||||||
padding: 12px;
|
|
||||||
border: 1px solid #cbd5e0;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 1rem;
|
|
||||||
background: white;
|
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form .form-input:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #4299e1;
|
|
||||||
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-form .form-input.error {
|
|
||||||
border-color: #e53e3e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-message {
|
|
||||||
color: #e53e3e;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.success-message {
|
|
||||||
color: #38a169;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-top: 30px;
|
|
||||||
padding-top: 20px;
|
|
||||||
border-top: 1px solid #e1e5e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn {
|
|
||||||
background: #48bb78;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn:hover {
|
|
||||||
background: #38a169;
|
|
||||||
}
|
|
||||||
|
|
||||||
.save-btn:disabled {
|
|
||||||
background: #a0aec0;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel-btn {
|
|
||||||
background: #e53e3e;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-radius: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel-btn:hover {
|
|
||||||
background: #c53030;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.form-grid {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-actions {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="dashboard-body">
|
<body class="dashboard-body">
|
||||||
<div id="root">
|
<div id="root">
|
||||||
|
|
@ -312,6 +47,12 @@
|
||||||
<aside class="dashboard-sidebar">
|
<aside class="dashboard-sidebar">
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="sidebar-list">
|
<ul class="sidebar-list">
|
||||||
|
<li class="sidebar-item">
|
||||||
|
<a href="/client/profile" class="sidebar-link active">
|
||||||
|
<i class="fas fa-user sidebar-icon"></i>
|
||||||
|
<span>Profile</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="/client/dashboard" class="sidebar-link">
|
<a href="/client/dashboard" class="sidebar-link">
|
||||||
<i class="fas fa-chart-bar sidebar-icon"></i>
|
<i class="fas fa-chart-bar sidebar-icon"></i>
|
||||||
|
|
@ -330,12 +71,6 @@
|
||||||
<span>Projects</span>
|
<span>Projects</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar-item">
|
|
||||||
<a href="/client/profile" class="sidebar-link active">
|
|
||||||
<i class="fas fa-user sidebar-icon"></i>
|
|
||||||
<span>Profile</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
||||||
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
||||||
|
|
@ -450,6 +185,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="logoutModal" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="modal-title">Confirm Logout</h2>
|
||||||
|
<button class="modal-close" onclick="closeLogoutModal()">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="logout-modal-body">
|
||||||
|
<div class="logout-icon">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="logout-title">Are you sure you want to logout?</h3>
|
||||||
|
<p class="logout-message">You will be logged out of your account and redirected to the login page.</p>
|
||||||
|
<div class="logout-actions">
|
||||||
|
<button class="logout-cancel-btn" onclick="closeLogoutModal()">Cancel</button>
|
||||||
|
<button class="logout-confirm-btn" id="confirmLogoutBtn">Yes, Logout</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -646,6 +403,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Logout Modal Functions
|
||||||
|
function openLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'none';
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
// Event listeners
|
// Event listeners
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
loadProfileData();
|
loadProfileData();
|
||||||
|
|
@ -667,18 +437,28 @@
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener('keydown', function(e) {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
closePasswordModal();
|
closePasswordModal();
|
||||||
|
closeLogoutModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('logoutModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeLogoutModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logout button - opens confirmation modal instead of directly logging out
|
||||||
|
document.getElementById('logoutButton').addEventListener('click', openLogoutModal);
|
||||||
|
|
||||||
|
// Confirm logout button
|
||||||
|
document.getElementById('confirmLogoutBtn').addEventListener('click', handleLogout);
|
||||||
|
|
||||||
// Mobile menu toggle
|
// Mobile menu toggle
|
||||||
const menuToggle = document.querySelector('.mobile-menu-button');
|
const menuToggle = document.querySelector('.mobile-menu-button');
|
||||||
const sidebar = document.querySelector('.dashboard-sidebar');
|
const sidebar = document.querySelector('.dashboard-sidebar');
|
||||||
menuToggle.addEventListener('click', () => {
|
menuToggle.addEventListener('click', () => {
|
||||||
sidebar.classList.toggle('active');
|
sidebar.classList.toggle('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logout button
|
|
||||||
document.getElementById('logoutButton').addEventListener('click', handleLogout);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,12 @@
|
||||||
</div> -->
|
</div> -->
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="sidebar-list">
|
<ul class="sidebar-list">
|
||||||
|
<li class="sidebar-item">
|
||||||
|
<a href="/client/profile" class="sidebar-link">
|
||||||
|
<i class="fas fa-user sidebar-icon"></i>
|
||||||
|
<span>Profile</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="/client/dashboard" class="sidebar-link">
|
<a href="/client/dashboard" class="sidebar-link">
|
||||||
<i class="fas fa-chart-bar sidebar-icon"></i>
|
<i class="fas fa-chart-bar sidebar-icon"></i>
|
||||||
|
|
@ -78,12 +84,6 @@
|
||||||
<span>Projects</span>
|
<span>Projects</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar-item">
|
|
||||||
<a href="/client/profile" class="sidebar-link">
|
|
||||||
<i class="fas fa-user sidebar-icon"></i>
|
|
||||||
<span>Profile</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
||||||
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
||||||
|
|
@ -167,6 +167,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="logoutModal" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="modal-title">Confirm Logout</h2>
|
||||||
|
<button class="modal-close" onclick="closeLogoutModal()">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="logout-modal-body">
|
||||||
|
<div class="logout-icon">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="logout-title">Are you sure you want to logout?</h3>
|
||||||
|
<p class="logout-message">You will be logged out of your account and redirected to the login page.</p>
|
||||||
|
<div class="logout-actions">
|
||||||
|
<button class="logout-cancel-btn" onclick="closeLogoutModal()">Cancel</button>
|
||||||
|
<button class="logout-confirm-btn" id="confirmLogoutBtn">Yes, Logout</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
// Theme management
|
// Theme management
|
||||||
|
|
@ -435,6 +457,18 @@
|
||||||
// Optional: Auto-refresh data every 30 seconds
|
// Optional: Auto-refresh data every 30 seconds
|
||||||
setInterval(loadDashboardData, 30000);
|
setInterval(loadDashboardData, 30000);
|
||||||
|
|
||||||
|
// Logout Modal Functions
|
||||||
|
function openLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'none';
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Load dashboard data
|
// Load dashboard data
|
||||||
|
|
@ -447,13 +481,24 @@
|
||||||
sidebar.classList.toggle('active');
|
sidebar.classList.toggle('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logout button
|
// Close modal with escape key
|
||||||
const logoutButton = document.getElementById('logoutButton');
|
document.addEventListener('keydown', function(e) {
|
||||||
logoutButton.addEventListener('click', () => {
|
if (e.key === 'Escape') {
|
||||||
if (confirm('Are you sure you want to logout?')) {
|
closeLogoutModal();
|
||||||
handleLogout();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('logoutModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeLogoutModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logout button - opens confirmation modal instead of directly logging out
|
||||||
|
document.getElementById('logoutButton').addEventListener('click', openLogoutModal);
|
||||||
|
|
||||||
|
// Confirm logout button
|
||||||
|
document.getElementById('confirmLogoutBtn').addEventListener('click', handleLogout);
|
||||||
});
|
});
|
||||||
|
|
||||||
modalClose.addEventListener('click', closeProjectModal);
|
modalClose.addEventListener('click', closeProjectModal);
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,12 @@
|
||||||
<aside class="dashboard-sidebar">
|
<aside class="dashboard-sidebar">
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
<ul class="sidebar-list">
|
<ul class="sidebar-list">
|
||||||
|
<li class="sidebar-item">
|
||||||
|
<a href="/client/profile" class="sidebar-link">
|
||||||
|
<i class="fas fa-user sidebar-icon"></i>
|
||||||
|
<span>Profile</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="/client/dashboard" class="sidebar-link">
|
<a href="/client/dashboard" class="sidebar-link">
|
||||||
<i class="fas fa-chart-bar sidebar-icon"></i>
|
<i class="fas fa-chart-bar sidebar-icon"></i>
|
||||||
|
|
@ -64,12 +70,6 @@
|
||||||
<span>Projects</span>
|
<span>Projects</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="sidebar-item">
|
|
||||||
<a href="/client/profile" class="sidebar-link">
|
|
||||||
<i class="fas fa-user sidebar-icon"></i>
|
|
||||||
<span>Profile</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="sidebar-item">
|
<li class="sidebar-item">
|
||||||
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
<a href="javascript:void(0);" class="sidebar-link" id="logoutButton">
|
||||||
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
<i class="fas fa-sign-out-alt sidebar-icon"></i>
|
||||||
|
|
@ -203,6 +203,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="logoutModal" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 class="modal-title">Confirm Logout</h2>
|
||||||
|
<button class="modal-close" onclick="closeLogoutModal()">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="logout-modal-body">
|
||||||
|
<div class="logout-icon">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="logout-title">Are you sure you want to logout?</h3>
|
||||||
|
<p class="logout-message">You will be logged out of your account and redirected to the login page.</p>
|
||||||
|
<div class="logout-actions">
|
||||||
|
<button class="logout-cancel-btn" onclick="closeLogoutModal()">Cancel</button>
|
||||||
|
<button class="logout-confirm-btn" id="confirmLogoutBtn">Yes, Logout</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
// Theme management
|
// Theme management
|
||||||
|
|
@ -486,6 +508,19 @@
|
||||||
// Optional: Auto-refresh data every 30 seconds
|
// Optional: Auto-refresh data every 30 seconds
|
||||||
setInterval(loadDashboardData, 30000);
|
setInterval(loadDashboardData, 30000);
|
||||||
|
|
||||||
|
// Logout Modal Functions
|
||||||
|
function openLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLogoutModal() {
|
||||||
|
const modal = document.getElementById('logoutModal');
|
||||||
|
modal.style.display = 'none';
|
||||||
|
document.body.style.overflow = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Load dashboard data
|
// Load dashboard data
|
||||||
loadDashboardData();
|
loadDashboardData();
|
||||||
|
|
@ -497,13 +532,24 @@
|
||||||
sidebar.classList.toggle('active');
|
sidebar.classList.toggle('active');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Logout button
|
// Close modal with escape key
|
||||||
const logoutButton = document.getElementById('logoutButton');
|
document.addEventListener('keydown', function(e) {
|
||||||
logoutButton.addEventListener('click', () => {
|
if (e.key === 'Escape') {
|
||||||
if (confirm('Are you sure you want to logout?')) {
|
closeLogoutModal();
|
||||||
handleLogout();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.getElementById('logoutModal').addEventListener('click', function(e) {
|
||||||
|
if (e.target === this) {
|
||||||
|
closeLogoutModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Logout button - opens confirmation modal instead of directly logging out
|
||||||
|
document.getElementById('logoutButton').addEventListener('click', openLogoutModal);
|
||||||
|
|
||||||
|
// Confirm logout button
|
||||||
|
document.getElementById('confirmLogoutBtn').addEventListener('click', handleLogout);
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue