- Express + EJS server-rendered app - Supabase PostgreSQL database - Auth: username/password with bcrypt - Dashboard with business stats - Load CRUD with filters - WhatsApp message parser - Payment tracking - Shipper & vehicle management - Reports (monthly, top shippers, routes) - Government-app aesthetic (tricolor theme) - Dark mode support - Docker + Coolify deployment ready - Seed data from existing business ledger (88 loads, 41 shippers, 70 vehicles)
75 lines
2.4 KiB
Text
75 lines
2.4 KiB
Text
<%- include('../partials/header', { activeMenu: 'reports' }) %>
|
|
|
|
<div class="page-header">
|
|
<div>
|
|
<h1 class="page-title">📈 Reports</h1>
|
|
<p class="page-subtitle">Business analytics and insights</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header"><h3 class="card-title">Monthly Summary</h3></div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table">
|
|
<thead><tr><th>Month</th><th>Loads</th><th>Freight</th><th>Commission</th><th>Pending</th></tr></thead>
|
|
<tbody>
|
|
<% for (const [key, m] of monthly) { %>
|
|
<tr>
|
|
<td><strong><%= m.label %></strong></td>
|
|
<td><%= m.count %></td>
|
|
<td><%= formatINR(m.freight) %></td>
|
|
<td class="text-success"><%= formatINR(m.commission) %></td>
|
|
<td class="text-danger"><%= formatINR(m.pending) %></td>
|
|
</tr>
|
|
<% } %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid-2 mt-4">
|
|
<div class="card">
|
|
<div class="card-header"><h3 class="card-title">Top Shippers</h3></div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table">
|
|
<thead><tr><th>Shipper</th><th>Loads</th><th>Freight</th><th>Commission</th></tr></thead>
|
|
<tbody>
|
|
<% for (const s of shippers) { %>
|
|
<tr>
|
|
<td><a href="/shippers/<%= encodeURIComponent(s.id) %>"><%= s.name %></a></td>
|
|
<td><%= s.load_count || 0 %></td>
|
|
<td><%= formatINR(s.total_freight) %></td>
|
|
<td class="text-success"><%= formatINR(s.total_commission) %></td>
|
|
</tr>
|
|
<% } %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header"><h3 class="card-title">Top Routes</h3></div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table">
|
|
<thead><tr><th>Route</th><th>Loads</th><th>Commission</th></tr></thead>
|
|
<tbody>
|
|
<% for (const r of routes) { %>
|
|
<tr>
|
|
<td><%= r.route %></td>
|
|
<td><%= r.count %></td>
|
|
<td class="text-success"><%= formatINR(r.total_commission) %></td>
|
|
</tr>
|
|
<% } %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%- include('../partials/footer') %>
|