Skip to content

Commit 1072218

Browse files
Remove moment.js and related locale files; add portal date utilities for locale-aware date formatting
1 parent 39ab3d0 commit 1072218

361 files changed

Lines changed: 449 additions & 122944 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/XtremeIdiots.Portal.Web/ApiControllers/AdminActionsController.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,16 @@ public async Task<IActionResult> GetAdminActionsAjax(CancellationToken cancellat
105105
data = items.Select(a => new
106106
{
107107
adminActionId = a.AdminActionId,
108-
created = a.Created.ToString("yyyy-MM-dd HH:mm"),
108+
created = DateTime.SpecifyKind(a.Created, DateTimeKind.Utc).ToString("o"),
109109
gameType = a.Player?.GameType.ToString(),
110110
type = a.Type.ToString(),
111111
player = a.Player?.Username,
112112
playerId = a.PlayerId,
113113
guid = a.Player?.Guid,
114114
admin = a.UserProfile?.DisplayName ?? "Unclaimed",
115-
expires = a.Expires?.ToString("yyyy-MM-dd HH:mm") ?? (a.Type == AdminActionType.Ban ? "Never" : string.Empty)
115+
expiresUtc = a.Expires.HasValue ? DateTime.SpecifyKind(a.Expires.Value, DateTimeKind.Utc).ToString("o") : null,
116+
isPermanent = !a.Expires.HasValue && a.Type == AdminActionType.Ban,
117+
isExpired = a.Expires.HasValue && a.Expires.Value <= DateTime.UtcNow
116118
})
117119
});
118120
}, nameof(GetAdminActionsAjax)).ConfigureAwait(false);
@@ -185,14 +187,16 @@ public async Task<IActionResult> GetUnclaimedAdminActionsAjax(CancellationToken
185187
responseItems.Add(new
186188
{
187189
adminActionId = a.AdminActionId,
188-
created = a.Created.ToString("yyyy-MM-dd HH:mm"),
190+
created = DateTime.SpecifyKind(a.Created, DateTimeKind.Utc).ToString("o"),
189191
gameType = a.Player?.GameType.ToString(),
190192
type = a.Type.ToString(),
191193
player = a.Player?.Username,
192194
playerId = a.PlayerId,
193195
guid = a.Player?.Guid,
194196
admin = a.UserProfile?.DisplayName ?? "Unclaimed",
195-
expires = a.Expires?.ToString("yyyy-MM-dd HH:mm") ?? (a.Type == AdminActionType.Ban ? "Never" : string.Empty),
197+
expiresUtc = a.Expires.HasValue ? DateTime.SpecifyKind(a.Expires.Value, DateTimeKind.Utc).ToString("o") : null,
198+
isPermanent = !a.Expires.HasValue && a.Type == AdminActionType.Ban,
199+
isExpired = a.Expires.HasValue && a.Expires.Value <= DateTime.UtcNow,
196200
canClaim
197201
});
198202
}
@@ -292,13 +296,15 @@ public async Task<IActionResult> GetMyAdminActionsAjax(CancellationToken cancell
292296
recordsFiltered = apiResponse.Result.Pagination?.FilteredCount,
293297
data = items.Select(a => new
294298
{
295-
created = a.Created.ToString("yyyy-MM-dd HH:mm"),
299+
created = DateTime.SpecifyKind(a.Created, DateTimeKind.Utc).ToString("o"),
296300
gameType = a.Player?.GameType.ToString(),
297301
type = a.Type.ToString(),
298302
player = a.Player?.Username,
299303
playerId = a.PlayerId,
300304
guid = a.Player?.Guid,
301-
expires = a.Expires?.ToString("yyyy-MM-dd HH:mm") ?? (a.Type == AdminActionType.Ban ? "Never" : string.Empty),
305+
expiresUtc = a.Expires.HasValue ? DateTime.SpecifyKind(a.Expires.Value, DateTimeKind.Utc).ToString("o") : null,
306+
isPermanent = !a.Expires.HasValue && a.Type == AdminActionType.Ban,
307+
isExpired = a.Expires.HasValue && a.Expires.Value <= DateTime.UtcNow,
302308
id = a.AdminActionId,
303309
text = a.Text
304310
})

src/XtremeIdiots.Portal.Web/ApiControllers/ExternalNotificationsController.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ private async Task<object> BuildPublicFeedAsync(int take, CancellationToken canc
193193
publicNotifications.Add(new
194194
{
195195
type = "admin-action",
196+
actionType = action.Type.ToString(),
197+
gameType = action.Player?.GameType.ToString(),
196198
title = $"{action.UserProfile?.DisplayName ?? "Admin"} {actionText} {action.Player?.Username}",
197199
message = $"{action.Type} on {action.Player?.GameType}",
198200
iconUrl = $"{portalBaseUrl}/images/game-icons/{action.Player?.GameType}.png",

src/XtremeIdiots.Portal.Web/ApiControllers/MapsController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public async Task<IActionResult> GetMapVotesAjax(CancellationToken cancellationT
157157
playerId = v.PlayerId,
158158
serverName = v.GameServer?.Title,
159159
like = v.Like,
160-
timestamp = v.Timestamp.ToString("yyyy-MM-dd HH:mm")
160+
timestamp = DateTime.SpecifyKind(v.Timestamp, DateTimeKind.Utc).ToString("o")
161161
})
162162
});
163163
}, nameof(GetMapVotesAjax)).ConfigureAwait(false);

src/XtremeIdiots.Portal.Web/Controllers/ServerAdminController.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ public async Task<IActionResult> GetServerLiveChatLog(Guid id, Guid? lastMessage
10821082
.Select(m => new
10831083
{
10841084
chatMessageId = m.ChatMessageId,
1085-
timestamp = m.Timestamp.ToString("yyyy-MM-dd HH:mm"),
1085+
timestamp = DateTime.SpecifyKind(m.Timestamp, DateTimeKind.Utc).ToString("o"),
10861086
username = m.Username,
10871087
message = m.Message,
10881088
playerId = m.PlayerId,
@@ -1108,7 +1108,7 @@ public async Task<IActionResult> GetServerLiveChatLog(Guid id, Guid? lastMessage
11081108
{
11091109
messages,
11101110
count = messages.Count,
1111-
serverTime = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")
1111+
serverTime = DateTime.UtcNow.ToString("o")
11121112
});
11131113
}, nameof(GetServerLiveChatLog)).ConfigureAwait(false);
11141114
}
Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
using Microsoft.AspNetCore.Razor.TagHelpers;
2-
using System.Security.Claims;
3-
using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1;
42

53
namespace XtremeIdiots.Portal.Web.Helpers;
64

75
/// <summary>
8-
/// Renders an expiry date with Active / Expired badge inside a <span>.
9-
/// Usage: <expiry-badge expires-utc="@Model.Expires" user="@User" />
6+
/// Renders an expiry date with Active / Expired / Permanent badge inside a <span>.
7+
/// Expiry status is determined server-side (authoritative).
8+
/// Client-side JS re-formats the date portion in the user's locale.
9+
/// Usage: <expiry-badge expires-utc="@Model.Expires" />
1010
/// </summary>
1111
[HtmlTargetElement("expiry-badge")]
1212
public class ExpiryBadgeTagHelper : TagHelper
1313
{
1414
[HtmlAttributeName("expires-utc")] public DateTime? ExpiresUtc { get; set; }
15-
[HtmlAttributeName("user")] public ClaimsPrincipal? User { get; set; }
1615

1716
public override void Process(TagHelperContext context, TagHelperOutput output)
1817
{
1918
output.TagName = "span";
2019
output.TagMode = TagMode.StartTagAndEndTag;
20+
2121
if (ExpiresUtc is null)
2222
{
2323
output.Content.SetHtmlContent("<span title=\"No expiry\">Never</span>");
@@ -26,24 +26,16 @@ public override void Process(TagHelperContext context, TagHelperOutput output)
2626

2727
var now = DateTime.UtcNow;
2828
var expired = ExpiresUtc.Value <= now;
29-
var displayDate = ExpiresUtc.Value;
30-
// timezone via claim (same logic as existing helper)
31-
var tzClaim = User?.Claims.SingleOrDefault(c => c.Type == UserProfileClaimType.TimeZone);
32-
if (tzClaim is not null)
33-
{
34-
try
35-
{
36-
var tz = TimeZoneInfo.FindSystemTimeZoneById(tzClaim.Value);
37-
displayDate = TimeZoneInfo.ConvertTime(displayDate, tz);
38-
}
39-
catch { }
40-
}
29+
var utc = DateTime.SpecifyKind(ExpiresUtc.Value, DateTimeKind.Utc);
30+
var dateStr = utc.ToString("yyyy-MM-dd");
4131

42-
var dateStr = displayDate.ToString("D", System.Globalization.CultureInfo.CurrentUICulture);
4332
var badgeClass = expired ? "text-bg-danger" : "text-bg-success";
4433
var badgeText = expired ? "Expired" : "Active";
34+
var status = expired ? "expired" : "active";
4535
var title = expired ? $"Expired on {dateStr}" : $"Expires on {dateStr}";
46-
output.Attributes.SetAttribute("title", title);
47-
output.Content.SetHtmlContent($"{dateStr} <span class='badge {badgeClass} ms-1'>{badgeText}</span>");
36+
37+
output.Content.SetHtmlContent(
38+
$"<time datetime=\"{utc:o}\" data-dt=\"expiry\" data-dt-status=\"{status}\" title=\"{title}\">" +
39+
$"{dateStr} <span class=\"badge {badgeClass} ms-1\">{badgeText}</span></time>");
4840
}
4941
}

src/XtremeIdiots.Portal.Web/Helpers/TimeAgoTagHelper.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ namespace XtremeIdiots.Portal.Web.Helpers;
44

55
/// <summary>
66
/// Renders a <time> element with a relative "time ago" description and the absolute datetime in attributes.
7+
/// Client-side JS (portalDate.enhanceDateElements) re-formats in the user's locale and timezone.
78
/// Usage: <time time-ago utc="@Model.Created" show-absolute="true"></time>
89
/// </summary>
910
[HtmlTargetElement("time", Attributes = AttributeName)]
@@ -21,13 +22,18 @@ public class TimeAgoTagHelper : TagHelper
2122

2223
public override void Process(TagHelperContext context, TagHelperOutput output)
2324
{
24-
// Always render <time>
2525
output.TagName = "time";
2626
output.TagMode = TagMode.StartTagAndEndTag;
27-
output.Attributes.SetAttribute("datetime", Utc.ToString("o"));
28-
var rel = BuildRelative(Utc);
29-
var absolute = Utc.ToString("yyyy-MM-dd HH:mm");
27+
28+
var utc = DateTime.SpecifyKind(Utc, DateTimeKind.Utc);
29+
output.Attributes.SetAttribute("datetime", utc.ToString("o"));
30+
output.Attributes.SetAttribute("data-dt", "relative");
31+
32+
// Server-rendered fallback for noscript users
33+
var rel = BuildRelative(utc);
34+
var absolute = utc.ToString("yyyy-MM-dd HH:mm");
3035
output.Content.SetHtmlContent(ShowAbsolute ? $"{rel} ({absolute} UTC)" : rel);
36+
3137
output.Attributes.RemoveAll(AttributeName);
3238
output.Attributes.RemoveAll(UtcAttributeName);
3339
output.Attributes.RemoveAll(ShowAbsoluteAttributeName);
Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,33 @@
1-
using Microsoft.AspNetCore.Mvc.Rendering;
2-
using Microsoft.AspNetCore.Mvc.ViewFeatures;
31
using Microsoft.AspNetCore.Razor.TagHelpers;
4-
using System.Security.Claims;
5-
using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1;
62

73
namespace XtremeIdiots.Portal.Web.Helpers;
84

95
/// <summary>
10-
/// Renders a <time> element converted into the user's timezone based on the TimeZone claim.
11-
/// Usage: <time user-time utc="@model.Date" /> (user resolved from ViewContext)
6+
/// Renders a <time> element with a UTC datetime that client-side JS localizes.
7+
/// No server-side timezone conversion — the browser handles locale and timezone natively.
8+
/// Usage: <time user-time utc="@model.Date" />
129
/// </summary>
1310
[HtmlTargetElement("time", Attributes = AttributeName)]
1411
public class UserTimeTagHelper : TagHelper
1512
{
1613
internal const string AttributeName = "user-time";
1714
private const string UtcAttributeName = "utc";
18-
private const string FormatAttributeName = "format";
1915

2016
[HtmlAttributeName(UtcAttributeName)] public DateTime Utc { get; set; }
21-
[HtmlAttributeName(FormatAttributeName)] public string? Format { get; set; }
22-
23-
[ViewContext] public ViewContext? ViewContext { get; set; }
2417

2518
public override void Process(TagHelperContext context, TagHelperOutput output)
2619
{
2720
output.TagName = "time";
2821
output.TagMode = TagMode.StartTagAndEndTag;
29-
var user = ViewContext?.HttpContext?.User;
30-
var display = ConvertToUserTime(user, Utc);
31-
var text = Format is not null ? display.ToString(Format) : display.ToString();
32-
output.Attributes.SetAttribute("datetime", Utc.ToString("o"));
33-
output.Content.SetContent(text);
22+
23+
var utc = DateTime.SpecifyKind(Utc, DateTimeKind.Utc);
24+
output.Attributes.SetAttribute("datetime", utc.ToString("o"));
25+
output.Attributes.SetAttribute("data-dt", "localized");
26+
27+
// Server-rendered fallback for noscript users
28+
output.Content.SetContent($"{utc:yyyy-MM-dd HH:mm} UTC");
29+
3430
output.Attributes.RemoveAll(AttributeName);
3531
output.Attributes.RemoveAll(UtcAttributeName);
36-
output.Attributes.RemoveAll(FormatAttributeName);
37-
}
38-
39-
private static DateTime ConvertToUserTime(ClaimsPrincipal? user, DateTime utc)
40-
{
41-
if (user is null)
42-
return utc;
43-
var timezoneClaim = user.Claims.SingleOrDefault(c => c.Type == UserProfileClaimType.TimeZone);
44-
if (timezoneClaim is null)
45-
return utc;
46-
try
47-
{
48-
var tz = TimeZoneInfo.FindSystemTimeZoneById(timezoneClaim.Value);
49-
return TimeZoneInfo.ConvertTime(utc, tz);
50-
}
51-
catch
52-
{
53-
return utc;
54-
}
5532
}
5633
}

src/XtremeIdiots.Portal.Web/Views/AdminActions/_MyAdminActionDetailsPanel.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<div class="small text-muted">Created <time time-ago utc="@adminAction.Created"></time>
4646
@if (adminAction.Expires.HasValue)
4747
{
48-
<span>| <expiry-badge expires-utc="@adminAction.Expires" user="@User"></expiry-badge></span>
48+
<span>| <expiry-badge expires-utc="@adminAction.Expires"></expiry-badge></span>
4949
}
5050
@if (player?.GameType is not null)
5151
{

src/XtremeIdiots.Portal.Web/Views/ChangeLog/Index.cshtml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,18 +234,7 @@
234234
}
235235
236236
function formatDate(dateString) {
237-
const date = new Date(dateString);
238-
const now = new Date();
239-
const diffMs = now - date;
240-
const diffMins = Math.floor(diffMs / 60000);
241-
const diffHours = Math.floor(diffMs / 3600000);
242-
const diffDays = Math.floor(diffMs / 86400000);
243-
244-
if (diffMins < 1) return 'just now';
245-
if (diffMins < 60) return `${diffMins}m ago`;
246-
if (diffHours < 24) return `${diffHours}h ago`;
247-
if (diffDays < 7) return `${diffDays}d ago`;
248-
return date.toLocaleDateString();
237+
return portalDate.formatRelativeTime(dateString);
249238
}
250239
251240
function getCommitIcon(message) {

src/XtremeIdiots.Portal.Web/Views/Dashboard/Index.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@
330330
{
331331
var total = day.Bans + day.TempBans + day.Kicks + day.Warnings + day.Observations;
332332
<tr>
333-
<td>@day.Date.ToString("dd MMM")</td>
333+
<td><time user-time utc="@day.Date"></time></td>
334334
<td class="text-center">
335335
@if (day.Bans > 0) { <span class="badge bg-danger">@day.Bans</span> } else { <span class="text-muted">0</span> }
336336
</td>

0 commit comments

Comments
 (0)