diff --git a/GroomWise.Application/Observables/ObservableAppointment.cs b/GroomWise.Application/Observables/ObservableAppointment.cs index ebc6377..f6ecaec 100644 --- a/GroomWise.Application/Observables/ObservableAppointment.cs +++ b/GroomWise.Application/Observables/ObservableAppointment.cs @@ -3,7 +3,6 @@ // Unauthorized copying or redistribution of all files, in source and binary forms via any medium // without written, signed consent from the author is strictly prohibited. -using GroomWise.Domain.Entities; using GroomWise.Domain.Enums; using Lombok.NET; using Swordfish.NET.Collections; @@ -13,21 +12,30 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservableAppointment { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] - private DateTime? _date; + [Property] + private Guid _id; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] + private DateOnly? _date; + + [Property] + private TimeOnly? _startTime; + + [Property] + private TimeOnly? _endTime; + + [Property] private AppointmentStatus? _status; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ObservablePet? _pet; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ObservableCustomer? _customer; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ConcurrentObservableCollection? _employees = new(); - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ConcurrentObservableCollection? _services = new(); } diff --git a/GroomWise.Application/Observables/ObservableAppointmentService.cs b/GroomWise.Application/Observables/ObservableAppointmentService.cs index 760ff8a..99dbab0 100644 --- a/GroomWise.Application/Observables/ObservableAppointmentService.cs +++ b/GroomWise.Application/Observables/ObservableAppointmentService.cs @@ -10,6 +10,6 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservableAppointmentService { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ObservableGroomingService _groomingService; } diff --git a/GroomWise.Application/Observables/ObservableCustomer.cs b/GroomWise.Application/Observables/ObservableCustomer.cs index 94932a6..a3adddf 100644 --- a/GroomWise.Application/Observables/ObservableCustomer.cs +++ b/GroomWise.Application/Observables/ObservableCustomer.cs @@ -12,24 +12,24 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservableCustomer { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private Guid _id; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _fullName; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _address; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _contactNumber; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _email; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ConcurrentObservableCollection _appointments = new(); - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private ConcurrentObservableCollection _pets = new(); } diff --git a/GroomWise.Application/Observables/ObservableEmployee.cs b/GroomWise.Application/Observables/ObservableEmployee.cs index 8d0c6eb..40a78f8 100644 --- a/GroomWise.Application/Observables/ObservableEmployee.cs +++ b/GroomWise.Application/Observables/ObservableEmployee.cs @@ -11,40 +11,40 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservableEmployee { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private Guid _id; public string FullName => $"{FirstName} {LastName}"; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _prefix; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _firstName; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _middleName; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _lastName; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _suffix; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _address; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _contactNumber; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string _email; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private IList? _pets; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private IList? _appointments; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private IList? _roles; } diff --git a/GroomWise.Application/Observables/ObservableGroomingService.cs b/GroomWise.Application/Observables/ObservableGroomingService.cs index 368d437..c1fab95 100644 --- a/GroomWise.Application/Observables/ObservableGroomingService.cs +++ b/GroomWise.Application/Observables/ObservableGroomingService.cs @@ -10,16 +10,16 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservableGroomingService { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private Guid _id; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _type; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private double _hourSpan; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private double _minuteSpan; public TimeSpan TimeSpan @@ -32,6 +32,6 @@ public TimeSpan TimeSpan } } - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _description; } diff --git a/GroomWise.Application/Observables/ObservablePet.cs b/GroomWise.Application/Observables/ObservablePet.cs index 432acb8..9ac7121 100644 --- a/GroomWise.Application/Observables/ObservablePet.cs +++ b/GroomWise.Application/Observables/ObservablePet.cs @@ -11,19 +11,19 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservablePet { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private Guid _id; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _name; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private int? _age; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _breed; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _gender; } diff --git a/GroomWise.Application/Observables/ObservableProduct.cs b/GroomWise.Application/Observables/ObservableProduct.cs index d88163d..e3e127e 100644 --- a/GroomWise.Application/Observables/ObservableProduct.cs +++ b/GroomWise.Application/Observables/ObservableProduct.cs @@ -10,15 +10,15 @@ namespace GroomWise.Application.Observables; [NotifyPropertyChanged] public partial class ObservableProduct { - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private Guid _id; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _productName; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private string? _productDescription; - [Property(PropertyChangeType = PropertyChangeType.PropertyChanged)] + [Property] private int _quantity; } diff --git a/GroomWise.Application/ViewModels/AppointmentViewModel.cs b/GroomWise.Application/ViewModels/AppointmentViewModel.cs index d6f145f..5a7c4ba 100644 --- a/GroomWise.Application/ViewModels/AppointmentViewModel.cs +++ b/GroomWise.Application/ViewModels/AppointmentViewModel.cs @@ -50,7 +50,10 @@ public partial class AppointmentViewModel partial void OnInitialize() { PopulateCollections(); - ActiveAppointment = new ObservableAppointment { Date = DateTime.Today }; + ActiveAppointment = new ObservableAppointment + { + Date = DateOnly.FromDateTime(DateTime.Today) + }; } private async void PopulateCollections() @@ -58,7 +61,7 @@ private async void PopulateCollections() await Task.Run(() => { var appointments = GroomWiseDbContext.Appointments - .GetMultiple(appointment => appointment.Date >= DateTime.Today) + .GetMultiple(appointment => appointment.Date >= DateOnly.FromDateTime(DateTime.Now)) .Select(AppointmentMapper.ToObservable) .OrderBy(appointment => appointment.Date); @@ -90,11 +93,36 @@ await Task.Run(() => DialogService.CreateAddAppointmentsDialog(this, NavigationService); return; } - ActiveAppointment = new ObservableAppointment { Date = DateTime.Today }; + ActiveAppointment = new ObservableAppointment + { + Date = DateOnly.FromDateTime(DateTime.Today) + }; DialogService.CreateCustomerSelectionDialog(this, NavigationService); }); } + [Command] + private async Task CancelAppointment(object param) + { + if (param is ObservableAppointment appointment) + { + await Task.Run(() => + { + var dialogResult = DialogService.Create( + "Appointments", + $"Cancel {appointment.Customer.FullName.Split(" ")[0]}'s Appointment?", + NavigationService + ); + + if (dialogResult is true) + { + Appointments.Remove(appointment); + GroomWiseDbContext.Appointments.Delete(appointment.Id); + } + }); + } + } + [Command] private async Task SelectCustomer(object param) { @@ -141,8 +169,8 @@ ActiveAppointment.Services is null } var dialogResult = DialogService.Create( - "GroomWise", - "Create Appointment?", + "Appointments", + $"Book Appointment for {ActiveAppointment.Customer.FullName.Split(" ")[0]}?", NavigationService ); if (dialogResult is true) @@ -153,7 +181,10 @@ ActiveAppointment.Services is null EventAggregator.Publish( new PublishNotificationEvent($"Appointment saved", NotificationType.Success) ); - ActiveAppointment = new ObservableAppointment { Date = DateTime.Today }; + ActiveAppointment = new ObservableAppointment + { + Date = DateOnly.FromDateTime(DateTime.Today) + }; OnPropertyChanged(nameof(ActiveAppointment.Date)); PopulateCollections(); } diff --git a/GroomWise.Application/ViewModels/DashboardViewModel.cs b/GroomWise.Application/ViewModels/DashboardViewModel.cs index ec0e9e3..383cf12 100644 --- a/GroomWise.Application/ViewModels/DashboardViewModel.cs +++ b/GroomWise.Application/ViewModels/DashboardViewModel.cs @@ -39,7 +39,9 @@ private async void PopulateCollections() await Task.Run(() => { var appointments = GroomWiseDbContext.Appointments - .GetMultiple(appointment => appointment.Date == DateTime.Today) + .GetMultiple( + appointment => appointment.Date == DateOnly.FromDateTime(DateTime.Today) + ) .Select(AppointmentMapper.ToObservable) .OrderBy(appointment => appointment.Date); Appointments = new ConcurrentObservableCollection(appointments); diff --git a/GroomWise.Domain/Entities/Appointment.cs b/GroomWise.Domain/Entities/Appointment.cs index c04e2ed..ce660cc 100644 --- a/GroomWise.Domain/Entities/Appointment.cs +++ b/GroomWise.Domain/Entities/Appointment.cs @@ -13,7 +13,9 @@ public class Appointment : IEntity { [BsonId] public Guid Id { get; set; } - public DateTime? Date { get; set; } + public DateOnly? Date { get; set; } + public TimeOnly? StartTime { get; set; } + public TimeOnly? EndTime { get; set; } public AppointmentStatus? Status { get; set; } public Pet? Pet { get; set; } public Customer? Customer { get; set; } diff --git a/GroomWise.WPF/Converters/DateOnlyToDateTimeConverter.cs b/GroomWise.WPF/Converters/DateOnlyToDateTimeConverter.cs new file mode 100644 index 0000000..c08325f --- /dev/null +++ b/GroomWise.WPF/Converters/DateOnlyToDateTimeConverter.cs @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Russell Camo (Russkyc).- All Rights Reserved +// +// Unauthorized copying or redistribution of all files, in source and binary forms via any medium +// without written, signed consent from the author is strictly prohibited. + +using System; +using System.Globalization; +using System.Windows.Data; + +namespace GroomWise.Converters; + +[ValueConversion(typeof(DateOnly), typeof(DateTime))] +public class DateOnlyToDateTimeConverter : IValueConverter +{ + public static DateOnlyToDateTimeConverter Instance = new(); + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var dt = (DateOnly)value; + return new DateTime(dt.Year, dt.Month, dt.Day); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + var d = (DateTime)value; + return DateOnly.FromDateTime(d); + } +} diff --git a/GroomWise.WPF/Views/Dialogs/AddAppointmentsView.xaml b/GroomWise.WPF/Views/Dialogs/AddAppointmentsView.xaml index c017b46..d05a025 100644 --- a/GroomWise.WPF/Views/Dialogs/AddAppointmentsView.xaml +++ b/GroomWise.WPF/Views/Dialogs/AddAppointmentsView.xaml @@ -49,7 +49,7 @@ Margin="5" VerticalAlignment="Top" IsEditable="True" - SelectedDate="{Binding ActiveAppointment.Date, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> + SelectedDate="{Binding ActiveAppointment.Date, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={x:Static converter:DateOnlyToDateTimeConverter.Instance}}" /> diff --git a/GroomWise.WPF/Views/Dialogs/AddServicesView.xaml b/GroomWise.WPF/Views/Dialogs/AddServicesView.xaml index d328e6a..4ffbcad 100644 --- a/GroomWise.WPF/Views/Dialogs/AddServicesView.xaml +++ b/GroomWise.WPF/Views/Dialogs/AddServicesView.xaml @@ -58,7 +58,7 @@ IsEditable="True" IsSynchronizedWithCurrentItem="True" Placeholder="Hours" - SelectedValue="{Binding ActiveGroomingService.HourSpan, UpdateSourceTrigger=PropertyChanged}"> + Text="{Binding ActiveGroomingService.HourSpan, UpdateSourceTrigger=PropertyChanged}"> 0 1 2 @@ -77,7 +77,7 @@ IsEditable="True" IsSynchronizedWithCurrentItem="True" Placeholder="Minutes" - SelectedValue="{Binding ActiveGroomingService.MinuteSpan, UpdateSourceTrigger=PropertyChanged}"> + Text="{Binding ActiveGroomingService.MinuteSpan, UpdateSourceTrigger=PropertyChanged}"> 0 5 10 diff --git a/GroomWise.WPF/Views/Templates/AppointmentCardTemplate.xaml b/GroomWise.WPF/Views/Templates/AppointmentCardTemplate.xaml index 4e1b1ff..7a661d4 100644 --- a/GroomWise.WPF/Views/Templates/AppointmentCardTemplate.xaml +++ b/GroomWise.WPF/Views/Templates/AppointmentCardTemplate.xaml @@ -8,6 +8,8 @@ xmlns:observables="clr-namespace:GroomWise.Application.Observables;assembly=GroomWise.Application" xmlns:pages="clr-namespace:GroomWise.Views.Pages" xmlns:russkyc="clr-namespace:org.russkyc.moderncontrols;assembly=Russkyc.ModernControls.WPF" + xmlns:viewModels="clr-namespace:GroomWise.Application.ViewModels;assembly=GroomWise.Application" + xmlns:wpf="clr-namespace:Material.Icons.WPF;assembly=Material.Icons.WPF" Height="75" d:DataContext="{d:DesignInstance observables:ObservableAppointment, IsDesignTimeCreatable=True}" @@ -29,10 +31,7 @@ HoverForeground="{DynamicResource fg-000}" PressedBackground="{DynamicResource bg-200}" PressedForeground="{DynamicResource fg-000}" /> - + @@ -44,7 +43,8 @@ Height="52" Margin="7,0,0,0" Background="{DynamicResource primary-default}" - CornerRadius="6"> + CornerRadius="6" + IsHitTestVisible="False"> + VerticalAlignment="Center" + IsHitTestVisible="False"> - +