Skip to content

Commit 63e5b50

Browse files
authored
Merge pull request #43 from valincius/v4.1.0
v4.1.0
2 parents e4b2a0f + 20fd5c1 commit 63e5b50

22 files changed

+305
-106
lines changed

BlazorScheduler/BlazorScheduler.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
57
<Authors>John Valincius</Authors>
68
<Company>Valincius</Company>
79
<Description>Scheduler component library for Blazor.</Description>
810
<PackageLicenseExpression>MIT</PackageLicenseExpression>
911
<PackageProjectUrl></PackageProjectUrl>
1012
<RepositoryUrl>https://github.com/valincius/BlazorScheduler</RepositoryUrl>
11-
<Version>4.0.0</Version>
13+
<Version>4.1.0</Version>
1214
</PropertyGroup>
1315

1416
<ItemGroup>

BlazorScheduler/Components/Appointment.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,40 @@ namespace BlazorScheduler
77
{
88
public partial class Appointment : ComponentBase, IDisposable
99
{
10-
[CascadingParameter] public Scheduler Scheduler { get; set; }
10+
[CascadingParameter] public Scheduler Scheduler { get; set; } = null!;
1111

12-
[Parameter] public RenderFragment ChildContent { get; set; }
12+
[Parameter] public RenderFragment? ChildContent { get; set; }
1313

14-
[Parameter] public Func<Task> OnClick { get; set; }
14+
[Parameter] public Func<Task>? OnClick { get; set; }
15+
[Parameter] public Func<DateTime, DateTime, Task>? OnReschedule { get; set; }
1516

1617
[Parameter] public DateTime Start { get; set; }
1718
[Parameter] public DateTime End { get; set; }
18-
[Parameter] public string Color { get; set; }
19+
[Parameter] public string? Color { get; set; }
20+
21+
private bool _isVisible = true;
22+
public bool IsVisible
23+
{
24+
get => _isVisible;
25+
set
26+
{
27+
if (value != _isVisible)
28+
{
29+
_isVisible = value;
30+
StateHasChanged();
31+
}
32+
}
33+
}
1934

2035
protected override void OnInitialized()
2136
{
2237
Scheduler.AddAppointment(this);
38+
Color ??= Scheduler.ThemeColor;
39+
2340
base.OnInitialized();
2441
}
2542

26-
public void Click(MouseEventArgs e)
43+
public void Click(MouseEventArgs _)
2744
{
2845
OnClick?.Invoke();
2946
}

BlazorScheduler/Components/Scheduler.razor

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
else
1616
{
1717
<div class="actions">
18-
<button class="btn today" @onclick="() => ChangeMonth()">@Config.TodayButtonText</button>
18+
<button class="btn today" @onclick="() => ChangeMonth()">@TodayButtonText</button>
1919
<div class="navigation">
2020
<button class="btn icon-btn" @onclick="() => ChangeMonth(-1)">
2121
<svg viewBox="0 0 24 24">
@@ -46,7 +46,7 @@
4646
<div class="week header">
4747
@for (int d=0;d<7;d++)
4848
{
49-
int dayNumber = (int)(Config.StartDayOfWeek + d) % 7;
49+
int dayNumber = (int)(StartDayOfWeek + d) % 7;
5050
string dayName = CultureInfo.CurrentCulture.DateTimeFormat.DayNames[dayNumber];
5151
<div class="day-of-month">
5252
<span class="full-dayname">@dayName</span>
@@ -56,11 +56,21 @@
5656
</div>
5757
<CascadingValue IsFixed="true" Value="this">
5858
@Appointments
59-
@if (_showNewAppointment)
59+
@if (_draggingStart is not null && _draggingEnd is not null)
6060
{
61-
<Appointment @ref="NewAppointment" Start="_newAppointmentStart" End="_newAppointmentEnd" Color="@Config.ThemeColor">
62-
New Appointment
63-
</Appointment>
61+
@if (_showNewAppointment)
62+
{
63+
<Appointment @ref="DraggingAppointment" Start="_draggingStart.Value" End="_draggingEnd.Value" Color="@ThemeColor">
64+
New Appointment
65+
</Appointment>
66+
}
67+
68+
@if (_reschedulingAppointment is not null)
69+
{
70+
<Appointment @ref="DraggingAppointment" Start="_draggingStart.Value" End="_draggingEnd.Value" Color="@_reschedulingAppointment.Color">
71+
@_reschedulingAppointment?.ChildContent
72+
</Appointment>
73+
}
6474
}
6575

6676
@foreach (var week in GetDaysInRange().Chunk(7))

BlazorScheduler/Components/Scheduler.razor.cs

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,41 @@
55
using System.Linq;
66
using System.Threading.Tasks;
77
using BlazorScheduler.Internal.Extensions;
8-
using BlazorScheduler.Configuration;
98
using BlazorScheduler.Internal.Components;
109
using System.Collections.ObjectModel;
1110

1211
namespace BlazorScheduler
1312
{
1413
public partial class Scheduler : IAsyncDisposable
1514
{
16-
[Parameter] public RenderFragment Appointments { get; set; }
17-
[Parameter] public RenderFragment<Scheduler> HeaderTemplate { get; set; }
18-
[Parameter] public RenderFragment<DateTime> DayTemplate { get; set; }
19-
20-
[Parameter] public Func<DateTime, DateTime, Task> OnRequestNewData { get; set; }
21-
[Parameter] public Func<DateTime, DateTime, Task> OnAddingNewAppointment { get; set; }
22-
[Parameter] public Func<DateTime, Task> OnOverflowAppointmentClick { get; set; }
23-
24-
[Parameter] public Config Config { get; set; } = new();
15+
[Parameter] public RenderFragment Appointments { get; set; } = null!;
16+
[Parameter] public RenderFragment<Scheduler>? HeaderTemplate { get; set; }
17+
[Parameter] public RenderFragment<DateTime>? DayTemplate { get; set; }
18+
19+
[Parameter] public Func<DateTime, DateTime, Task>? OnRequestNewData { get; set; }
20+
[Parameter] public Func<DateTime, DateTime, Task>? OnAddingNewAppointment { get; set; }
21+
[Parameter] public Func<DateTime, Task>? OnOverflowAppointmentClick { get; set; }
22+
23+
#region Config
24+
[Parameter] public bool AlwaysShowYear { get; set; } = true;
25+
[Parameter] public int MaxVisibleAppointmentsPerDay { get; set; } = 5;
26+
[Parameter] public bool EnableDragging { get; set; } = true;
27+
[Parameter] public bool EnableRescheduling { get; set; }
28+
[Parameter] public string ThemeColor { get; set; } = "aqua";
29+
[Parameter] public DayOfWeek StartDayOfWeek { get; set; } = DayOfWeek.Sunday;
30+
[Parameter] public string TodayButtonText { get; set; } = "Today";
31+
[Parameter] public string PlusOthersText { get; set; } = "+ {n} others";
32+
#endregion
2533

2634
public DateTime CurrentDate { get; private set; }
27-
public Appointment NewAppointment { get; private set; }
35+
public Appointment? DraggingAppointment { get; private set; }
2836

2937
private string MonthDisplay
3038
{
3139
get
3240
{
3341
var res = CurrentDate.ToString("MMMM");
34-
if (Config.AlwaysShowYear || CurrentDate.Year != DateTime.Today.Year)
42+
if (AlwaysShowYear || CurrentDate.Year != DateTime.Today.Year)
3543
{
3644
return res += CurrentDate.ToString(" yyyy");
3745
}
@@ -40,12 +48,12 @@ private string MonthDisplay
4048
}
4149

4250
private readonly ObservableCollection<Appointment> _appointments = new();
43-
private DotNetObjectReference<Scheduler> _objReference;
51+
private DotNetObjectReference<Scheduler> _objReference = null!;
4452
private bool _loading = false;
4553

4654
public bool _showNewAppointment;
47-
private DateTime _draggingAppointmentAnchor;
48-
private DateTime _newAppointmentStart, _newAppointmentEnd;
55+
private DateTime? _draggingAppointmentAnchor;
56+
private DateTime? _draggingStart, _draggingEnd;
4957

5058
protected override async Task OnInitializedAsync()
5159
{
@@ -110,9 +118,9 @@ private async Task ChangeMonth(int months = 0)
110118

111119
private (DateTime, DateTime) GetDateRangeForCurrentMonth()
112120
{
113-
var startDate = new DateTime(CurrentDate.Year, CurrentDate.Month, 1).GetPrevious(Config.StartDayOfWeek);
121+
var startDate = new DateTime(CurrentDate.Year, CurrentDate.Month, 1).GetPrevious(StartDayOfWeek);
114122
var endDate = new DateTime(CurrentDate.Year, CurrentDate.Month, DateTime.DaysInMonth(CurrentDate.Year, CurrentDate.Month))
115-
.GetNext((DayOfWeek)((int)(Config.StartDayOfWeek - 1 + 7) % 7));
123+
.GetNext((DayOfWeek)((int)(StartDayOfWeek - 1 + 7) % 7));
116124

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

128136
private IEnumerable<Appointment> GetAppointmentsInRange(DateTime start, DateTime end)
129137
{
130-
var appointmentsInTimeframe = _appointments.Where(x => (start, end).Overlaps((x.Start, x.End)));
138+
var appointmentsInTimeframe = _appointments
139+
.Where(x => x.IsVisible)
140+
.Where(x => (start, end).Overlaps((x.Start.Date, x.End.Date)));
141+
131142
return appointmentsInTimeframe
132143
.OrderBy(x => x.Start)
133144
.ThenByDescending(x => (x.End - x.Start).Days);
134145
}
135146

147+
private Appointment? _reschedulingAppointment;
148+
public void BeginDrag(Appointment appointment)
149+
{
150+
if (!EnableRescheduling || appointment.OnReschedule is null || _reschedulingAppointment is not null || _showNewAppointment)
151+
return;
152+
153+
appointment.IsVisible = false;
154+
155+
_reschedulingAppointment = appointment;
156+
_draggingStart = appointment.Start;
157+
_draggingEnd = appointment.End;
158+
_draggingAppointmentAnchor = null;
159+
160+
StateHasChanged();
161+
}
162+
136163
public void BeginDrag(SchedulerDay day)
137164
{
138-
_newAppointmentStart = _newAppointmentEnd = day.Day;
165+
if (!EnableDragging)
166+
return;
167+
168+
_draggingStart = _draggingEnd = day.Day;
139169
_showNewAppointment = true;
140170

141-
_draggingAppointmentAnchor = _newAppointmentStart;
171+
_draggingAppointmentAnchor = _draggingStart;
142172
StateHasChanged();
143173
}
144174

175+
public bool IsDayBeingScheduled(Appointment appointment)
176+
=> ReferenceEquals(appointment, DraggingAppointment) && _reschedulingAppointment is not null;
177+
145178
[JSInvokable]
146179
public async Task OnMouseUp(int button)
147180
{
148-
if (button == 0)
181+
if (button == 0 && _draggingStart is not null && _draggingEnd is not null)
149182
{
150183
if (_showNewAppointment)
151184
{
152185
_showNewAppointment = false;
153-
await OnAddingNewAppointment?.Invoke(_newAppointmentStart, _newAppointmentEnd);
186+
if (OnAddingNewAppointment is not null)
187+
await OnAddingNewAppointment.Invoke(_draggingStart.Value, _draggingEnd.Value);
188+
189+
StateHasChanged();
190+
}
191+
192+
if (_reschedulingAppointment is not null)
193+
{
194+
var tempApp = _reschedulingAppointment;
195+
_reschedulingAppointment = null;
196+
197+
if (tempApp.OnReschedule is not null)
198+
await tempApp.OnReschedule.Invoke(_draggingStart.Value, _draggingEnd.Value);
199+
tempApp.IsVisible = true;
200+
154201
StateHasChanged();
155202
}
156203
}
@@ -159,10 +206,23 @@ public async Task OnMouseUp(int button)
159206
[JSInvokable]
160207
public void OnMouseMove(string date)
161208
{
162-
if (_showNewAppointment)
209+
if (_showNewAppointment && _draggingAppointmentAnchor is not null)
163210
{
164211
var day = DateTime.ParseExact(date, "yyyyMMdd", null);
165-
(_newAppointmentStart, _newAppointmentEnd) = day < _draggingAppointmentAnchor ? (day, _draggingAppointmentAnchor) : (_draggingAppointmentAnchor, day);
212+
(_draggingStart, _draggingEnd) = day < _draggingAppointmentAnchor ? (day, _draggingAppointmentAnchor.Value) : (_draggingAppointmentAnchor.Value, day);
213+
StateHasChanged();
214+
}
215+
216+
if (_reschedulingAppointment is not null)
217+
{
218+
var day = DateTime.ParseExact(date, "yyyyMMdd", null);
219+
_draggingAppointmentAnchor ??= day;
220+
221+
var diff = (day - _draggingAppointmentAnchor.Value).Days;
222+
223+
_draggingStart = _reschedulingAppointment.Start.AddDays(diff);
224+
_draggingEnd = _reschedulingAppointment.End.AddDays(diff);
225+
166226
StateHasChanged();
167227
}
168228
}

BlazorScheduler/Configuration/Config.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.

BlazorScheduler/GlobalSuppressions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This file is used by Code Analysis to maintain SuppressMessage
2+
// attributes that are applied to this project.
3+
// Project-level suppressions either have no target or are given
4+
// a specific target and scoped to a namespace, type, member, etc.
5+
6+
using System.Diagnostics.CodeAnalysis;
7+
8+
[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)")]

BlazorScheduler/Internal/Components/SchedulerAllDayAppointment.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
<div class="appointment @Classes.AsString()"
44
style="--start: @Start; --end: @End; --order: @Order; background-color: @Appointment.Color;"
5-
@onclick="Appointment.Click">
5+
@onmousedown="OnMouseDown" @onmouseup="OnMouseUp" @onmousemove="OnMouseMove">
66
@Appointment.ChildContent
77
</div>
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,52 @@
11
using Microsoft.AspNetCore.Components;
2+
using Microsoft.AspNetCore.Components.Web;
23
using System;
34
using System.Collections.Generic;
45

56
namespace BlazorScheduler.Internal.Components
67
{
78
public partial class SchedulerAllDayAppointment
89
{
9-
[CascadingParameter] public Scheduler Scheduler { get; set; }
10+
[CascadingParameter] public Scheduler Scheduler { get; set; } = null!;
1011

11-
[Parameter] public Appointment Appointment { get; set; }
12+
[Parameter] public Appointment Appointment { get; set; } = null!;
1213
[Parameter] public int Start { get; set; }
1314
[Parameter] public int End { get; set; }
1415
[Parameter] public int Order { get; set; }
1516

16-
private IEnumerable<string> Classes
17+
private IEnumerable<string> Classes
1718
{
1819
get
1920
{
20-
if (ReferenceEquals(Appointment, Scheduler.NewAppointment))
21+
if (ReferenceEquals(Appointment, Scheduler.DraggingAppointment))
2122
{
2223
yield return "new-appointment";
2324
}
2425
}
2526
}
27+
28+
private bool _drag;
29+
30+
private void OnMouseDown(MouseEventArgs e)
31+
{
32+
if (e.Button == 0)
33+
_drag = false;
34+
}
35+
36+
private void OnMouseUp(MouseEventArgs e)
37+
{
38+
if (_drag)
39+
return;
40+
41+
Appointment.OnClick?.Invoke();
42+
}
43+
44+
private void OnMouseMove(MouseEventArgs e)
45+
{
46+
_drag = true;
47+
48+
if ((e.Buttons & 1) == 1)
49+
Scheduler.BeginDrag(Appointment);
50+
}
2651
}
2752
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@namespace BlazorScheduler.Internal.Components
22

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

0 commit comments

Comments
 (0)