| @inject PageHistoryManager PageHistoryManager | @inject PageHistoryManager PageHistoryManager | ||||
| @inject ReportDataProvider ReportDataProvider | @inject ReportDataProvider ReportDataProvider | ||||
| @inject Toaster Toaster | @inject Toaster Toaster | ||||
| @inject InputCursorHandler InputCursorHandler; | |||||
| <div class="row px-3 h-100"> | <div class="row px-3 h-100"> | ||||
| </div> | </div> | ||||
| <div class="row no-gutters w-100"> | <div class="row no-gutters w-100"> | ||||
| <div class="col-6" style="padding-right:0.5em"> | <div class="col-6" style="padding-right:0.5em"> | ||||
| <MatStringField Class="w-100" Label="@I18n["Firstname"]" Outlined="true" type="text" @bind-Value="@Account.Firstname" Required="true"></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["Firstname"]" Outlined="true" type="text" @bind-Value="@Account.Firstname" Required="true" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| <div class="col-6" style="padding-left:0.5em"> | <div class="col-6" style="padding-left:0.5em"> | ||||
| <MatStringField Class="w-100" Label="@I18n["Lastname"]" Outlined="true" type="text" @bind-Value="@Account.Lastname" Required="true"></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["Lastname"]" Outlined="true" type="text" @bind-Value="@Account.Lastname" Required="true" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row no-gutters align-items-center w-100"> | <div class="row no-gutters align-items-center w-100"> | ||||
| <div class="col-12"> | <div class="col-12"> | ||||
| <MatStringField Class="w-100" Label="@I18n["Address"]" Outlined="true" type="text" @bind-Value="@Account.Address" ></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["Address"]" Outlined="true" type="text" @bind-Value="@Account.Address" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row no-gutters align-items-center w-100"> | <div class="row no-gutters align-items-center w-100"> | ||||
| <div class="col-4" style="padding-right:0.5em"> | <div class="col-4" style="padding-right:0.5em"> | ||||
| <MatStringField Class="w-100" Label="@I18n["Zip"]" Outlined="true" type="text" @bind-Value="@Account.Zip"></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["Zip"]" Outlined="true" type="text" @bind-Value="@Account.Zip" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| <div class="col-8" style="padding-left:0.5em"> | <div class="col-8" style="padding-left:0.5em"> | ||||
| <MatStringField Class="w-100" Label="@I18n["City"]" Outlined="true" type="text" @bind-Value="@Account.City"></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["City"]" Outlined="true" type="text" @bind-Value="@Account.City" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row no-gutters align-items-center w-100"> | <div class="row no-gutters align-items-center w-100"> | ||||
| <div class="col-12"> | <div class="col-12"> | ||||
| <MatStringField Class="w-100" Label="@I18n["Phone"]" Outlined="true" type="text" @bind-Value="@Account.Phone" Required="true"></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["Phone"]" Outlined="true" type="text" @bind-Value="@Account.Phone" Required="true" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row no-gutters align-items-center w-100"> | <div class="row no-gutters align-items-center w-100"> | ||||
| <div class="col-12"> | <div class="col-12"> | ||||
| <MatStringField Class="w-100" Label="@I18n["Mail"]" Outlined="true" type="text" @bind-Value="@Account.Email"></MatStringField> | |||||
| <MatStringField Class="w-100" Label="@I18n["Mail"]" Outlined="true" type="text" @bind-Value="@Account.Email" | |||||
| OnKeyDown="@InputCursorHandler.OnKeyPressHandlerAsync"></MatStringField> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| Validator.ValidateContact(ReportDataProvider.Report); | Validator.ValidateContact(ReportDataProvider.Report); | ||||
| NavigationManager.NavigateTo("fundvelo/conclusion_missing"); | NavigationManager.NavigateTo("fundvelo/conclusion_missing"); | ||||
| } | } | ||||
| } catch (ArgumentException ex) { | |||||
| } catch (ArgumentException) { | |||||
| Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | ||||
| } | } | ||||
| } | } |
| try { | try { | ||||
| Validator.ValidateAlternatePickContact(ReportDataProvider.GetFoundReport()); | Validator.ValidateAlternatePickContact(ReportDataProvider.GetFoundReport()); | ||||
| NavigationManager.NavigateTo("fundvelo/account/Found"); | NavigationManager.NavigateTo("fundvelo/account/Found"); | ||||
| } catch (ArgumentException ex) { | |||||
| } catch (ArgumentException) { | |||||
| Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | ||||
| } | } | ||||
| } | } |
| MouseEvent mouseEvent = new MouseEvent(); | MouseEvent mouseEvent = new MouseEvent(); | ||||
| LatLng coordinates; | LatLng coordinates; | ||||
| LatLng devicePosition = await InitializeDeviceMapPosition(); | LatLng devicePosition = await InitializeDeviceMapPosition(); | ||||
| if (report != null && report.GeographicInfo.Latitude != 0 && report.GeographicInfo.Longitude != 0) { | |||||
| if (report != null && ((report.GeographicInfo.Latitude != 0 && report.GeographicInfo.Longitude != 0) || | |||||
| (ReportDataProvider.ReportRepositoryItem != null && ReportDataProvider.ReportRepositoryItem.ID != 0))) { | |||||
| bicycleGeoPosition.DisplayCity = await GetFormattedAddressZipAndTown(ReportDataProvider); | bicycleGeoPosition.DisplayCity = await GetFormattedAddressZipAndTown(ReportDataProvider); | ||||
| coordinates = new LatLng(report.GeographicInfo.Latitude, report.GeographicInfo.Longitude); | coordinates = new LatLng(report.GeographicInfo.Latitude, report.GeographicInfo.Longitude); | ||||
| mouseEvent.LatLng = coordinates; | mouseEvent.LatLng = coordinates; | ||||
| } else { | } else { | ||||
| NavigationManager.NavigateTo("fundvelo/account/Found"); | NavigationManager.NavigateTo("fundvelo/account/Found"); | ||||
| } | } | ||||
| } catch (ArgumentException ex) { | |||||
| } catch (ArgumentException) { | |||||
| Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | ||||
| } | } | ||||
| } | } |
| [Inject] | [Inject] | ||||
| private IStringLocalizer<Resources> I18n { get; init; } | private IStringLocalizer<Resources> I18n { get; init; } | ||||
| [Inject] | |||||
| private OnlineStatusProvider OnlineStatusProvider { get; init; } | |||||
| private NominatimService NominatimService { get; set; } | private NominatimService NominatimService { get; set; } | ||||
| if (this.addressDto == null) { | if (this.addressDto == null) { | ||||
| this.bicycleGeoPosition.Latitude = ReportDataProvider.GetFoundReport().GeographicInfo.Latitude; | this.bicycleGeoPosition.Latitude = ReportDataProvider.GetFoundReport().GeographicInfo.Latitude; | ||||
| this.bicycleGeoPosition.Longitude = ReportDataProvider.GetFoundReport().GeographicInfo.Longitude; | this.bicycleGeoPosition.Longitude = ReportDataProvider.GetFoundReport().GeographicInfo.Longitude; | ||||
| this.addressDto = await NominatimService.GetAddressForCoordinates(this.bicycleGeoPosition.Latitude, this.bicycleGeoPosition.Longitude); | |||||
| if (OnlineStatusProvider.Online && this.bicycleGeoPosition.Latitude != 0 && this.bicycleGeoPosition.Longitude != 0) { | |||||
| this.addressDto = await NominatimService.GetAddressForCoordinates(this.bicycleGeoPosition.Latitude, this.bicycleGeoPosition.Longitude); | |||||
| } | |||||
| if (this.addressDto == null) { | if (this.addressDto == null) { | ||||
| this.addressDto = new(); | this.addressDto = new(); | ||||
| this.addressDto.address = new(); | this.addressDto.address = new(); | ||||
| } | } | ||||
| protected async Task AddBicycleMarkerOnClickPosition(MouseEvent mouseEvent) { | protected async Task AddBicycleMarkerOnClickPosition(MouseEvent mouseEvent) { | ||||
| if (this.bicyclePositionMarker != null) { | |||||
| await bicyclePositionMarker.Remove(); | |||||
| if (mouseEvent.LatLng.Lat != 0 && mouseEvent.LatLng.Lng != 0) { | |||||
| if (this.bicyclePositionMarker != null) { | |||||
| await bicyclePositionMarker.Remove(); | |||||
| } | |||||
| this.bicyclePositionMarker = await this.MarkerFactory.CreateAndAddToMap(mouseEvent.LatLng, this.mapRef, this.bicycleMarkerOptions); | |||||
| } | } | ||||
| this.bicyclePositionMarker = await this.MarkerFactory.CreateAndAddToMap(mouseEvent.LatLng, this.mapRef, this.bicycleMarkerOptions); | |||||
| } | } | ||||
| protected async Task<LatLng> GetDeviceGeoLocation() { | protected async Task<LatLng> GetDeviceGeoLocation() { | ||||
| private async Task ShowBicycleGeoLocation() { | private async Task ShowBicycleGeoLocation() { | ||||
| if (this.bicycleGeoPosition.Latitude != 0 && this.bicycleGeoPosition.Longitude != 0) { | if (this.bicycleGeoPosition.Latitude != 0 && this.bicycleGeoPosition.Longitude != 0) { | ||||
| LatLng geoPosition = new(this.bicycleGeoPosition.Latitude, this.bicycleGeoPosition.Longitude); | LatLng geoPosition = new(this.bicycleGeoPosition.Latitude, this.bicycleGeoPosition.Longitude); | ||||
| await this.mapRef.SetZoom(16); | await this.mapRef.SetZoom(16); | ||||
| await this.mapRef.SetView(geoPosition); | await this.mapRef.SetView(geoPosition); | ||||
| } else if (!String.IsNullOrEmpty(this.bicycleGeoPosition.Address) && | |||||
| !String.IsNullOrEmpty(this.bicycleGeoPosition.Zip) && | |||||
| !String.IsNullOrEmpty(this.bicycleGeoPosition.City)) { | |||||
| LatLng geoPosition = await NominatimService.GetCoordinatesForAddress(bicycleGeoPosition.Address + ", " + bicycleGeoPosition.Zip + " " + bicycleGeoPosition.City); | |||||
| this.bicycleGeoPosition.Latitude = geoPosition.Lat; | |||||
| this.bicycleGeoPosition.Longitude = geoPosition.Lng; | |||||
| await this.mapRef.SetZoom(16); | |||||
| await this.mapRef.SetView(geoPosition); | |||||
| MouseEvent mouseEvent = new MouseEvent(); | |||||
| mouseEvent.LatLng = geoPosition; | |||||
| await AddBicycleMarkerOnClickPosition(mouseEvent); | |||||
| } | } | ||||
| } | } | ||||
| transmittedReports.Remove(item); | transmittedReports.Remove(item); | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| Toaster.ShowSuccess(I18n.GetString("Success.DeleteReport.Title"), I18n.GetString("Success.DeleteReport.Msg", item.ID)); | Toaster.ShowSuccess(I18n.GetString("Success.DeleteReport.Title"), I18n.GetString("Success.DeleteReport.Msg", item.ID)); | ||||
| } catch (Exception ex) { | |||||
| } catch (Exception) { | |||||
| Toaster.ShowWarning(I18n.GetString("Error.DeleteReport.Title"), I18n.GetString("Error.DeleteReport.Msg", item.ID)); | Toaster.ShowWarning(I18n.GetString("Error.DeleteReport.Title"), I18n.GetString("Error.DeleteReport.Msg", item.ID)); | ||||
| } | } | ||||
| } | } |
| try { | try { | ||||
| Validator.ValidateMissingReportKeyData(ReportDataProvider.GetMissingReport()); | Validator.ValidateMissingReportKeyData(ReportDataProvider.GetMissingReport()); | ||||
| NavigationManager.NavigateTo("fundvelo/account/Missing"); | NavigationManager.NavigateTo("fundvelo/account/Missing"); | ||||
| } catch (ArgumentException ex) { | |||||
| } catch (ArgumentException) { | |||||
| Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | Toaster.ShowWarning(I18n.GetString("Warning.MandatoryFields.Title"), I18n.GetString("Warning.MandatoryFields.Msg")); | ||||
| } | } | ||||
| } | } |
| pendingReports.Remove(item); | pendingReports.Remove(item); | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| Toaster.ShowSuccess(I18n.GetString("Success.DeleteReport.Title"), I18n.GetString("Success.DeleteReport.Msg", item.ID)); | Toaster.ShowSuccess(I18n.GetString("Success.DeleteReport.Title"), I18n.GetString("Success.DeleteReport.Msg", item.ID)); | ||||
| } catch (Exception ex) { | |||||
| } catch (Exception) { | |||||
| Toaster.ShowWarning(I18n.GetString("Error.DeleteReport.Title"), I18n.GetString("Error.DeleteReport.Msg", item.ID)); | Toaster.ShowWarning(I18n.GetString("Error.DeleteReport.Title"), I18n.GetString("Error.DeleteReport.Msg", item.ID)); | ||||
| } | } | ||||
| } | } |
| builder.Services.AddSingleton<ReportDataProvider>(); | builder.Services.AddSingleton<ReportDataProvider>(); | ||||
| builder.Services.AddSingleton<OnlineStatusProvider>(); | builder.Services.AddSingleton<OnlineStatusProvider>(); | ||||
| builder.Services.AddSingleton<ScrollLockRemover>(); | builder.Services.AddSingleton<ScrollLockRemover>(); | ||||
| builder.Services.AddSingleton<InputCursorHandler>(); | |||||
| builder.Services.AddScoped<ReportRepositoryService>(); | builder.Services.AddScoped<ReportRepositoryService>(); | ||||
| builder.Services.AddScoped<Toaster>(); | builder.Services.AddScoped<Toaster>(); | ||||
| builder.Services.AddScoped<UserDataProvider>(); | builder.Services.AddScoped<UserDataProvider>(); |
| private void decodeDisplayCity(string displayCity) { | private void decodeDisplayCity(string displayCity) { | ||||
| if (!String.IsNullOrEmpty(displayCity)) { | if (!String.IsNullOrEmpty(displayCity)) { | ||||
| displayCity = displayCity.Trim(); | |||||
| char[] delimiterChars = { '-', ' ' }; | char[] delimiterChars = { '-', ' ' }; | ||||
| string[] tokens = displayCity.Split(delimiterChars); | string[] tokens = displayCity.Split(delimiterChars); | ||||
| if (tokens.Length == 3) { | if (tokens.Length == 3) { |
| using cwebplusApp.Shared.Models; | using cwebplusApp.Shared.Models; | ||||
| using FisSst.BlazorMaps; | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| //using Json.Net; | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | |||||
| using System.Globalization; | using System.Globalization; | ||||
| using System.Net.Http; | using System.Net.Http; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| return null; | return null; | ||||
| } | } | ||||
| } | } | ||||
| public static async ValueTask<LatLng> GetCoordinatesForAddress(string addressZipCity) { | |||||
| HttpClient httpClient = new() { BaseAddress = new Uri("https://nominatim.openstreetmap.org/") }; | |||||
| try { | |||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format("search?q={0}&format=json", addressZipCity)); | |||||
| if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) { | |||||
| string contentStr = await httpResult.Content.ReadAsStringAsync(); | |||||
| var settings = new JsonSerializerSettings(); | |||||
| settings.NullValueHandling = NullValueHandling.Ignore; | |||||
| List<NominatimCoordinates> coordinatesDtos = JsonConvert.DeserializeObject<List<NominatimCoordinates>>(contentStr, settings); | |||||
| return new LatLng(coordinatesDtos[0].lat, coordinatesDtos[0].lon); | |||||
| } | |||||
| return null; | |||||
| } catch (Exception) { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| } | |||||
| public class NominatimCoordinates { | |||||
| public double lat; | |||||
| public double lon; | |||||
| } | } | ||||
| } | } |
| using Microsoft.AspNetCore.Components.Web; | |||||
| using Microsoft.JSInterop; | |||||
| using System; | |||||
| using System.Threading.Tasks; | |||||
| namespace cwebplusApp.Shared.Services { | |||||
| public class InputCursorHandler { | |||||
| private readonly IJSRuntime jsRuntime; | |||||
| public InputCursorHandler(IJSRuntime _jsRuntime) { | |||||
| this.jsRuntime = _jsRuntime; | |||||
| } | |||||
| public async Task OnKeyPressHandlerAsync(KeyboardEventArgs e) { | |||||
| Console.WriteLine("Key pressed: " + e.Key); | |||||
| var reference = DotNetObjectReference.Create(this); | |||||
| if (e.Key.Equals("Enter") || e.Key.Equals("ArrowRight")) { | |||||
| await jsRuntime.InvokeVoidAsync("MoveCursorToNextInput", reference, e.Key); | |||||
| //await MoveInputCursor(true); | |||||
| } else if (e.Key.Equals("ArrowLeft")) { | |||||
| await jsRuntime.InvokeVoidAsync("MoveCursorToPreviousInput", reference); | |||||
| //await MoveInputCursor(false); | |||||
| } | |||||
| } | |||||
| //public async Task MoveInputCursor(bool forward) { | |||||
| // var reference = DotNetObjectReference.Create(this); | |||||
| // if (forward) { | |||||
| // await jsRuntime.InvokeVoidAsync("MoveCursorToNextInput", reference); | |||||
| // } else { | |||||
| // await jsRuntime.InvokeVoidAsync("MoveCursorToPreviousInput", reference); | |||||
| // } | |||||
| //} | |||||
| } | |||||
| } |
| private readonly IJSRuntime jsRuntime; | private readonly IJSRuntime jsRuntime; | ||||
| public ScrollLockRemover(IJSRuntime _jsRuntime) { | public ScrollLockRemover(IJSRuntime _jsRuntime) { | ||||
| jsRuntime = _jsRuntime; | |||||
| this.jsRuntime = _jsRuntime; | |||||
| } | } | ||||
| public async Task removeScrollLockAsync() { | public async Task removeScrollLockAsync() { |
| function RemoveScrollLock(dotNetObjRef) { | function RemoveScrollLock(dotNetObjRef) { | ||||
| document.querySelector("body.mdc-dialog-scroll-lock")?.classList.remove("mdc-dialog-scroll-lock"); | document.querySelector("body.mdc-dialog-scroll-lock")?.classList.remove("mdc-dialog-scroll-lock"); | ||||
| } | } | ||||
| function MoveCursorToNextInput(dotNetObjRef, key) { | |||||
| if (key == "Enter" || key == "ArrowRight") { | |||||
| var activeInput = document.activeElement; | |||||
| var inputs = document.getElementsByTagName("input"); | |||||
| var arr = Array.prototype.slice.call(inputs) | |||||
| var index = arr.indexOf(activeInput); | |||||
| if (index + 1 < arr.length && (key == "Enter" || activeInput.selectionStart == activeInput.value.length)) { | |||||
| arr[index + 1].focus(); | |||||
| setTimeout(function () { arr[index + 1].select(); }, 50); | |||||
| } | |||||
| } | |||||
| } | |||||
| function MoveCursorToPreviousInput(dotNetObjRef) { | |||||
| var activeInput = document.activeElement; | |||||
| var inputs = document.getElementsByTagName("input"); | |||||
| var arr = Array.prototype.slice.call(inputs) | |||||
| var index = arr.indexOf(activeInput); | |||||
| if (index - 1 >= 0 && activeInput.selectionStart == 0) { | |||||
| arr[index - 1].focus(); | |||||
| setTimeout(function () { arr[index - 1].select(); }, 50); | |||||
| } | |||||
| } | |||||
| </script> | </script> | ||||
| <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" | <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" |