Skip to content

Commit b84a747

Browse files
wip
1 parent cf7bfe9 commit b84a747

19 files changed

Lines changed: 468 additions & 311 deletions

File tree

EstateManagementUI.BlazorServer/Components/App.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
<body class="h-full">
1717
<Routes />
1818
<ReconnectModal />
19-
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" crossorigin="anonymous"></script>
20-
<script src="js/charts.js"></script>
2119
<script src="js/site.js"></script>
2220
<script src="@Assets["_framework/blazor.web.js"]"></script>
21+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" crossorigin="anonymous"></script>
22+
<script src="js/charts.js"></script>
2323
</body>
2424

2525
</html>

EstateManagementUI.BlazorServer/Components/Pages/Reporting/AnalyticalCharts.razor

Lines changed: 4 additions & 228 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
@using EstateManagementUI.BusinessLogic.Requests
44
@using global::Shared.General
55
@rendermode InteractiveServer
6+
@inherits AuthorizedComponentBase
67
@inject IMediator Mediator
78
@inject IJSRuntime JSRuntime
8-
@inherits EstateManagementUI.BlazorServer.Components.Common.CustomComponentBase
9-
@inject ILogger<AnalyticalCharts> Logger
109
@inject AuthenticationStateProvider AuthenticationStateProvider
1110

1211
<PageTitle>Analytical Charts (Volume &amp; Value)</PageTitle>
@@ -146,7 +145,7 @@
146145
<h3 class="card-title">Transaction Volume Over Time</h3>
147146
</div>
148147
<div class="card-body">
149-
<canvas id="volumeChart" style="max-height: 400px;"></canvas>
148+
<canvas @ref="volumeCanvas" id="volumeChart" style="max-height: 400px;"></canvas>
150149
</div>
151150
</div>
152151

@@ -156,232 +155,9 @@
156155
<h3 class="card-title">Transaction Value Over Time</h3>
157156
</div>
158157
<div class="card-body">
159-
<canvas id="valueChart" style="max-height: 400px;"></canvas>
158+
<canvas @ref="valueCanvas" id="valueChart" style="max-height: 400px;"></canvas>
160159
</div>
161160
</div>
162161
</div>
163162
}
164-
</div>
165-
166-
@code {
167-
private bool isLoading = true;
168-
private string? errorMessage;
169-
170-
private List<ComparisonDateModel>? comparisonDates;
171-
private string _selectedComparisonDate = DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd");
172-
private string _selectedChartType = "line";
173-
174-
private decimal totalValue = 0;
175-
private int totalCount = 0;
176-
private decimal averageValue = 0;
177-
private decimal netSettlement = 0;
178-
179-
private List<TodaysSalesCountByHourModel>? salesCountData;
180-
private List<TodaysSalesValueByHourModel>? salesValueData;
181-
private TodaysSalesModel? todaysSales;
182-
private TodaysSettlementModel? todaysSettlement;
183-
184-
protected override async Task OnInitializedAsync()
185-
{
186-
await LoadDashboardData();
187-
await base.OnInitializedAsync();
188-
}
189-
190-
protected override async Task OnAfterRenderAsync(bool firstRender)
191-
{
192-
if (firstRender)
193-
{
194-
// Give Chart.js time to load from CDN
195-
await this.WaitOnUIRefresh();
196-
}
197-
198-
if (!isLoading && salesCountData != null && salesValueData != null)
199-
{
200-
try
201-
{
202-
// Check if Chart.js is available
203-
var isChartJsLoaded = await JSRuntime.InvokeAsync<bool>("eval", "typeof Chart !== 'undefined'");
204-
if (!isChartJsLoaded)
205-
{
206-
Logger.LogWarning("Chart.js not loaded yet, will retry on next render");
207-
return;
208-
}
209-
210-
await UpdateCharts();
211-
}
212-
catch (Exception ex)
213-
{
214-
Logger.LogError(ex, "Error in OnAfterRenderAsync");
215-
}
216-
}
217-
}
218-
219-
private async Task LoadDashboardData()
220-
{
221-
try
222-
{
223-
isLoading = true;
224-
errorMessage = null;
225-
StateHasChanged();
226-
227-
var correlationId = new CorrelationId(Guid.NewGuid());
228-
// Note: These are stubbed values used throughout the test environment
229-
// In production, these would come from the authentication context
230-
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
231-
var user = authState.User;
232-
var estateIdClaim = ClaimsHelper.GetUserClaim(user, "estateId");
233-
if (estateIdClaim.IsFailed)
234-
return;
235-
Guid estateId = Guid.Parse(estateIdClaim.Data.Value);
236-
var accessToken = "stubbed-token";
237-
238-
// Load comparison dates first (only if not already loaded)
239-
if (comparisonDates == null || !comparisonDates.Any())
240-
{
241-
var comparisonDatesResult = await Mediator.Send(new Queries.GetComparisonDatesQuery(correlationId, estateId));
242-
if (comparisonDatesResult.IsSuccess)
243-
{
244-
comparisonDates = ModelFactory.ConvertFrom(comparisonDatesResult.Data);
245-
if (comparisonDates != null && comparisonDates.Any())
246-
{
247-
_selectedComparisonDate = comparisonDates.First().Date.ToString("yyyy-MM-dd");
248-
}
249-
}
250-
}
251-
252-
if (!DateTime.TryParse(_selectedComparisonDate, out var comparisonDate))
253-
{
254-
comparisonDate = DateTime.Now.AddDays(-7);
255-
}
256-
257-
// Load all data in parallel
258-
var salesCountTask = Mediator.Send(new Queries.GetTodaysSalesCountByHourQuery(correlationId, accessToken, estateId, comparisonDate));
259-
var salesValueTask = Mediator.Send(new Queries.GetTodaysSalesValueByHourQuery(correlationId, accessToken, estateId, comparisonDate));
260-
var todaysSalesTask = Mediator.Send(new TransactionQueries.GetTodaysSalesQuery(correlationId, estateId, comparisonDate));
261-
var settlementTask = Mediator.Send(new Queries.GetTodaysSettlementQuery(correlationId, accessToken, estateId, comparisonDate));
262-
263-
await Task.WhenAll(salesCountTask, salesValueTask, todaysSalesTask, settlementTask);
264-
265-
// Process results
266-
if (salesCountTask.Result.IsSuccess)
267-
salesCountData = ModelFactory.ConvertFrom(salesCountTask.Result.Data);
268-
269-
if (salesValueTask.Result.IsSuccess)
270-
salesValueData = ModelFactory.ConvertFrom(salesValueTask.Result.Data);
271-
272-
if (todaysSalesTask.Result.IsSuccess)
273-
todaysSales = ModelFactory.ConvertFrom(todaysSalesTask.Result.Data);
274-
275-
if (settlementTask.Result.IsSuccess)
276-
todaysSettlement = ModelFactory.ConvertFrom(settlementTask.Result.Data);
277-
278-
// Calculate KPIs
279-
CalculateKPIs();
280-
}
281-
catch (Exception ex)
282-
{
283-
errorMessage = $"Failed to load data: {ex.Message}";
284-
}
285-
finally
286-
{
287-
isLoading = false;
288-
StateHasChanged();
289-
}
290-
}
291-
292-
private void CalculateKPIs()
293-
{
294-
if (todaysSales != null)
295-
{
296-
totalValue = todaysSales.TodaysSalesValue;
297-
totalCount = todaysSales.TodaysSalesCount;
298-
averageValue = totalCount > 0 ? totalValue / totalCount : 0;
299-
}
300-
301-
if (todaysSettlement != null)
302-
{
303-
netSettlement = todaysSettlement.TodaysSettlementValue;
304-
}
305-
}
306-
307-
private async Task OnFiltersChanged()
308-
{
309-
await LoadDashboardData();
310-
}
311-
312-
private async Task UpdateCharts()
313-
{
314-
try
315-
{
316-
if (salesCountData == null || salesValueData == null)
317-
{
318-
Logger.LogWarning("Chart data is null - salesCountData: {SalesCountData}, salesValueData: {SalesValueData}",
319-
salesCountData == null ? "null" : "not null",
320-
salesValueData == null ? "null" : "not null");
321-
return;
322-
}
323-
324-
Logger.LogInformation("Updating charts with {CountRecords} count records and {ValueRecords} value records",
325-
salesCountData.Count, salesValueData.Count);
326-
327-
// Create labels with date and time context
328-
var today = DateTime.Today;
329-
var comparisonDateParsed = DateTime.TryParse(_selectedComparisonDate, out var compDate) ? compDate : DateTime.Today.AddDays(-7);
330-
331-
var labels = salesCountData.Select(d => $"{d.Hour:00}:00").ToArray();
332-
var todaysCountData = salesCountData.Select(d => d.TodaysSalesCount).ToArray();
333-
var comparisonCountData = salesCountData.Select(d => d.ComparisonSalesCount).ToArray();
334-
335-
var todaysValueData = salesValueData.Select(d => (double)d.TodaysSalesValue).ToArray();
336-
var comparisonValueData = salesValueData.Select(d => (double)d.ComparisonSalesValue).ToArray();
337-
338-
var comparisonLabel = GetComparisonLabel();
339-
var todayLabel = today.ToString("MMM dd");
340-
var comparisonDateLabel = compDate.ToString("MMM dd");
341-
342-
Logger.LogInformation("Chart labels: {Labels}, Today data points: {TodayCount}, Comparison data points: {CompCount}",
343-
string.Join(", ", labels), todaysCountData.Length, comparisonCountData.Length);
344-
345-
// Update Volume Chart
346-
await JSRuntime.InvokeVoidAsync("updateOrCreateChart",
347-
"volumeChart",
348-
_selectedChartType,
349-
labels,
350-
new object[]
351-
{
352-
new { label = $"Today ({todayLabel}) Volume", data = todaysCountData, borderColor = "rgb(59, 130, 246)", backgroundColor = "rgba(59, 130, 246, 0.1)", tension = 0.4 },
353-
new { label = $"{comparisonLabel} ({comparisonDateLabel}) Volume", data = comparisonCountData, borderColor = "rgb(156, 163, 175)", backgroundColor = "rgba(156, 163, 175, 0.1)", tension = 0.4 }
354-
},
355-
"Transaction Count"
356-
);
357-
358-
// Update Value Chart
359-
await JSRuntime.InvokeVoidAsync("updateOrCreateChart",
360-
"valueChart",
361-
_selectedChartType,
362-
labels,
363-
new object[]
364-
{
365-
new { label = $"Today ({todayLabel}) Value", data = todaysValueData, borderColor = "rgb(16, 185, 129)", backgroundColor = "rgba(16, 185, 129, 0.1)", tension = 0.4 },
366-
new { label = $"{comparisonLabel} ({comparisonDateLabel}) Value", data = comparisonValueData, borderColor = "rgb(156, 163, 175)", backgroundColor = "rgba(156, 163, 175, 0.1)", tension = 0.4 }
367-
},
368-
"Transaction Value ($)"
369-
);
370-
371-
Logger.LogInformation("Charts updated successfully");
372-
}
373-
catch (Exception ex)
374-
{
375-
Logger.LogError(ex, "Error updating charts");
376-
}
377-
}
378-
379-
private string GetComparisonLabel()
380-
{
381-
if (comparisonDates == null) return "Comparison";
382-
if (!DateTime.TryParse(_selectedComparisonDate, out var date))
383-
return "Comparison";
384-
var comparisonDate = comparisonDates.FirstOrDefault(d => d.Date.Date == date.Date);
385-
return comparisonDate?.Description ?? date.ToString("MMM dd");
386-
}
387-
}
163+
</div>

0 commit comments

Comments
 (0)