Files
Extrudex/frontend/src/app/components/inventory-summary/inventory-summary.component.html

145 lines
5.3 KiB
HTML
Raw Normal View History

<!-- Inventory Dashboard Summary — filament metrics at a glance -->
<section class="inventory-summary" role="region" aria-label="Inventory summary">
<!-- 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>
}
<!-- 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>
}
<!-- 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>
<!-- 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>
<!-- Average Cost per Gram -->
@if (avgCostPerGram() !== null) {
<div class="summary-item metric-card"
matTooltip="Average cost per gram across priced, active spools"
matTooltipPosition="below">
<mat-icon aria-hidden="true" class="metric-icon">scale</mat-icon>
<div class="metric-content">
<span class="metric-value">${{ avgCostPerGram()!.toFixed(2) }}/g</span>
<span class="metric-label">Avg Cost/g</span>
</div>
</div>
}
<!-- Total Usage -->
<div class="summary-item metric-card"
matTooltip="Total filament used across all spools"
matTooltipPosition="below">
<mat-icon aria-hidden="true" class="metric-icon">trending_down</mat-icon>
<div class="metric-content">
<span class="metric-value">{{ formatWeight(totalGramsUsed()) }}</span>
<span class="metric-label">Total Used</span>
</div>
</div>
<!-- Estimated Used Value -->
@if (estimatedUsedValue() !== null) {
<div class="summary-item metric-card"
matTooltip="Estimated value of filament consumed"
matTooltipPosition="below">
<mat-icon aria-hidden="true" class="metric-icon">receipt_long</mat-icon>
<div class="metric-content">
<span class="metric-value">{{ formatCurrency(estimatedUsedValue()!) }}</span>
<span class="metric-label">Used 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>
}
</section>