11@page " /"
2+ @using System .Net
23@inject HttpClient Http
34@inject NavigationManager Nav
45@inject IJSRuntime JS
56@using Markdig
67
78<PageTitle >Project Reporting</PageTitle >
89
10+ @if (ShowLoginPrompt )
11+ {
12+ <FluentCard Style =" padding:0.5rem 1rem; margin-bottom:1rem;" >
13+ <FluentStack Orientation =" Orientation.Horizontal" Gap =" 10" VerticalAlignment =" VerticalAlignment.Center" >
14+ <FluentIcon Value =" @(new Icons.Regular.Size20.LockClosed())" />
15+ <FluentStack >
16+ <strong >@LoginPromptText </strong >
17+ <span >Sign in again to continue .</span >
18+ </FluentStack >
19+ <FluentButton Appearance =" Appearance.Accent" OnClick =" TriggerLogin" >Sign in </FluentButton >
20+ </FluentStack >
21+ </FluentCard >
22+ }
23+
924@if (Report is null )
1025{
1126 <FluentCard Style =" padding:1rem; margin-bottom:1rem;" >
1227 <h2 >Select a Project </h2 >
1328 @if (IsLoadingProjects )
1429 {
15- <FluentProgressRing />
30+ <FluentProgressRing />
1631 <p >Loading projects .. .</p >
1732 }
1833 else if (! string .IsNullOrEmpty (ErrorMessage ))
3146 <PropertyColumn Property =" @(p => p.Manager)" Title =" Manager" />
3247 <PropertyColumn Property =" @(p => p.Company)" Title =" Company" />
3348 <TemplateColumn Title =" Actions" >
34- <FluentButton Appearance =" Appearance.Accent"
35- OnClick =" @(() => GenerateReport(context.ProjectId))"
49+ <FluentButton Appearance =" Appearance.Accent"
50+ OnClick =" @(() => GenerateReport(context.ProjectId))"
3651 Disabled =" IsGeneratingReport" >
3752 @( IsGeneratingReport && GeneratingProjectId == context .ProjectId ? " Generating..." : " Generate Report" )
3853 </FluentButton >
8297 else
8398 {
8499 <FluentDataGrid Items =" @Report.Phases.AsQueryable()" GenerateFooter =" false" >
85- <PropertyColumn Property =" @(p => p.PhaseName)" Title =" Name" />
86- <PropertyColumn Property =" @(p => p.Status)" Title =" Status" />
87- <PropertyColumn Property =" @(p => p.EstimatedHours)" Title =" Est Hrs" />
88- <PropertyColumn Property =" @(p => p.ActualHours)" Title =" Actual Hrs" />
100+ <PropertyColumn Property =" @(p => p.PhaseName)" Title =" Name" />
101+ <PropertyColumn Property =" @(p => p.Status)" Title =" Status" />
102+ <PropertyColumn Property =" @(p => p.EstimatedHours)" Title =" Est Hrs" />
103+ <PropertyColumn Property =" @(p => p.ActualHours)" Title =" Actual Hrs" />
89104 </FluentDataGrid >
90105 }
91106 </FluentTab >
@@ -97,11 +112,11 @@ else
97112 else
98113 {
99114 <FluentDataGrid Items =" @Report.Tickets.AsQueryable()" GenerateFooter =" false" >
100- <PropertyColumn Property =" @(t => t.TicketNumber)" Title =" Number" />
101- <PropertyColumn Property =" @(t => t.Summary)" Title =" Summary" />
102- <PropertyColumn Property =" @(t => t.Status)" Title =" Status" />
103- <PropertyColumn Property =" @(t => t.EstimatedHours)" Title =" Est Hrs" />
104- <PropertyColumn Property =" @(t => t.ActualHours)" Title =" Actual Hrs" />
115+ <PropertyColumn Property =" @(t => t.TicketNumber)" Title =" Number" />
116+ <PropertyColumn Property =" @(t => t.Summary)" Title =" Summary" />
117+ <PropertyColumn Property =" @(t => t.Status)" Title =" Status" />
118+ <PropertyColumn Property =" @(t => t.EstimatedHours)" Title =" Est Hrs" />
119+ <PropertyColumn Property =" @(t => t.ActualHours)" Title =" Actual Hrs" />
105120 </FluentDataGrid >
106121 }
107122 </FluentTab >
116131 bool IsGeneratingReport ;
117132 int GeneratingProjectId ;
118133 bool IsPdfLoading ;
134+ bool ShowLoginPrompt ;
135+ string LoginPromptText = " Please sign in to continue." ;
119136 string ? ErrorMessage ;
120137 string AiSummaryHtml => Report ? .AiGeneratedSummary is null ? string .Empty : Markdown .ToHtml (Report .AiGeneratedSummary );
121138
@@ -131,6 +148,11 @@ else
131148 try
132149 {
133150 var response = await Http .GetAsync (" api/projects" );
151+ if (response .StatusCode == HttpStatusCode .Unauthorized )
152+ {
153+ HandleUnauthorized (" Please sign in to load projects." );
154+ return ;
155+ }
134156 if (! response .IsSuccessStatusCode )
135157 {
136158 ErrorMessage = $" Failed to load projects: {response .StatusCode }" ;
@@ -158,6 +180,11 @@ else
158180 {
159181 var req = new ProjectCompletionReportRequest { ProjectId = projectId };
160182 var httpResp = await Http .PostAsJsonAsync (" api/reports/project-completion" , req );
183+ if (httpResp .StatusCode == HttpStatusCode .Unauthorized )
184+ {
185+ HandleUnauthorized (" Please sign in to generate a report." );
186+ return ;
187+ }
161188 if (! httpResp .IsSuccessStatusCode )
162189 {
163190 ErrorMessage = $" Failed to generate report: {httpResp .StatusCode }" ;
@@ -191,6 +218,11 @@ else
191218 try
192219 {
193220 var httpResp = await Http .PostAsJsonAsync (" api/reports/project-completion/pdf" , Report );
221+ if (httpResp .StatusCode == HttpStatusCode .Unauthorized )
222+ {
223+ HandleUnauthorized (" Please sign in to download the PDF." );
224+ return ;
225+ }
194226 if (! httpResp .IsSuccessStatusCode )
195227 {
196228 ErrorMessage = $" Failed to generate PDF: {httpResp .StatusCode }" ;
@@ -210,4 +242,16 @@ else
210242 IsPdfLoading = false ;
211243 }
212244 }
245+
246+ void HandleUnauthorized (string message )
247+ {
248+ LoginPromptText = message ;
249+ ShowLoginPrompt = true ;
250+ ErrorMessage = null ;
251+ }
252+
253+ void TriggerLogin ()
254+ {
255+ Nav .NavigateTo (" /login?post_login_redirect_uri=.referrer" , forceLoad : true );
256+ }
213257}
0 commit comments