From 1f7df973c1aecbfcc611458cd1ba99eb4cd698eb Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:48:00 +0200 Subject: [PATCH] Fix invalid ICS and PDF export returning validation errors as file content (#33) * Initial plan * Fix client-side export error handling and identify validation root cause Co-authored-by: clayschaad <11883505+clayschaad@users.noreply.github.com> * Complete fix for invalid ICS and PDF export issue Co-authored-by: clayschaad <11883505+clayschaad@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: clayschaad <11883505+clayschaad@users.noreply.github.com> --- Client/Pages/Index.razor | 16 +++++++++ Client/Pages/Index.razor.cs | 70 +++++++++++++++++++++++++++++++------ Shared/TransportModels.cs | 8 ++--- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/Client/Pages/Index.razor b/Client/Pages/Index.razor index 17c7f58..cd3d8a3 100644 --- a/Client/Pages/Index.razor +++ b/Client/Pages/Index.razor @@ -10,6 +10,22 @@

Shift Scheduler - @CurrentMonthYear

+@if (!string.IsNullOrEmpty(_errorMessage)) +{ + +} + +@if (!string.IsNullOrEmpty(_successMessage)) +{ + +} + @if (_isLoadingInitial) {
diff --git a/Client/Pages/Index.razor.cs b/Client/Pages/Index.razor.cs index d4c548a..fc11afb 100644 --- a/Client/Pages/Index.razor.cs +++ b/Client/Pages/Index.razor.cs @@ -20,6 +20,8 @@ namespace ShiftScheduler.Client.Pages private int EditYear { get; set; } private bool _isLoadingTransport = false; private bool _isLoadingInitial = false; + private string _errorMessage = string.Empty; + private string _successMessage = string.Empty; private string CurrentMonthYear => new DateTime(EditYear, EditMonth, 1).ToString("MMMM yyyy"); @@ -98,21 +100,67 @@ namespace ShiftScheduler.Client.Pages private async Task ExportToIcs() { - var shiftsWithTransportList = SelectedShiftsWithTransport.Values.ToList(); - var response = await HttpClient.PostAsJsonAsync("api/shift/export_ics", shiftsWithTransportList); - var bytes = await response.Content.ReadAsByteArrayAsync(); - var base64 = Convert.ToBase64String(bytes); - var fileUrl = $"data:text/calendar;base64,{base64}"; - NavigationManager.NavigateTo(fileUrl, true); + try + { + _errorMessage = string.Empty; + _successMessage = string.Empty; + StateHasChanged(); + + var shiftsWithTransportList = SelectedShiftsWithTransport.Values.ToList(); + var response = await HttpClient.PostAsJsonAsync("api/shift/export_ics", shiftsWithTransportList); + + if (response.IsSuccessStatusCode) + { + var bytes = await response.Content.ReadAsByteArrayAsync(); + var base64 = Convert.ToBase64String(bytes); + var fileUrl = $"data:text/calendar;base64,{base64}"; + NavigationManager.NavigateTo(fileUrl, true); + _successMessage = "ICS file exported successfully!"; + } + else + { + var errorContent = await response.Content.ReadAsStringAsync(); + _errorMessage = $"Failed to export ICS file: {response.StatusCode}. {errorContent}"; + } + } + catch (Exception ex) + { + _errorMessage = $"Error exporting ICS file: {ex.Message}"; + } + + StateHasChanged(); } private async Task ExportToPdf() { - var shiftsWithTransportList = SelectedShiftsWithTransport.Values.ToList(); - var response = await HttpClient.PostAsJsonAsync("api/shift/export_pdf", shiftsWithTransportList); - var bytes = await response.Content.ReadAsByteArrayAsync(); - var base64 = Convert.ToBase64String(bytes); - await JSRuntime.InvokeVoidAsync("downloadFile", $"Schedule {EditYear}-{EditMonth:D2}.pdf", "application/pdf", base64); + try + { + _errorMessage = string.Empty; + _successMessage = string.Empty; + StateHasChanged(); + + var shiftsWithTransportList = SelectedShiftsWithTransport.Values.ToList(); + var response = await HttpClient.PostAsJsonAsync("api/shift/export_pdf", shiftsWithTransportList); + + if (response.IsSuccessStatusCode) + { + var bytes = await response.Content.ReadAsByteArrayAsync(); + var base64 = Convert.ToBase64String(bytes); + await JSRuntime.InvokeVoidAsync("downloadFile", $"Schedule {EditYear}-{EditMonth:D2}.pdf", "application/pdf", base64); + _successMessage = "PDF file exported successfully!"; + } + else + { + var errorContent = await response.Content.ReadAsStringAsync(); + _errorMessage = $"Failed to export PDF file: {response.StatusCode}. {errorContent}"; + } + } + catch (Exception ex) + { + _errorMessage = $"Error exporting PDF file: {ex.Message}"; + } + + StateHasChanged(); } private async Task SaveScheduleToStorage() diff --git a/Shared/TransportModels.cs b/Shared/TransportModels.cs index d0b1c8b..311a684 100644 --- a/Shared/TransportModels.cs +++ b/Shared/TransportModels.cs @@ -17,7 +17,7 @@ namespace ShiftScheduler.Shared public string DepartureTime { get; set; } = string.Empty; public string ArrivalTime { get; set; } = string.Empty; public string Duration { get; set; } = string.Empty; - public string Platform { get; set; } = string.Empty; + public string? Platform { get; set; } = string.Empty; public List Sections { get; set; } = new(); } @@ -38,9 +38,9 @@ namespace ShiftScheduler.Shared public class TransportCheckpoint { public TransportStation? Station { get; set; } - public string Departure { get; set; } = string.Empty; - public string Arrival { get; set; } = string.Empty; - public string Platform { get; set; } = string.Empty; + public string? Departure { get; set; } = string.Empty; + public string? Arrival { get; set; } = string.Empty; + public string? Platform { get; set; } = string.Empty; } public class TransportStation