@page "/home" @using Microsoft.AspNetCore.Authorization @using Indotalent.Infrastructure.Authorization.Identity @using Indotalent.Features.Root.Home.Cqrs @using Indotalent.Features.Root.Home @attribute [Authorize(Roles = $"{ApplicationRoles.Admin},{ApplicationRoles.Member}")] @inject HomeService HomeService @inject IJSRuntime JS WMS Dashboard
@* HEADER *@

WMS Dashboard

@* ROW 1: 12-col KPI layout *@
@* Key Metrics Card *@

WMS Overview

Key Metrics

Stock on Hand

@_data.FormattedStock

Inventory Value

@_data.FormattedInvValue

MTD Inbound

@_data.FormattedMonthlyIn

MTD Outbound

@_data.FormattedMonthlyOut

SKUs: @_data.TotalSku.ToString("N0") FY @DateTime.Now.Year
@* 8 Small KPI Cards (row 1, cols 6-12) *@

Total GR

@_data.GrCount

Total DO

@_data.DoCount

Stock Acc

@_data.StockAccuracy%

Order Fulfill

@_data.OrderFulfillmentRate%

Scrapping

@_data.ScrapCount

Adjustments

@_data.AdjustmentCount

Pending IN

@_data.PendingInbound

Pending OUT

@_data.PendingOutbound

@* Metrics Matrix *@

WMS Metrics Matrix

Key indicators across warehouse operations

@{ var mmItems = new[] { new { Title = "Total GR", Sub = _data.GrCount.ToString(), ColorClass = "mm-c1" }, new { Title = "Total DO", Sub = _data.DoCount.ToString(), ColorClass = "mm-c2" }, new { Title = "Stock on Hand", Sub = _data.FormattedStock, ColorClass = "mm-c3" }, new { Title = "Inventory Value", Sub = _data.FormattedInvValue, ColorClass = "mm-c4" }, new { Title = "MTD Inbound", Sub = _data.FormattedMonthlyIn, ColorClass = "mm-c5" }, new { Title = "MTD Outbound", Sub = _data.FormattedMonthlyOut, ColorClass = "mm-c6" }, new { Title = "Accuracy", Sub = $"{_data.StockAccuracy}%", ColorClass = "mm-c7" }, new { Title = "Fulfillment", Sub = $"{_data.OrderFulfillmentRate}%", ColorClass = "mm-c8" }, new { Title = "Pending IN", Sub = _data.PendingInbound.ToString(), ColorClass = "mm-c9" }, new { Title = "Pending OUT", Sub = _data.PendingOutbound.ToString(), ColorClass = "mm-c10" }, new { Title = "Scrapping", Sub = _data.ScrapCount.ToString(), ColorClass = "mm-c11" }, new { Title = "Adjustments", Sub = _data.AdjustmentCount.ToString(), ColorClass = "mm-c12" }, new { Title = "SKUs", Sub = _data.TotalSku.ToString("N0"), ColorClass = "mm-c13" }, new { Title = "Warehouses", Sub = _data.WarehouseCount.ToString(), ColorClass = "mm-c14" }, new { Title = "Transfers", Sub = _data.TransferCount.ToString(), ColorClass = "mm-c15" }, new { Title = "StockCounts", Sub = _data.StockCountCount.ToString(), ColorClass = "mm-c16" }, new { Title = "MTD Tx", Sub = _data.MonthlyTransactionCount.ToString("N0"), ColorClass = "mm-c17" }, new { Title = "Yearly IN", Sub = ((decimal)_data.YearlyInboundQty).ToString("N0"), ColorClass = "mm-c18" }, new { Title = "Yearly OUT", Sub = ((decimal)_data.YearlyOutboundQty).ToString("N0"), ColorClass = "mm-c19" }, new { Title = "Inv Value", Sub = _data.FormattedInvValue, ColorClass = "mm-c20" } }; } @foreach (var item in mmItems) {

@item.Title

@item.Sub

}
@* ROW 2: Stock Movement Trend + Module Breakdown *@

Stock Movement Trend

Monthly inbound vs outbound

Inbound Outbound

Module Breakdown

By transaction count

@if (_data.ModuleBreakdown.Any()) { var mbTotal = _data.ModuleBreakdown.Sum(x => x.Count); @foreach (var mb in _data.ModuleBreakdown) { var pct = mbTotal > 0 ? Math.Round((double)mb.Count / mbTotal * 100) : 0;
@mb.Label @pct%
} } else {
GR 0%
DO 0%
ADJ 0%
SCRP 0%
}
@* ROW 3: Warehouse Summary + Module Breakdown Detail + Yearly Movement *@

Warehouse Summary

As of @DateTime.Now.ToString("MMMM dd, yyyy")

@if (_data.PipelineSummary.Any()) { @foreach (var ps in _data.PipelineSummary) {

@ps.Label

@ps.Value

} }
Accuracy@_data.StockAccuracy% SKUs@_data.TotalSku.ToString("N0")

Module Detail

By transaction count

@foreach (var mb in _data.ModuleBreakdown) {
@(mb.Label?.Length > 3 ? mb.Label[..3] : mb.Label)

@mb.Label

@mb.Count

}
Total: @_data.ModuleBreakdown.Sum(x => x.Count) Modules: @_data.ModuleBreakdown.Count

Yearly Movement

@DateTime.Now.Year summary

@foreach (var ym in _data.YearlyMovement) {
@ym.Qty.ToString("N0")

@ym.Category

}
@* ROW 4: Recent Transactions + WMS Activity *@

Recent Transactions

Latest movements

@if (_data.RecentTransactions.Any()) { @foreach (var d in _data.RecentTransactions) { } } else { }
DateTx#ProductQtyModule
@(d.Date?.ToString("MMM dd") ?? "-") @d.Number @d.Description @d.Quantity.ToString("N0") @d.Module
No recent transactions available
MTD Tx: @_data.MonthlyTransactionCount.ToString("N0") Pending: @(_data.PendingInbound + _data.PendingOutbound)

WMS Activity

Real-time updates

Live
@if (_data.ActivityFeeds.Any()) { @foreach (var af in _data.ActivityFeeds) {

@af.Title

@af.Detail

@af.TimeAgo

@af.ChipLabel
} } else {

No recent activity

}
@* ROW 5: Conversion Metrics + Top Products + Warehouse KPIs *@

Conversion Metrics

@DateTime.Now.Year Performance

@foreach (var cm in _data.ConversionMetrics) {

@cm.Label

@cm.Current / @cm.Target
}
Accuracy: @_data.StockAccuracy% @(_data.StockAccuracy >= 95 ? "On Track" : "Improving")

Top Products

By movement volume

@if (_data.TopProducts.Any()) { var tpColors = new[] { "#f97316", "#f59e0b", "#6366f1", "#8b5cf6", "#06b6d4" }; @for (int i = 0; i < Math.Min(_data.TopProducts.Count, 5); i++) { var p = _data.TopProducts[i];

@p.ProductName

@p.TotalMovement.ToString("N0")

} } else {

No product data available

}
SKUs: @_data.TotalSku.ToString("N0")Value: @_data.FormattedInvValue

Warehouse KPIs

Per warehouse summary

@if (_data.WarehouseKpis.Any()) { @foreach (var wk in _data.WarehouseKpis) {

@wk.WarehouseName

@wk.SkuCount SKUs

@((decimal)wk.StockQty)
} } else {

No warehouse data

}
@code { private DashboardWmsResponse _data = new(); private bool _isLoading = true; private bool _chartsInitialized = false; private bool _dataReady = false; protected override async Task OnInitializedAsync() { _isLoading = true; try { var res = await HomeService.GetWmsDashboardStatsAsync(); if (res?.IsSuccess == true && res.Value != null) { _data = res.Value; _dataReady = true; StateHasChanged(); } } finally { _isLoading = false; } } protected override async Task OnAfterRenderAsync(bool firstRender) { if (_dataReady && !_chartsInitialized) { _chartsInitialized = true; await InitCharts(); } } private async Task InitCharts() { // Chart 1: Stock Movement Trend (Inbound vs Outbound) var movementLabels = _data.StockMovementTrend.Any() ? _data.StockMovementTrend.Select(x => x.Label ?? "").ToArray() : new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun" }; var inboundData = _data.StockMovementTrend.Any() ? _data.StockMovementTrend.Select(x => x.InQty).ToArray() : new double[6]; var outboundData = _data.StockMovementTrend.Any() ? _data.StockMovementTrend.Select(x => x.OutQty).ToArray() : new double[6]; // Chart 2: Module Breakdown doughnut var moduleLabels = _data.ModuleBreakdown.Any() ? _data.ModuleBreakdown.Select(x => x.Label ?? "").ToArray() : new[] { "GR", "DO", "ADJ", "SCRP" }; var moduleData = _data.ModuleBreakdown.Any() ? _data.ModuleBreakdown.Select(x => (double)x.Count).Cast().ToArray() : new object[] { 10, 10, 10, 10 }; var moduleColors = _data.ModuleBreakdown.Any() ? _data.ModuleBreakdown.Select(x => x.Color ?? "#06b6d4").ToArray() : new[] { "#06b6d4", "#10b981", "#6366f1", "#dc2626" }; // Chart 3: Yearly Movement bar var yearlyLabels = _data.YearlyMovement.Any() ? _data.YearlyMovement.Select(x => x.Category ?? "").ToArray() : new[] { "Inbound", "Outbound", "Net" }; var yearlyData = _data.YearlyMovement.Any() ? _data.YearlyMovement.Select(x => x.Qty).ToArray() : new double[] { 0, 0, 0 }; var yearlyColors = _data.YearlyMovement.Any() ? _data.YearlyMovement.Select(x => x.Color ?? "#6366f1").ToArray() : new[] { "#10b981", "#e11d48", "#6366f1" }; await JS.InvokeVoidAsync("initWmsDashboardCharts", movementLabels, inboundData, outboundData, moduleLabels, moduleData, moduleColors, yearlyLabels, yearlyData, yearlyColors); } } @* Chart initialization script *@