2026-04-27 21:10:16 -04:00
|
|
|
<!-- Inventory Dashboard Summary — filament metrics at a glance -->
|
|
|
|
|
<section class="inventory-summary" role="region" aria-label="Inventory summary">
|
2026-04-27 18:11:30 -04:00
|
|
|
|
2026-04-27 21:10:16 -04:00
|
|
|
<!-- Loading State -->
|
|
|
|
|
@if (loading()) {
|
|
|
|
|
<div class="summary-loading" role="status" aria-live="polite">
|
|
|
|
|
<mat-icon aria-hidden="true" class="spin">sync</mat-icon>
|
|
|
|
|
<span>Loading inventory...</span>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
2026-04-27 18:11:30 -04:00
|
|
|
|
2026-04-27 21:10:16 -04:00
|
|
|
<!-- Error State -->
|
|
|
|
|
@else if (error()) {
|
|
|
|
|
<div class="summary-error" role="alert" aria-live="assertive">
|
|
|
|
|
<mat-icon aria-hidden="true">error_outline</mat-icon>
|
|
|
|
|
<span>{{ error() }}</span>
|
|
|
|
|
<button class="retry-btn" (click)="refresh()" aria-label="Retry loading inventory">
|
|
|
|
|
<mat-icon aria-hidden="true">refresh</mat-icon>
|
|
|
|
|
Retry
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
2026-04-27 18:11:30 -04:00
|
|
|
|
2026-04-27 21:10:16 -04:00
|
|
|
<!-- Loaded State -->
|
|
|
|
|
@else {
|
|
|
|
|
<!-- Health Status Indicator -->
|
|
|
|
|
<div class="summary-item health-status"
|
|
|
|
|
[class]="healthClass()"
|
|
|
|
|
[matTooltip]="healthLabel()"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon aria-hidden="true">
|
|
|
|
|
@switch (healthClass()) {
|
|
|
|
|
@case ('critical') { error }
|
|
|
|
|
@case ('low') { warning }
|
|
|
|
|
@default { check_circle }
|
|
|
|
|
}
|
|
|
|
|
</mat-icon>
|
|
|
|
|
<span class="health-text">{{ healthLabel() }}</span>
|
|
|
|
|
</div>
|
2026-04-27 18:11:30 -04:00
|
|
|
|
2026-04-27 21:10:16 -04:00
|
|
|
<!-- Total Spool Count -->
|
|
|
|
|
<div class="summary-item metric-card"
|
|
|
|
|
matTooltip="Total filament spools in inventory"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon aria-hidden="true" class="metric-icon">inventory_2</mat-icon>
|
|
|
|
|
<div class="metric-content">
|
|
|
|
|
<span class="metric-value">{{ totalCount() }}</span>
|
|
|
|
|
<span class="metric-label">Total Spools</span>
|
|
|
|
|
</div>
|
|
|
|
|
@if (activeCount() < totalCount()) {
|
|
|
|
|
<span class="metric-detail">{{ activeCount() }} active</span>
|
|
|
|
|
}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Low Stock Count -->
|
|
|
|
|
<div class="summary-item metric-card"
|
|
|
|
|
[class.has-alert]="hasLowStock()"
|
|
|
|
|
[class.has-critical]="hasCritical()"
|
|
|
|
|
[matTooltip]="hasCritical()
|
|
|
|
|
? criticalCount() + ' critical, ' + (lowStockCount() - criticalCount()) + ' low'
|
|
|
|
|
: hasLowStock()
|
|
|
|
|
? lowStockCount() + ' spools at or below 25% remaining'
|
|
|
|
|
: 'All spools above 25% remaining'"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon aria-hidden="true" class="metric-icon">
|
|
|
|
|
@if (hasCritical()) { error }
|
|
|
|
|
@else if (hasLowStock()) { warning }
|
|
|
|
|
@else { check_circle }
|
|
|
|
|
</mat-icon>
|
|
|
|
|
<div class="metric-content">
|
|
|
|
|
<span class="metric-value">{{ lowStockCount() }}</span>
|
|
|
|
|
<span class="metric-label">Low Stock</span>
|
|
|
|
|
</div>
|
|
|
|
|
@if (hasCritical()) {
|
|
|
|
|
<span class="metric-detail critical-detail">{{ criticalCount() }} critical</span>
|
|
|
|
|
}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Estimated Total Value -->
|
|
|
|
|
<div class="summary-item metric-card"
|
|
|
|
|
matTooltip="Estimated total value of active spools"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon aria-hidden="true" class="metric-icon">payments</mat-icon>
|
|
|
|
|
<div class="metric-content">
|
|
|
|
|
<span class="metric-value">{{ formatCurrency(totalValue()) }}</span>
|
|
|
|
|
<span class="metric-label">Est. Value</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Overall Remaining Stock Bar -->
|
|
|
|
|
<div class="summary-item metric-card stock-bar-card"
|
|
|
|
|
matTooltip="{{ formatWeight(totalRemainingGrams()) }} of {{ formatWeight(totalCapacityGrams()) }} remaining"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon aria-hidden="true" class="metric-icon">line_weight</mat-icon>
|
|
|
|
|
<div class="metric-content stock-bar-content">
|
|
|
|
|
<div class="stock-bar-header">
|
|
|
|
|
<span class="metric-value">{{ overallRemainingPercent() }}%</span>
|
|
|
|
|
<span class="metric-label">Remaining</span>
|
|
|
|
|
</div>
|
|
|
|
|
<mat-progress-bar
|
|
|
|
|
mode="determinate"
|
|
|
|
|
[value]="overallRemainingPercent()"
|
|
|
|
|
[ngClass]="healthClass()">
|
|
|
|
|
</mat-progress-bar>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
2026-04-27 18:11:30 -04:00
|
|
|
</section>
|