UI timezone
This commit is contained in:
@@ -44,6 +44,7 @@ public static class ServiceCollectionExtensions
|
|||||||
services.AddScoped<LayerService>();
|
services.AddScoped<LayerService>();
|
||||||
services.AddScoped<DataInboxService>();
|
services.AddScoped<DataInboxService>();
|
||||||
services.AddScoped<JobService>();
|
services.AddScoped<JobService>();
|
||||||
|
services.AddScoped<DateTimeHelper>();
|
||||||
|
|
||||||
// Filter state services (scoped to maintain state during user session)
|
// Filter state services (scoped to maintain state during user session)
|
||||||
services.AddScoped<LayerFilterStateService>();
|
services.AddScoped<LayerFilterStateService>();
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
<RowTemplate Context="row">
|
<RowTemplate Context="row">
|
||||||
<MudTd DataLabel="Name"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Name</div></MudTd>
|
<MudTd DataLabel="Name"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Name</div></MudTd>
|
||||||
<MudTd DataLabel="Source"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Source</div></MudTd>
|
<MudTd DataLabel="Source"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.Source</div></MudTd>
|
||||||
<MudTd DataLabel="Created At"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@row.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")</div></MudTd>
|
<MudTd DataLabel="Created At"><div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">@DateTimeHelper.FormatDateTime(row.CreatedAt)</div></MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
<NoRecordsContent>
|
<NoRecordsContent>
|
||||||
<MudText>No data inbox items to display</MudText>
|
<MudText>No data inbox items to display</MudText>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public partial class Index : ComponentBase
|
|||||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||||
[Inject] private DataInboxFilterStateService FilterStateService { get; set; } = default!;
|
[Inject] private DataInboxFilterStateService FilterStateService { get; set; } = default!;
|
||||||
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
||||||
|
[Inject] private DateTimeHelper DateTimeHelper { get; set; } = default!;
|
||||||
|
|
||||||
|
|
||||||
private PagedResult<DataInboxDto> dataInbox = new();
|
private PagedResult<DataInboxDto> dataInbox = new();
|
||||||
@@ -23,6 +24,7 @@ public partial class Index : ComponentBase
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await DateTimeHelper.InitializeAsync();
|
||||||
filterRequest = FilterStateService.FilterRequest;
|
filterRequest = FilterStateService.FilterRequest;
|
||||||
await LoadDataInbox();
|
await LoadDataInbox();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
@inject EntityChangeHubService HubService
|
@inject EntityChangeHubService HubService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject ISnackbar Snackbar
|
@inject ISnackbar Snackbar
|
||||||
|
@inject DateTimeHelper DateTimeHelper
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
|
|
||||||
<MudCard>
|
<MudCard>
|
||||||
@@ -92,14 +93,14 @@
|
|||||||
</MudItem>
|
</MudItem>
|
||||||
|
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
<MudTextField Value="@job.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")"
|
<MudTextField Value="@DateTimeHelper.FormatDateTime(job.CreatedAt)"
|
||||||
Label="Created At"
|
Label="Created At"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
ReadOnly="true"
|
ReadOnly="true"
|
||||||
FullWidth="true"/>
|
FullWidth="true"/>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
<MudTextField Value="@(job.LastAttemptAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "-")"
|
<MudTextField Value="@DateTimeHelper.FormatDateTime(job.LastAttemptAt)"
|
||||||
Label="Last Attempt At"
|
Label="Last Attempt At"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
ReadOnly="true"
|
ReadOnly="true"
|
||||||
@@ -107,7 +108,7 @@
|
|||||||
</MudItem>
|
</MudItem>
|
||||||
|
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
<MudTextField Value="@(job.CompletedAt?.ToString("yyyy-MM-dd HH:mm:ss") ?? "-")"
|
<MudTextField Value="@DateTimeHelper.FormatDateTime(job.CompletedAt)"
|
||||||
Label="Completed At"
|
Label="Completed At"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
ReadOnly="true"
|
ReadOnly="true"
|
||||||
@@ -161,6 +162,7 @@
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await DateTimeHelper.InitializeAsync();
|
||||||
await LoadJob();
|
await LoadJob();
|
||||||
|
|
||||||
// Subscribe to SignalR entity changes
|
// Subscribe to SignalR entity changes
|
||||||
|
|||||||
@@ -111,12 +111,12 @@
|
|||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd DataLabel="Created">
|
<MudTd DataLabel="Created">
|
||||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||||
@row.CreatedAt.ToString("yyyy-MM-dd HH:mm")
|
@DateTimeHelper.FormatDateTime(row.CreatedAt, "yyyy-MM-dd HH:mm")
|
||||||
</div>
|
</div>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd DataLabel="Last Attempt">
|
<MudTd DataLabel="Last Attempt">
|
||||||
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
<div @oncontextmenu="@(async (e) => await OnRowRightClick(e, row))" @oncontextmenu:preventDefault="true">
|
||||||
@(row.LastAttemptAt?.ToString("yyyy-MM-dd HH:mm") ?? "-")
|
@DateTimeHelper.FormatDateTime(row.LastAttemptAt, "yyyy-MM-dd HH:mm")
|
||||||
</div>
|
</div>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public partial class Index : ComponentBase, IDisposable
|
|||||||
[Inject] private ISnackbar Snackbar { get; set; } = default!;
|
[Inject] private ISnackbar Snackbar { get; set; } = default!;
|
||||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||||
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
[Inject] private IJSRuntime JSRuntime { get; set; } = default!;
|
||||||
|
[Inject] private DateTimeHelper DateTimeHelper { get; set; } = default!;
|
||||||
|
|
||||||
private PagedResult<QueueJob> jobs = new();
|
private PagedResult<QueueJob> jobs = new();
|
||||||
private bool isLoading = false;
|
private bool isLoading = false;
|
||||||
@@ -25,6 +26,7 @@ public partial class Index : ComponentBase, IDisposable
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await DateTimeHelper.InitializeAsync();
|
||||||
await LoadJobs();
|
await LoadJobs();
|
||||||
|
|
||||||
// Subscribe to SignalR entity changes
|
// Subscribe to SignalR entity changes
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
<MudTextField Value="@layer.CreatedAt.ToString("g")"
|
<MudTextField Value="@DateTimeHelper.FormatDateTime(layer.CreatedAt, "yyyy-MM-dd HH:mm")"
|
||||||
Label="Created"
|
Label="Created"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
ReadOnly="true"
|
ReadOnly="true"
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
AdornmentText="@(layer.CreatedBy?.Username ?? "")"/>
|
AdornmentText="@(layer.CreatedBy?.Username ?? "")"/>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
<MudItem xs="12" md="6">
|
<MudItem xs="12" md="6">
|
||||||
<MudTextField Value="@layer.ModifiedAt.ToString("g")"
|
<MudTextField Value="@DateTimeHelper.FormatDateTime(layer.ModifiedAt, "yyyy-MM-dd HH:mm")"
|
||||||
Label="Modified"
|
Label="Modified"
|
||||||
Variant="Variant.Outlined"
|
Variant="Variant.Outlined"
|
||||||
ReadOnly="true"
|
ReadOnly="true"
|
||||||
@@ -316,7 +316,7 @@
|
|||||||
<RowTemplate>
|
<RowTemplate>
|
||||||
<MudTd DataLabel="Code">@context.Code</MudTd>
|
<MudTd DataLabel="Code">@context.Code</MudTd>
|
||||||
<MudTd DataLabel="Description">@context.Desc1</MudTd>
|
<MudTd DataLabel="Description">@context.Desc1</MudTd>
|
||||||
<MudTd DataLabel="Modified">@context.ModifiedAt.ToString("g")</MudTd>
|
<MudTd DataLabel="Modified">@DateTimeHelper.FormatDateTime(context.ModifiedAt, "yyyy-MM-dd HH:mm")</MudTd>
|
||||||
<MudTd DataLabel="Modified By">@GetModifiedByUsername(context.ModifiedById)</MudTd>
|
<MudTd DataLabel="Modified By">@GetModifiedByUsername(context.ModifiedById)</MudTd>
|
||||||
</RowTemplate>
|
</RowTemplate>
|
||||||
</MudTable>
|
</MudTable>
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ public partial class Details : ComponentBase
|
|||||||
[Inject]
|
[Inject]
|
||||||
private ISnackbar Snackbar { get; set; } = null!;
|
private ISnackbar Snackbar { get; set; } = null!;
|
||||||
|
|
||||||
|
[Inject]
|
||||||
|
private DateTimeHelper DateTimeHelper { get; set; } = null!;
|
||||||
|
|
||||||
private LayerDto? layer;
|
private LayerDto? layer;
|
||||||
private List<RecordDto> records = new();
|
private List<RecordDto> records = new();
|
||||||
private List<string> displayedColumns = new();
|
private List<string> displayedColumns = new();
|
||||||
@@ -52,6 +55,7 @@ public partial class Details : ComponentBase
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
await DateTimeHelper.InitializeAsync();
|
||||||
await LoadLayer();
|
await LoadLayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
80
DiunaBI.UI.Shared/Services/DateTimeHelper.cs
Normal file
80
DiunaBI.UI.Shared/Services/DateTimeHelper.cs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
using Microsoft.JSInterop;
|
||||||
|
|
||||||
|
namespace DiunaBI.UI.Shared.Services;
|
||||||
|
|
||||||
|
public class DateTimeHelper
|
||||||
|
{
|
||||||
|
private readonly IJSRuntime _jsRuntime;
|
||||||
|
private TimeZoneInfo? _userTimeZone;
|
||||||
|
private bool _initialized = false;
|
||||||
|
|
||||||
|
public DateTimeHelper(IJSRuntime jsRuntime)
|
||||||
|
{
|
||||||
|
_jsRuntime = jsRuntime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
if (_initialized) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the user's timezone from JavaScript
|
||||||
|
var timeZoneId = await _jsRuntime.InvokeAsync<string>("eval", "Intl.DateTimeFormat().resolvedOptions().timeZone");
|
||||||
|
|
||||||
|
// Try to find the TimeZoneInfo
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_userTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Fallback to local timezone if the IANA timezone ID is not found
|
||||||
|
_userTimeZone = TimeZoneInfo.Local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Fallback to local timezone if JavaScript interop fails
|
||||||
|
_userTimeZone = TimeZoneInfo.Local;
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FormatDateTime(DateTime? dateTime, string format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
{
|
||||||
|
if (!dateTime.HasValue)
|
||||||
|
return "-";
|
||||||
|
|
||||||
|
if (!_initialized)
|
||||||
|
{
|
||||||
|
// If not initialized yet, just format as-is (will be UTC)
|
||||||
|
return dateTime.Value.ToString(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert UTC to user's timezone
|
||||||
|
var localDateTime = TimeZoneInfo.ConvertTimeFromUtc(dateTime.Value, _userTimeZone ?? TimeZoneInfo.Local);
|
||||||
|
return localDateTime.ToString(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FormatDate(DateTime? dateTime, string format = "yyyy-MM-dd")
|
||||||
|
{
|
||||||
|
return FormatDateTime(dateTime, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FormatTime(DateTime? dateTime, string format = "HH:mm:ss")
|
||||||
|
{
|
||||||
|
return FormatDateTime(dateTime, format);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTimeZoneAbbreviation()
|
||||||
|
{
|
||||||
|
if (!_initialized || _userTimeZone == null)
|
||||||
|
return "UTC";
|
||||||
|
|
||||||
|
return _userTimeZone.IsDaylightSavingTime(DateTime.Now)
|
||||||
|
? _userTimeZone.DaylightName
|
||||||
|
: _userTimeZone.StandardName;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user