using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewFeatures; using PowderCoating.Core.Entities; using PowderCoating.Core.Enums; namespace PowderCoating.Web.Helpers { /// /// Extension methods on for storing toast /// notification messages that survive a POST→redirect→GET cycle. /// /// TempData is used (rather than ViewBag or ViewData) because toast messages /// must survive an HTTP redirect: a controller sets the message before calling /// RedirectToAction, and the layout reads and renders it on the next GET. /// TempData is session-backed and automatically cleared after it is read. /// /// /// The four well-known string keys (Success, Error, Warning, /// Info) match the JavaScript toast-renderer in _Layout.cshtml; /// changing them here requires a matching update in the layout script. /// /// public static class ToastHelper { /// TempData key read by the layout to render a green success toast. private const string SuccessKey = "Success"; /// TempData key read by the layout to render a red error toast. private const string ErrorKey = "Error"; /// TempData key read by the layout to render a yellow warning toast. private const string WarningKey = "Warning"; /// TempData key read by the layout to render a yellow warning toast that does not auto-dismiss. private const string WarningPermanentKey = "WarningPermanent"; /// TempData key read by the layout to render a blue info toast. private const string InfoKey = "Info"; /// /// Stores a success (green) toast message in TempData for display on the /// next page render after a redirect. /// /// The TempData dictionary for the current request. /// The human-readable success message. public static void Success(this ITempDataDictionary tempData, string message) { tempData[SuccessKey] = message; } /// /// Stores an error (red) toast message in TempData for display on the /// next page render after a redirect. /// /// The TempData dictionary for the current request. /// The human-readable error message. public static void Error(this ITempDataDictionary tempData, string message) { tempData[ErrorKey] = message; } /// /// Stores a warning (yellow) toast message in TempData for display on the /// next page render after a redirect. /// /// The TempData dictionary for the current request. /// The human-readable warning message. public static void Warning(this ITempDataDictionary tempData, string message) { tempData[WarningKey] = message; } /// /// 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. /// public static void WarningPermanent(this ITempDataDictionary tempData, string message) { tempData[WarningPermanentKey] = message; } /// /// Stores an informational (blue) toast message in TempData for display on /// the next page render after a redirect. /// /// The TempData dictionary for the current request. /// The human-readable informational message. public static void Info(this ITempDataDictionary tempData, string message) { tempData[InfoKey] = message; } } /// /// Convenience extension methods on that delegate to /// via the controller's own TempData. /// /// These shorten controller code from TempData.Success("…") to the /// more readable this.ToastSuccess("…"), which reads closer to /// natural language and is consistent with other MVC helper conventions. /// /// public static class ControllerToastExtensions { /// /// Stores a success (green) toast in the controller's TempData. /// Convenience wrapper around . /// /// The calling MVC controller. /// The success message to display after redirect. public static void ToastSuccess(this Controller controller, string message) { controller.TempData.Success(message); } /// /// Stores an error (red) toast in the controller's TempData. /// Convenience wrapper around . /// /// The calling MVC controller. /// The error message to display after redirect. public static void ToastError(this Controller controller, string message) { controller.TempData.Error(message); } /// /// Stores a warning (yellow) toast in the controller's TempData. /// Convenience wrapper around . /// /// The calling MVC controller. /// The warning message to display after redirect. public static void ToastWarning(this Controller controller, string message) { controller.TempData.Warning(message); } /// /// 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. /// public static void ToastWarningPermanent(this Controller controller, string message) { controller.TempData.WarningPermanent(message); } /// /// Stores an informational (blue) toast in the controller's TempData. /// Convenience wrapper around . /// /// The calling MVC controller. /// The informational message to display after redirect. public static void ToastInfo(this Controller controller, string message) { controller.TempData.Info(message); } /// /// Translates a outcome into the appropriate /// toast severity and message. /// /// Sent notifications use Info (not Success) because the notification is a /// side effect of the main action — the main action already gets a Success /// toast. Skipped and Failed outcomes are Warning (not Error) because the /// primary operation succeeded even if the notification did not. /// /// /// The calling MVC controller. /// /// The most recent record, or null /// if no notification was attempted (in which case this method is a no-op). /// public static void SetNotificationResultToast(this Controller controller, NotificationLog? log) { if (log == null) return; var channel = log.Channel == NotificationChannel.Sms ? "SMS" : "Email"; switch (log.Status) { case NotificationStatus.Sent: controller.ToastInfo($"{channel} sent to {log.RecipientName} ({log.Recipient})."); break; case NotificationStatus.Skipped: controller.ToastWarning(!string.IsNullOrEmpty(log.Message) ? $"{channel} skipped: {log.Message}" : $"{channel} notification was skipped."); break; case NotificationStatus.Failed: controller.ToastWarningPermanent(!string.IsNullOrEmpty(log.ErrorMessage) ? $"{channel} delivery failed: {log.ErrorMessage}" : $"{channel} notification failed."); break; } } } }