refactor: hoist Moscow offset + sport labels into shared helpers (HIGH)

* New Marathon.Domain.ValueObjects.MoscowTime with Offset, Now, and
  EndOfMoscowDay(DateOnly) — replaces ~15 inline TimeSpan.FromHours(3)
  literals across Domain/Application/Infrastructure/UI.
* New Marathon.UI.Services.SportLabels.Resolve(IStringLocalizer, int) —
  replaces 6 near-identical SportLabel switch bodies in EventListShell,
  Events/Detail, Anomalies/AnomalyFeed, Results/ResultsList,
  Results/ResultsLoader, and AnomalyCard. Single source of truth for the
  6/11/22723/43658 sport-code mapping. Pages keep a one-liner wrapper so
  the call sites stay terse.
This commit is contained in:
2026-05-09 15:40:35 +03:00
parent d1e6ce7ce2
commit fed3a09695
18 changed files with 92 additions and 96 deletions
@@ -252,8 +252,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
var moscow = TimeSpan.FromHours(3);
await UpdateFilter(_filter with { From = new DateTimeOffset(v.Date, moscow) });
await UpdateFilter(_filter with { From = new DateTimeOffset(v.Date, MoscowTime.Offset) });
}
}
@@ -261,8 +260,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
var moscow = TimeSpan.FromHours(3);
await UpdateFilter(_filter with { To = new DateTimeOffset(v.Date, moscow).AddDays(1).AddSeconds(-1) });
await UpdateFilter(_filter with { To = MoscowTime.EndOfMoscowDay(DateOnly.FromDateTime(v.Date)) });
}
}
@@ -283,14 +281,7 @@
_ => L["Anomaly.Severity.Low"],
};
private string SportLabel(int code) => code switch
{
6 => L["Sport.Basketball"],
11 => L["Sport.Football"],
22723 => L["Sport.Tennis"],
43658 => L["Sport.Hockey"],
_ => string.Format(System.Globalization.CultureInfo.InvariantCulture, "Sport {0}", code),
};
private string SportLabel(int code) => SportLabels.Resolve(L, code);
private static string FormatDate(DateTimeOffset? value)
=> value?.ToString("yyyy-MM-dd") ?? string.Empty;
+1 -8
View File
@@ -306,14 +306,7 @@
_ => "—",
};
private string SportLabel(int code) => code switch
{
6 => L["Sport.Basketball"],
11 => L["Sport.Football"],
22723 => L["Sport.Tennis"],
43658 => L["Sport.Hockey"],
_ => $"Sport {code}",
};
private string SportLabel(int code) => SportLabels.Resolve(L, code);
private string BetTypeLabel(BetType t) => t switch
{
@@ -164,8 +164,6 @@
</style>
@code {
private static readonly TimeSpan MoscowOffset = TimeSpan.FromHours(3);
private DateTimeOffset _from;
private DateTimeOffset _to;
private string _searchInput = string.Empty;
@@ -181,7 +179,7 @@
protected override async Task OnInitializedAsync()
{
var todayMoscow = new DateTimeOffset(DateTime.UtcNow.Date, TimeSpan.Zero).ToOffset(MoscowOffset);
var todayMoscow = new DateTimeOffset(DateTime.UtcNow.Date, TimeSpan.Zero).ToOffset(MoscowTime.Offset);
_from = todayMoscow.AddDays(-30);
_to = todayMoscow.AddDays(1).AddSeconds(-1);
@@ -246,7 +244,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
_from = new DateTimeOffset(v.Date, MoscowOffset);
_from = new DateTimeOffset(v.Date, MoscowTime.Offset);
await LoadAsync();
}
}
@@ -255,7 +253,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
_to = new DateTimeOffset(v.Date, MoscowOffset).AddDays(1).AddSeconds(-1);
_to = new DateTimeOffset(v.Date, MoscowTime.Offset).AddDays(1).AddSeconds(-1);
await LoadAsync();
}
}
@@ -311,14 +309,7 @@
_ => "draw",
};
private string SportLabel(int code) => code switch
{
6 => L["Sport.Basketball"],
11 => L["Sport.Football"],
22723 => L["Sport.Tennis"],
43658 => L["Sport.Hockey"],
_ => $"Sport {code}",
};
private string SportLabel(int code) => SportLabels.Resolve(L, code);
public void Dispose()
{
@@ -204,8 +204,6 @@
</style>
@code {
private static readonly TimeSpan MoscowOffset = TimeSpan.FromHours(3);
private DateTimeOffset _from;
private DateTimeOffset _to;
private LoaderMode _mode = LoaderMode.AllInRange;
@@ -234,7 +232,7 @@
protected override async Task OnInitializedAsync()
{
var todayMoscow = new DateTimeOffset(DateTime.UtcNow.Date, TimeSpan.Zero).ToOffset(MoscowOffset);
var todayMoscow = new DateTimeOffset(DateTime.UtcNow.Date, TimeSpan.Zero).ToOffset(MoscowTime.Offset);
_from = todayMoscow.AddDays(-7);
_to = todayMoscow.AddDays(1).AddSeconds(-1);
await ReloadCandidatesAsync();
@@ -347,7 +345,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
_from = new DateTimeOffset(v.Date, MoscowOffset);
_from = new DateTimeOffset(v.Date, MoscowTime.Offset);
await ReloadCandidatesAsync();
}
}
@@ -356,7 +354,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
_to = new DateTimeOffset(v.Date, MoscowOffset).AddDays(1).AddSeconds(-1);
_to = new DateTimeOffset(v.Date, MoscowTime.Offset).AddDays(1).AddSeconds(-1);
await ReloadCandidatesAsync();
}
}
@@ -400,14 +398,7 @@
_ => o.ToString(),
};
private string SportLabel(int code) => code switch
{
6 => L["Sport.Basketball"],
11 => L["Sport.Football"],
22723 => L["Sport.Tennis"],
43658 => L["Sport.Hockey"],
_ => $"Sport {code}",
};
private string SportLabel(int code) => SportLabels.Resolve(L, code);
private static string FormatDate(DateTimeOffset value) => value.ToString("yyyy-MM-dd");
@@ -437,8 +437,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
var moscow = TimeSpan.FromHours(3);
await UpdateFilter(_filter with { From = new DateTimeOffset(v.Date, moscow) });
await UpdateFilter(_filter with { From = new DateTimeOffset(v.Date, MoscowTime.Offset) });
}
}
@@ -446,8 +445,7 @@
{
if (DateTimeOffset.TryParse(e.Value?.ToString(), out var v))
{
var moscow = TimeSpan.FromHours(3);
await UpdateFilter(_filter with { To = new DateTimeOffset(v.Date, moscow).AddDays(1).AddSeconds(-1) });
await UpdateFilter(_filter with { To = MoscowTime.EndOfMoscowDay(DateOnly.FromDateTime(v.Date)) });
}
}
@@ -519,14 +517,7 @@
private static string FormatDate(DateTimeOffset value)
=> value.ToString("yyyy-MM-dd");
private string SportLabel(int code) => code switch
{
6 => L["Sport.Basketball"],
11 => L["Sport.Football"],
22723 => L["Sport.Tennis"],
43658 => L["Sport.Hockey"],
_ => $"Sport {code}",
};
private string SportLabel(int code) => SportLabels.Resolve(L, code);
private readonly record struct RatesSnap(decimal? Win1, decimal? Draw, decimal? Win2);