CUB-43: add inventory dashboard summary component with FilamentService
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
} from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { FilamentService } from '../../services/filament.service';
|
||||
import { classifyStockLevel } from '../../models/filament.model';
|
||||
|
||||
/**
|
||||
* InventorySummaryComponent — dashboard summary for filament inventory metrics.
|
||||
*
|
||||
* Displays three key metrics driven by FilamentService:
|
||||
* - Total filament count (active spools)
|
||||
* - Low stock count (spools classified as 'low' or 'critical')
|
||||
* - Estimated total filament value (sum of purchase prices for active spools)
|
||||
*
|
||||
* All values update dynamically whenever FilamentService data changes.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-inventory-summary',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
],
|
||||
templateUrl: './inventory-summary.component.html',
|
||||
styleUrl: './inventory-summary.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InventorySummaryComponent {
|
||||
private readonly filamentService = inject(FilamentService);
|
||||
|
||||
/** Computed: total number of active filament spools */
|
||||
readonly totalFilamentCount = computed(() =>
|
||||
this.filamentService.filaments().filter((f) => f.isActive).length
|
||||
);
|
||||
|
||||
/** Computed: count of spools at low or critical stock levels */
|
||||
readonly lowStockCount = computed(() =>
|
||||
this.filamentService.filaments().filter((f) => {
|
||||
const level = classifyStockLevel(f);
|
||||
return level === 'low' || level === 'critical';
|
||||
}).length
|
||||
);
|
||||
|
||||
/** Computed: count of spools at critical stock level only */
|
||||
readonly criticalStockCount = computed(() =>
|
||||
this.filamentService.filaments().filter(
|
||||
(f) => classifyStockLevel(f) === 'critical'
|
||||
).length
|
||||
);
|
||||
|
||||
/** Computed: estimated total value of all active spools with a recorded price */
|
||||
readonly estimatedTotalValue = computed(() =>
|
||||
this.filamentService
|
||||
.filaments()
|
||||
.filter((f) => f.isActive && f.purchasePrice !== null)
|
||||
.reduce((sum, f) => sum + (f.purchasePrice ?? 0), 0)
|
||||
);
|
||||
|
||||
/** Computed: whether there are low-stock spools to highlight */
|
||||
readonly hasLowStock = computed(() => this.lowStockCount() > 0);
|
||||
|
||||
/** Computed: whether there are critical-stock spools */
|
||||
readonly hasCriticalStock = computed(() => this.criticalStockCount() > 0);
|
||||
|
||||
/** Format a currency value for display */
|
||||
formatCurrency(value: number): string {
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 2,
|
||||
}).format(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user