Update: 2026-07-24 23:23:54
This commit is contained in:
@@ -28,10 +28,19 @@
|
||||
</div>
|
||||
|
||||
<form id="loginForm">
|
||||
<div style="display:flex; background:rgba(15, 23, 42, 0.6); padding:4px; border-radius:var(--radius-md); border:1px solid var(--border-color); margin-bottom:1.5rem;">
|
||||
<button type="button" id="modeLiveBtn" class="btn" style="flex:1; justify-center:center; padding:0.5rem; font-size:0.82rem; border-radius:var(--radius-sm); background:var(--primary); color:#fff;">
|
||||
<i class="ph-bold ph-database"></i> Live Backend API
|
||||
</button>
|
||||
<button type="button" id="modeDemoBtn" class="btn" style="flex:1; justify-center:center; padding:0.5rem; font-size:0.82rem; border-radius:var(--radius-sm); color:var(--text-muted); background:transparent;">
|
||||
<i class="ph-bold ph-flask"></i> Interactive Demo
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="loginEmail">Admin Email</label>
|
||||
<label class="form-label" for="loginEmail">Admin Email / Phone</label>
|
||||
<div class="form-input-group">
|
||||
<input type="email" id="loginEmail" class="form-input" placeholder="admin@siromove.com" value="admin@siromove.com" required>
|
||||
<input type="text" id="loginEmail" class="form-input" placeholder="admin@siromove.com or +962..." value="admin@siromove.com" required>
|
||||
<i class="ph ph-envelope"></i>
|
||||
</div>
|
||||
</div>
|
||||
@@ -500,6 +509,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OTP Verification Modal -->
|
||||
<div class="modal-overlay" id="otpModal">
|
||||
<div class="modal-content" style="max-width: 400px; text-align: center;">
|
||||
<div style="width: 56px; height: 56px; border-radius: var(--radius-full); background: var(--primary-light); color: var(--primary); display: inline-flex; align-items: center; justify-content: center; font-size: 1.75rem; margin-bottom: 1rem;">
|
||||
<i class="ph ph-whatsapp-logo"></i>
|
||||
</div>
|
||||
<h3 style="color: #fff; margin-bottom: 0.5rem;">WhatsApp Verification Code</h3>
|
||||
<p style="color: var(--text-muted); font-size: 0.88rem; margin-bottom: 1.5rem;" id="otpPhoneText">
|
||||
A 3-digit verification code was sent to your WhatsApp.
|
||||
</p>
|
||||
|
||||
<div style="display: flex; gap: 0.5rem; justify-content: center; margin-bottom: 1.5rem;">
|
||||
<input type="text" maxlength="3" id="otpInput" class="form-input" style="text-align: center; font-size: 1.5rem; letter-spacing: 0.5rem; font-weight: 700; width: 140px;" placeholder="123">
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-primary" id="submitOtpBtn">
|
||||
<i class="ph-bold ph-check"></i> Verify & Sign In
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-secondary" onclick="closeOtpModal()" style="width: 100%; margin-top: 0.75rem; justify-content: center;">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -47,24 +47,180 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
setupEvents();
|
||||
}
|
||||
|
||||
// Web Device Fingerprint Generator
|
||||
function getWebFingerprint() {
|
||||
let fp = localStorage.getItem('siro_web_fp');
|
||||
if (!fp) {
|
||||
fp = 'web_' + Math.random().toString(36).substring(2) + Date.now().toString(36);
|
||||
localStorage.setItem('siro_web_fp', fp);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
const deviceFingerprint = getWebFingerprint();
|
||||
|
||||
// Mode State (Live vs Demo)
|
||||
let isLiveMode = true;
|
||||
|
||||
const modeLiveBtn = document.getElementById('modeLiveBtn');
|
||||
const modeDemoBtn = document.getElementById('modeDemoBtn');
|
||||
|
||||
modeLiveBtn?.addEventListener('click', () => {
|
||||
isLiveMode = true;
|
||||
modeLiveBtn.style.background = 'var(--primary)';
|
||||
modeLiveBtn.style.color = '#fff';
|
||||
modeDemoBtn.style.background = 'transparent';
|
||||
modeDemoBtn.style.color = 'var(--text-muted)';
|
||||
});
|
||||
|
||||
modeDemoBtn?.addEventListener('click', () => {
|
||||
isLiveMode = false;
|
||||
modeDemoBtn.style.background = 'var(--primary)';
|
||||
modeDemoBtn.style.color = '#fff';
|
||||
modeLiveBtn.style.background = 'transparent';
|
||||
modeLiveBtn.style.color = 'var(--text-muted)';
|
||||
});
|
||||
|
||||
// Auth Functions
|
||||
function checkAuth() {
|
||||
if (currentUser) {
|
||||
authWrapper.classList.add('hidden');
|
||||
if (currentUser.isLive && currentUser.jwt) {
|
||||
fetchLiveDashboardData();
|
||||
}
|
||||
} else {
|
||||
authWrapper.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
loginForm?.addEventListener('submit', (e) => {
|
||||
let pendingOtpPhone = '';
|
||||
let pendingOtpPassword = '';
|
||||
|
||||
loginForm?.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
const email = document.getElementById('loginEmail').value;
|
||||
currentUser = { name: 'Super Admin', email: email, role: 'Administrator', authMethod: 'Password' };
|
||||
localStorage.setItem('siro_admin_user', JSON.stringify(currentUser));
|
||||
authWrapper.classList.add('hidden');
|
||||
showNotification('Welcome back, Super Admin!', 'success');
|
||||
const phone = document.getElementById('loginEmail').value.trim();
|
||||
const password = document.getElementById('loginPass').value.trim();
|
||||
|
||||
if (isLiveMode) {
|
||||
showNotification('Authenticating device with server...', 'info');
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('phone', phone);
|
||||
formData.append('password', password);
|
||||
formData.append('fingerprint', deviceFingerprint);
|
||||
formData.append('aud', 'admin');
|
||||
|
||||
const response = await fetch('/backend/Admin/auth/login.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const res = await response.json();
|
||||
if (response.ok && res.status === 'success') {
|
||||
if (res.jwt) {
|
||||
currentUser = {
|
||||
name: res.admin?.name || 'Admin',
|
||||
email: res.admin?.email || phone,
|
||||
role: res.admin?.role || 'Administrator',
|
||||
jwt: res.jwt,
|
||||
isLive: true
|
||||
};
|
||||
localStorage.setItem('siro_admin_user', JSON.stringify(currentUser));
|
||||
authWrapper.classList.add('hidden');
|
||||
showNotification('Access Granted! Device Fingerprint Verified.', 'success');
|
||||
fetchLiveDashboardData();
|
||||
} else if (res.message && res.message.status === 'otp_required' || res.status === 'otp_required') {
|
||||
pendingOtpPhone = phone;
|
||||
pendingOtpPassword = password;
|
||||
const masked = res.phone || res.message?.phone || phone;
|
||||
document.getElementById('otpPhoneText').textContent = `Verification code sent to WhatsApp (${masked})`;
|
||||
document.getElementById('otpModal').classList.add('active');
|
||||
}
|
||||
} else {
|
||||
showNotification(res.message || 'Invalid credentials or device not registered.', 'warning');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
showNotification('Cannot connect to Live Backend. Entering Demo Mode.', 'info');
|
||||
currentUser = { name: 'Super Admin (Demo)', email: phone, role: 'Administrator', isLive: false };
|
||||
localStorage.setItem('siro_admin_user', JSON.stringify(currentUser));
|
||||
authWrapper.classList.add('hidden');
|
||||
}
|
||||
} else {
|
||||
currentUser = { name: 'Super Admin (Demo)', email: phone, role: 'Administrator', isLive: false };
|
||||
localStorage.setItem('siro_admin_user', JSON.stringify(currentUser));
|
||||
authWrapper.classList.add('hidden');
|
||||
showNotification('Welcome to Interactive Demo Mode!', 'success');
|
||||
}
|
||||
});
|
||||
|
||||
// Submit OTP Code
|
||||
document.getElementById('submitOtpBtn')?.addEventListener('click', async () => {
|
||||
const otp = document.getElementById('otpInput').value.trim();
|
||||
if (!otp || otp.length < 3) {
|
||||
showNotification('Please enter the 3-digit OTP code', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('otp', otp);
|
||||
formData.append('fingerprint', deviceFingerprint);
|
||||
formData.append('aud', 'admin');
|
||||
|
||||
const response = await fetch('/backend/Admin/auth/verify_login.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const res = await response.json();
|
||||
if (response.ok && res.status === 'success') {
|
||||
currentUser = {
|
||||
name: res.admin?.name || 'Admin',
|
||||
email: res.admin?.email || pendingOtpPhone,
|
||||
role: res.admin?.role || 'Administrator',
|
||||
jwt: res.jwt,
|
||||
isLive: true
|
||||
};
|
||||
localStorage.setItem('siro_admin_user', JSON.stringify(currentUser));
|
||||
closeOtpModal();
|
||||
authWrapper.classList.add('hidden');
|
||||
showNotification('OTP Verified! Welcome back, Admin.', 'success');
|
||||
fetchLiveDashboardData();
|
||||
} else {
|
||||
showNotification(res.message || 'Invalid OTP code', 'danger');
|
||||
}
|
||||
} catch (err) {
|
||||
showNotification('OTP verification error', 'danger');
|
||||
}
|
||||
});
|
||||
|
||||
window.closeOtpModal = function() {
|
||||
document.getElementById('otpModal')?.classList.remove('active');
|
||||
};
|
||||
|
||||
async function fetchLiveDashboardData() {
|
||||
try {
|
||||
const response = await fetch('/backend/Admin/dashbord.php', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${currentUser?.jwt || ''}`
|
||||
}
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data && data.status === 'success' && data.data && data.data[0]) {
|
||||
const stats = data.data[0];
|
||||
// Update DOM elements with real MySQL DB counters
|
||||
const revCard = document.querySelector('.stat-card .stat-value');
|
||||
if (revCard && stats.countRide) {
|
||||
revCard.textContent = `${stats.countRide} Trips`;
|
||||
}
|
||||
showNotification('Live Database Stats Synchronized!', 'success');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Using local fallback metrics for display.');
|
||||
}
|
||||
}
|
||||
|
||||
const fingerprintLoginBtn = document.getElementById('fingerprintLoginBtn');
|
||||
fingerprintLoginBtn?.addEventListener('click', async () => {
|
||||
showNotification('Touch Fingerprint sensor on your device...', 'info');
|
||||
|
||||
Reference in New Issue
Block a user