Add progress overlay to AI Catalog Price Check

Shows a modal overlay with animated progress bar and batch-aware status messages
while Claude is analyzing. Progress animates in two phases: ease-out to ~85%
over the estimated duration, then a slow crawl to 99% so it never falsely
"completes" before the server responds.

- Overlay driven by CSS (hidden until .active added by JS)
- Item count passed from controller as data-item-count on the run button
- Batch count derived from item count (batches of 25) to show accurate
  "Analyzing batch N of M…" messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 19:27:08 -04:00
parent 360edace72
commit 9943c11571
3 changed files with 132 additions and 3 deletions
@@ -938,6 +938,9 @@ namespace PowderCoating.Web.Controllers
r => r.CompanyId == currentUser.CompanyId);
var report = existing.OrderByDescending(r => r.RunAt).FirstOrDefault();
var activeItems = await _unitOfWork.CatalogItems.FindAsync(ci => ci.IsActive);
ViewBag.ActiveItemCount = activeItems.Count();
CatalogPriceCheckReportDto? dto = null;
if (report != null)
{
@@ -35,16 +35,69 @@
.summary-stat .num { font-size: 2rem; font-weight: 700; line-height: 1; }
.summary-stat .lbl { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; opacity: 0.7; }
.run-btn-wrap { min-height: 3rem; }
/* Progress overlay */
#price-check-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(15, 23, 42, 0.55);
z-index: 1050;
align-items: center;
justify-content: center;
}
#price-check-overlay.active { display: flex; }
.progress-card {
background: #fff;
border-radius: 1rem;
padding: 2.5rem 2rem;
width: 100%;
max-width: 440px;
text-align: center;
box-shadow: 0 20px 60px rgba(0,0,0,0.25);
}
.progress-card .icon { font-size: 3rem; color: #4f46e5; margin-bottom: 1rem; }
.progress-card h5 { font-weight: 700; margin-bottom: 0.25rem; }
.progress-card .status-msg { font-size: 0.9rem; color: #64748b; min-height: 1.4em; margin-bottom: 1.25rem; }
.progress-bar-track {
height: 8px;
background: #e2e8f0;
border-radius: 99px;
overflow: hidden;
margin-bottom: 0.75rem;
}
.progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, #4f46e5, #7c3aed);
border-radius: 99px;
width: 0%;
transition: width 0.6s ease;
}
.progress-card .pct-label { font-size: 0.8rem; color: #94a3b8; }
</style>
}
<!-- Progress overlay (shown while AI is running) -->
<div id="price-check-overlay">
<div class="progress-card">
<div class="icon"><i class="bi bi-robot"></i></div>
<h5>Analyzing your catalog</h5>
<p class="status-msg" id="overlay-status">Preparing items…</p>
<div class="progress-bar-track">
<div class="progress-bar-fill" id="overlay-bar"></div>
</div>
<div class="pct-label"><span id="overlay-pct">0</span>% complete</div>
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-4">
<a asp-action="Index" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left me-1"></i> Back to Catalog
</a>
<form asp-action="RunAiPriceCheck" method="post" id="runForm" class="run-btn-wrap">
@Html.AntiForgeryToken()
<button type="submit" class="btn btn-primary" id="runBtn">
<button type="submit" class="btn btn-primary" id="runBtn"
data-item-count="@(ViewBag.ActiveItemCount ?? 0)">
<i class="bi bi-robot me-2"></i>
@(Model == null ? "Run Price Check" : "Re-run Price Check")
</button>