Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions EstateManagementUI.BlazorServer/Components/App.razor
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
<body class="h-full">
<Routes />
<ReconnectModal />
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" crossorigin="anonymous"></script>
<script src="js/charts.js"></script>
<script src="js/site.js"></script>
<script src="@Assets["_framework/blazor.web.js"]"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" crossorigin="anonymous"></script>
<script src="js/charts.js"></script>
</body>

</html>
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
@using EstateManagementUI.BusinessLogic.Requests
@using global::Shared.General
@rendermode InteractiveServer
@inherits AuthorizedComponentBase
@inject IMediator Mediator
@inject IJSRuntime JSRuntime
@inherits EstateManagementUI.BlazorServer.Components.Common.CustomComponentBase
@inject ILogger<AnalyticalCharts> Logger
@inject AuthenticationStateProvider AuthenticationStateProvider

<PageTitle>Analytical Charts (Volume &amp; Value)</PageTitle>
Expand Down Expand Up @@ -161,227 +160,4 @@
</div>
</div>
}
</div>

@code {
private bool isLoading = true;
private string? errorMessage;

private List<ComparisonDateModel>? comparisonDates;
private string _selectedComparisonDate = DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd");
private string _selectedChartType = "line";

private decimal totalValue = 0;
private int totalCount = 0;
private decimal averageValue = 0;
private decimal netSettlement = 0;

private List<TodaysSalesCountByHourModel>? salesCountData;
private List<TodaysSalesValueByHourModel>? salesValueData;
private TodaysSalesModel? todaysSales;
private TodaysSettlementModel? todaysSettlement;

protected override async Task OnInitializedAsync()
{
await LoadDashboardData();
await base.OnInitializedAsync();
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// Give Chart.js time to load from CDN
await this.WaitOnUIRefresh();
}

if (!isLoading && salesCountData != null && salesValueData != null)
{
try
{
// Check if Chart.js is available
var isChartJsLoaded = await JSRuntime.InvokeAsync<bool>("eval", "typeof Chart !== 'undefined'");
if (!isChartJsLoaded)
{
Logger.LogWarning("Chart.js not loaded yet, will retry on next render");
return;
}

await UpdateCharts();
}
catch (Exception ex)
{
Logger.LogError(ex, "Error in OnAfterRenderAsync");
}
}
}

private async Task LoadDashboardData()
{
try
{
isLoading = true;
errorMessage = null;
StateHasChanged();

var correlationId = new CorrelationId(Guid.NewGuid());
// Note: These are stubbed values used throughout the test environment
// In production, these would come from the authentication context
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
var estateIdClaim = ClaimsHelper.GetUserClaim(user, "estateId");
if (estateIdClaim.IsFailed)
return;
Guid estateId = Guid.Parse(estateIdClaim.Data.Value);
var accessToken = "stubbed-token";

// Load comparison dates first (only if not already loaded)
if (comparisonDates == null || !comparisonDates.Any())
{
var comparisonDatesResult = await Mediator.Send(new Queries.GetComparisonDatesQuery(correlationId, estateId));
if (comparisonDatesResult.IsSuccess)
{
comparisonDates = ModelFactory.ConvertFrom(comparisonDatesResult.Data);
if (comparisonDates != null && comparisonDates.Any())
{
_selectedComparisonDate = comparisonDates.First().Date.ToString("yyyy-MM-dd");
}
}
}

if (!DateTime.TryParse(_selectedComparisonDate, out var comparisonDate))
{
comparisonDate = DateTime.Now.AddDays(-7);
}

// Load all data in parallel
var salesCountTask = Mediator.Send(new Queries.GetTodaysSalesCountByHourQuery(correlationId, accessToken, estateId, comparisonDate));
var salesValueTask = Mediator.Send(new Queries.GetTodaysSalesValueByHourQuery(correlationId, accessToken, estateId, comparisonDate));
var todaysSalesTask = Mediator.Send(new TransactionQueries.GetTodaysSalesQuery(correlationId, estateId, comparisonDate));
var settlementTask = Mediator.Send(new Queries.GetTodaysSettlementQuery(correlationId, accessToken, estateId, comparisonDate));

await Task.WhenAll(salesCountTask, salesValueTask, todaysSalesTask, settlementTask);

// Process results
if (salesCountTask.Result.IsSuccess)
salesCountData = ModelFactory.ConvertFrom(salesCountTask.Result.Data);

if (salesValueTask.Result.IsSuccess)
salesValueData = ModelFactory.ConvertFrom(salesValueTask.Result.Data);

if (todaysSalesTask.Result.IsSuccess)
todaysSales = ModelFactory.ConvertFrom(todaysSalesTask.Result.Data);

if (settlementTask.Result.IsSuccess)
todaysSettlement = ModelFactory.ConvertFrom(settlementTask.Result.Data);

// Calculate KPIs
CalculateKPIs();
}
catch (Exception ex)
{
errorMessage = $"Failed to load data: {ex.Message}";
}
finally
{
isLoading = false;
StateHasChanged();
}
}

private void CalculateKPIs()
{
if (todaysSales != null)
{
totalValue = todaysSales.TodaysSalesValue;
totalCount = todaysSales.TodaysSalesCount;
averageValue = totalCount > 0 ? totalValue / totalCount : 0;
}

if (todaysSettlement != null)
{
netSettlement = todaysSettlement.TodaysSettlementValue;
}
}

private async Task OnFiltersChanged()
{
await LoadDashboardData();
}

private async Task UpdateCharts()
{
try
{
if (salesCountData == null || salesValueData == null)
{
Logger.LogWarning("Chart data is null - salesCountData: {SalesCountData}, salesValueData: {SalesValueData}",
salesCountData == null ? "null" : "not null",
salesValueData == null ? "null" : "not null");
return;
}

Logger.LogInformation("Updating charts with {CountRecords} count records and {ValueRecords} value records",
salesCountData.Count, salesValueData.Count);

// Create labels with date and time context
var today = DateTime.Today;
var comparisonDateParsed = DateTime.TryParse(_selectedComparisonDate, out var compDate) ? compDate : DateTime.Today.AddDays(-7);

var labels = salesCountData.Select(d => $"{d.Hour:00}:00").ToArray();
var todaysCountData = salesCountData.Select(d => d.TodaysSalesCount).ToArray();
var comparisonCountData = salesCountData.Select(d => d.ComparisonSalesCount).ToArray();

var todaysValueData = salesValueData.Select(d => (double)d.TodaysSalesValue).ToArray();
var comparisonValueData = salesValueData.Select(d => (double)d.ComparisonSalesValue).ToArray();

var comparisonLabel = GetComparisonLabel();
var todayLabel = today.ToString("MMM dd");
var comparisonDateLabel = compDate.ToString("MMM dd");

Logger.LogInformation("Chart labels: {Labels}, Today data points: {TodayCount}, Comparison data points: {CompCount}",
string.Join(", ", labels), todaysCountData.Length, comparisonCountData.Length);

// Update Volume Chart
await JSRuntime.InvokeVoidAsync("updateOrCreateChart",
"volumeChart",
_selectedChartType,
labels,
new object[]
{
new { label = $"Today ({todayLabel}) Volume", data = todaysCountData, borderColor = "rgb(59, 130, 246)", backgroundColor = "rgba(59, 130, 246, 0.1)", tension = 0.4 },
new { label = $"{comparisonLabel} ({comparisonDateLabel}) Volume", data = comparisonCountData, borderColor = "rgb(156, 163, 175)", backgroundColor = "rgba(156, 163, 175, 0.1)", tension = 0.4 }
},
"Transaction Count"
);

// Update Value Chart
await JSRuntime.InvokeVoidAsync("updateOrCreateChart",
"valueChart",
_selectedChartType,
labels,
new object[]
{
new { label = $"Today ({todayLabel}) Value", data = todaysValueData, borderColor = "rgb(16, 185, 129)", backgroundColor = "rgba(16, 185, 129, 0.1)", tension = 0.4 },
new { label = $"{comparisonLabel} ({comparisonDateLabel}) Value", data = comparisonValueData, borderColor = "rgb(156, 163, 175)", backgroundColor = "rgba(156, 163, 175, 0.1)", tension = 0.4 }
},
"Transaction Value ($)"
);

Logger.LogInformation("Charts updated successfully");
}
catch (Exception ex)
{
Logger.LogError(ex, "Error updating charts");
}
}

private string GetComparisonLabel()
{
if (comparisonDates == null) return "Comparison";
if (!DateTime.TryParse(_selectedComparisonDate, out var date))
return "Comparison";
var comparisonDate = comparisonDates.FirstOrDefault(d => d.Date.Date == date.Date);
return comparisonDate?.Description ?? date.ToString("MMM dd");
}
}
</div>
Loading
Loading