shoc-backend/SeaHaven.Services/Helpers/NotificationFeedOrdering.cs
Alexandre Brandizzi da0b29f769 feat(notifications): serve the Notification Center feed grouped by reason
Adds GET /api/notifications, a per-user read model derived from live
work-order state: Unassigned (grouped, High), No Vendor and Aveta Missing
(per work order, Medium) and Vendor Conflict, account-scoped from claims
and ordered by section severity with a fixed reason tie-break.
2026-09-18 12:40:37 -03:00

57 lines
2.3 KiB
C#

using SeaHaven.Services.DTOs;
namespace SeaHaven.Services.Helpers
{
public static class NotificationFeedOrdering
{
/// <summary>
/// Drops empty sections, orders items by severity then recency, and orders sections by
/// their highest severity with the fixed reason order breaking ties.
/// </summary>
public static IReadOnlyList<NotificationSectionDto> Order(
IEnumerable<(string Reason, int Count, IReadOnlyList<NotificationItemDto> Items)> sections)
{
return sections
.Where(section => section.Items.Count > 0)
.Select(section =>
{
var items = section.Items
.OrderByDescending(item => NotificationSeverities.Rank(item.Severity))
.ThenByDescending(item => item.TriggeredAt)
.ThenBy(item => item.Id, StringComparer.Ordinal)
.ToList();
return new NotificationSectionDto
{
Reason = section.Reason,
Label = NotificationReasons.Labels[section.Reason],
Severity = items[0].Severity,
Count = section.Count,
Items = items
};
})
.OrderByDescending(section => NotificationSeverities.Rank(section.Severity))
.ThenBy(section => ReasonIndex(section.Reason))
.ToList();
}
private static int ReasonIndex(string reason)
{
for (var index = 0; index < NotificationReasons.Order.Count; index++)
{
if (NotificationReasons.Order[index] == reason)
return index;
}
return NotificationReasons.Order.Count;
}
}
public static class NotificationBusinessTime
{
/// <summary>Business-calendar date of <paramref name="utcNow"/> in the dashboard's time zone.</summary>
public static DateOnly Today(DateTime utcNow)
{
var timezone = TimeZoneInfo.FindSystemTimeZoneById(DashboardBusinessTime.TimeZoneId);
return DateOnly.FromDateTime(TimeZoneInfo.ConvertTimeFromUtc(utcNow, timezone));
}
}
}