Date / Time validations

This PR ensures time fields are required when dates are set, using Oqtane validation and dynamically toggles the required attribute on time inputs when their corresponding date fields have values. Benefits:
- Uses Oqtane's validation for a polished UX.
- Reduces custom validation code.
- Aligns with our internal form logic.

- Tested across all date/time scenarios—works flawlessly!
**Testing Confirmed:**
- Date + Time Provided → Saves successfully.
- No Date + No Time → Optional (no validation).
- Date + No Time → Browser blocks submission with icon error.
This commit is contained in:
Leigh Pointer
2025-06-10 12:27:55 +02:00
parent ff450ca43a
commit 1412737036
2 changed files with 23 additions and 14 deletions

View File

@ -56,7 +56,7 @@
<input id="starting" type="date" class="form-control" @bind="@_startDate" />
</div>
<div class="col">
<input id="starting" type="time" class="form-control" placeholder="hh:mm" @bind="@_startTime" />
<input id="starting" type="time" class="form-control" @bind="@_startTime" placeholder="hh:mm" required="@(_startDate.HasValue)" />
</div>
</div>
</div>
@ -69,7 +69,7 @@
<input id="ending" type="date" class="form-control" @bind="@_endDate" />
</div>
<div class="col">
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" />
<input id="ending" type="time" class="form-control" placeholder="hh:mm" @bind="@_endTime" required="@(_endDate.HasValue)" />
</div>
</div>
</div>
@ -82,7 +82,7 @@
<input id="next" type="date" class="form-control" @bind="@_nextDate" />
</div>
<div class="col">
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" />
<input id="next" type="time" class="form-control" placeholder="hh:mm" @bind="@_nextTime" required="@(_nextDate.HasValue)" />
</div>
</div>
</div>
@ -176,18 +176,18 @@
{
job.Interval = int.Parse(_interval);
}
job.StartDate = _startDate.HasValue && _startTime.HasValue
? LocalToUtc(_startDate.Value.Date.Add(_startTime.Value.TimeOfDay))
: null;
job.StartDate = _startDate.HasValue && _startTime.HasValue
? LocalToUtc(_startDate.GetValueOrDefault().Date.Add(_startTime.GetValueOrDefault().TimeOfDay))
: null;
job.EndDate = _endDate.HasValue && _endTime.HasValue
? LocalToUtc(_endDate.Value.Date.Add(_endTime.Value.TimeOfDay))
: null;
job.EndDate = _endDate.HasValue && _endTime.HasValue
? LocalToUtc(_endDate.GetValueOrDefault().Date.Add(_endTime.GetValueOrDefault().TimeOfDay))
: null;
job.NextExecution = _nextDate.HasValue && _nextTime.HasValue
? LocalToUtc(_nextDate.Value.Date.Add(_nextTime.Value.TimeOfDay))
: null;
job.RetentionHistory = int.Parse(_retentionHistory);
job.NextExecution = _nextDate.HasValue && _nextTime.HasValue
? LocalToUtc(_nextDate.GetValueOrDefault().Date.Add(_nextTime.GetValueOrDefault().TimeOfDay))
: null;
job.RetentionHistory = int.Parse(_retentionHistory);
try
{
@ -206,5 +206,4 @@
AddModuleMessage(Localizer["Message.Required.JobInfo"], MessageType.Warning);
}
}
}

View File

@ -503,6 +503,10 @@ namespace Oqtane.Modules
// date conversion methods
public DateTime? UtcToLocal(DateTime? datetime)
{
// Early return if input is null
if (datetime == null)
return null;
TimeZoneInfo timezone = null;
try
{
@ -519,11 +523,16 @@ namespace Oqtane.Modules
{
// The time zone ID was not found on the local computer
}
return Utilities.UtcAsLocalDateTime(datetime, timezone);
}
public DateTime? LocalToUtc(DateTime? datetime)
{
// Early return if input is null
if (datetime == null)
return null;
TimeZoneInfo timezone = null;
try
{
@ -540,6 +549,7 @@ namespace Oqtane.Modules
{
// The time zone ID was not found on the local computer
}
return Utilities.LocalDateAndTimeAsUtc(datetime, timezone);
}