Add mobile card view to Bills/Expenses list page

Wraps the desktop table in table-responsive to fix horizontal scrolling,
and adds a mobile-card-view section matching the pattern used on Invoices,
PurchaseOrders, and other list pages. Cards show type, number, vendor,
status, date, due date, amount, balance due, and memo/account.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 18:48:48 -04:00
parent deb248b2a6
commit 2c179bc892
@@ -92,6 +92,7 @@
{ {
<div class="card shadow-sm"> <div class="card shadow-sm">
<div class="card-body p-0"> <div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0"> <table class="table table-hover mb-0">
<thead class="table-light"> <thead class="table-light">
<tr> <tr>
@@ -181,6 +182,92 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="mobile-card-view">
<div class="mobile-card-list">
@foreach (var entry in Model)
{
var isBill = entry.EntryType == "Bill";
var detailUrl = isBill
? Url.Action("Details", "Bills", new { id = entry.Id })
: Url.Action("Details", "Expenses", new { id = entry.Id });
<div class="mobile-data-card" onclick="window.location='@detailUrl'"
style="@(entry.IsOverdue ? "border-left: 3px solid #f59e0b;" : "")">
<div class="mobile-card-header">
<div class="mobile-card-icon" style="background: linear-gradient(135deg, @(isBill ? "#3b82f6 0%, #2563eb" : "#6b7280 0%, #4b5563") 100%);">
<i class="bi @(isBill ? "bi-file-text" : "bi-receipt")"></i>
</div>
<div class="mobile-card-title">
<h6>@entry.Number</h6>
<small>@entry.VendorName</small>
</div>
<div class="ms-auto">
@if (isBill)
{
<span class="badge bg-primary-subtle text-primary border border-primary-subtle">Bill</span>
}
else
{
<span class="badge bg-secondary-subtle text-secondary border border-secondary-subtle">Expense</span>
}
</div>
</div>
<div class="mobile-card-body">
<div class="mobile-card-row">
<span class="mobile-card-label">Status</span>
<span class="mobile-card-value"><span class="badge bg-@entry.StatusColor">@entry.StatusLabel</span></span>
</div>
<div class="mobile-card-row">
<span class="mobile-card-label">Date</span>
<span class="mobile-card-value">@entry.Date.ToString("MMM d, yyyy")</span>
</div>
@if (entry.DueDate.HasValue)
{
<div class="mobile-card-row">
<span class="mobile-card-label">Due</span>
<span class="mobile-card-value @(entry.IsOverdue ? "text-danger fw-medium" : "")">
@entry.DueDate.Value.ToString("MMM d, yyyy")
@if (entry.IsOverdue) { <i class="bi bi-exclamation-circle ms-1"></i> }
</span>
</div>
}
<div class="mobile-card-row">
<span class="mobile-card-label">Amount</span>
<span class="mobile-card-value fw-semibold">@entry.Total.ToString("C")</span>
</div>
@if (isBill)
{
<div class="mobile-card-row">
<span class="mobile-card-label">Balance Due</span>
<span class="mobile-card-value @(entry.BalanceDue > 0 ? "fw-semibold text-danger" : "text-muted")">
@entry.BalanceDue.ToString("C")
</span>
</div>
}
@{
var memoText = isBill ? entry.Memo : entry.AccountName;
}
@if (!string.IsNullOrEmpty(memoText))
{
<div class="mobile-card-row">
<span class="mobile-card-label">@(isBill ? "Memo" : "Account")</span>
<span class="mobile-card-value text-muted small">
@memoText
@if (entry.HasReceipt) { <i class="bi bi-paperclip ms-1" title="Has receipt"></i> }
</span>
</div>
}
</div>
<div class="mobile-card-footer">
<a href="@detailUrl" class="btn btn-sm @(isBill ? "btn-outline-primary" : "btn-outline-secondary")"
onclick="event.stopPropagation()">
<i class="bi bi-eye me-1"></i>View
</a>
</div>
</div>
}
</div>
</div>
</div>
</div> </div>
} }
else else