| </div> | </div> | ||||
| </div> | </div> | ||||
| @if (string.IsNullOrEmpty(FromRoute)) { | |||||
| <div class="row no-gutters align-items-end justify-content-center w-100" style="padding-bottom:2em"> | |||||
| <MatButton Class="w-100" Raised="true" @onclick="SaveUserData">@i18n["Save"]</MatButton> | |||||
| @if (!string.IsNullOrEmpty(FromRoute)) { | |||||
| <div class="row no-gutters justify-content-end w-100"> | |||||
| <MatRipple class="inputfile-mat-ripple" Color="@MatRippleColor.Default" @onclick="SaveUserData" Style="background: lightgrey; width: 64px; height: 64px; border-radius: 32px; align-items: flex-end; justify-content: center; display: inline-flex;"> | |||||
| <label> | |||||
| <svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 20 20" height="48px" viewBox="0 0 20 20" width="48px" fill="#000000"> | |||||
| <g><rect fill="none" height="20" width="20" /></g> | |||||
| <g> | |||||
| <g> | |||||
| <path d="M8,8.5c0.83,0,1.5-0.67,1.5-1.5S8.83,5.5,8,5.5S6.5,6.17,6.5,7S7.17,8.5,8,8.5z M12.28,13.66 C10.98,12.9,9.5,12.5,8,12.5s-2.98,0.4-4.28,1.16c-0.14,0.08-0.22,0.25-0.22,0.42v0.41h9v-0.41 C12.5,13.91,12.41,13.74,12.28,13.66z" opacity=".3" /> | |||||
| <path d="M8,10c1.66,0,3-1.34,3-3S9.66,4,8,4S5,5.34,5,7S6.34,10,8,10z M8,5.5c0.83,0,1.5,0.67,1.5,1.5S8.83,8.5,8,8.5 S6.5,7.83,6.5,7S7.17,5.5,8,5.5z M13.03,12.37C11.56,11.5,9.84,11,8,11s-3.56,0.5-5.03,1.37C2.36,12.72,2,13.39,2,14.09V16h12 v-1.91C14,13.39,13.64,12.72,13.03,12.37z M12.5,14.5h-9v-0.41c0-0.18,0.09-0.34,0.22-0.42C5.02,12.9,6.5,12.5,8,12.5 s2.98,0.4,4.28,1.16c0.14,0.08,0.22,0.25,0.22,0.42V14.5z" /> | |||||
| </g> | |||||
| <polygon points="18,7.75 16.25,7.75 16.25,6 14.75,6 14.75,7.75 13,7.75 13,9.25 14.75,9.25 14.75,11 16.25,11 16.25,9.25 18,9.25" /> | |||||
| </g> | |||||
| </svg> | |||||
| </label> | |||||
| </MatRipple> | |||||
| </div> | </div> | ||||
| } else { | |||||
| <div class="row no-gutters align-items-end justify-content-center w-100" style="padding-bottom:2em"> | <div class="row no-gutters align-items-end justify-content-center w-100" style="padding-bottom:2em"> | ||||
| <div class="col" style="padding-right:0.5em"> | <div class="col" style="padding-right:0.5em"> | ||||
| <MatButton Class="w-100" Outlined="true" @onclick="Cancel">@i18n["Cancel"]</MatButton> | <MatButton Class="w-100" Outlined="true" @onclick="Cancel">@i18n["Cancel"]</MatButton> | ||||
| <MatButton Class="w-100" Raised="true" @onclick="Next">@i18n["Send"]</MatButton> | <MatButton Class="w-100" Raised="true" @onclick="Next">@i18n["Send"]</MatButton> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| } else { | |||||
| <div class="row no-gutters align-items-end justify-content-center w-100" style="padding-bottom:2em"> | |||||
| <MatButton Class="w-100" Raised="true" @onclick="SaveUserDataAndClose">@i18n["Save"]</MatButton> | |||||
| </div> | |||||
| } | } | ||||
| </div> | </div> | ||||
| PageHistoryManager.OnBeforeNavigateBack = new EventCallback(this, (Action)OnBeforeNavigateBack); | PageHistoryManager.OnBeforeNavigateBack = new EventCallback(this, (Action)OnBeforeNavigateBack); | ||||
| PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | ||||
| Account = await GetUserData(); | Account = await GetUserData(); | ||||
| if (ReportDataProvider.Report != null) { | |||||
| if (!string.IsNullOrEmpty(FromRoute) && ReportDataProvider.Report != null) { | |||||
| UserDataProvider.mapUserData(Account, ReportDataProvider.Report); | UserDataProvider.mapUserData(Account, ReportDataProvider.Report); | ||||
| } | } | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| } | } | ||||
| } | } | ||||
| private async void SaveUserData() { | |||||
| private async Task SaveUserData() { | |||||
| await UserDataProvider.Save(Account); | await UserDataProvider.Save(Account); | ||||
| } | |||||
| private async void SaveUserDataAndClose() { | |||||
| await SaveUserData(); | |||||
| NavigationManager.NavigateTo("caritas_services"); | NavigationManager.NavigateTo("caritas_services"); | ||||
| } | } | ||||
| private async Task<UserData> GetUserData() { | private async Task<UserData> GetUserData() { | ||||
| return await UserDataProvider.Get(); | return await UserDataProvider.Get(); | ||||
| } | } |
| Toaster.ShowError(response.Message, response.GetDataAsFormattedList()); | Toaster.ShowError(response.Message, response.GetDataAsFormattedList()); | ||||
| } else { | } else { | ||||
| Toaster.ShowWarning(i18n.GetString("Warning.NoConnection.Title"), i18n.GetString("Warning.NoConnection.Msg")); | Toaster.ShowWarning(i18n.GetString("Warning.NoConnection.Title"), i18n.GetString("Warning.NoConnection.Msg")); | ||||
| PageHistoryManager.Reset(); | |||||
| } | } | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| AppState.NotifyChanged(); | AppState.NotifyChanged(); |
| protected override void OnInitialized() { | protected override void OnInitialized() { | ||||
| PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | ||||
| ReportDataProvider.Report = null; | ReportDataProvider.Report = null; | ||||
| ReportDataProvider.ReportRepositoryItem = null; | |||||
| base.OnInitialized(); | base.OnInitialized(); | ||||
| } | } | ||||
| <h6 style="font-style:italic;padding-bottom:1em">@i18n["Info.Report.Transmitting"]</h6> | <h6 style="font-style:italic;padding-bottom:1em">@i18n["Info.Report.Transmitting"]</h6> | ||||
| </div> | </div> | ||||
| } else { | } else { | ||||
| if (responseOk) { | |||||
| if (ResposeStatus.OK == responseStatus) { | |||||
| <MatHeadline5 Style="font-family:Ubuntu; text-align:center">@i18n["FinishedTextMissing"]</MatHeadline5> | <MatHeadline5 Style="font-family:Ubuntu; text-align:center">@i18n["FinishedTextMissing"]</MatHeadline5> | ||||
| <MatSubtitle1 Class="w-100" Style="font-family:Ubuntu; text-align:left; font-weight:800">@i18n["FinishedTextMissing_Heading1"]</MatSubtitle1> | <MatSubtitle1 Class="w-100" Style="font-family:Ubuntu; text-align:left; font-weight:800">@i18n["FinishedTextMissing_Heading1"]</MatSubtitle1> | ||||
| <ul class="w-100"> | <ul class="w-100"> | ||||
| @code { | @code { | ||||
| private bool responseOk = false; | |||||
| enum ResposeStatus : ushort { | |||||
| OK = 1, | |||||
| Error = 10, | |||||
| NoConnection = 20 | |||||
| } | |||||
| private ResposeStatus responseStatus = ResposeStatus.NoConnection; | |||||
| private bool running = true; | private bool running = true; | ||||
| ReportResponse response; | ReportResponse response; | ||||
| PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | PageHistoryManager.AddPageToHistory(NavigationManager.Uri); | ||||
| try { | try { | ||||
| response = await IBicycleRestService.SendMissingReport(ReportDataProvider.Report); | response = await IBicycleRestService.SendMissingReport(ReportDataProvider.Report); | ||||
| responseOk = System.Net.HttpStatusCode.OK == response.StatusCode ? true : false; | |||||
| responseStatus = response == null ? ResposeStatus.NoConnection : System.Net.HttpStatusCode.OK == response.StatusCode ? ResposeStatus.OK : ResposeStatus.Error; | |||||
| } catch (HttpRequestException ex) { | } catch (HttpRequestException ex) { | ||||
| response = new(i18n.GetString("MissingBike"), new string[] { ex.Message }); | response = new(i18n.GetString("MissingBike"), new string[] { ex.Message }); | ||||
| responseOk = false; | |||||
| responseStatus = ResposeStatus.Error; | |||||
| } | } | ||||
| running = false; | running = false; | ||||
| if (responseOk) { | |||||
| if (ResposeStatus.OK == responseStatus) { | |||||
| Toaster.ShowSuccess(i18n.GetString("MissingBike"), response.Message); | Toaster.ShowSuccess(i18n.GetString("MissingBike"), response.Message); | ||||
| PageHistoryManager.Reset(); | PageHistoryManager.Reset(); | ||||
| } else { | |||||
| } else if (ResposeStatus.Error == responseStatus) { | |||||
| Toaster.ShowError(response.Message, response.GetDataAsFormattedList()); | Toaster.ShowError(response.Message, response.GetDataAsFormattedList()); | ||||
| } else { | |||||
| Toaster.ShowWarning(i18n.GetString("Warning.NoConnection.Title"), i18n.GetString("Warning.NoConnection.Msg")); | |||||
| PageHistoryManager.Reset(); | |||||
| } | } | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| AppState.NotifyChanged(); | AppState.NotifyChanged(); |
| @inject MasterDataService MasterDataService; | @inject MasterDataService MasterDataService; | ||||
| @inject Toaster Toaster; | @inject Toaster Toaster; | ||||
| @inject IConfiguration Configuration; | @inject IConfiguration Configuration; | ||||
| @inject IBicycleRestService IBicycleRestService; | |||||
| @inject OnlineStatusProvider OnlineStatusProvider; | |||||
| @inject IBicycleRestService BicycleRestService; | |||||
| <div class="row h-100 justify-content-center"> | <div class="row h-100 justify-content-center"> | ||||
| <div class="row align-items-end vw-100 h-50"> | <div class="row align-items-end vw-100 h-50"> | ||||
| <div class="col text-center"> | <div class="col text-center"> | ||||
| <h3 style="font-style:italic;padding-bottom:1em">@i18n["Welcome"]</h3> | <h3 style="font-style:italic;padding-bottom:1em">@i18n["Welcome"]</h3> | ||||
| @*<div> | |||||
| <MatButton Disabled="@btnDisabled" Raised="true" Style="width:50%" @onclick="@((e) => NavigateToNext())">@i18n["Login"]</MatButton> | |||||
| </div>*@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div class="row align-items-center justify-content-center vw-100 h-25"> | <div class="row align-items-center justify-content-center vw-100 h-25"> | ||||
| showProgressCircle = true; | showProgressCircle = true; | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| try { | try { | ||||
| IBicycleRestService.Initialize(Configuration, OnlineStatusProvider); | |||||
| BicycleRestService.Initialize(Configuration); | |||||
| await MasterDataService.SynchronizeMasterdata(); | await MasterDataService.SynchronizeMasterdata(); | ||||
| await BicycleRestService.TrySendPendingReports(); | |||||
| } catch (Exception) { | } catch (Exception) { | ||||
| Toaster.ShowWarning(i18n.GetString("Warning.Masterdata.Title"), i18n.GetString("Warning.Masterdata.Msg")); | Toaster.ShowWarning(i18n.GetString("Warning.Masterdata.Title"), i18n.GetString("Warning.Masterdata.Msg")); | ||||
| } finally { | } finally { |
| builder.Services.AddSingleton<PageHistoryManager>(); | builder.Services.AddSingleton<PageHistoryManager>(); | ||||
| builder.Services.AddSingleton<ReportDataProvider>(); | builder.Services.AddSingleton<ReportDataProvider>(); | ||||
| builder.Services.AddSingleton<OnlineStatusProvider>(); | builder.Services.AddSingleton<OnlineStatusProvider>(); | ||||
| builder.Services.AddSingleton<ReportRepositoryService>(); | |||||
| builder.Services.AddScoped<Toaster>(); | builder.Services.AddScoped<Toaster>(); | ||||
| builder.Services.AddScoped<UserDataProvider>(); | builder.Services.AddScoped<UserDataProvider>(); | ||||
| builder.Services.AddScoped<MasterDataService>(); | builder.Services.AddScoped<MasterDataService>(); |
| namespace cwebplusApp.Shared.Models { | |||||
| public class FoundReportRepositoryItem : ReportRepositoryItem { | |||||
| private FoundReport report; | |||||
| public FoundReport Report { get => report; set => report = value; } | |||||
| public FoundReportRepositoryItem(FoundReport _report, long identifier) : base(Type.FOUND, identifier) { | |||||
| this.report = _report; | |||||
| } | |||||
| } | |||||
| } |
| namespace cwebplusApp.Shared.Models { | |||||
| public class MissingReportRepositoryItem : ReportRepositoryItem { | |||||
| private MissingReport report; | |||||
| public MissingReport Report { get => report; set => report = value; } | |||||
| public MissingReportRepositoryItem(MissingReport _report, long identifier) : base(Type.MISSING, identifier) { | |||||
| this.report = _report; | |||||
| } | |||||
| } | |||||
| } |
| using System; | |||||
| namespace cwebplusApp.Shared.Models { | |||||
| public abstract class ReportRepositoryItem { | |||||
| public enum Type { FOUND, MISSING } | |||||
| private long id; | |||||
| private string serverRefNbr; | |||||
| private bool transmitted; | |||||
| private Type reportType; | |||||
| public long ID { get => id; set => id = value; } | |||||
| public string ServerRefNbr { get => serverRefNbr; set => serverRefNbr = value; } | |||||
| public bool Transmitted { get => transmitted; set => transmitted = value; } | |||||
| public Type ReportType { get => reportType; set => reportType = value; } | |||||
| public ReportRepositoryItem(Type _reportType, long identifier) { | |||||
| this.id = identifier; | |||||
| this.reportType = _reportType; | |||||
| this.transmitted = false; | |||||
| } | |||||
| public override bool Equals(Object obj) { | |||||
| if ((obj == null) || !this.GetType().Equals(obj.GetType())) { | |||||
| return false; | |||||
| } else { | |||||
| ReportRepositoryItem rri = (ReportRepositoryItem)obj; | |||||
| return (ID == rri.ID); | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| private void LocationChanged(object sender, LocationChangedEventArgs e) { | private void LocationChanged(object sender, LocationChangedEventArgs e) { | ||||
| locUrl = i18n.GetString(e.Location.Replace(NavigationManager.BaseUri, "")); | locUrl = i18n.GetString(e.Location.Replace(NavigationManager.BaseUri, "")); | ||||
| if (IsInServicesUrl(e)) { | |||||
| if (IsInServicesUrl(e.Location)) { | |||||
| Index = 1; | Index = 1; | ||||
| } else if (e.Location.Contains("account")) { | } else if (e.Location.Contains("account")) { | ||||
| Index = 2; | Index = 2; | ||||
| } else if (e.Location.Contains("extras")) { | |||||
| Index = 3; | |||||
| } else if (e.Location.Contains("info")) { | } else if (e.Location.Contains("info")) { | ||||
| Index = 4; | Index = 4; | ||||
| } else { | } else { | ||||
| Index = 3; | |||||
| Index = 0; | |||||
| } | } | ||||
| StateHasChanged(); | StateHasChanged(); | ||||
| } | } | ||||
| private bool IsInServicesUrl(LocationChangedEventArgs e) { | |||||
| return (e.Location.Contains("caritas_services") || e.Location.Contains("lost_found") || e.Location.Contains("keydata") | |||||
| || e.Location.Contains("account/") || e.Location.Contains("conclusion_")); | |||||
| private bool IsInServicesUrl(string location) { | |||||
| return (location.Contains("caritas_services") || location.Contains("lost_found") || location.Contains("keydata") | |||||
| || location.Contains("account/") || location.Contains("conclusion_")); | |||||
| } | } | ||||
| private bool HandleAppBarContainer() { | private bool HandleAppBarContainer() { | ||||
| string baseUri = NavigationManager.BaseUri; | string baseUri = NavigationManager.BaseUri; | ||||
| string delta = uri.Replace(baseUri, ""); | string delta = uri.Replace(baseUri, ""); | ||||
| if (delta.Equals("caritas_services")) { | |||||
| Index = 1; | |||||
| } else if (delta.Equals("account")) { | |||||
| Index = 2; | |||||
| } else if (delta.Equals("info")) { | |||||
| Index = 4; | |||||
| if (delta == null || delta.Equals("")) { | |||||
| return false; | |||||
| } else { | } else { | ||||
| Index = 3; | |||||
| if (IsInServicesUrl(delta)) { | |||||
| Index = 1; | |||||
| } else if (delta.Equals("account")) { | |||||
| Index = 2; | |||||
| } else if (delta.Equals("extras")) { | |||||
| Index = 3; | |||||
| } else if (delta.Equals("info")) { | |||||
| Index = 4; | |||||
| } else { | |||||
| Index = 0; | |||||
| } | |||||
| return true; | |||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| private bool BackButtonDisabled() { | private bool BackButtonDisabled() { |
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Globalization; | using System.Globalization; | ||||
| using System.Net; | |||||
| using System.Net.Http; | using System.Net.Http; | ||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| private static readonly string VERSION = "v1"; | private static readonly string VERSION = "v1"; | ||||
| private HttpClient httpClient; | private HttpClient httpClient; | ||||
| public IConfiguration Configuration { get; set; } | |||||
| public OnlineStatusProvider OnlineStatusProvider { get; set; } | |||||
| private IConfiguration configuration; | |||||
| private OnlineStatusProvider onlineStatusProvider; | |||||
| private ReportRepositoryService reportRepositoryService; | |||||
| private ReportDataProvider reportDataProvider; | |||||
| public void Initialize(IConfiguration configuration, OnlineStatusProvider onlineStatusProvider) { | |||||
| this.Configuration = configuration; | |||||
| this.OnlineStatusProvider = onlineStatusProvider; | |||||
| string hostBaseUrl = Configuration.GetValue<string>("host_base_url"); | |||||
| public BicycleRestService(ReportRepositoryService _reportRepositoryService, OnlineStatusProvider _onlineStatusProvider, | |||||
| ReportDataProvider _reportDataProvider) { | |||||
| this.reportRepositoryService = _reportRepositoryService; | |||||
| this.onlineStatusProvider = _onlineStatusProvider; | |||||
| this.reportDataProvider = _reportDataProvider; | |||||
| } | |||||
| public void Initialize(IConfiguration _configuration) { | |||||
| this.configuration = _configuration; | |||||
| string hostBaseUrl = configuration.GetValue<string>("host_base_url"); | |||||
| if (!String.IsNullOrEmpty(hostBaseUrl)) { | if (!String.IsNullOrEmpty(hostBaseUrl)) { | ||||
| this.httpClient = new HttpClient { BaseAddress = new Uri(hostBaseUrl) }; | this.httpClient = new HttpClient { BaseAddress = new Uri(hostBaseUrl) }; | ||||
| } | } | ||||
| public async Task<List<ColorItem>> GetColors() { | public async Task<List<ColorItem>> GetColors() { | ||||
| if (httpClient != null) { | if (httpClient != null) { | ||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_colors"); | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_colors"); | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | if (!String.IsNullOrEmpty(subResourceUrl)) { | ||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | ||||
| public async Task<List<BicycleType>> GetBicycleTypes() { | public async Task<List<BicycleType>> GetBicycleTypes() { | ||||
| if (httpClient != null) { | if (httpClient != null) { | ||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_types"); | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_types"); | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | if (!String.IsNullOrEmpty(subResourceUrl)) { | ||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | ||||
| public async Task<List<Brand>> GetBrands() { | public async Task<List<Brand>> GetBrands() { | ||||
| if (httpClient != null) { | if (httpClient != null) { | ||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_brands"); | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_brands"); | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | if (!String.IsNullOrEmpty(subResourceUrl)) { | ||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | ||||
| } | } | ||||
| public async Task<ReportResponse> SendFoundReport(Report report) { | public async Task<ReportResponse> SendFoundReport(Report report) { | ||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_foundreport"); | |||||
| return await SendReport(report, subResourceUrl); | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_foundreport"); | |||||
| return await SendReport(report, subResourceUrl, new FoundReportRepositoryItem((FoundReport)report, GetCurrentTimeInMillis())); | |||||
| } | |||||
| private async Task<ReportResponse> SendFoundReport(FoundReportRepositoryItem reportRepositoryItem) { | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_foundreport"); | |||||
| return await SendReport(reportRepositoryItem.Report, subResourceUrl, reportRepositoryItem); | |||||
| } | } | ||||
| public async Task<ReportResponse> SendMissingReport(Report report) { | public async Task<ReportResponse> SendMissingReport(Report report) { | ||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_missingreport"); | |||||
| return await SendReport(report, subResourceUrl); | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_missingreport"); | |||||
| return await SendReport(report, subResourceUrl, new MissingReportRepositoryItem((MissingReport)report, GetCurrentTimeInMillis())); | |||||
| } | } | ||||
| protected async Task<ReportResponse> SendReport(Report report, string subResourceUrl) { | |||||
| if (OnlineStatusProvider.Online) { | |||||
| public async Task<ReportResponse> SendMissingReport(MissingReportRepositoryItem reportRepositoryItem) { | |||||
| string subResourceUrl = configuration.GetValue<string>("subresource_url_missingreport"); | |||||
| return await SendReport(reportRepositoryItem.Report, subResourceUrl, reportRepositoryItem); | |||||
| } | |||||
| public async Task TrySendPendingReports() { | |||||
| await TrySendFoundPendingReports(); | |||||
| await TrySendMissingPendingReports(); | |||||
| } | |||||
| public async Task TrySendFoundPendingReports() { | |||||
| List<FoundReportRepositoryItem> pendingFoundReports = await reportRepositoryService.GetPendingFoundReports(); | |||||
| foreach (FoundReportRepositoryItem item in pendingFoundReports) { | |||||
| try { | |||||
| ReportResponse response = await SendFoundReport(item); | |||||
| } catch (Exception) { | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| public async Task TrySendMissingPendingReports() { | |||||
| List<MissingReportRepositoryItem> pendingMissingReports = await reportRepositoryService.GetPendingMissingReports(); | |||||
| foreach (MissingReportRepositoryItem item in pendingMissingReports) { | |||||
| try { | |||||
| ReportResponse response = await SendMissingReport(item); | |||||
| } catch (Exception) { | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| protected async Task<ReportResponse> SendReport(Report report, string subResourceUrl, ReportRepositoryItem reportRepositoryItem) { | |||||
| ReportResponse response = null; | |||||
| if (onlineStatusProvider.Online && !reportRepositoryItem.Transmitted) { | |||||
| if (httpClient != null) { | if (httpClient != null) { | ||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | if (!String.IsNullOrEmpty(subResourceUrl)) { | ||||
| string reportJson = JsonConvert.SerializeObject(report); | string reportJson = JsonConvert.SerializeObject(report); | ||||
| HttpContent content = new StringContent(reportJson, Encoding.UTF8, "application/json"); | HttpContent content = new StringContent(reportJson, Encoding.UTF8, "application/json"); | ||||
| HttpResponseMessage httpResult = await httpClient.PostAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName), content); | HttpResponseMessage httpResult = await httpClient.PostAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName), content); | ||||
| string msg = await httpResult.Content.ReadAsStringAsync(); | string msg = await httpResult.Content.ReadAsStringAsync(); | ||||
| ReportResponse response = JsonConvert.DeserializeObject<ReportResponse>(msg); | |||||
| response = JsonConvert.DeserializeObject<ReportResponse>(msg); | |||||
| response.StatusCode = httpResult.StatusCode; | response.StatusCode = httpResult.StatusCode; | ||||
| if (HttpStatusCode.OK == response.StatusCode) { | |||||
| reportRepositoryItem.ServerRefNbr = response.Data[0]; | |||||
| reportRepositoryItem.Transmitted = true; | |||||
| await reportRepositoryService.SaveReport(reportRepositoryItem); | |||||
| } | |||||
| return response; | return response; | ||||
| } | } | ||||
| } | } | ||||
| throw new HttpRequestException("HTTP client not initialized!"); | throw new HttpRequestException("HTTP client not initialized!"); | ||||
| } else { | |||||
| //TODO: Save to app storage | |||||
| return null; | |||||
| } | } | ||||
| await reportRepositoryService.SaveReport(reportRepositoryItem); | |||||
| return response; | |||||
| } | |||||
| private long GetCurrentTimeInMillis() { | |||||
| return DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| namespace cwebplusApp.Shared.Services { | namespace cwebplusApp.Shared.Services { | ||||
| public interface IBicycleRestService { | public interface IBicycleRestService { | ||||
| void Initialize(IConfiguration configuration, OnlineStatusProvider onlineStatusProvider); | |||||
| void Initialize(IConfiguration configuration); | |||||
| Task<List<ColorItem>> GetColors(); | Task<List<ColorItem>> GetColors(); | ||||
| Task<ReportResponse> SendFoundReport(Report report); | Task<ReportResponse> SendFoundReport(Report report); | ||||
| Task<ReportResponse> SendMissingReport(Report report); | Task<ReportResponse> SendMissingReport(Report report); | ||||
| Task TrySendPendingReports(); | |||||
| Task TrySendFoundPendingReports(); | |||||
| Task TrySendMissingPendingReports(); | |||||
| } | } | ||||
| } | } |
| using cwebplusApp.Shared.Models; | |||||
| using Microsoft.Extensions.Configuration; | |||||
| using System.Collections.Generic; | |||||
| using System.Threading.Tasks; | |||||
| namespace cwebplusApp.Shared.Services { | |||||
| public interface ILFBicycleRest { | |||||
| void Initialize(IConfiguration configuration); | |||||
| Task<List<ColorItem>> GetColors(); | |||||
| Task<List<BicycleType>> GetBicycleTypes(); | |||||
| Task<List<Brand>> GetBrands(); | |||||
| Task<ReportResponse> SendFoundReport(Report report); | |||||
| Task<ReportResponse> SendMissingReport(Report report); | |||||
| } | |||||
| } |
| using cwebplusApp.Shared.Models; | |||||
| using Microsoft.AspNetCore.Components; | |||||
| using Microsoft.Extensions.Configuration; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Globalization; | |||||
| using System.Net.Http; | |||||
| using System.Text; | |||||
| using System.Threading.Tasks; | |||||
| namespace cwebplusApp.Shared.Services { | |||||
| // REST interface responsible to submit lost or found reports and get the available master data. | |||||
| public class LFBicycleRest : ILFBicycleRest { | |||||
| private static readonly string VERSION = "v1"; | |||||
| private HttpClient httpClient; | |||||
| [Inject] | |||||
| public IConfiguration Configuration { get; set; } | |||||
| public void Initialize(IConfiguration configuration) { | |||||
| this.Configuration = configuration; | |||||
| string hostBaseUrl = Configuration.GetValue<string>("host_base_url"); | |||||
| if (!String.IsNullOrEmpty(hostBaseUrl)) { | |||||
| this.httpClient = new HttpClient { BaseAddress = new Uri(hostBaseUrl) }; | |||||
| } | |||||
| } | |||||
| public async Task<List<ColorItem>> GetColors() { | |||||
| if (httpClient != null) { | |||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_colors"); | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | |||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | |||||
| if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) { | |||||
| ColorItem[] colors = JsonConvert.DeserializeObject<ColorItem[]>(await httpResult.Content.ReadAsStringAsync()); | |||||
| return new List<ColorItem>(colors); | |||||
| } | |||||
| throw new HttpRequestException("HTTP error " + httpResult.StatusCode); | |||||
| } | |||||
| } | |||||
| throw new HttpRequestException("HTTP client not initialized!"); | |||||
| } | |||||
| public async Task<List<BicycleType>> GetBicycleTypes() { | |||||
| if (httpClient != null) { | |||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_types"); | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | |||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | |||||
| if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) { | |||||
| BicycleType[] bicycleTypes = JsonConvert.DeserializeObject<BicycleType[]>(await httpResult.Content.ReadAsStringAsync()); | |||||
| return new List<BicycleType>(bicycleTypes); | |||||
| } | |||||
| throw new HttpRequestException("HTTP error " + httpResult.StatusCode); | |||||
| } | |||||
| } | |||||
| throw new HttpRequestException("HTTP client not initialized!"); | |||||
| } | |||||
| public async Task<List<Brand>> GetBrands() { | |||||
| if (httpClient != null) { | |||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_brands"); | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | |||||
| HttpResponseMessage httpResult = await httpClient.GetAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName)); | |||||
| if (httpResult.StatusCode == System.Net.HttpStatusCode.OK) { | |||||
| Brand[] brands = JsonConvert.DeserializeObject<Brand[]>(await httpResult.Content.ReadAsStringAsync()); | |||||
| return new List<Brand>(brands); | |||||
| } | |||||
| throw new HttpRequestException("HTTP error " + httpResult.StatusCode); | |||||
| } | |||||
| } | |||||
| throw new HttpRequestException("HTTP client not initialized!"); | |||||
| } | |||||
| public async Task<ReportResponse> SendFoundReport(Report report) { | |||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_foundreport"); | |||||
| return await SendReport(report, subResourceUrl); | |||||
| } | |||||
| public async Task<ReportResponse> SendMissingReport(Report report) { | |||||
| string subResourceUrl = Configuration.GetValue<string>("subresource_url_missingreport"); | |||||
| return await SendReport(report, subResourceUrl); | |||||
| } | |||||
| protected async Task<ReportResponse> SendReport(Report report, string subResourceUrl) { | |||||
| if (httpClient != null) { | |||||
| if (!String.IsNullOrEmpty(subResourceUrl)) { | |||||
| string reportJson = JsonConvert.SerializeObject(report); | |||||
| HttpContent content = new StringContent(reportJson, Encoding.UTF8, "application/json"); | |||||
| HttpResponseMessage httpResult = await httpClient.PostAsync(string.Format(subResourceUrl, VERSION, CultureInfo.CurrentCulture.TwoLetterISOLanguageName), content); | |||||
| string msg = await httpResult.Content.ReadAsStringAsync(); | |||||
| ReportResponse response = JsonConvert.DeserializeObject<ReportResponse>(msg); | |||||
| response.StatusCode = httpResult.StatusCode; | |||||
| return response; | |||||
| } | |||||
| } | |||||
| throw new HttpRequestException("HTTP client not initialized!"); | |||||
| } | |||||
| } | |||||
| } |
| } else if (key == KeyNameBcTypes) { | } else if (key == KeyNameBcTypes) { | ||||
| _bicycleTypes = null; | _bicycleTypes = null; | ||||
| Changed?.Invoke(this, EventArgs.Empty); | Changed?.Invoke(this, EventArgs.Empty); | ||||
| } else if (key == KeyNameBrands) { | |||||
| _brands = null; | |||||
| Changed?.Invoke(this, EventArgs.Empty); | |||||
| } | } | ||||
| } | } | ||||
| public class ReportDataProvider { | public class ReportDataProvider { | ||||
| public Report Report { get; set; } | public Report Report { get; set; } | ||||
| public ReportRepositoryItem ReportRepositoryItem { get; set; } | |||||
| public FoundReport GetFoundReport() { | public FoundReport GetFoundReport() { |
| using cwebplusApp.Shared.Models; | |||||
| using Microsoft.JSInterop; | |||||
| using Newtonsoft.Json; | |||||
| using System; | |||||
| using System.Collections.Generic; | |||||
| using System.Threading.Tasks; | |||||
| namespace cwebplusApp.Shared.Services { | |||||
| public sealed class ReportRepositoryService { | |||||
| private const string KeyNameFoundReports = "foundReportRepository"; | |||||
| private const string KeyNameMissingReports = "missingReportRepository"; | |||||
| private readonly IJSRuntime jsRuntime; | |||||
| private bool initialized; | |||||
| public event EventHandler Changed; | |||||
| public ReportRepositoryService(IJSRuntime jsRuntime) { | |||||
| this.jsRuntime = jsRuntime; | |||||
| } | |||||
| public async Task SaveReport(ReportRepositoryItem reportRepositoryItem) { | |||||
| if (reportRepositoryItem is FoundReportRepositoryItem fItem) { | |||||
| await SaveFoundReport(fItem); | |||||
| } else if (reportRepositoryItem is MissingReportRepositoryItem mItem) { | |||||
| await SaveMissingReport(mItem); | |||||
| } | |||||
| } | |||||
| public async ValueTask<List<FoundReportRepositoryItem>> GetFoundReports() { | |||||
| // Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed. | |||||
| // This way, you can reload the settings when another instance of the application (tab / window) save the settings | |||||
| if (!initialized) { | |||||
| // Create a reference to the current object, so the JS function can call the public method "OnStorageUpdated" | |||||
| var reference = DotNetObjectReference.Create(this); | |||||
| await this.jsRuntime.InvokeVoidAsync("BlazorRegisterStorageEvent", reference); | |||||
| this.initialized = true; | |||||
| } | |||||
| // Read the JSON string that contains the data from the local storage | |||||
| List<FoundReportRepositoryItem> result; | |||||
| var str = await this.jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameFoundReports); | |||||
| if (str != null) { | |||||
| result = JsonConvert.DeserializeObject<List<FoundReportRepositoryItem>>(str) ?? new(); | |||||
| } else { | |||||
| result = new(); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public async ValueTask<List<FoundReportRepositoryItem>> GetPendingFoundReports() { | |||||
| List<FoundReportRepositoryItem> pendingFoundReps = new(); | |||||
| List<FoundReportRepositoryItem> foundReps = await GetFoundReports(); | |||||
| foreach (FoundReportRepositoryItem report in foundReps) { | |||||
| if (!report.Transmitted) { | |||||
| pendingFoundReps.Add(report); | |||||
| } | |||||
| } | |||||
| return pendingFoundReps; | |||||
| } | |||||
| public async ValueTask<List<MissingReportRepositoryItem>> GetMissingReports() { | |||||
| // Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed. | |||||
| // This way, you can reload the settings when another instance of the application (tab / window) save the settings | |||||
| if (!initialized) { | |||||
| // Create a reference to the current object, so the JS function can call the public method "OnStorageUpdated" | |||||
| var reference = DotNetObjectReference.Create(this); | |||||
| await this.jsRuntime.InvokeVoidAsync("BlazorRegisterStorageEvent", reference); | |||||
| this.initialized = true; | |||||
| } | |||||
| // Read the JSON string that contains the data from the local storage | |||||
| List<MissingReportRepositoryItem> result; | |||||
| var str = await this.jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyNameMissingReports); | |||||
| if (str != null) { | |||||
| result = JsonConvert.DeserializeObject<List<MissingReportRepositoryItem>>(str) ?? new(); | |||||
| } else { | |||||
| result = new(); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| public async ValueTask<List<MissingReportRepositoryItem>> GetPendingMissingReports() { | |||||
| List<MissingReportRepositoryItem> pendingMissingReps = new(); | |||||
| List<MissingReportRepositoryItem> missingReps = await GetMissingReports(); | |||||
| foreach (MissingReportRepositoryItem report in missingReps) { | |||||
| if (!report.Transmitted) { | |||||
| pendingMissingReps.Add(report); | |||||
| } | |||||
| } | |||||
| return pendingMissingReps; | |||||
| } | |||||
| public async Task SaveFoundReport(FoundReportRepositoryItem foundReportRepositoryItem) { | |||||
| List<FoundReportRepositoryItem> foundReps = await GetFoundReports(); | |||||
| foundReps.Remove(foundReportRepositoryItem); | |||||
| foundReps.Add(foundReportRepositoryItem); | |||||
| var json = JsonConvert.SerializeObject(foundReps); | |||||
| await jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameFoundReports, json); | |||||
| } | |||||
| public async Task SaveMissingReport(MissingReportRepositoryItem missingReportRepositoryItem) { | |||||
| List<MissingReportRepositoryItem> missingReps = await GetMissingReports(); | |||||
| missingReps.Remove(missingReportRepositoryItem); | |||||
| missingReps.Add(missingReportRepositoryItem); | |||||
| var json = JsonConvert.SerializeObject(missingReps); | |||||
| await jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyNameMissingReports, json); | |||||
| } | |||||
| // This method is called from BlazorRegisterStorageEvent when the storage changed | |||||
| [JSInvokable] | |||||
| public void OnStorageUpdated(string key) { | |||||
| if (key == KeyNameMissingReports || key == KeyNameFoundReports) { | |||||
| // Reset the settings. The next call to Get will reload the data | |||||
| Changed?.Invoke(this, EventArgs.Empty); | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| namespace cwebplusApp.Shared.Services { | namespace cwebplusApp.Shared.Services { | ||||
| public sealed class UserDataProvider { | public sealed class UserDataProvider { | ||||
| private const string KeyName = "account"; | |||||
| private const string KeyName = "account"; | |||||
| private readonly IJSRuntime _jsRuntime; | private readonly IJSRuntime _jsRuntime; | ||||
| private bool _initialized; | private bool _initialized; | ||||
| public event EventHandler Changed; | public event EventHandler Changed; | ||||
| public bool AutoSave { get; set; } = true; | |||||
| public UserDataProvider(IJSRuntime jsRuntime) { | public UserDataProvider(IJSRuntime jsRuntime) { | ||||
| _jsRuntime = jsRuntime; | _jsRuntime = jsRuntime; | ||||
| } | } |
| <PackageReference Include="BlazorGeolocation" Version="0.1.1" /> | <PackageReference Include="BlazorGeolocation" Version="0.1.1" /> | ||||
| <PackageReference Include="FisSst.BlazorMaps" Version="1.0.2" /> | <PackageReference Include="FisSst.BlazorMaps" Version="1.0.2" /> | ||||
| <PackageReference Include="MatBlazor" Version="2.9.0-develop-042" /> | <PackageReference Include="MatBlazor" Version="2.9.0-develop-042" /> | ||||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.8" /> | |||||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.8" PrivateAssets="all" /> | |||||
| <PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.8" /> | |||||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.9" /> | |||||
| <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.9" PrivateAssets="all" /> | |||||
| <PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.9" /> | |||||
| <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> | ||||
| <PackageReference Include="System.Configuration.ConfigurationManager" Version="5.0.0" /> | <PackageReference Include="System.Configuration.ConfigurationManager" Version="5.0.0" /> | ||||
| </ItemGroup> | </ItemGroup> |
| '/conclusion_missing', | '/conclusion_missing', | ||||
| '/doneimage', | '/doneimage', | ||||
| '/failureimage', | '/failureimage', | ||||
| '/warningimage', | |||||
| 'favicon.ico', | 'favicon.ico', | ||||
| 'images/batch_found.png', | 'images/batch_found.png', | ||||
| 'images/batch_fundvelo.png', | 'images/batch_fundvelo.png', | ||||
| '_content/blazoranimate/aos.css', | '_content/blazoranimate/aos.css', | ||||
| '_framework/blazor.webassembly.js', | '_framework/blazor.webassembly.js', | ||||
| '_framework/blazor.boot.json', | '_framework/blazor.boot.json', | ||||
| '_framework/dotnet.5.0.8.js', | |||||
| '_framework/dotnet.5.0.9.js', | |||||
| 'https://fonts.googleapis.com/css?family=Roboto:300,400,500', | 'https://fonts.googleapis.com/css?family=Roboto:300,400,500', | ||||
| 'https://fonts.googleapis.com/icon?family=Material+Icons', | 'https://fonts.googleapis.com/icon?family=Material+Icons', | ||||
| 'https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;700&display=swap', | 'https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;700&display=swap', | ||||
| }); | }); | ||||
| // fetch events (appsettings are always first fetched from network) | // fetch events (appsettings are always first fetched from network) | ||||
| self.addEventListener('fetch', function (event) { | |||||
| event.respondWith(networkOrCache(event.request).catch(function () { | |||||
| })); | |||||
| }) | |||||
| self.addEventListener('fetch', event => { | |||||
| if (event.request.url.endsWith(appsettings_url)) { | |||||
| fetch(event.request).then(function (response) { | |||||
| return caches.open(staticCacheName).then(function (cache) { | |||||
| console.log('update cache'); | |||||
| cache.put(event.request, response.clone()); | |||||
| return response; | |||||
| }); | |||||
| }).catch(function () { | |||||
| return useFallback(); | |||||
| }); | |||||
| } else { | |||||
| event.respondWith( | |||||
| caches.match(event.request).then(cacheRes => { | |||||
| return cacheRes || fetch(event.request); | |||||
| }) | |||||
| ); | |||||
| } | |||||
| }); | |||||
| function networkOrCache(request) { | |||||
| return fetch(request).then(function (response) { | |||||
| return response.ok ? response : fromCache(request); | |||||
| }).catch(function () { | |||||
| return fromCache(request); | |||||
| }); | |||||
| function useFallback() { | |||||
| return Promise.resolve(new Response(Appsettings_Fallback, { | |||||
| headers: { | |||||
| 'Content-Type': 'application/json' | |||||
| } | |||||
| })); | |||||
| } | } | ||||
| function fromCache(request) { | |||||
| return caches.open(staticCacheName).then(function (cache) { | |||||
| return cache.match(request).then(function (matching) { | |||||
| return matching || Promise.reject('request-not-in-cache'); | |||||
| }); | |||||
| }); | |||||
| var Appsettings_Fallback = { | |||||
| "host_base_url": "https://integrate.dynalias.net:9443/Fundvelo/", | |||||
| "subresource_url_colors": "api/{0}/{1}/fundvelo/colors", | |||||
| "subresource_url_brands": "api/{0}/{1}/fundvelo/brands", | |||||
| "subresource_url_types": "api/{0}/{1}/fundvelo/types", | |||||
| "subresource_url_foundreport": "api/{0}/{1}/fundvelo/fundmeldung", | |||||
| "subresource_url_missingreport": "api/{0}/{1}/fundvelo/suchauftrag" | |||||
| } | } |