Add WarningPermanent toast type and upgrade invoice failure notifications
Email delivery failures and PDF generation errors now show a permanent warning/error toast that requires manual dismissal, so users cannot accidentally miss critical action-blocking feedback. - ToastHelper: WarningPermanent TempData key + Warning/WarningPermanent extension methods on both ITempDataDictionary and Controller - SetNotificationResultToast: NotificationStatus.Failed now uses ToastWarningPermanent (previously auto-dismissed in 5 s) - InvoicesController.Send: TempData["Warning"] → TempData["WarningPermanent"] when PDF generation or email dispatch fails - InvoicesController.DownloadPdf: TempData["Error"] → TempData["ErrorPermanent"] with the actual exception message so root cause is visible - _Layout.cshtml: WarningPermanent hidden div - toast-notifications.js: WarningPermanent handler (timeOut: 0) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -917,7 +917,7 @@ public class InvoicesController : Controller
|
|||||||
|
|
||||||
TempData["Success"] = $"Invoice {invoice.InvoiceNumber} marked as sent.";
|
TempData["Success"] = $"Invoice {invoice.InvoiceNumber} marked as sent.";
|
||||||
if (!pdfAndNotifSucceeded)
|
if (!pdfAndNotifSucceeded)
|
||||||
TempData["Warning"] = "The invoice is marked as sent, but PDF generation or the customer email failed. Check the notification logs or your email configuration.";
|
TempData["WarningPermanent"] = "The invoice is marked as sent, but PDF generation or the customer email failed. Check the notification logs or your email configuration.";
|
||||||
return RedirectToAction(nameof(Details), new { id });
|
return RedirectToAction(nameof(Details), new { id });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -1302,8 +1302,8 @@ public class InvoicesController : Controller
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error generating PDF for invoice {Id}", id);
|
_logger.LogError(ex, "Error generating PDF for invoice {Id}. Inner: {Inner}", id, ex.InnerException?.Message ?? ex.Message);
|
||||||
TempData["Error"] = "An error occurred while generating the PDF.";
|
TempData["ErrorPermanent"] = $"PDF generation failed: {ex.Message}";
|
||||||
return RedirectToAction(nameof(Details), new { id });
|
return RedirectToAction(nameof(Details), new { id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ namespace PowderCoating.Web.Helpers
|
|||||||
/// <summary>TempData key read by the layout to render a yellow warning toast.</summary>
|
/// <summary>TempData key read by the layout to render a yellow warning toast.</summary>
|
||||||
private const string WarningKey = "Warning";
|
private const string WarningKey = "Warning";
|
||||||
|
|
||||||
|
/// <summary>TempData key read by the layout to render a yellow warning toast that does not auto-dismiss.</summary>
|
||||||
|
private const string WarningPermanentKey = "WarningPermanent";
|
||||||
|
|
||||||
/// <summary>TempData key read by the layout to render a blue info toast.</summary>
|
/// <summary>TempData key read by the layout to render a blue info toast.</summary>
|
||||||
private const string InfoKey = "Info";
|
private const string InfoKey = "Info";
|
||||||
|
|
||||||
@@ -67,6 +70,15 @@ namespace PowderCoating.Web.Helpers
|
|||||||
tempData[WarningKey] = message;
|
tempData[WarningKey] = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores a warning (yellow) toast that requires manual dismissal (no auto-timeout).
|
||||||
|
/// Use for critical warnings the user must not miss, such as email delivery failures.
|
||||||
|
/// </summary>
|
||||||
|
public static void WarningPermanent(this ITempDataDictionary tempData, string message)
|
||||||
|
{
|
||||||
|
tempData[WarningPermanentKey] = message;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores an informational (blue) toast message in TempData for display on
|
/// Stores an informational (blue) toast message in TempData for display on
|
||||||
/// the next page render after a redirect.
|
/// the next page render after a redirect.
|
||||||
@@ -123,6 +135,15 @@ namespace PowderCoating.Web.Helpers
|
|||||||
controller.TempData.Warning(message);
|
controller.TempData.Warning(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores a permanent warning (yellow, no auto-dismiss) in the controller's TempData.
|
||||||
|
/// Use for failures the user must not miss — email delivery errors, PDF generation failures.
|
||||||
|
/// </summary>
|
||||||
|
public static void ToastWarningPermanent(this Controller controller, string message)
|
||||||
|
{
|
||||||
|
controller.TempData.WarningPermanent(message);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores an informational (blue) toast in the controller's TempData.
|
/// Stores an informational (blue) toast in the controller's TempData.
|
||||||
/// Convenience wrapper around <see cref="ToastHelper.Info"/>.
|
/// Convenience wrapper around <see cref="ToastHelper.Info"/>.
|
||||||
@@ -165,7 +186,7 @@ namespace PowderCoating.Web.Helpers
|
|||||||
: $"{channel} notification was skipped.");
|
: $"{channel} notification was skipped.");
|
||||||
break;
|
break;
|
||||||
case NotificationStatus.Failed:
|
case NotificationStatus.Failed:
|
||||||
controller.ToastWarning(!string.IsNullOrEmpty(log.ErrorMessage)
|
controller.ToastWarningPermanent(!string.IsNullOrEmpty(log.ErrorMessage)
|
||||||
? $"{channel} delivery failed: {log.ErrorMessage}"
|
? $"{channel} delivery failed: {log.ErrorMessage}"
|
||||||
: $"{channel} notification failed.");
|
: $"{channel} notification failed.");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -890,6 +890,10 @@
|
|||||||
{
|
{
|
||||||
<div id="tempdata-warning-message" style="display:none;">@TempData["Warning"]</div>
|
<div id="tempdata-warning-message" style="display:none;">@TempData["Warning"]</div>
|
||||||
}
|
}
|
||||||
|
@if (TempData["WarningPermanent"] != null)
|
||||||
|
{
|
||||||
|
<div id="tempdata-warning-permanent-message" style="display:none;">@TempData["WarningPermanent"]</div>
|
||||||
|
}
|
||||||
@if (TempData["Info"] != null)
|
@if (TempData["Info"] != null)
|
||||||
{
|
{
|
||||||
<div id="tempdata-info-message" style="display:none;">@TempData["Info"]</div>
|
<div id="tempdata-info-message" style="display:none;">@TempData["Info"]</div>
|
||||||
|
|||||||
@@ -118,6 +118,12 @@ function displayTempDataMessages() {
|
|||||||
showWarning(warningMsg.textContent.trim());
|
showWarning(warningMsg.textContent.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Permanent warning — no auto-dismiss
|
||||||
|
const warningPerm = document.getElementById('tempdata-warning-permanent-message');
|
||||||
|
if (warningPerm && warningPerm.textContent.trim()) {
|
||||||
|
toastr.warning(warningPerm.textContent.trim(), 'Warning', { timeOut: 0, extendedTimeOut: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
// Info message
|
// Info message
|
||||||
const infoMsg = document.getElementById('tempdata-info-message');
|
const infoMsg = document.getElementById('tempdata-info-message');
|
||||||
if (infoMsg && infoMsg.textContent.trim()) {
|
if (infoMsg && infoMsg.textContent.trim()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user