Add PWA manifest, fix AI multi-coat pricing, and improve catalog lookup

- PWA: manifest.json + minimal service worker so iOS/Android persist camera
  permission after "Add to Home Screen"; theme-color and apple meta tags in layout
- PWA icons: 192x192 and 512x512 from transparent PCL logo; updated pcl-logo.png
- AI pricing: apply AdditionalCoatLaborPercent per extra coat on AI items,
  matching the calculated-item path (was ignoring extra coats entirely)
- AI wizard: live price recalc when coats are added/removed; session-expiry
  errors now show a clear "refresh and sign in" message instead of raw HTTP status;
  smooth-scroll to follow-up/results sections on AI response
- Catalog lookup: exclude SKUs already in company inventory from results;
  pass currentId on edit so own entry still appears; vendor-scoped search
  with cross-vendor fallback; result count shown in multi-match modal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-04 08:58:10 -04:00
parent 7de65910e3
commit 50b1794799
16 changed files with 158 additions and 26 deletions
@@ -3393,7 +3393,6 @@ public class QuotesController : Controller
/// Returns a tempId that the JS wizard tracks and submits as AiPhotoTempIds[] on form submit.
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
[EnableRateLimiting(AppConstants.RateLimitPolicies.Ai)]
public async Task<IActionResult> UploadAiPhoto(IFormFile? file)
{
@@ -3431,7 +3430,6 @@ public class QuotesController : Controller
/// so the model's estimates are calibrated to this company's pricing and material usage patterns.
/// </summary>
[HttpPost]
[ValidateAntiForgeryToken]
[EnableRateLimiting(AppConstants.RateLimitPolicies.Ai)]
public async Task<IActionResult> AiAnalyzeItem([FromBody] AiAnalyzeItemRequest request)
{
@@ -3604,6 +3602,11 @@ public class QuotesController : Controller
var complexityCharge = subtotal * complexityPct;
subtotal += complexityCharge;
// Additional coat charge — each coat beyond the first adds AdditionalCoatLaborPercent%,
// matching the formula in PricingCalculationService.CalculateQuoteItemPriceAsync.
if (request.CoatCount > 1)
subtotal += subtotal * (request.CoatCount - 1) * (costs.AdditionalCoatLaborPercent / 100m);
if (subtotal < costs.ShopMinimumCharge && costs.ShopMinimumCharge > 0)
subtotal = costs.ShopMinimumCharge;