diff --git a/TIAM.Database/DataLayers/Users/UserDal.cs b/TIAM.Database/DataLayers/Users/UserDal.cs index 04e0a18d..7d7a6075 100644 --- a/TIAM.Database/DataLayers/Users/UserDal.cs +++ b/TIAM.Database/DataLayers/Users/UserDal.cs @@ -37,6 +37,7 @@ namespace TIAM.Database.DataLayers.Users public Task GetUserModelDtoByIdAsync(Guid userId, bool onlyConfirmed) => SessionAsync(x => x.GetUserModelDtoById(userId, onlyConfirmed)); public Task GetUserModelDtoByEmailAsync(string email, bool onlyConfirmed) => SessionAsync(x => x.GetUserModelDtoByEmail(email, onlyConfirmed)); public Task> GetAllUsersModelDtoAsync() => SessionAsync(x => x.GetAllUsersModelDto().ToList()); + public Task> GetAllUsersModelDtoDetailAsync() => SessionAsync(x => x.GetAllUsersModelDetailDto().ToList()); public Task GetUserByPhoneNumberAsync(string phoneNumber) { diff --git a/TIAM.Entities/Emails/EmailMessage.cs b/TIAM.Entities/Emails/EmailMessage.cs index cb8f7f2a..43fe9321 100644 --- a/TIAM.Entities/Emails/EmailMessage.cs +++ b/TIAM.Entities/Emails/EmailMessage.cs @@ -1,6 +1,7 @@ using System.Collections.Specialized; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using AyCode.Entities.Messages; using AyCode.Interfaces.Entities; using AyCode.Interfaces.TimeStampInfo; using AyCode.Interfaces.Users; @@ -8,7 +9,7 @@ using AyCode.Interfaces.Users; namespace TIAM.Entities.Emails; [Table(nameof(EmailMessage))] -public class EmailMessage : IEntityGuid, ITimeStampInfo, IEmailRecipientsRelation, IEmailAddress +public class EmailMessage : NoticeBase, IEntityGuid, ITimeStampInfo, IEmailRecipientsRelation, IEmailAddress { public EmailMessage() { diff --git a/TIAMMobileApp/Services/UserDataServiceMobile.cs b/TIAMMobileApp/Services/UserDataServiceMobile.cs index 5e6dd506..85c7cb81 100644 --- a/TIAMMobileApp/Services/UserDataServiceMobile.cs +++ b/TIAMMobileApp/Services/UserDataServiceMobile.cs @@ -147,9 +147,14 @@ namespace TIAMMobileApp.Services return (isSuccess, user); } - public async Task?> GetUsersAsync() + public async Task?> GetUsersAsync() { - return await http.GetFromJsonAsync>(APIUrls.GetUsers); + return await http.GetFromJsonAsync>(APIUrls.GetUsers); + } + + public async Task?> GetUsersWithDetailsAsync() + { + return await http.GetFromJsonAsync>(APIUrls.GetUsersWithDetails); } public async Task GetUserByEmailAsync(string email) diff --git a/TIAMResources/TIAMResources.Designer.cs b/TIAMResources/TIAMResources.Designer.cs index a1080ab0..429472da 100644 --- a/TIAMResources/TIAMResources.Designer.cs +++ b/TIAMResources/TIAMResources.Designer.cs @@ -132,6 +132,15 @@ namespace TIAM.Resources { } } + /// + /// Looks up a localized string similar to Comment. + /// + public static string Comment { + get { + return ResourceManager.GetString("Comment", resourceCulture); + } + } + /// /// Looks up a localized string similar to Confirm Email. /// @@ -231,6 +240,15 @@ namespace TIAM.Resources { } } + /// + /// Looks up a localized string similar to Flight or train number. + /// + public static string FlightNumber { + get { + return ResourceManager.GetString("FlightNumber", resourceCulture); + } + } + /// /// Looks up a localized string similar to Forgot password?. /// @@ -294,6 +312,15 @@ namespace TIAM.Resources { } } + /// + /// Looks up a localized string similar to (if applicable). + /// + public static string Optional { + get { + return ResourceManager.GetString("Optional", resourceCulture); + } + } + /// /// Looks up a localized string similar to Password. /// diff --git a/TIAMResources/TIAMResources.hu.resx b/TIAMResources/TIAMResources.hu.resx index 47659a34..5b964a73 100644 --- a/TIAMResources/TIAMResources.hu.resx +++ b/TIAMResources/TIAMResources.hu.resx @@ -141,6 +141,9 @@ Küldés + + Megjegyzés + E-mail cím megerősítése @@ -174,6 +177,9 @@ E-mail + + Járatszám + Elfelejtett jelszó @@ -195,6 +201,9 @@ Utasok száma + + (ha van) + Jelszó diff --git a/TIAMResources/TIAMResources.resx b/TIAMResources/TIAMResources.resx index 7ecef8c6..55e6a1f7 100644 --- a/TIAMResources/TIAMResources.resx +++ b/TIAMResources/TIAMResources.resx @@ -141,6 +141,9 @@ Send + + Comment + Confirm Email @@ -174,6 +177,9 @@ Email + + Flight or train number + Forgot password? @@ -195,6 +201,9 @@ Passengers + + (if applicable) + Password diff --git a/TIAMSharedUI/Pages/Components/FullNameEditor.razor b/TIAMSharedUI/Pages/Components/FullNameEditor.razor new file mode 100644 index 00000000..9ccb75cc --- /dev/null +++ b/TIAMSharedUI/Pages/Components/FullNameEditor.razor @@ -0,0 +1,21 @@ +

+ @NullText +

+ + + + + + + +@code { + +} diff --git a/TIAMSharedUI/Pages/Components/FullNameEditor.razor.cs b/TIAMSharedUI/Pages/Components/FullNameEditor.razor.cs new file mode 100644 index 00000000..8065c94d --- /dev/null +++ b/TIAMSharedUI/Pages/Components/FullNameEditor.razor.cs @@ -0,0 +1,66 @@ +using DevExpress.Blazor; +using Microsoft.AspNetCore.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TIAMSharedUI.Pages.Components +{ + public partial class FullNameEditor : ComponentBase + { + + [Parameter] + public string FirstName { get; set; } + + [Parameter] + public string LastName { get; set; } + + public string FullName { get; set; } + + [Parameter] + public string NullText { get; set; } + + [Parameter] + public EventCallback FirstNameChanged { get; set; } + + [Parameter] + public EventCallback LastNameChanged { get; set; } + + public int InputDelay { get; set; } = 500; + public DxTextBox firstNameTextField; + public DxTextBox lastNameTextField; + + void OnFirstNameChanged(string newValue) + { + if (!string.IsNullOrEmpty(newValue)) + { + FirstName = newValue; + FullName = $"{newValue} {LastName}"; + } + else + { + FirstName = null; + firstNameTextField.Text = "Invalid data"; + } + FirstNameChanged.InvokeAsync(newValue); + } + void OnLastNameChanged(string newValue) + { + if (!string.IsNullOrEmpty(newValue)) + { + LastName = newValue; + FullName = $"{FirstName} {newValue}"; + } + else + { + LastName = null; + lastNameTextField.Text = "Invalid data"; + } + LastNameChanged.InvokeAsync(newValue); + } + + + } +} diff --git a/TIAMSharedUI/Pages/Components/InputWizard.razor.cs b/TIAMSharedUI/Pages/Components/InputWizard.razor.cs index 3ded9d9f..096b12f3 100644 --- a/TIAMSharedUI/Pages/Components/InputWizard.razor.cs +++ b/TIAMSharedUI/Pages/Components/InputWizard.razor.cs @@ -268,6 +268,8 @@ namespace TIAMSharedUI.Pages.Components editor.OpenComponent>(j); editor.AddAttribute(j++, "Date", property.GetValue(Data)); editor.AddAttribute(j++, "DateExpression", lambda); + editor.AddAttribute(j++, "TimeSectionVisible", true); + editor.AddAttribute(j++, "TimeSectionScrollPickerFormat", "tt h m"); editor.AddAttribute(j++, "CssClass", "form-field"); editor.AddAttribute(j++, "DateChanged", EventCallback.Factory.Create(this, str => { property.SetValue(Data, str); })); editor.CloseComponent(); @@ -378,6 +380,67 @@ namespace TIAMSharedUI.Pages.Components } + else if (property.PropertyType == typeof(string) && string.Compare(attrList.CustomDataType, "FullName", true) == 0) + { + + editor.OpenComponent(j); + editor.AddAttribute(j++, "NullText", "Please tell us your name."); + editor.AddAttribute(j++, "FirstNameChanged", EventCallback.Factory.Create(this, result => + { + LogToBrowserConsole.LogToBC($"FirstName changed to {result}"); + + //find property with name FirstName + PropertyInfo firstNameProperty = propertyList.FirstOrDefault(p => p.Name == "FirstName"); + firstNameProperty.SetValue(Data, result); + //find property with name LastName + PropertyInfo lastNameProperty = propertyList.FirstOrDefault(p => p.Name == "LastName"); + //combine the two values, if they are not null + if (firstNameProperty != null && lastNameProperty != null) + { + string firstName = result; + string lastName = (string)lastNameProperty.GetValue(Data); + string fullName = $"{firstName} {lastName}"; + property.SetValue(Data, fullName); + } + })); + + editor.AddAttribute(j++, "LastNameChanged", EventCallback.Factory.Create(this, result => + { + LogToBrowserConsole.LogToBC($"LastName changed to {result}"); + + //find property with name FirstName + PropertyInfo firstNameProperty = propertyList.FirstOrDefault(p => p.Name == "FirstName"); + //find property with name LastName + PropertyInfo lastNameProperty = propertyList.FirstOrDefault(p => p.Name == "LastName"); + lastNameProperty.SetValue(Data, result); + //combine the two values, if they are not null + if (firstNameProperty != null && lastNameProperty != null) + { + string firstName = (string)firstNameProperty.GetValue(Data); + string lastName = result; + string fullName = $"{firstName} {lastName}"; + property.SetValue(Data, fullName); + } + LogToBrowserConsole.LogToBC($"bleh: {property.Name} = {property.GetValue(Data)}"); + StateHasChanged(); // Add this line to refresh the UI + })); + + editor.CloseComponent(); + editor.OpenComponent(j++); + /*editor.AddAttribute(j++, "CssClass", "form-field");*/ + editor.AddAttribute(j++, "NullText", "Please type in the above fields"); + editor.AddAttribute(j++, "Enabled", false); + editor.AddAttribute(j++, "Text", property.GetValue(Data)); + editor.AddAttribute(j++, "TextExpression", lambda); + editor.AddAttribute(j++, "TextChanged", EventCallback.Factory.Create(this, str => + { + property.SetValue(Data, str); + LogToBrowserConsole.LogToBC($"bleh: {property.Name} = {property.GetValue(Data)}"); + })); + editor.CloseComponent(); + + } + break; } diff --git a/TIAMSharedUI/Pages/Formula1.razor b/TIAMSharedUI/Pages/Formula1.razor index 9da5d10b..cb0d6e64 100644 --- a/TIAMSharedUI/Pages/Formula1.razor +++ b/TIAMSharedUI/Pages/Formula1.razor @@ -378,12 +378,14 @@ new HeroSliderItem public List TransferIgnorList = new List { - "Id", + "Id", "UserId", "Destination", "PickupAddress", "ProductId", "TripDate", + "FirstName", + "LastName", "UserProductMappingId", "UserProductToCarId", "ReferralId", diff --git a/TIAMSharedUI/Pages/Index.razor b/TIAMSharedUI/Pages/Index.razor index 4d92efa7..4a44f4d4 100644 --- a/TIAMSharedUI/Pages/Index.razor +++ b/TIAMSharedUI/Pages/Index.razor @@ -125,15 +125,15 @@ public List TransferIgnorList = new List { - "Id", - "UserId", - "ProductId", + "Id", + "UserId", + "ProductId", + "FirstName", + "LastName", "UserProductMappingId", "UserProductToCarId", "ReferralId", - "Price", - "Driver", - "Comment" + "Price" }; /*protected override void OnAfterRender(bool isFirst) diff --git a/TIAMSharedUI/Pages/User/SysAdmins/Grid_MasterDetail_NestedGrid_DetailContent.razor b/TIAMSharedUI/Pages/User/SysAdmins/Grid_MasterDetail_NestedGrid_DetailContent.razor index 677472de..ede9c097 100644 --- a/TIAMSharedUI/Pages/User/SysAdmins/Grid_MasterDetail_NestedGrid_DetailContent.razor +++ b/TIAMSharedUI/Pages/User/SysAdmins/Grid_MasterDetail_NestedGrid_DetailContent.razor @@ -25,6 +25,7 @@ ColumnResizeMode="GridColumnResizeMode.NextColumn" ShowFilterRow="true"> + @@ -35,7 +36,7 @@ [Parameter] public bool KeyboardNavigationEnabled { get; set; } [Parameter] - public TIAM.Entities.Transfers.Transfer Customer { get; set; } + public Transfer Customer { get; set; } List DetailGridData { get; set; } diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageMessages.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageMessages.razor new file mode 100644 index 00000000..a845734d --- /dev/null +++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageMessages.razor @@ -0,0 +1,7 @@ +

ManageMessages

+ + + +@code { + +} diff --git a/TIAMSharedUI/Pages/User/SysAdmins/Products.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageProducts.razor similarity index 98% rename from TIAMSharedUI/Pages/User/SysAdmins/Products.razor rename to TIAMSharedUI/Pages/User/SysAdmins/ManageProducts.razor index 1861d934..42e8227d 100644 --- a/TIAMSharedUI/Pages/User/SysAdmins/Products.razor +++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageProducts.razor @@ -1,4 +1,4 @@ - +@page "/user/products" @using AyCode.Models.Messages @using TIAM.Entities.ServiceProviders @using TIAM.Resources @@ -8,6 +8,7 @@ @using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels @using TIAMWebApp.Shared.Application.Models.ClientSide.Messages @using TIAMWebApp.Shared.Application.Utility +@layout AdminLayout @inject LogToBrowserConsole logToBrowserConsole @inject IStringLocalizer localizer @@ -97,5 +98,6 @@ @code { + } diff --git a/TIAMSharedUI/Pages/User/SysAdmins/Products.razor.cs b/TIAMSharedUI/Pages/User/SysAdmins/ManageProducts.razor.cs similarity index 97% rename from TIAMSharedUI/Pages/User/SysAdmins/Products.razor.cs rename to TIAMSharedUI/Pages/User/SysAdmins/ManageProducts.razor.cs index 3bd7c8ba..a1df12ff 100644 --- a/TIAMSharedUI/Pages/User/SysAdmins/Products.razor.cs +++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageProducts.razor.cs @@ -11,15 +11,21 @@ using Microsoft.AspNetCore.Components; using TIAM.Entities.ServiceProviders; using TIAM.Core.Enums; using TIAMWebApp.Shared.Application.Services; +using TIAMWebApp.Shared.Application.Utility; namespace TIAMSharedUI.Pages.User.SysAdmins { - public partial class Products :ComponentBase + public partial class ManageProducts :ComponentBase { IGrid Grid { get; set; } object? ProductData { get; set; } + public void ColumnChooserButton_Click() + { + Grid.ShowColumnChooser(); + } + public ProductWizardModel myModel = new ProductWizardModel(); @@ -158,10 +164,5 @@ namespace TIAMSharedUI.Pages.User.SysAdmins } } - void ColumnChooserButton_Click() - { - Grid.ShowColumnChooser(); - } - } } diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor new file mode 100644 index 00000000..ec49909e --- /dev/null +++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageTransfers.razor @@ -0,0 +1,421 @@ +@page "/user/transfers" +@using AyCode.Models.Messages +@using BlazorAnimation +@using TIAM.Core.Enums +@using TIAM.Entities.ServiceProviders +@using TIAM.Entities.Transfers +@using TIAM.Models.Dtos.Users +@using TIAM.Resources +@using TIAMSharedUI.Pages.Components +@using TIAMSharedUI.Shared +@using TIAMWebApp.Shared.Application.Interfaces +@using TIAMWebApp.Shared.Application.Models +@using TIAMWebApp.Shared.Application.Models.ClientSide.UI +@using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels +@using TIAMWebApp.Shared.Application.Models.ClientSide.Messages +@using TIAMWebApp.Shared.Application.Models.PageModels +@using TIAMWebApp.Shared.Application.Utility +@layout AdminLayout +@inject LogToBrowserConsole logToBrowserConsole +@inject IStringLocalizer localizer +@inject IWizardProcessor wizardProcessor +@inject ITransferDataService transferDataService +Transfers + +
+

Transfer management

+

Manage transfers here!

+
+ + + + + + + + + + + +
+
+
+ +
+ + + + +
+
+ +
+ + + + + + + + + + + + + + + @{ + var keyField = context.Value; + var keyItem = (Transfer)context.DataItem; + string buttonText = "Contact"; + + } + + + + + + @{ + + TransferStatusModel keyField = Statuses.FirstOrDefault(x => x.StatusValue == Convert.ToInt16(context.Value)); + string transferStatusText = keyField.StatusName; +

@transferStatusText

+ } +
+
+
+ + + + + @{ + var transfer2 = (Transfer)EditFormContext.EditModel; + } + + + @EditFormContext.GetEditor("FirstName") + + + @EditFormContext.GetEditor("LastName") + + + @EditFormContext.GetEditor("ToAddress") + + + @EditFormContext.GetEditor("FromAddress") + + + + + + + + + @EditFormContext.GetEditor("PassengerCount") + + + + @EditFormContext.GetEditor("TransferStatusType") + + + + + + +
+ +
+
+ + +
+ + + + + + + + + + +
+
+
+ + + + + +
+ + +
+
+ +
+
+ +
+
+ + +@code { + + + public Transfer myModel = new Transfer(); + + public List TransferData { get; set; } + + bool PopupVisible { get; set; } + public List ignoreList = new List + { + "ReceiverEmailAddress", + "ReceiverId", + "SenderEmailAddress", + "SenderId", + "ContextId" + }; + + public List? Statuses { get; set; } + + public MessageWizardModel messageWizardModel = new MessageWizardModel(); + + public List? AppoinmentData { get; set; } + + DateTime StartDate { get; set; } = DateTime.Today; + DxSchedulerDataStorage DataStorage = new DxSchedulerDataStorage(); + + + void SendMail(Transfer Item) + { + logToBrowserConsole.LogToBC($"Sending mail to {Item.ContactEmail}"); + PopupVisible = true; + } + + void CancelCreateClick() + { + + PopupVisible = false; + } + void EulaPopupClosed() + { + //cancel clicked + + } + void EulaPopupClosing(PopupClosingEventArgs args) + { + //myModel = new TransferWizardModel(); + messageWizardModel = new MessageWizardModel(); + } + + //----------------------------------------------------------------------------------- + + + public async Task SubmitForm(object Result) + { + var email = await wizardProcessor.ProcessWizardAsync(Result.GetType(), Result); + + logToBrowserConsole.LogToBC($"Submitted nested form: {Result.GetType().FullName}"); + } + + void Grid_CustomizeElement(GridCustomizeElementEventArgs e) + { + if (e.ElementType == GridElementType.DataRow && (System.Byte)e.Grid.GetRowValue(e.VisibleIndex, "TransferStatusType") == 5) + { + e.CssClass = "bg-important"; + } + else if (e.ElementType == GridElementType.DataRow && (System.Byte)e.Grid.GetRowValue(e.VisibleIndex, "TransferStatusType") > 5 && (System.Byte)e.Grid.GetRowValue(e.VisibleIndex, "TransferStatusType") < 35) + { + e.CssClass = "bg-attention"; + } + else if (e.ElementType == GridElementType.DataRow && (System.Byte)e.Grid.GetRowValue(e.VisibleIndex, "TransferStatusType") == 35) + { + e.CssClass = "bg-finished"; + } + else if (e.ElementType == GridElementType.DataRow && (System.Byte)e.Grid.GetRowValue(e.VisibleIndex, "TransferStatusType") > 35) + { + e.CssClass = "bg-cancel"; + } + if (e.ElementType == GridElementType.HeaderCell) + { + e.Style = "background-color: rgba(0, 0, 0, 0.08)"; + e.CssClass = "header-bold"; + } + } + + void Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e) + { + if (e.IsNew) + { + var transferEditModel = (Transfer)e.EditModel; //TODO not valid cast + transferEditModel.Id = Guid.NewGuid(); + transferEditModel.ToAddress = "Where to?"; + transferEditModel.FromAddress = "From where?"; + transferEditModel.Appointment = DateTime.UtcNow.AddDays(3); + transferEditModel.PassengerCount = 1; + transferEditModel.FirstName = "John"; + transferEditModel.LastName = "Doe"; + transferEditModel.ContactPhone = "+00000000000"; + transferEditModel.ContactEmail = "your@email.address"; + } + } + + async Task Grid_EditModelSaving(GridEditModelSavingEventArgs e) + { + bool success = false; + if (e.IsNew) + { + //add new orderData to orderData array + logToBrowserConsole.LogToBC("New orderData added"); + //await transferDataService.CreateTransfer((TransferWizardModel)e.EditModel); + } + else + { + logToBrowserConsole.LogToBC("orderData updated at id " + ((Transfer)e.EditModel).Id); + + success = await transferDataService.UpdateTransferAsync((Transfer)e.EditModel); + + } + //get transfer from TransferData by Id + + // foreach (var transferToModify in (List)TransferData) + // { + // myModel = (Transfer)e.EditModel; + + // if (transferToModify.Id == myModel.Id) + // { + // //transferToModify.Driver = myModel.Driver; + // } + // } + if (success) + await UpdateDataAsync(); + } + async Task Grid_DataItemDeleting(GridDataItemDeletingEventArgs e) + { + //await NwindDataService.RemoveEmployeeAsync((EditableEmployee)e.DataItem); + //remove orderData from orderData array + logToBrowserConsole.LogToBC("orderData deleted"); + //await UpdateDataAsync(); + } + async Task UpdateDataAsync() + { + //refresh grid + TransferData = await transferDataService.GetTransfersAsync(); + logToBrowserConsole.LogToBC("orderData grid refreshed"); + } + + protected override async Task OnInitializedAsync() + { + Statuses = new List + { + new TransferStatusModel(Convert.ToInt16(TransferStatusType.OrderSubmitted), "Order submitted"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.OrderConfirmed), "Order confirmed"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.AssignedToDriver), "Assigned to driver"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.DriverConfirmed), "Driver confirmed"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.DriverEnRoute), "Driver enroute"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.PassengerPickup), "Passenger in car"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.Finished), "Finished"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.UserCanceled), "User cancelled"), + new TransferStatusModel(Convert.ToInt16(TransferStatusType.AdminDenied), "Admin cancelled") + }; + TransferData = (await transferDataService.GetTransfersAsync()).OrderBy(x => x.TransferStatusType).ThenByDescending(x => x.OrderId).ToList(); + AppoinmentData = new List(); + foreach (var transfer in TransferData) + { + // var bnm = DataStorage.CreateAppointmentItem(); + // bnm.Start = transfer.Appointment; + // bnm.Description = $"{transfer.FullName}, {transfer.ToAddress}"; + // bnm.Location = transfer.FromAddress; + // bnm.Subject = "Simple transfer"; + + AppoinmentData.Add(new AppointmentModel { StartDate = transfer.Appointment, EndDate=transfer.Appointment.AddMinutes(30), Description = $"{transfer.FullName}, {transfer.ToAddress}", Location = transfer.FromAddress, Caption = "Simple transfer" }); + } + + DataStorage = new DxSchedulerDataStorage(); + DataStorage.AppointmentMappings = new DxSchedulerAppointmentMappings() + { + Type = "AppointmentType", + Start = "StartDate", + End = "EndDate", + Subject = "Caption", + AllDay = "AllDay", + Location = "Location", + Description = "Description", + LabelId = "Label", + StatusId = "Status", + RecurrenceInfo = "Recurrence" + }; + DataStorage.AppointmentsSource = AppoinmentData; + + + base.OnInitialized(); + + } + + void ColumnChooserButton_Click() + { + Grid2.ShowColumnChooser(); + } + + IGrid Grid2 { get; set; } + object MasterGridData { get; set; } + bool AutoCollapseDetailRow { get; set; } + + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + Grid2.ExpandDetailRow(0); + } + } + void AutoCollapseDetailRow_Changed(bool newValue) + { + AutoCollapseDetailRow = newValue; + if (newValue) + { + Grid2.BeginUpdate(); + Grid2.CollapseAllDetailRows(); + Grid2.ExpandDetailRow(0); + Grid2.EndUpdate(); + } + } +} + + + diff --git a/TIAMSharedUI/Pages/User/SysAdmins/ManageUsers.razor b/TIAMSharedUI/Pages/User/SysAdmins/ManageUsers.razor new file mode 100644 index 00000000..67ddf023 --- /dev/null +++ b/TIAMSharedUI/Pages/User/SysAdmins/ManageUsers.razor @@ -0,0 +1,337 @@ +@page "/user/users" +@using AyCode.Models.Messages +@using BlazorAnimation +@using TIAM.Core.Enums +@using TIAM.Entities.Products +@using TIAM.Entities.ServiceProviders +@using TIAM.Entities.Transfers +@using TIAM.Entities.Users +@using TIAM.Models.Dtos.Profiles +@using TIAM.Models.Dtos.Users +@using TIAM.Resources +@using TIAMSharedUI.Pages.Components +@using TIAMSharedUI.Shared +@using TIAMWebApp.Shared.Application.Interfaces +@using TIAMWebApp.Shared.Application.Models +@using TIAMWebApp.Shared.Application.Models.ClientSide.UI +@using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels +@using TIAMWebApp.Shared.Application.Models.ClientSide.Messages +@using TIAMWebApp.Shared.Application.Models.PageModels +@using TIAMWebApp.Shared.Application.Utility +@layout AdminLayout +@inject LogToBrowserConsole logToBrowserConsole +@inject IStringLocalizer localizer +@inject ISessionService sessionService +@inject IWizardProcessor wizardProcessor +@inject IUserDataService userDataService +Transfers + +
+

User management

+

Manage transfers here!

+
+ + + + + + + + + + +
+
+
+ +
+
+
+ +
+ + + + + + + + + + + + + + @{ + var keyField = context.Value; + var keyItem = (UserModelDtoDetail)context.DataItem; + + string buttonText = "Contact"; + + } + + + + + + + + @{ + var transfer2 = (UserModelDtoDetail)EditFormContext.EditModel; + } + + + @EditFormContext.GetEditor("UserDto.EmailAddress") + + + @EditFormContext.GetEditor("UserDto.EmailAddress") + + + @EditFormContext.GetEditor("UserDto.EmailConfirmed") + + + @EditFormContext.GetEditor("UserDto.PhoneNumber") + + + @EditFormContext.GetEditor("Profile.FirstName") + + + @EditFormContext.GetEditor("Profile.LastName") + + + + + + + + + +
+ +
+
+
+ +
+
+ +
+
+ +@code { + public UserModelDtoDetail myModel = new UserModelDtoDetail(); + + public List? UserData { get; set; } + + bool PopupVisible { get; set; } + + IGrid? Grid { get; set; } + object? MasterGridData { get; set; } + bool AutoCollapseDetailRow { get; set; } + + public List ignoreList = new List + { + "ReceiverEmailAddress", + "ReceiverId", + "SenderEmailAddress", + "SenderId", + "ContextId" + }; + + public MessageWizardModel messageWizardModel = new MessageWizardModel(); + + + + + async void SendMail(UserModelDtoDetail Item) + { + var user = await userDataService.GetUserDetailByIdAsync(Item.Id); + logToBrowserConsole.LogToBC($"Sending mail to {user.UserDto.EmailAddress}"); + + messageWizardModel.ReceiverId = user.Id; + messageWizardModel.ReceiverEmailAddress = user.UserDto.EmailAddress; + messageWizardModel.SenderId = sessionService.User.UserId; + messageWizardModel.SenderEmailAddress = sessionService.User.Email; + logToBrowserConsole.LogToBC($"Sending mail to {messageWizardModel.ReceiverEmailAddress} from {messageWizardModel.SenderId}"); + PopupVisible = true; + } + + void CancelCreateClick() + { + + PopupVisible = false; + } + void EulaPopupClosed() + { + //cancel clicked + + } + void EulaPopupClosing(PopupClosingEventArgs args) + { + //myModel = new TransferWizardModel(); + messageWizardModel = new MessageWizardModel(); + } + + //----------------------------------------------------------------------------------- + + + public async Task SubmitForm(object Result) + { + var email = await wizardProcessor.ProcessWizardAsync(Result.GetType(), Result); + + logToBrowserConsole.LogToBC($"Submitted nested form: {Result.GetType().FullName}"); + } + + void Grid_CustomizeElement(GridCustomizeElementEventArgs e) + { + if (e.ElementType == GridElementType.DataRow && e.VisibleIndex % 2 == 1) + { + e.CssClass = "bg-alt"; + } + if (e.ElementType == GridElementType.HeaderCell) + { + e.Style = "background-color: rgba(0, 0, 0, 0.08); font-style=bold"; + + } + } + + + void Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e) + { + if (e.IsNew) + { + var userEditModel = (UserModelDtoDetail)e.EditModel; //TODO not valid cast + userEditModel.Id = Guid.NewGuid(); + + userEditModel.UserDto = new UserDtoDetail(); + userEditModel.UserDto.AffiliateId = Guid.NewGuid(); + userEditModel.UserDto.EmailAddress = ""; + userEditModel.UserDto.PhoneNumber = ""; + userEditModel.Profile = new ProfileDto(); + userEditModel.Profile.Name = "New user"; + + userEditModel.Products = new List(); + + userEditModel.ServiceProviders = new List(); + + userEditModel.UserProductMappings = new List(); + } + } + + async Task Grid_EditModelSaving(GridEditModelSavingEventArgs e) + { + if (e.IsNew) + { + //add new orderData to orderData array + RegistrationModel registration = new RegistrationModel(); + //TODO: Refractor to userDataService + Random random = new Random(); + string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + string password = new string(Enumerable.Repeat(chars, 10) + .Select(s => s[random.Next(s.Length)]).ToArray()); + + registration.Email = ((UserModelDtoDetail)e.EditModel).UserDto.EmailAddress; + registration.PhoneNumber = ((UserModelDtoDetail)e.EditModel).UserDto.PhoneNumber; + registration.Password = password; + registration.ReferralId = null; + + + await userDataService.CreateGuestUser(registration); + logToBrowserConsole.LogToBC("New user created added"); + } + else + { + logToBrowserConsole.LogToBC("orderData updated at id " + ((UserModelDtoDetail)e.EditModel).Id); + + //await transferDataService.UpdateTransferAsync((TransferWizardModel)e.EditModel); + //modify transferData where transferData.Id == e.EditModel.Id + } + //get transfer from TransferData by Id + + // foreach (var transferToModify in (List)TransferData) + // { + // myModel = (Transfer)e.EditModel; + + // if (transferToModify.Id == myModel.Id) + // { + // //transferToModify.Driver = myModel.Driver; + // } + // } + + await UpdateDataAsync(); + } + async Task Grid_DataItemDeleting(GridDataItemDeletingEventArgs e) + { + //await NwindDataService.RemoveEmployeeAsync((EditableEmployee)e.DataItem); + //remove orderData from orderData array + logToBrowserConsole.LogToBC("orderData deleted"); + //await UpdateDataAsync(); + } + async Task UpdateDataAsync() + { + //refresh grid + UserData = await userDataService.GetUsersWithDetailsAsync(); + logToBrowserConsole.LogToBC("orderData grid refreshed"); + } + + protected override async Task OnInitializedAsync() + { + UserData = (await userDataService.GetUsersWithDetailsAsync())?.OrderBy(x => x.Profile?.Name).ToList(); + base.OnInitialized(); + } + + void ColumnChooserButton_Click() + { + Grid?.ShowColumnChooser(); + } + + protected override void OnAfterRender(bool firstRender) + { + if (firstRender) + { + Grid?.ExpandDetailRow(0); + } + } + void AutoCollapseDetailRow_Changed(bool newValue) + { + AutoCollapseDetailRow = newValue; + if (newValue) + { + Grid?.BeginUpdate(); + Grid?.CollapseAllDetailRows(); + Grid?.ExpandDetailRow(0); + Grid?.EndUpdate(); + } + } +} diff --git a/TIAMSharedUI/Pages/User/SysAdmins/TransferManagement.razor b/TIAMSharedUI/Pages/User/SysAdmins/TransferManagement.razor deleted file mode 100644 index 361d8676..00000000 --- a/TIAMSharedUI/Pages/User/SysAdmins/TransferManagement.razor +++ /dev/null @@ -1,393 +0,0 @@ -@page "/user/transfers" -@using AyCode.Models.Messages -@using BlazorAnimation -@using TIAM.Core.Enums -@using TIAM.Entities.ServiceProviders -@using TIAM.Entities.Transfers -@using TIAM.Models.Dtos.Users -@using TIAM.Resources -@using TIAMSharedUI.Pages.Components -@using TIAMSharedUI.Shared -@using TIAMWebApp.Shared.Application.Interfaces -@using TIAMWebApp.Shared.Application.Models -@using TIAMWebApp.Shared.Application.Models.ClientSide.UI -@using TIAMWebApp.Shared.Application.Models.ClientSide.UI.WizardModels -@using TIAMWebApp.Shared.Application.Models.ClientSide.Messages -@using TIAMWebApp.Shared.Application.Utility -@layout AdminLayout -@inject LogToBrowserConsole logToBrowserConsole -@inject IStringLocalizer localizer -@inject IWizardProcessor wizardProcessor -@inject ITransferDataService transferDataService -Transfers - -
-

Transfer management

-

Manage transfers here!

-
- -
-
-
- -
-
- - - - - - - - - - - - - - @{ - - TransferStatusModel keyField = Statuses.FirstOrDefault(x => x.StatusValue == Convert.ToInt16(context.Value)); - string driverText = keyField.StatusName; -

@driverText

- } -
-
-
- - - - - @{ - var transfer2 = (Transfer)EditFormContext.EditModel; - } - - - @EditFormContext.GetEditor("ToAddress") - - - @EditFormContext.GetEditor("FromAddress") - - - @EditFormContext.GetEditor("Appointment") - - - @EditFormContext.GetEditor("PassengerCount") - - - - @EditFormContext.GetEditor("TransferStatusType") - - - - - - -
- -
- - -
-
- -
- - - - - - - - - - - - @{ - var keyField = context.Value; - @context.Value - } - - - - - - @* *@ - @* - - - @{ - var keyField = context.Value; - var keyItem = (TransferWizardModel)context.DataItem; - string buttonText = "Contact"; - - } - - *@ - @* - - @{ - DriverModel keyField = (DriverModel)context.Value; - string driverText = keyField.Name; -

@driverText

- } -
-
*@ - -
- - - @{ - var transfer = (TransferWizardModel)EditFormContext.EditModel; - } - - - @EditFormContext.GetEditor("ToAddress") - - - @EditFormContext.GetEditor("FromAddress") - - - @EditFormContext.GetEditor("Appointment") - - - @EditFormContext.GetEditor("PassengerCount") - - @* - @EditFormContext.GetEditor("FullName") - - - @EditFormContext.GetEditor("PhoneNumber") - - - @EditFormContext.GetEditor("EmailAddress") - *@ - @* - - - *@ - - - - -
- - -
- - - - -
-
-
- -
-
- -
-
- - -@code { - - IGrid Grid { get; set; } - //object? TransferData { get; set; } - - public TransferWizardModel myModel = new TransferWizardModel(); - - public List TransferData { get; set; } - - bool PopupVisible { get; set; } - public List ignoreList = new List - { - "ReceiverEmailAddress", - "ReceiverId", - "SenderEmailAddress", - "SenderId", - "ContextId" - }; - - public List Statuses { get; set; } - - public MessageWizardModel messageWizardModel = new MessageWizardModel(); - - //IEnumerable drivers { get; set; } - - - void SendMail(TransferWizardModel Item) - { - logToBrowserConsole.LogToBC($"Sending mail to {Item.EmailAddress}"); - PopupVisible = true; - } - - void CancelCreateClick() - { - - PopupVisible = false; - } - void EulaPopupClosed() - { - //cancel clicked - - } - void EulaPopupClosing(PopupClosingEventArgs args) - { - //myModel = new TransferWizardModel(); - messageWizardModel = new MessageWizardModel(); - } - - //----------------------------------------------------------------------------------- - - - public async Task SubmitForm(object Result) - { - var email = await wizardProcessor.ProcessWizardAsync(Result.GetType(), Result); - - logToBrowserConsole.LogToBC($"Submitted nested form: {Result.GetType().FullName}"); - } - - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - //if (firstRender) - // await Grid.StartEditRowAsync(0); - } - - void Grid_CustomizeEditModel(GridCustomizeEditModelEventArgs e) - { - if (e.IsNew) - { - var newEmployee = (TransferWizardModel)e.EditModel; - newEmployee.Id = Guid.NewGuid(); - newEmployee.Destination = "ghjgkg hkgh ghjkghgkjgh"; - newEmployee.PickupAddress = "ghjgkg hkgh ghjkghgkjgh"; - newEmployee.TripDate = DateTime.UtcNow.AddDays(3); - newEmployee.NumberOfPassengers = 1; - newEmployee.FullName = "ghjgkg hkgh ghjkghgkjgh"; - newEmployee.PhoneNumber = "+13021234567"; - newEmployee.EmailAddress = "ghjgkg hkgh ghjkghgkjgh"; - } - } - - async Task Grid_EditModelSaving(GridEditModelSavingEventArgs e) - { - if (e.IsNew) - //add new orderData to orderData array - logToBrowserConsole.LogToBC("New orderData added"); - //await NwindDataService.InsertEmployeeAsync((EditableEmployee)e.EditModel); - else - logToBrowserConsole.LogToBC("orderData updated"); - //modify transferData where transferData.Id == e.EditModel.Id - //get transfer from TransferData by Id - - foreach (var transferToModify in (List)TransferData) - { - myModel = (TransferWizardModel)e.EditModel; - - if (transferToModify.Id == myModel.Id) - { - //transferToModify.Driver = myModel.Driver; - } - } - - //await NwindDataService.UpdateEmployeeAsync((EditableEmployee)e.DataItem, (EditableEmployee)e.EditModel); - await UpdateDataAsync(); - } - async Task Grid_DataItemDeleting(GridDataItemDeletingEventArgs e) - { - //await NwindDataService.RemoveEmployeeAsync((EditableEmployee)e.DataItem); - //remove orderData from orderData array - logToBrowserConsole.LogToBC("orderData deleted"); - //await UpdateDataAsync(); - } - async Task UpdateDataAsync() - { - //DataSource = await NwindDataService.GetEmployeesEditableAsync(); - //refresh grid - logToBrowserConsole.LogToBC("orderData grid refreshed"); - } - - protected override async Task OnInitializedAsync() - { - Statuses = new List - { - new TransferStatusModel(Convert.ToInt16(TransferStatusType.OrderSubmitted), "Order submitted"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.OrderConfirmed), "Order confirmed"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.AssignedToDriver), "Assigned to driver"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.DriverConfirmed), "Driver confirmed"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.DriverEnRoute), "Driver enroute"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.PassengerPickup), "Passenger in car"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.Finished), "Finished"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.UserCanceled), "User cancelled"), - new TransferStatusModel(Convert.ToInt16(TransferStatusType.AdminDenied), "Admin cancelled") - }; - TransferData = (await transferDataService.GetTransfersAsync()).OrderBy(x => x.TransferStatusType).ThenByDescending(x => x.OrderId).ToList(); - base.OnInitialized(); - - } - - void ColumnChooserButton_Click() - { - Grid2.ShowColumnChooser(); - } - - IGrid Grid2 { get; set; } - object MasterGridData { get; set; } - bool AutoCollapseDetailRow { get; set; } - - protected override void OnAfterRender(bool firstRender) - { - if (firstRender) - { - Grid2.ExpandDetailRow(0); - } - } - void AutoCollapseDetailRow_Changed(bool newValue) - { - AutoCollapseDetailRow = newValue; - if (newValue) - { - Grid2.BeginUpdate(); - Grid2.CollapseAllDetailRows(); - Grid2.ExpandDetailRow(0); - Grid2.EndUpdate(); - } - } -} - - - diff --git a/TIAMSharedUI/Pages/User/SysAdmins/UserGrid_MasterDetail_NestedGrid_ServiceProviders.razor b/TIAMSharedUI/Pages/User/SysAdmins/UserGrid_MasterDetail_NestedGrid_ServiceProviders.razor new file mode 100644 index 00000000..3ceb542f --- /dev/null +++ b/TIAMSharedUI/Pages/User/SysAdmins/UserGrid_MasterDetail_NestedGrid_ServiceProviders.razor @@ -0,0 +1,122 @@ +@using TIAM.Entities.Products +@using TIAM.Entities.ServiceProviders +@using TIAM.Entities.Transfers +@using TIAM.Entities.Drivers +@using TIAM.Entities.Users +@using TIAM.Models.Dtos.Users +@using TIAMWebApp.Shared.Application.Interfaces +@using TIAMWebApp.Shared.Application.Utility +@inject IUserDataService NwindDataService +@inject IServiceProviderDataService serviceProviderDataService +@inject LogToBrowserConsole logToBrowserConsole + +
+ UserProductMapping +
+ + + + + + + + + + @{ + var transfer2 = (UserProductMapping)EditFormContext.EditModel; + } + + + @EditFormContext.GetEditor("UserId") + + + + + + @EditFormContext.GetEditor("Permissions") + + + + + + + + + +@code { + [Parameter] + public bool KeyboardNavigationEnabled { get; set; } + [Parameter] + public UserModelDtoDetail Customer { get; set; } + + List DetailGridData; + + List AvailableServices; + + public UserModelDtoDetail UserInfo; + + protected override async Task OnInitializedAsync() + { + + //get userproductmappings by customer id + if (Customer.ServiceProviders == null) + DetailGridData = new List(); + else + DetailGridData = Customer.ServiceProviders; + + AvailableServices = await serviceProviderDataService.GetServiceProvidersAsync(); + logToBrowserConsole.LogToBC($"DetailGridData: {DetailGridData.Count}"); + } + + void CustomizeEditModel(GridCustomizeEditModelEventArgs e) + { + if (e.IsNew) + { + UserProductMapping newProductMapping = new UserProductMapping(); + newProductMapping.ProductId = Guid.NewGuid(); + newProductMapping.UserId = Customer.Id; + newProductMapping.Permissions = 1; + + e.EditModel = newProductMapping; + } + } + + async Task EditModelSaving(GridEditModelSavingEventArgs e) + { + if (e.IsNew) + //add new orderData to orderData array + logToBrowserConsole.LogToBC("New orderData added"); + //await NwindDataService.InsertEmployeeAsync((EditableEmployee)e.EditModel); + else + logToBrowserConsole.LogToBC("orderData updated"); + + //await NwindDataService.UpdateEmployeeAsync((EditableEmployee)e.DataItem, (EditableEmployee)e.EditModel); + + await UpdateDataAsync(); + } + async Task DataItemDeleting(GridDataItemDeletingEventArgs e) + { + //await NwindDataService.RemoveEmployeeAsync((EditableEmployee)e.DataItem); + //remove orderData from orderData array + logToBrowserConsole.LogToBC("orderData deleted"); + //await UpdateDataAsync(); + } + async Task UpdateDataAsync() + { + //DataSource = await NwindDataService.GetEmployeesEditableAsync(); + //refresh grid + logToBrowserConsole.LogToBC("orderData grid refreshed"); + } + +} \ No newline at end of file diff --git a/TIAMSharedUI/Pages/User/SysAdmins/UserGrid_MasterDetail_NestedGrid_UserProductMapping.razor b/TIAMSharedUI/Pages/User/SysAdmins/UserGrid_MasterDetail_NestedGrid_UserProductMapping.razor new file mode 100644 index 00000000..52b7990d --- /dev/null +++ b/TIAMSharedUI/Pages/User/SysAdmins/UserGrid_MasterDetail_NestedGrid_UserProductMapping.razor @@ -0,0 +1,121 @@ +@using TIAM.Entities.Products +@using TIAM.Entities.Transfers +@using TIAM.Entities.Drivers +@using TIAM.Entities.Users +@using TIAM.Models.Dtos.Users +@using TIAMWebApp.Shared.Application.Interfaces +@using TIAMWebApp.Shared.Application.Utility +@inject IUserDataService NwindDataService +@inject IServiceProviderDataService serviceProviderDataService +@inject LogToBrowserConsole logToBrowserConsole + +
+ UserProductMapping +
+ + + + + + + + + + @{ + var transfer2 = (UserProductMapping)EditFormContext.EditModel; + } + + + @EditFormContext.GetEditor("UserId") + + + + + + @EditFormContext.GetEditor("Permissions") + + + + + + + + + +@code { + [Parameter] + public bool KeyboardNavigationEnabled { get; set; } + [Parameter] + public UserModelDtoDetail Customer { get; set; } + + List DetailGridData; + + List AvailableProducts; + + public UserModelDtoDetail UserInfo; + + protected override async Task OnInitializedAsync() + { + + //get userproductmappings by customer id + if (Customer.UserProductMappings == null) + DetailGridData = new List(); + else + DetailGridData = Customer.UserProductMappings; + + AvailableProducts = await serviceProviderDataService.GetAllProductsAsync(); + logToBrowserConsole.LogToBC($"DetailGridData: {DetailGridData.Count}"); + } + + void CustomizeEditModel(GridCustomizeEditModelEventArgs e) + { + if (e.IsNew) + { + UserProductMapping newProductMapping = new UserProductMapping(); + newProductMapping.ProductId = Guid.NewGuid(); + newProductMapping.UserId = Customer.Id; + newProductMapping.Permissions = 1; + + e.EditModel = newProductMapping; + } + } + + async Task EditModelSaving(GridEditModelSavingEventArgs e) + { + if (e.IsNew) + //add new orderData to orderData array + logToBrowserConsole.LogToBC("New orderData added"); + //await NwindDataService.InsertEmployeeAsync((EditableEmployee)e.EditModel); + else + logToBrowserConsole.LogToBC("orderData updated"); + + //await NwindDataService.UpdateEmployeeAsync((EditableEmployee)e.DataItem, (EditableEmployee)e.EditModel); + + await UpdateDataAsync(); + } + async Task DataItemDeleting(GridDataItemDeletingEventArgs e) + { + //await NwindDataService.RemoveEmployeeAsync((EditableEmployee)e.DataItem); + //remove orderData from orderData array + logToBrowserConsole.LogToBC("orderData deleted"); + //await UpdateDataAsync(); + } + async Task UpdateDataAsync() + { + //DataSource = await NwindDataService.GetEmployeesEditableAsync(); + //refresh grid + logToBrowserConsole.LogToBC("orderData grid refreshed"); + } + +} \ No newline at end of file diff --git a/TIAMSharedUI/Shared/Users/AdminNavMenu.razor b/TIAMSharedUI/Shared/Users/AdminNavMenu.razor index 0be24562..a214d2e5 100644 --- a/TIAMSharedUI/Shared/Users/AdminNavMenu.razor +++ b/TIAMSharedUI/Shared/Users/AdminNavMenu.razor @@ -66,6 +66,11 @@ Transfers +