feat(centralui): DateTimeRangeFilter reusable from/to input component (T35c)

This commit is contained in:
Joseph Doherty
2026-06-18 19:39:05 -04:00
parent 7b41c2c202
commit 9ee21205d6
2 changed files with 144 additions and 0 deletions
@@ -0,0 +1,57 @@
@* Reusable from/to datetime-local input pair for filter bars.
INPUT-ONLY: emits raw DateTime? (Unspecified kind) via FromChanged / ToChanged.
UTC conversion is the caller's responsibility — no Apply button, no service injection. *@
<div class="row g-2 align-items-end">
<div class="col-auto">
<label class="form-label small mb-1" for="@(IdPrefix)-from">@FromLabel</label>
<input id="@(IdPrefix)-from"
type="datetime-local"
class="form-control form-control-sm"
data-test="@(IdPrefix)-from"
value="@From?.ToString("yyyy-MM-ddTHH:mm")"
@onchange="OnFromChanged" />
</div>
<div class="col-auto">
<label class="form-label small mb-1" for="@(IdPrefix)-to">@ToLabel</label>
<input id="@(IdPrefix)-to"
type="datetime-local"
class="form-control form-control-sm"
data-test="@(IdPrefix)-to"
value="@To?.ToString("yyyy-MM-ddTHH:mm")"
@onchange="OnToChanged" />
</div>
</div>
@code {
[Parameter] public DateTime? From { get; set; }
[Parameter] public EventCallback<DateTime?> FromChanged { get; set; }
[Parameter] public DateTime? To { get; set; }
[Parameter] public EventCallback<DateTime?> ToChanged { get; set; }
/// <summary>Prefix applied to all id/data-test attributes. Pages pass short codes like "no", "sc", "audit-filter".</summary>
[Parameter] public string IdPrefix { get; set; } = "dtr";
[Parameter] public string FromLabel { get; set; } = "From";
[Parameter] public string ToLabel { get; set; } = "To";
private async Task OnFromChanged(ChangeEventArgs e)
{
var parsed = ParseInput(e.Value?.ToString());
await FromChanged.InvokeAsync(parsed);
}
private async Task OnToChanged(ChangeEventArgs e)
{
var parsed = ParseInput(e.Value?.ToString());
await ToChanged.InvokeAsync(parsed);
}
private static DateTime? ParseInput(string? raw)
{
if (string.IsNullOrWhiteSpace(raw))
return null;
return DateTime.TryParse(raw, out var dt) ? dt : null;
}
}