You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Components/DatePicker/DateRangePicker.razor.cs

305 lines
9.1 KiB

2 years ago
using Connected.Annotations;
using Connected.Extensions;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
namespace Connected.Components;
public partial class DateRangePicker : DatePickerBase
{
private DateTime? _firstDate = null, _secondDate;
private DateRange _dateRange;
private Range<string> _rangeText;
protected override bool IsRange => true;
public DateRangePicker()
{
DisplayMonths = 2;
AdornmentAriaLabel = "Open Date Range Picker";
}
/// <summary>
/// Fired when the DateFormat changes.
/// </summary>
[Parameter] public EventCallback<DateRange> DateRangeChanged { get; set; }
/// <summary>
/// The currently selected range (two-way bindable). If null, then nothing was selected.
/// </summary>
[Parameter]
[Category(CategoryTypes.FormComponent.Data)]
public DateRange DateRange
{
get => _dateRange;
set => SetDateRangeAsync(value, true).AndForget();
}
protected async Task SetDateRangeAsync(DateRange range, bool updateValue)
{
if (_dateRange != range)
{
var doesRangeContainDisabledDates = range?.Start != null && range?.End != null && Enumerable
.Range(0, int.MaxValue)
.Select(index => range.Start.Value.AddDays(index))
.TakeWhile(date => date <= range.End.Value)
.Any(date => IsDateDisabledFunc(date.Date));
if (doesRangeContainDisabledDates)
{
_rangeText = null;
await SetTextAsync(null, false);
return;
}
_dateRange = range;
_value = range?.End;
if (updateValue)
{
Converter.GetError = false;
if (_dateRange == null)
{
_rangeText = null;
await SetTextAsync(null, false);
}
else
{
_rangeText = new Range<string>(
Converter.Set(_dateRange.Start),
Converter.Set(_dateRange.End));
await SetTextAsync(_dateRange.ToString(Converter), false);
}
}
await DateRangeChanged.InvokeAsync(_dateRange);
BeginValidate();
}
}
private Range<string> RangeText
{
get => _rangeText;
set
{
if (_rangeText?.Equals(value) ?? value == null)
return;
Touched = true;
_rangeText = value;
SetDateRangeAsync(ParseDateRangeValue(value?.Start, value?.End), false).AndForget();
}
}
private RangeInput<string> _rangeInput;
/// <summary>
/// Focuses the start date of MudDateRangePicker
/// </summary>
/// <returns></returns>
public ValueTask FocusStartAsync() => _rangeInput.FocusStartAsync();
/// <summary>
/// Selects the start date of MudDateRangePicker
/// </summary>
/// <returns></returns>
public ValueTask SelectStartAsync() => _rangeInput.SelectStartAsync();
/// <summary>
/// Selects the specified range of the start date text
/// </summary>
/// <param name="pos1">Start position of the selection</param>
/// <param name="pos2">End position of the selection</param>
/// <returns></returns>
public ValueTask SelectRangeStartAsync(int pos1, int pos2) => _rangeInput.SelectRangeStartAsync(pos1, pos2);
/// <summary>
/// Focuses the end date of MudDateRangePicker
/// </summary>
/// <returns></returns>
public ValueTask FocusEndAsync() => _rangeInput.FocusEndAsync();
/// <summary>
/// Selects the end date of MudDateRangePicker
/// </summary>
/// <returns></returns>
public ValueTask SelectEndAsync() => _rangeInput.SelectEndAsync();
/// <summary>
/// Selects the specified range of the end date text
/// </summary>
/// <param name="pos1">Start position of the selection</param>
/// <param name="pos2">End position of the selection</param>
/// <returns></returns>
public ValueTask SelectRangeEndAsync(int pos1, int pos2) => _rangeInput.SelectRangeEndAsync(pos1, pos2);
protected override Task DateFormatChanged(string newFormat)
{
Touched = true;
return SetTextAsync(_dateRange?.ToString(Converter), false);
}
protected override Task StringValueChanged(string value)
{
Touched = true;
// Update the daterange property (without updating back the Value property)
return SetDateRangeAsync(ParseDateRangeValue(value), false);
}
protected override bool HasValue(DateTime? value)
{
return null != value && value.HasValue;
}
private DateRange ParseDateRangeValue(string value)
{
return DateRange.TryParse(value, Converter, out var dateRange) ? dateRange : null;
}
private DateRange ParseDateRangeValue(string start, string end)
{
return DateRange.TryParse(start, end, Converter, out var dateRange) ? dateRange : null;
}
protected override void OnPickerClosed()
{
_firstDate = null;
base.OnPickerClosed();
}
protected override string GetDayClasses(int month, DateTime day)
{
var b = new CssBuilder("mud-day");
if (day < GetMonthStart(month) || day > GetMonthEnd(month))
{
return b.AddClass("mud-hidden").Build();
}
if ((_firstDate != null && _secondDate != null && _firstDate < day && _secondDate > day) ||
(_firstDate == null && _dateRange != null && _dateRange.Start < day && _dateRange.End > day))
{
return b
.AddClass("mud-range")
.AddClass("mud-range-between")
.Build();
}
if ((_firstDate != null && day == _firstDate) ||
(_firstDate == null && _dateRange != null && _dateRange.Start == day && DateRange.End != day))
{
return b.AddClass("mud-selected")
.AddClass("mud-range")
.AddClass("mud-range-start-selected")
.AddClass("mud-range-selection", _firstDate != null)
.AddClass($"mud-theme-{Color.ToDescriptionString()}")
.Build();
}
if ((_firstDate != null && _secondDate != null && day == _secondDate) ||
(_firstDate == null && _dateRange != null && _dateRange.Start != day && _dateRange.End == day))
{
return b.AddClass("mud-selected")
.AddClass("mud-range")
.AddClass("mud-range-end-selected")
.AddClass($"mud-theme-{Color.ToDescriptionString()}")
.Build();
}
if (_firstDate == null && _dateRange != null && _dateRange.Start == _dateRange.End && _dateRange.Start == day)
{
return b.AddClass("mud-selected").AddClass($"mud-theme-{Color.ToDescriptionString()}").Build();
}
else if (_firstDate != null && day > _firstDate)
{
return b.AddClass("mud-range")
.AddClass("mud-range-selection", _secondDate == null)
.AddClass($"mud-range-selection-{Color.ToDescriptionString()}", _firstDate != null)
.Build();
}
if (day == DateTime.Today)
{
return b.AddClass("mud-current")
.AddClass("mud-range", _firstDate != null && day > _firstDate)
.AddClass("mud-range-selection", _firstDate != null && day > _firstDate)
.AddClass($"mud-range-selection-{Color.ToDescriptionString()}", _firstDate != null && day > _firstDate)
.AddClass($"mud-{Color.ToDescriptionString()}-text")
.Build();
}
return b.Build();
}
protected override async void OnDayClicked(DateTime dateTime)
{
if (_firstDate == null || _firstDate > dateTime || _secondDate != null)
{
_secondDate = null;
_firstDate = dateTime;
return;
}
_secondDate = dateTime;
if (PickerActions == null || AutoClose)
{
Submit();
if (PickerVariant != PickerVariant.Static)
{
await Task.Delay(ClosingDelay);
Close(false);
}
}
}
protected override void OnOpened()
{
_secondDate = null;
base.OnOpened();
}
protected internal override async void Submit()
{
if (ReadOnly)
return;
if (_firstDate == null || _secondDate == null)
return;
await SetDateRangeAsync(new DateRange(_firstDate, _secondDate), true);
_firstDate = null;
_secondDate = null;
}
public override void Clear(bool close = true)
{
DateRange = null;
_firstDate = _secondDate = null;
base.Clear();
}
protected override string GetTitleDateString()
{
if (_firstDate != null)
return $"{FormatTitleDate(_firstDate)} - {FormatTitleDate(_secondDate)}";
return DateRange?.Start != null
? $"{FormatTitleDate(DateRange.Start)} - {FormatTitleDate(DateRange.End)}"
: "";
}
protected override DateTime GetCalendarStartOfMonth()
{
var date = StartMonth ?? DateRange?.Start ?? DateTime.Today;
return date.StartOfMonth(Culture);
}
protected override int GetCalendarYear(int year)
{
var date = DateRange?.Start ?? DateTime.Today;
var diff = date.Year - year;
var calenderYear = Culture.Calendar.GetYear(date);
return calenderYear - diff;
}
}