Complete mobile card view coverage for all remaining pages

- CSS fix: change blanket .table-responsive hide to only trigger when
  a .mobile-card-view sibling exists (.mobile-card-view ~ .table-responsive
  and :has() rule) — auto-fixes 60+ forms/reports/detail/help pages that
  were showing blank on mobile by making their tables scroll instead
- Add mobile card views to remaining list pages:
  JobsPriority (overdue jobs, main board, maintenance sections)
  NotificationLogs (email/SMS log entries)
  AiUsageReport (per-company AI usage breakdown)
  GiftCertificates/BulkResult (batch certificate list)
  Inventory/SamplePanels (Need to Order + On Wall tabs)
  BannedIps (active bans + lifted/expired bans)
  OnboardingProgress (per-company activation funnel)
  ReleaseNotes/Manage (versioned changelog entries)
  StorageMigration/Results (file migration status list)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-14 23:31:38 -04:00
parent f467862877
commit cf6acc125f
10 changed files with 780 additions and 2 deletions
@@ -126,6 +126,77 @@
}
else
{
<div class="mobile-card-view">
<div class="mobile-card-list">
@{ lastMfr = null; }
@foreach (var item in needOrder)
{
if (string.IsNullOrWhiteSpace(selectedMfr) && item.Manufacturer != lastMfr)
{
lastMfr = item.Manufacturer;
<div class="text-uppercase fw-semibold text-muted small px-2 py-1 border-bottom mt-2">
@(string.IsNullOrWhiteSpace(item.Manufacturer) ? "No Manufacturer" : item.Manufacturer)
</div>
}
<div class="mobile-data-card">
<div class="mobile-card-header">
@if (!string.IsNullOrWhiteSpace(item.ColorCode))
{
<div class="mobile-card-icon" style="background: @(item.ColorCode.StartsWith("#") ? item.ColorCode : "#" + item.ColorCode); border: 1px solid var(--bs-border-color);"></div>
}
else
{
<div class="mobile-card-icon" style="background: linear-gradient(135deg, #64748b 0%, #475569 100%);">
<i class="bi bi-palette"></i>
</div>
}
<div class="mobile-card-title">
<h6>@(item.ColorName ?? item.Name)</h6>
<small>@(item.Manufacturer ?? "No Manufacturer")</small>
</div>
</div>
<div class="mobile-card-body">
@if (!string.IsNullOrWhiteSpace(item.ManufacturerPartNumber))
{
<div class="mobile-card-row">
<span class="mobile-card-label">Part #</span>
<span class="mobile-card-value text-muted">@item.ManufacturerPartNumber</span>
</div>
}
@if (!string.IsNullOrWhiteSpace(item.Finish))
{
<div class="mobile-card-row">
<span class="mobile-card-label">Finish</span>
<span class="mobile-card-value">@item.Finish</span>
</div>
}
<div class="mobile-card-row">
<span class="mobile-card-label">In Stock</span>
<span class="mobile-card-value">
@if (item.QuantityOnHand > 0)
{
<span class="badge bg-success bg-opacity-10 text-success">@item.QuantityOnHand.ToString("N2") @item.UnitOfMeasure</span>
}
else
{
<span class="text-muted">None</span>
}
</span>
</div>
</div>
<div class="mobile-card-footer">
<button class="btn btn-sm btn-outline-success btn-toggle-panel"
data-item-id="@item.Id" data-has-panel="true">
<i class="bi bi-check-lg me-1"></i>Got It
</button>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-eye"></i>
</a>
</div>
</div>
}
</div>
</div>
<div class="table-responsive">
<table class="table table-hover mb-0" id="needTable">
<thead class="table-group-divider">
@@ -220,6 +291,68 @@
}
else
{
<div class="mobile-card-view">
<div class="mobile-card-list">
@{ lastMfr = null; }
@foreach (var item in onHand)
{
if (string.IsNullOrWhiteSpace(selectedMfr) && item.Manufacturer != lastMfr)
{
lastMfr = item.Manufacturer;
<div class="text-uppercase fw-semibold text-muted small px-2 py-1 border-bottom mt-2">
@(string.IsNullOrWhiteSpace(item.Manufacturer) ? "No Manufacturer" : item.Manufacturer)
</div>
}
<div class="mobile-data-card">
<div class="mobile-card-header">
@if (!string.IsNullOrWhiteSpace(item.ColorCode))
{
<div class="mobile-card-icon" style="background: @(item.ColorCode.StartsWith("#") ? item.ColorCode : "#" + item.ColorCode); border: 1px solid var(--bs-border-color);"></div>
}
else
{
<div class="mobile-card-icon" style="background: linear-gradient(135deg, #059669 0%, #047857 100%);">
<i class="bi bi-palette"></i>
</div>
}
<div class="mobile-card-title">
<h6>@(item.ColorName ?? item.Name)</h6>
<small>@(item.Manufacturer ?? "No Manufacturer")</small>
</div>
</div>
<div class="mobile-card-body">
@if (!string.IsNullOrWhiteSpace(item.ManufacturerPartNumber))
{
<div class="mobile-card-row">
<span class="mobile-card-label">Part #</span>
<span class="mobile-card-value text-muted">@item.ManufacturerPartNumber</span>
</div>
}
@if (!string.IsNullOrWhiteSpace(item.Finish))
{
<div class="mobile-card-row">
<span class="mobile-card-label">Finish</span>
<span class="mobile-card-value">@item.Finish</span>
</div>
}
<div class="mobile-card-row">
<span class="mobile-card-label">Status</span>
<span class="mobile-card-value"><span class="badge bg-success"><i class="bi bi-check-circle me-1"></i>On Wall</span></span>
</div>
</div>
<div class="mobile-card-footer">
<button class="btn btn-sm btn-outline-danger btn-toggle-panel"
data-item-id="@item.Id" data-has-panel="false">
<i class="bi bi-x-lg me-1"></i>Remove
</button>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-eye"></i>
</a>
</div>
</div>
}
</div>
</div>
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead class="table-group-divider">