Update: 2026-07-25 01:02:01
This commit is contained in:
@@ -7,6 +7,12 @@
|
||||
"runtimeArgs": ["run", "dev"],
|
||||
"port": 5183,
|
||||
"cwd": "transit_dashboard"
|
||||
},
|
||||
{
|
||||
"name": "siro-admin",
|
||||
"runtimeExecutable": "python3",
|
||||
"runtimeArgs": ["-m", "http.server", "8899", "--directory", "dashboard/siro-admin"],
|
||||
"port": 8899
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -844,3 +844,257 @@ h1, h2, h3, h4, h5, h6 {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Console additions — live data states, charts, toasts
|
||||
========================================================================== */
|
||||
|
||||
/* Auth extras */
|
||||
.secure-strip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.6rem 0.85rem;
|
||||
margin-bottom: 1.5rem;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--success-bg);
|
||||
color: var(--success);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.device-note {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: 1.25rem;
|
||||
font-size: 0.74rem;
|
||||
color: var(--text-subtle);
|
||||
}
|
||||
|
||||
.device-note code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.btn-primary[disabled] {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* OTP modal */
|
||||
.otp-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--success-bg);
|
||||
color: var(--success);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.otp-input {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
letter-spacing: 0.5rem;
|
||||
font-weight: 700;
|
||||
width: 150px;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
/* Header / nav */
|
||||
.live-indicator[data-state="loading"] { color: var(--warning); }
|
||||
.live-indicator[data-state="loading"] .pulse-dot { background: var(--warning); }
|
||||
.live-indicator[data-state="error"] { color: var(--danger); }
|
||||
.live-indicator[data-state="error"] .pulse-dot { background: var(--danger); animation: none; }
|
||||
|
||||
.nav-count {
|
||||
margin-left: auto;
|
||||
min-width: 20px;
|
||||
padding: 0 0.4rem;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--danger);
|
||||
color: #fff;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.stamp {
|
||||
font-size: 0.76rem;
|
||||
color: var(--text-subtle);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-sub {
|
||||
font-weight: 400;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-subtle);
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
/* Table states */
|
||||
.table-msg {
|
||||
text-align: center;
|
||||
padding: 2.25rem 1rem !important;
|
||||
color: var(--text-subtle);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.table-msg.is-error { color: var(--danger); }
|
||||
|
||||
.route-cell {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.danger-btn:hover {
|
||||
background: var(--danger-bg);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
/* Charts */
|
||||
.donut-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.75rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
font-size: 0.78rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.legend-item i {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.legend-item strong { color: var(--text-main); }
|
||||
|
||||
/* Key/value & distribution lists */
|
||||
.mini-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
|
||||
.kv-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 0.7rem 0.25rem;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.kv-row:last-child { border-bottom: none; }
|
||||
.kv-row strong { color: var(--text-main); font-weight: 600; text-align: right; }
|
||||
|
||||
.mix-row { padding: 0.55rem 0.25rem; }
|
||||
|
||||
.mix-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
|
||||
.mix-head strong { color: var(--text-main); }
|
||||
.mix-pct { color: var(--text-subtle); font-weight: 400; font-size: 0.78rem; }
|
||||
|
||||
.mix-track {
|
||||
height: 7px;
|
||||
border-radius: var(--radius-full);
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mix-fill {
|
||||
height: 100%;
|
||||
border-radius: var(--radius-full);
|
||||
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Modal head */
|
||||
.modal-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.modal-head h3 { color: var(--text-main); font-family: 'Outfit', sans-serif; }
|
||||
|
||||
.modal-content { max-height: 85vh; overflow-y: auto; }
|
||||
|
||||
/* Toasts */
|
||||
.toast {
|
||||
position: fixed;
|
||||
bottom: 24px;
|
||||
right: 24px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
max-width: 380px;
|
||||
padding: 0.85rem 1.15rem;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border-color);
|
||||
border-left: 3px solid var(--primary);
|
||||
color: var(--text-main);
|
||||
font-size: 0.86rem;
|
||||
box-shadow: var(--shadow-md);
|
||||
animation: toastIn 0.28s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.toast.leaving { opacity: 0; transform: translateY(8px); transition: var(--transition-smooth); }
|
||||
.toast i { font-size: 1.15rem; }
|
||||
.toast-success { border-left-color: var(--success); }
|
||||
.toast-success i { color: var(--success); }
|
||||
.toast-danger { border-left-color: var(--danger); }
|
||||
.toast-danger i { color: var(--danger); }
|
||||
.toast-warning { border-left-color: var(--warning); }
|
||||
.toast-warning i { color: var(--warning); }
|
||||
.toast-info i { color: var(--primary); }
|
||||
|
||||
@keyframes toastIn {
|
||||
from { opacity: 0; transform: translateY(12px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
.toast { left: 16px; right: 16px; max-width: none; }
|
||||
}
|
||||
|
||||
.chart-container canvas {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.data-table td strong,
|
||||
.data-table .badge {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
+181
-207
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Siro Admin | Enterprise Operations Dashboard</title>
|
||||
<title>Siro Admin | Operations Console</title>
|
||||
|
||||
<!-- Fonts & Icons -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
@@ -24,49 +24,39 @@
|
||||
<i class="ph-bold ph-car"></i>
|
||||
<span>SIRO ADMIN</span>
|
||||
</div>
|
||||
<p class="auth-subtitle">Enterprise Operations & Control Portal</p>
|
||||
<p class="auth-subtitle">Operations & Control Console</p>
|
||||
</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 class="secure-strip">
|
||||
<i class="ph-fill ph-shield-check"></i>
|
||||
<span>Secure session · device-bound token · WhatsApp OTP</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="loginEmail">Admin Email / Phone</label>
|
||||
<div class="form-input-group">
|
||||
<input type="text" id="loginEmail" class="form-input" placeholder="hamzaayed@siromove.com or +962..." value="hamzaayed@siromove.com" required>
|
||||
<input type="text" id="loginEmail" class="form-input" placeholder="you@siromove.com or +9627..." autocomplete="username" required>
|
||||
<i class="ph ph-envelope"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="loginPass">Password / Security PIN</label>
|
||||
<label class="form-label" for="loginPass">Password</label>
|
||||
<div class="form-input-group">
|
||||
<input type="password" id="loginPass" class="form-input" value="••••••••••••" required>
|
||||
<input type="password" id="loginPass" class="form-input" placeholder="Enter your password" autocomplete="current-password" required>
|
||||
<i class="ph ph-lock-key"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary" style="margin-top: 1.25rem;">
|
||||
<i class="ph-bold ph-sign-in"></i> Sign In to Portal
|
||||
<button type="submit" class="btn-primary" id="loginSubmitBtn" style="margin-top: 1.25rem;">
|
||||
<i class="ph-bold ph-sign-in"></i> <span>Sign In</span>
|
||||
</button>
|
||||
|
||||
<div style="display:flex; align-items:center; margin: 1.25rem 0; color: var(--text-subtle); font-size: 0.8rem;">
|
||||
<div style="flex:1; height:1px; background:var(--border-color);"></div>
|
||||
<span style="padding: 0 0.75rem;">OR BIOMETRIC AUTH</span>
|
||||
<div style="flex:1; height:1px; background:var(--border-color);"></div>
|
||||
<div class="device-note">
|
||||
<i class="ph ph-fingerprint"></i>
|
||||
<span>This browser is registered as a trusted device: <code id="fpPreview">…</code></span>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-secondary" id="fingerprintLoginBtn" style="width:100%; justify-content:center; padding:0.8rem; border-color:var(--primary); color:var(--text-main);">
|
||||
<i class="ph-bold ph-fingerprint" style="font-size:1.4rem; color:var(--primary);"></i>
|
||||
<span>Authenticate with Fingerprint / WebAuthn</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -87,45 +77,50 @@
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-menu">
|
||||
<div class="menu-label">Main Menu</div>
|
||||
<div class="menu-label">Operations</div>
|
||||
<a class="nav-item active" data-view="dashboardView">
|
||||
<i class="ph ph-squares-four"></i>
|
||||
<span>Dashboard</span>
|
||||
<span>Overview</span>
|
||||
</a>
|
||||
<a class="nav-item" data-view="ridesView">
|
||||
<i class="ph ph-path"></i>
|
||||
<span>Rides & Dispatch</span>
|
||||
<span>Rides</span>
|
||||
</a>
|
||||
<a class="nav-item" data-view="driversView">
|
||||
<i class="ph ph-steering-wheel"></i>
|
||||
<span>Captains / Drivers</span>
|
||||
<span>Captains</span>
|
||||
</a>
|
||||
<a class="nav-item" data-view="passengersView">
|
||||
<i class="ph ph-users"></i>
|
||||
<span>Passengers</span>
|
||||
</a>
|
||||
|
||||
<div class="menu-label">Management</div>
|
||||
<div class="menu-label">Business</div>
|
||||
<a class="nav-item" data-view="financialsView">
|
||||
<i class="ph ph-currency-circle-dollar"></i>
|
||||
<span>Financials & Reports</span>
|
||||
<span>Financials</span>
|
||||
</a>
|
||||
<a class="nav-item" data-view="approvalsView">
|
||||
<i class="ph ph-user-check"></i>
|
||||
<span>Approvals</span>
|
||||
<span class="nav-count" id="approvalsCount" hidden>0</span>
|
||||
</a>
|
||||
<a class="nav-item" data-view="complaintsView">
|
||||
<i class="ph ph-warning-circle"></i>
|
||||
<span>Support & Complaints</span>
|
||||
<span>Complaints</span>
|
||||
</a>
|
||||
<a class="nav-item" data-view="systemView">
|
||||
<i class="ph ph-cpu"></i>
|
||||
<span>System Status</span>
|
||||
<i class="ph ph-shield-check"></i>
|
||||
<span>Session & Security</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<div class="user-profile-mini">
|
||||
<div class="avatar">SA</div>
|
||||
<div class="avatar" id="userAvatar">SA</div>
|
||||
<div class="user-info">
|
||||
<div class="name">Super Admin</div>
|
||||
<div class="role">Operations Lead</div>
|
||||
<div class="name" id="userName">Admin</div>
|
||||
<div class="role" id="userRole">—</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn-icon" id="logoutBtn" title="Sign Out">
|
||||
@@ -145,174 +140,154 @@
|
||||
</button>
|
||||
<div class="search-box">
|
||||
<i class="ph ph-magnifying-glass"></i>
|
||||
<input type="text" id="globalSearch" placeholder="Search trips, drivers, passengers...">
|
||||
<input type="text" id="globalSearch" placeholder="Filter the current table…">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-right">
|
||||
<div class="live-indicator">
|
||||
<span class="pulse-dot"></span> Live Fleet Network
|
||||
<div class="live-indicator" id="connectionPill">
|
||||
<span class="pulse-dot"></span> <span id="connectionText">Connecting…</span>
|
||||
</div>
|
||||
<button class="btn-icon" title="Notifications">
|
||||
<i class="ph ph-bell"></i>
|
||||
</button>
|
||||
<button class="btn-icon" title="Settings">
|
||||
<i class="ph ph-gear"></i>
|
||||
<button class="btn-icon" id="refreshBtn" title="Refresh data">
|
||||
<i class="ph ph-arrows-clockwise"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="content-body">
|
||||
|
||||
<!-- ================= 1. DASHBOARD OVERVIEW ================= -->
|
||||
<!-- ================= 1. OVERVIEW ================= -->
|
||||
<section class="page-view active" id="dashboardView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Operations Dashboard</h1>
|
||||
<p>Real-time analytics and fleet performance metrics</p>
|
||||
<h1>Operations Overview</h1>
|
||||
<p>Live figures read directly from the production database</p>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<button class="btn btn-secondary"><i class="ph ph-calendar"></i> Today</button>
|
||||
<button class="btn btn-primary" style="width: auto;"><i class="ph ph-download-simple"></i> Export PDF</button>
|
||||
<span class="stamp" id="lastUpdated">—</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KPI Cards Grid -->
|
||||
<!-- Primary KPIs -->
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value">$42,850</div>
|
||||
<div class="stat-title">Today's Revenue</div>
|
||||
<div class="stat-value" data-kpi="rides">—</div>
|
||||
<div class="stat-title">Total Rides</div>
|
||||
</div>
|
||||
<div class="stat-icon primary"><i class="ph ph-currency-dollar"></i></div>
|
||||
<div class="stat-icon primary"><i class="ph ph-path"></i></div>
|
||||
</div>
|
||||
<div class="stat-footer">
|
||||
<span class="trend-badge up"><i class="ph ph-trend-up"></i> +14.2%</span>
|
||||
<span class="trend-text">vs yesterday</span>
|
||||
<span class="trend-badge up"><i class="ph ph-plus"></i> <span data-kpi="ridesMonth">—</span></span>
|
||||
<span class="trend-text">this month</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value">1,482</div>
|
||||
<div class="stat-title">Active Rides</div>
|
||||
<div class="stat-value" data-kpi="completed">—</div>
|
||||
<div class="stat-title">Completed Rides</div>
|
||||
</div>
|
||||
<div class="stat-icon success"><i class="ph ph-car-profile"></i></div>
|
||||
<div class="stat-icon success"><i class="ph ph-check-circle"></i></div>
|
||||
</div>
|
||||
<div class="stat-footer">
|
||||
<span class="trend-badge up"><i class="ph ph-trend-up"></i> +8.6%</span>
|
||||
<span class="trend-text">fleet active</span>
|
||||
<span class="trend-badge up"><i class="ph ph-percent"></i> <span data-kpi="completionRate">—</span></span>
|
||||
<span class="trend-text">completion rate</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value">324</div>
|
||||
<div class="stat-title">Captains Online</div>
|
||||
<div class="stat-value" data-kpi="drivers">—</div>
|
||||
<div class="stat-title">Registered Captains</div>
|
||||
</div>
|
||||
<div class="stat-icon info"><i class="ph ph-steering-wheel"></i></div>
|
||||
</div>
|
||||
<div class="stat-footer">
|
||||
<span class="trend-badge up"><i class="ph ph-check"></i> 94% online rate</span>
|
||||
<span class="trend-badge up"><i class="ph ph-plus"></i> <span data-kpi="driversMonth">—</span></span>
|
||||
<span class="trend-text">joined this month</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value">98.4%</div>
|
||||
<div class="stat-title">Dispatch Rate</div>
|
||||
<div class="stat-value" data-kpi="passengers">—</div>
|
||||
<div class="stat-title">Registered Passengers</div>
|
||||
</div>
|
||||
<div class="stat-icon warning"><i class="ph ph-lightning"></i></div>
|
||||
<div class="stat-icon warning"><i class="ph ph-users"></i></div>
|
||||
</div>
|
||||
<div class="stat-footer">
|
||||
<span class="trend-badge down"><i class="ph ph-trend-down"></i> -0.4%</span>
|
||||
<span class="trend-text">avg 3.2m wait</span>
|
||||
<span class="trend-badge up"><i class="ph ph-plus"></i> <span data-kpi="passengersMonth">—</span></span>
|
||||
<span class="trend-text">joined this month</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Charts Section -->
|
||||
<!-- Charts -->
|
||||
<div class="dashboard-grid">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Revenue & Trip Surge Analytics</h3>
|
||||
<button class="btn btn-secondary btn-sm">Weekly</button>
|
||||
<h3 class="card-title">Rides per Day <span class="card-sub">last 21 days</span></h3>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<canvas id="revenueChart"></canvas>
|
||||
<canvas id="ridesTrendChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Live Dispatch Feed</h3>
|
||||
<h3 class="card-title">Ride Outcomes</h3>
|
||||
</div>
|
||||
<div style="display:flex; flex-direction:column; gap:1rem;">
|
||||
<div style="display:flex; align-items:center; gap:0.75rem; padding:0.75rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-md);">
|
||||
<div style="width:36px; height:36px; border-radius:var(--radius-full); background:var(--success-bg); color:var(--success); display:flex; align-items:center; justify-content:center;">
|
||||
<i class="ph ph-check-circle"></i>
|
||||
<div class="chart-container donut-wrap">
|
||||
<canvas id="statusDonut"></canvas>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight:600; font-size:0.88rem;">Ride SR-9842 Completed</div>
|
||||
<div style="font-size:0.75rem; color:var(--text-subtle);">Driver: Khalid H. | $14.50</div>
|
||||
<div class="legend" id="statusLegend"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; align-items:center; gap:0.75rem; padding:0.75rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-md);">
|
||||
<div style="width:36px; height:36px; border-radius:var(--radius-full); background:var(--primary-light); color:var(--primary); display:flex; align-items:center; justify-content:center;">
|
||||
<i class="ph ph-arrows-clockwise"></i>
|
||||
<div class="dashboard-grid">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Demand by Time of Day</h3>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight:600; font-size:0.88rem;">New Dispatch SR-9846</div>
|
||||
<div style="font-size:0.75rem; color:var(--text-subtle);">Driver: Bilal M. | Sweifieh</div>
|
||||
<div class="chart-container" style="height:200px;">
|
||||
<canvas id="timeOfDayChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; align-items:center; gap:0.75rem; padding:0.75rem; background:rgba(255,255,255,0.03); border-radius:var(--radius-md);">
|
||||
<div style="width:36px; height:36px; border-radius:var(--radius-full); background:var(--warning-bg); color:var(--warning); display:flex; align-items:center; justify-content:center;">
|
||||
<i class="ph ph-star"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight:600; font-size:0.88rem;">5-Star Rating Submitted</div>
|
||||
<div style="font-size:0.75rem; color:var(--text-subtle);">Rider: Sarah M.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Service Mix</h3>
|
||||
</div>
|
||||
<div class="mini-list" id="serviceMix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 2. RIDES & DISPATCH VIEW ================= -->
|
||||
<!-- ================= 2. RIDES ================= -->
|
||||
<section class="page-view" id="ridesView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Rides & Dispatch Management</h1>
|
||||
<p>Monitor real-time passenger trips, statuses, and fare details</p>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<button class="btn btn-primary" style="width:auto;"><i class="ph ph-plus"></i> Manual Dispatch</button>
|
||||
<h1>Rides</h1>
|
||||
<p>Trips, assigned captains, fares and live status</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar">
|
||||
<div class="filter-inputs">
|
||||
<select class="select-input">
|
||||
<option>All Statuses</option>
|
||||
<option>Completed</option>
|
||||
<option>In Progress</option>
|
||||
<option>Cancelled</option>
|
||||
</select>
|
||||
<select class="select-input">
|
||||
<option>All Cities</option>
|
||||
<option>Amman</option>
|
||||
<option>Zarqa</option>
|
||||
<option>Irbid</option>
|
||||
<select class="select-input" id="rideStatusFilter">
|
||||
<option value="All">All statuses</option>
|
||||
<option value="Pending">Waiting for a captain</option>
|
||||
<option value="Begin">In progress</option>
|
||||
<option value="Completed">Completed</option>
|
||||
<option value="Canceled">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
<span class="stamp" id="ridesMeta">—</span>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@@ -320,33 +295,33 @@
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Trip ID</th>
|
||||
<th>Trip</th>
|
||||
<th>Passenger</th>
|
||||
<th>Driver</th>
|
||||
<th>Captain</th>
|
||||
<th>Route</th>
|
||||
<th>Fare</th>
|
||||
<th>Status</th>
|
||||
<th>Time</th>
|
||||
<th>Action</th>
|
||||
<th>Created</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ridesTableBody">
|
||||
<!-- Populated by JS -->
|
||||
</tbody>
|
||||
<tbody id="ridesTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 3. DRIVERS VIEW ================= -->
|
||||
<!-- ================= 3. CAPTAINS ================= -->
|
||||
<section class="page-view" id="driversView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Captains & Drivers</h1>
|
||||
<p>Verify documents, manage online fleet, and inspect ratings</p>
|
||||
<h1>Captains</h1>
|
||||
<p>Fleet roster, ratings and trip volume</p>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<button class="btn btn-primary" style="width:auto;"><i class="ph ph-user-plus"></i> Add New Driver</button>
|
||||
<button class="btn btn-secondary btn-sm" id="driversPrev"><i class="ph ph-caret-left"></i></button>
|
||||
<span class="stamp" id="driversMeta">—</span>
|
||||
<button class="btn btn-secondary btn-sm" id="driversNext"><i class="ph ph-caret-right"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -355,30 +330,28 @@
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Driver ID</th>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Phone</th>
|
||||
<th>Vehicle</th>
|
||||
<th>Email</th>
|
||||
<th>Rating</th>
|
||||
<th>Total Trips</th>
|
||||
<th>Trips</th>
|
||||
<th>Cancellations</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="driversTableBody">
|
||||
<!-- Populated by JS -->
|
||||
</tbody>
|
||||
<tbody id="driversTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 4. PASSENGERS VIEW ================= -->
|
||||
<!-- ================= 4. PASSENGERS ================= -->
|
||||
<section class="page-view" id="passengersView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Passengers & Customers</h1>
|
||||
<p>Customer accounts, trip history, and subscription status</p>
|
||||
<h1>Passengers</h1>
|
||||
<p>Most active customer accounts by trip count</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -387,112 +360,117 @@
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Customer ID</th>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Trips Count</th>
|
||||
<th>Contact</th>
|
||||
<th>Trips</th>
|
||||
<th>Rating</th>
|
||||
<th>Joined Date</th>
|
||||
<th>Account Status</th>
|
||||
<th>Action</th>
|
||||
<th>Cancellations</th>
|
||||
<th>Joined</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="passengersTableBody">
|
||||
<!-- Populated by JS -->
|
||||
</tbody>
|
||||
<tbody id="passengersTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 5. FINANCIALS VIEW ================= -->
|
||||
<!-- ================= 5. FINANCIALS ================= -->
|
||||
<section class="page-view" id="financialsView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Financials & Reports</h1>
|
||||
<p>Payout calculations, platform commissions, and exported ledgers</p>
|
||||
</div>
|
||||
<div class="page-actions">
|
||||
<button class="btn btn-primary" style="width:auto;"><i class="ph ph-file-text"></i> Generate Report</button>
|
||||
<h1>Financials</h1>
|
||||
<p>Earnings, fares and distance aggregates across all recorded trips</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">$184,200</div>
|
||||
<div class="stat-title">Gross Revenue (This Month)</div>
|
||||
<div class="stat-value" data-kpi="driverEarnings">—</div>
|
||||
<div class="stat-title">Captain earnings (completed trips)</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">$27,630</div>
|
||||
<div class="stat-title">Platform Net Commission (15%)</div>
|
||||
<div class="stat-value" data-kpi="avgFare">—</div>
|
||||
<div class="stat-title">Average passenger fare</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">$156,570</div>
|
||||
<div class="stat-title">Driver Payouts Processed</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 6. COMPLAINTS VIEW ================= -->
|
||||
<section class="page-view" id="complaintsView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Support & Complaints Triage</h1>
|
||||
<p>Customer issues, lost & found, and ride rating disputes</p>
|
||||
<div class="stat-value" data-kpi="totalDistance">—</div>
|
||||
<div class="stat-title">Total distance covered</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div style="padding:1rem; text-align:center; color:var(--text-muted);">
|
||||
<i class="ph ph-shield-check" style="font-size:3rem; color:var(--success); margin-bottom:0.5rem; display:block;"></i>
|
||||
<h3>All high-priority complaints resolved</h3>
|
||||
<p style="font-size:0.88rem; margin-top:0.25rem;">0 active tickets requiring immediate escalation.</p>
|
||||
<div class="card-header"><h3 class="card-title">Trip Performance</h3></div>
|
||||
<div class="mini-list" id="tripPerformance"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 6. APPROVALS ================= -->
|
||||
<section class="page-view" id="approvalsView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Pending Approvals</h1>
|
||||
<p>Admin and service accounts awaiting activation</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="table-responsive">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Phone</th>
|
||||
<th>Type</th>
|
||||
<th>Requested role</th>
|
||||
<th>Requested at</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="approvalsTableBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 7. SYSTEM STATUS VIEW ================= -->
|
||||
<section class="page-view" id="systemView">
|
||||
<!-- ================= 7. COMPLAINTS ================= -->
|
||||
<section class="page-view" id="complaintsView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>System Health & Microservices</h1>
|
||||
<p>Server nodes, API gateways, database latency, and websocket connections</p>
|
||||
<h1>Complaints</h1>
|
||||
<p>Volume of customer complaints filed</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value" style="color:var(--success);">Healthy</div>
|
||||
<div class="stat-title">Location Server</div>
|
||||
<div class="stat-value" data-kpi="complaintsToday">—</div>
|
||||
<div class="stat-title">Filed today</div>
|
||||
</div>
|
||||
<div class="stat-icon success"><i class="ph ph-map-pin-line"></i></div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" data-kpi="complaintsWeek">—</div>
|
||||
<div class="stat-title">This week</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value" data-kpi="complaintsMonth">—</div>
|
||||
<div class="stat-title">This month</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ================= 8. SESSION & SECURITY ================= -->
|
||||
<section class="page-view" id="systemView">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<h1>Session & Security</h1>
|
||||
<p>Details of the credential currently authorising this console</p>
|
||||
</div>
|
||||
<div class="stat-footer"><span class="trend-text">Latency: 14ms</span></div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value" style="color:var(--success);">Healthy</div>
|
||||
<div class="stat-title">Ride Dispatch Engine</div>
|
||||
</div>
|
||||
<div class="stat-icon success"><i class="ph ph-cpu"></i></div>
|
||||
</div>
|
||||
<div class="stat-footer"><span class="trend-text">Latency: 22ms</span></div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="stat-header">
|
||||
<div>
|
||||
<div class="stat-value" style="color:var(--success);">Healthy</div>
|
||||
<div class="stat-title">Payment Server</div>
|
||||
</div>
|
||||
<div class="stat-icon success"><i class="ph ph-credit-card"></i></div>
|
||||
</div>
|
||||
<div class="stat-footer"><span class="trend-text">Latency: 45ms</span></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="mini-list" id="sessionInfo"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -503,29 +481,25 @@
|
||||
<!-- Details Modal -->
|
||||
<div class="modal-overlay" id="detailsModal">
|
||||
<div class="modal-content">
|
||||
<div id="modalBodyContent">
|
||||
<!-- Dynamic content -->
|
||||
</div>
|
||||
<div id="modalBodyContent"></div>
|
||||
</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>
|
||||
<div class="otp-icon"><i class="ph ph-whatsapp-logo"></i></div>
|
||||
<h3 style="color: #fff; margin-bottom: 0.5rem;">WhatsApp Verification</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">
|
||||
<input type="text" maxlength="3" inputmode="numeric" id="otpInput" class="form-input otp-input" placeholder="123">
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-primary" id="submitOtpBtn">
|
||||
<i class="ph-bold ph-check"></i> Verify & Sign In
|
||||
<i class="ph-bold ph-check"></i> <span>Verify & Sign In</span>
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-secondary" onclick="closeOtpModal()" style="width: 100%; margin-top: 0.75rem; justify-content: center;">
|
||||
|
||||
+805
-552
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user