@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 SCM Enterprise Intelligence
@if (_isLoading) {

Loading SCM Dashboard...

} else {
@* HEADER *@

SCM Dashboard

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

SCM Overview

Key Metrics

MTD Sales

@_data.FormattedSales

MTD Purchase

@_data.FormattedPurchase

Total Receivable

@_data.FormattedReceivable

Total Payable

@_data.FormattedPayable

Chain Accuracy: @_data.ChainAccuracyIndex% FY @DateTime.Now.Year
@* 8 Small KPI Cards (row 1 & 2) *@

Pending PR

@_data.PendingPR

Pending SQ

@_data.PendingSQ

Pending GR

@_data.PendingGR

Pending DO

@_data.PendingDO

Active Cust

@_data.ActiveCustomer

Active Vend

@_data.ActiveVendor

Inbound Qty

@_data.InboundQtyMTD.ToString("N0")

Outbound Qty

@_data.OutboundQtyMTD.ToString("N0")

@* ROW 2: Doc Matrix *@

SCM Document Matrix

All module document totals

@foreach (var doc in _data.DocGrid) { var colorClass = "mm-c" + ((Array.IndexOf(_data.DocGrid.ToArray(), doc) % 20) + 1);

@doc.Label

@doc.Value docs

}
@* ROW 3: Revenue Trend + Product Categories Donut *@

Sales vs Purchase Trend

Monthly revenue vs procurement

Sales Purchase

Product Categories

By product group

@if (_data.ProductCategories.Any()) { var donutColors = new[] { "#2563eb", "#f97316", "#ec4899", "#8b5cf6", "#06b6d4", "#10b981", "#f59e0b", "#e11d48" }; @foreach (var cat in _data.ProductCategories.Take(8)) { var idx = _data.ProductCategories.IndexOf(cat);
@cat.Label @cat.Value
} } else {
General 0
}
@* ROW 4: PO Status + GR Status + Inventory Flow *@
@* PO Status Breakdown *@

PO Status Breakdown

Total: @_data.TotalPO POs

@foreach (var s in _data.POStatusBreakdown) {

@s.Status

@s.Count POs

}
@* GR Status Breakdown *@

GR Status Breakdown

Total: @_data.TotalGR GRs

@foreach (var s in _data.GRStatusBreakdown) {

@s.Status

@s.Count GRs

}
@* Inventory Flow *@

Inventory Flow

MTD movement

@_data.InboundQtyMTD.ToString("N0")

Inbound

@_data.OutboundQtyMTD.ToString("N0")

Outbound

@_data.ChainAccuracyIndex%

Accuracy

@* ROW 5: Recent POs + Recent GRs *@
@* Recent POs *@

Recent Purchase Orders

Latest PO transactions

@if (_data.RecentPOs.Any()) { @foreach (var po in _data.RecentPOs) { } } else { }
DatePO#VendorAmountStatus
@(po.OrderDate?.ToString("MMM dd") ?? "-") @po.Number @po.VendorName @po.Amount.ToString("N0") @po.Status
No recent POs available
Total POs: @_data.TotalPO MTD Purchase: @_data.FormattedPurchase
@* Recent GRs *@

Recent Goods Receives

Latest receiving activity

@if (_data.RecentGRs.Any()) { @foreach (var gr in _data.RecentGRs) { } } else { }
DateGR#PO RefStatus
@(gr.ReceiveDate?.ToString("MMM dd") ?? "-") @gr.Number @gr.PONumber @gr.Status
No recent GRs available
Total GRs: @_data.TotalGR
@* ROW 6: Vendor PO Totals + PR/DO Status + Flow Log *@
@* Vendor PO Totals *@

Top Vendors (PO)

Total PO value per vendor

@if (_data.VendorPOTotals.Any()) { @foreach (var v in _data.VendorPOTotals.Take(8)) {

@v.Label

@v.Value
} } else {

No vendor data available

}
@* PR & DO Status *@

PR & DO Status

Requisition & delivery overview

Purchase Requisitions

@foreach (var s in _data.PRStatusBreakdown) {
@s.Status
@s.Count
}

Delivery Orders

@foreach (var s in _data.DOStatusBreakdown) {
@s.Status
@s.Count
}
PRs: @_data.TotalPR DOs: @_data.TotalDO
@* Supply Chain Flow Log *@

Supply Chain Flow

Real-time inventory movements

Live
@if (_data.GlobalFlowLog.Any()) { @foreach (var tx in _data.GlobalFlowLog.Take(8)) { var initials = (tx.Module ?? "SCM").Length >= 2 ? (tx.Module ?? "SCM")[..2].ToUpper() : "SC"; var avatarColors = new[] { "#2563eb", "#10b981", "#f59e0b", "#6366f1", "#ec4899", "#e11d48", "#8b5cf6", "#06b6d4" }; var avatarColor = avatarColors[Math.Abs(tx.Module?.GetHashCode() ?? 0) % avatarColors.Length];
@initials

@tx.Module

#@tx.Number · WH: @tx.Partner · Qty: @tx.Qty.ToString("N0")

@tx.Date?.ToString("dd MMM HH:mm")

@tx.Status
} } else {

No recent flow

}
}
@code { private DashboardScmResponse _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.GetScmDashboardStatsAsync(); 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() { var revenueLabels = _data.MonthlySalesVsPurchase.Any() ? _data.MonthlySalesVsPurchase.Select(x => x.Label).ToArray() : new[] { "Jan", "Feb", "Mar", "Apr", "May", "Jun" }; var salesData = _data.MonthlySalesVsPurchase.Any() ? _data.MonthlySalesVsPurchase.Select(x => x.SalesAmount).ToArray() : new double[] { 0, 0, 0, 0, 0, 0 }; var purchaseData = _data.MonthlySalesVsPurchase.Any() ? _data.MonthlySalesVsPurchase.Select(x => x.PurchaseAmount).ToArray() : new double[] { 0, 0, 0, 0, 0, 0 }; var catList = _data.ProductCategories.Take(8).ToList(); var defaultColors = new[] { "#2563eb", "#f97316", "#ec4899", "#8b5cf6", "#06b6d4", "#10b981", "#f59e0b", "#e11d48" }; var donutLabels = catList.Any() ? catList.Select(x => x.Label).ToArray() : new[] { "General" }; var donutData = catList.Any() ? catList.Select(x => double.TryParse(x.Value, out var v) ? v : 0).Cast().ToArray() : new object[] { 0 }; var donutColors = catList.Any() ? catList.Select((x, i) => defaultColors[i % defaultColors.Length]).ToArray() : new[] { "#2563eb" }; var flowLabels = new[] { "Inbound", "Outbound", "Accuracy" }; var flowCounts = new[] { _data.InboundQtyMTD, _data.OutboundQtyMTD, _data.ChainAccuracyIndex * 10 }; var flowColors = new[] { "#10b981", "#e11d48", "#6366f1" }; await JS.InvokeVoidAsync("initDashboardCharts", revenueLabels, salesData, purchaseData, donutLabels, donutData, donutColors, flowLabels, flowCounts, flowColors); } } @* Chart initialization script *@