Skip to content

Commit

Permalink
Merge pull request #43 from valincius/v4.1.0
Browse files Browse the repository at this point in the history
v4.1.0
  • Loading branch information
valincius committed Jan 24, 2022
2 parents e4b2a0f + 20fd5c1 commit 63e5b50
Show file tree
Hide file tree
Showing 22 changed files with 305 additions and 106 deletions.
4 changes: 3 additions & 1 deletion BlazorScheduler/BlazorScheduler.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>

<Authors>John Valincius</Authors>
<Company>Valincius</Company>
<Description>Scheduler component library for Blazor.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl></PackageProjectUrl>
<RepositoryUrl>https://github.com/valincius/BlazorScheduler</RepositoryUrl>
<Version>4.0.0</Version>
<Version>4.1.0</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
27 changes: 22 additions & 5 deletions BlazorScheduler/Components/Appointment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,40 @@ namespace BlazorScheduler
{
public partial class Appointment : ComponentBase, IDisposable
{
[CascadingParameter] public Scheduler Scheduler { get; set; }
[CascadingParameter] public Scheduler Scheduler { get; set; } = null!;

[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public RenderFragment? ChildContent { get; set; }

[Parameter] public Func<Task> OnClick { get; set; }
[Parameter] public Func<Task>? OnClick { get; set; }
[Parameter] public Func<DateTime, DateTime, Task>? OnReschedule { get; set; }

[Parameter] public DateTime Start { get; set; }
[Parameter] public DateTime End { get; set; }
[Parameter] public string Color { get; set; }
[Parameter] public string? Color { get; set; }

private bool _isVisible = true;
public bool IsVisible
{
get => _isVisible;
set
{
if (value != _isVisible)
{
_isVisible = value;
StateHasChanged();
}
}
}

protected override void OnInitialized()
{
Scheduler.AddAppointment(this);
Color ??= Scheduler.ThemeColor;

base.OnInitialized();
}

public void Click(MouseEventArgs e)
public void Click(MouseEventArgs _)
{
OnClick?.Invoke();
}
Expand Down
22 changes: 16 additions & 6 deletions BlazorScheduler/Components/Scheduler.razor
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
else
{
<div class="actions">
<button class="btn today" @onclick="() => ChangeMonth()">@Config.TodayButtonText</button>
<button class="btn today" @onclick="() => ChangeMonth()">@TodayButtonText</button>
<div class="navigation">
<button class="btn icon-btn" @onclick="() => ChangeMonth(-1)">
<svg viewBox="0 0 24 24">
Expand Down Expand Up @@ -46,7 +46,7 @@
<div class="week header">
@for (int d=0;d<7;d++)
{
int dayNumber = (int)(Config.StartDayOfWeek + d) % 7;
int dayNumber = (int)(StartDayOfWeek + d) % 7;
string dayName = CultureInfo.CurrentCulture.DateTimeFormat.DayNames[dayNumber];
<div class="day-of-month">
<span class="full-dayname">@dayName</span>
Expand All @@ -56,11 +56,21 @@
</div>
<CascadingValue IsFixed="true" Value="this">
@Appointments
@if (_showNewAppointment)
@if (_draggingStart is not null && _draggingEnd is not null)
{
<Appointment @ref="NewAppointment" Start="_newAppointmentStart" End="_newAppointmentEnd" Color="@Config.ThemeColor">
New Appointment
</Appointment>
@if (_showNewAppointment)
{
<Appointment @ref="DraggingAppointment" Start="_draggingStart.Value" End="_draggingEnd.Value" Color="@ThemeColor">
New Appointment
</Appointment>
}

@if (_reschedulingAppointment is not null)
{
<Appointment @ref="DraggingAppointment" Start="_draggingStart.Value" End="_draggingEnd.Value" Color="@_reschedulingAppointment.Color">
@_reschedulingAppointment?.ChildContent
</Appointment>
}
}

@foreach (var week in GetDaysInRange().Chunk(7))
Expand Down
108 changes: 84 additions & 24 deletions BlazorScheduler/Components/Scheduler.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,41 @@
using System.Linq;
using System.Threading.Tasks;
using BlazorScheduler.Internal.Extensions;
using BlazorScheduler.Configuration;
using BlazorScheduler.Internal.Components;
using System.Collections.ObjectModel;

namespace BlazorScheduler
{
public partial class Scheduler : IAsyncDisposable
{
[Parameter] public RenderFragment Appointments { get; set; }
[Parameter] public RenderFragment<Scheduler> HeaderTemplate { get; set; }
[Parameter] public RenderFragment<DateTime> DayTemplate { get; set; }

[Parameter] public Func<DateTime, DateTime, Task> OnRequestNewData { get; set; }
[Parameter] public Func<DateTime, DateTime, Task> OnAddingNewAppointment { get; set; }
[Parameter] public Func<DateTime, Task> OnOverflowAppointmentClick { get; set; }

[Parameter] public Config Config { get; set; } = new();
[Parameter] public RenderFragment Appointments { get; set; } = null!;
[Parameter] public RenderFragment<Scheduler>? HeaderTemplate { get; set; }
[Parameter] public RenderFragment<DateTime>? DayTemplate { get; set; }

[Parameter] public Func<DateTime, DateTime, Task>? OnRequestNewData { get; set; }
[Parameter] public Func<DateTime, DateTime, Task>? OnAddingNewAppointment { get; set; }
[Parameter] public Func<DateTime, Task>? OnOverflowAppointmentClick { get; set; }

#region Config
[Parameter] public bool AlwaysShowYear { get; set; } = true;
[Parameter] public int MaxVisibleAppointmentsPerDay { get; set; } = 5;
[Parameter] public bool EnableDragging { get; set; } = true;
[Parameter] public bool EnableRescheduling { get; set; }
[Parameter] public string ThemeColor { get; set; } = "aqua";
[Parameter] public DayOfWeek StartDayOfWeek { get; set; } = DayOfWeek.Sunday;
[Parameter] public string TodayButtonText { get; set; } = "Today";
[Parameter] public string PlusOthersText { get; set; } = "+ {n} others";
#endregion

public DateTime CurrentDate { get; private set; }
public Appointment NewAppointment { get; private set; }
public Appointment? DraggingAppointment { get; private set; }

private string MonthDisplay
{
get
{
var res = CurrentDate.ToString("MMMM");
if (Config.AlwaysShowYear || CurrentDate.Year != DateTime.Today.Year)
if (AlwaysShowYear || CurrentDate.Year != DateTime.Today.Year)
{
return res += CurrentDate.ToString(" yyyy");
}
Expand All @@ -40,12 +48,12 @@ private string MonthDisplay
}

private readonly ObservableCollection<Appointment> _appointments = new();
private DotNetObjectReference<Scheduler> _objReference;
private DotNetObjectReference<Scheduler> _objReference = null!;
private bool _loading = false;

public bool _showNewAppointment;
private DateTime _draggingAppointmentAnchor;
private DateTime _newAppointmentStart, _newAppointmentEnd;
private DateTime? _draggingAppointmentAnchor;
private DateTime? _draggingStart, _draggingEnd;

protected override async Task OnInitializedAsync()
{
Expand Down Expand Up @@ -110,9 +118,9 @@ private async Task ChangeMonth(int months = 0)

private (DateTime, DateTime) GetDateRangeForCurrentMonth()
{
var startDate = new DateTime(CurrentDate.Year, CurrentDate.Month, 1).GetPrevious(Config.StartDayOfWeek);
var startDate = new DateTime(CurrentDate.Year, CurrentDate.Month, 1).GetPrevious(StartDayOfWeek);
var endDate = new DateTime(CurrentDate.Year, CurrentDate.Month, DateTime.DaysInMonth(CurrentDate.Year, CurrentDate.Month))
.GetNext((DayOfWeek)((int)(Config.StartDayOfWeek - 1 + 7) % 7));
.GetNext((DayOfWeek)((int)(StartDayOfWeek - 1 + 7) % 7));

return (startDate, endDate);
}
Expand All @@ -127,30 +135,69 @@ private IEnumerable<DateTime> GetDaysInRange()

private IEnumerable<Appointment> GetAppointmentsInRange(DateTime start, DateTime end)
{
var appointmentsInTimeframe = _appointments.Where(x => (start, end).Overlaps((x.Start, x.End)));
var appointmentsInTimeframe = _appointments
.Where(x => x.IsVisible)
.Where(x => (start, end).Overlaps((x.Start.Date, x.End.Date)));

return appointmentsInTimeframe
.OrderBy(x => x.Start)
.ThenByDescending(x => (x.End - x.Start).Days);
}

private Appointment? _reschedulingAppointment;
public void BeginDrag(Appointment appointment)
{
if (!EnableRescheduling || appointment.OnReschedule is null || _reschedulingAppointment is not null || _showNewAppointment)
return;

appointment.IsVisible = false;

_reschedulingAppointment = appointment;
_draggingStart = appointment.Start;
_draggingEnd = appointment.End;
_draggingAppointmentAnchor = null;

StateHasChanged();
}

public void BeginDrag(SchedulerDay day)
{
_newAppointmentStart = _newAppointmentEnd = day.Day;
if (!EnableDragging)
return;

_draggingStart = _draggingEnd = day.Day;
_showNewAppointment = true;

_draggingAppointmentAnchor = _newAppointmentStart;
_draggingAppointmentAnchor = _draggingStart;
StateHasChanged();
}

public bool IsDayBeingScheduled(Appointment appointment)
=> ReferenceEquals(appointment, DraggingAppointment) && _reschedulingAppointment is not null;

[JSInvokable]
public async Task OnMouseUp(int button)
{
if (button == 0)
if (button == 0 && _draggingStart is not null && _draggingEnd is not null)
{
if (_showNewAppointment)
{
_showNewAppointment = false;
await OnAddingNewAppointment?.Invoke(_newAppointmentStart, _newAppointmentEnd);
if (OnAddingNewAppointment is not null)
await OnAddingNewAppointment.Invoke(_draggingStart.Value, _draggingEnd.Value);

StateHasChanged();
}

if (_reschedulingAppointment is not null)
{
var tempApp = _reschedulingAppointment;
_reschedulingAppointment = null;

if (tempApp.OnReschedule is not null)
await tempApp.OnReschedule.Invoke(_draggingStart.Value, _draggingEnd.Value);
tempApp.IsVisible = true;

StateHasChanged();
}
}
Expand All @@ -159,10 +206,23 @@ public async Task OnMouseUp(int button)
[JSInvokable]
public void OnMouseMove(string date)
{
if (_showNewAppointment)
if (_showNewAppointment && _draggingAppointmentAnchor is not null)
{
var day = DateTime.ParseExact(date, "yyyyMMdd", null);
(_newAppointmentStart, _newAppointmentEnd) = day < _draggingAppointmentAnchor ? (day, _draggingAppointmentAnchor) : (_draggingAppointmentAnchor, day);
(_draggingStart, _draggingEnd) = day < _draggingAppointmentAnchor ? (day, _draggingAppointmentAnchor.Value) : (_draggingAppointmentAnchor.Value, day);
StateHasChanged();
}

if (_reschedulingAppointment is not null)
{
var day = DateTime.ParseExact(date, "yyyyMMdd", null);
_draggingAppointmentAnchor ??= day;

var diff = (day - _draggingAppointmentAnchor.Value).Days;

_draggingStart = _reschedulingAppointment.Start.AddDays(diff);
_draggingEnd = _reschedulingAppointment.End.AddDays(diff);

StateHasChanged();
}
}
Expand Down
15 changes: 0 additions & 15 deletions BlazorScheduler/Configuration/Config.cs

This file was deleted.

8 changes: 8 additions & 0 deletions BlazorScheduler/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.

using System.Diagnostics.CodeAnalysis;

[assembly: SuppressMessage("Usage", "BL0005:Component parameter should not be set outside of its component.", Justification = "<Pending>", Scope = "member", Target = "~M:BlazorScheduler.Scheduler.OnMouseMove(System.String)")]
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

<div class="appointment @Classes.AsString()"
style="--start: @Start; --end: @End; --order: @Order; background-color: @Appointment.Color;"
@onclick="Appointment.Click">
@onmousedown="OnMouseDown" @onmouseup="OnMouseUp" @onmousemove="OnMouseMove">
@Appointment.ChildContent
</div>
Original file line number Diff line number Diff line change
@@ -1,27 +1,52 @@
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System;
using System.Collections.Generic;

namespace BlazorScheduler.Internal.Components
{
public partial class SchedulerAllDayAppointment
{
[CascadingParameter] public Scheduler Scheduler { get; set; }
[CascadingParameter] public Scheduler Scheduler { get; set; } = null!;

[Parameter] public Appointment Appointment { get; set; }
[Parameter] public Appointment Appointment { get; set; } = null!;
[Parameter] public int Start { get; set; }
[Parameter] public int End { get; set; }
[Parameter] public int Order { get; set; }

private IEnumerable<string> Classes
private IEnumerable<string> Classes
{
get
{
if (ReferenceEquals(Appointment, Scheduler.NewAppointment))
if (ReferenceEquals(Appointment, Scheduler.DraggingAppointment))
{
yield return "new-appointment";
}
}
}

private bool _drag;

private void OnMouseDown(MouseEventArgs e)
{
if (e.Button == 0)
_drag = false;
}

private void OnMouseUp(MouseEventArgs e)
{
if (_drag)
return;

Appointment.OnClick?.Invoke();
}

private void OnMouseMove(MouseEventArgs e)
{
_drag = true;

if ((e.Buttons & 1) == 1)
Scheduler.BeginDrag(Appointment);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@namespace BlazorScheduler.Internal.Components

<div class="appointment" style="--start: @Start; --order: @Order;" @onclick="Appointment.Click">
<div class="appointment appointment-timed @Classes.AsString()" style="--start: @Start; --order: @Order;" @onmousedown="OnMouseDown" @onmouseup="OnMouseUp" @onmousemove="OnMouseMove">
<span class="dot" style="background-color: @Appointment.Color;"></span>
@Appointment.ChildContent - @Appointment.Start.ToString("htt") to @Appointment.End.ToString("htt")
</div>

0 comments on commit 63e5b50

Please sign in to comment.