|
|
@@ -1,76 +1,123 @@
|
|
|
-import { Component, Inject } from '@angular/core';
|
|
|
-import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
|
|
|
-import { MatTableModule } from '@angular/material/table';
|
|
|
+import { Component, Inject, Input, OnInit } from '@angular/core';
|
|
|
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
|
|
+import { Activity } from '../../activity/activity.interface';
|
|
|
+import { MatDialogModule } from '@angular/material/dialog';
|
|
|
import { MatButtonModule } from '@angular/material/button';
|
|
|
+import { MatExpansionModule } from '@angular/material/expansion';
|
|
|
import { CommonModule } from '@angular/common';
|
|
|
-import { Activity } from '../../activity/activity.interface';
|
|
|
+interface WorkerActivity {
|
|
|
+ activityName: string;
|
|
|
+ outputs: { name: string; value: number; uom: string }[];
|
|
|
+}
|
|
|
|
|
|
-interface WorkerInfo {
|
|
|
- workerName: string;
|
|
|
- activityName: string;
|
|
|
+interface WorkerSummary {
|
|
|
+ name: string;
|
|
|
+ activities: WorkerActivity[];
|
|
|
}
|
|
|
|
|
|
@Component({
|
|
|
- selector: 'app-calculate-dialog',
|
|
|
- standalone: true,
|
|
|
- templateUrl: './calculate-dialog.component.html',
|
|
|
- styleUrls: ['./calculate-dialog.component.css'],
|
|
|
- imports: [CommonModule, MatDialogModule, MatTableModule, MatButtonModule],
|
|
|
+ selector: 'app-calculate-dialog',
|
|
|
+ standalone: true,
|
|
|
+ imports: [
|
|
|
+ MatDialogModule,
|
|
|
+ MatButtonModule,
|
|
|
+ MatExpansionModule,
|
|
|
+ CommonModule
|
|
|
+ ],
|
|
|
+ templateUrl: './calculate-dialog.component.html',
|
|
|
+ styleUrls: ['./calculate-dialog.component.css'],
|
|
|
})
|
|
|
-export class CalculateDialogComponent {
|
|
|
- workers: WorkerInfo[] = [];
|
|
|
- totalOutput = 0;
|
|
|
- totalTarget = 0;
|
|
|
- totalDurationHours = 0;
|
|
|
-
|
|
|
- constructor(@Inject(MAT_DIALOG_DATA) public data: { activities: Activity[] }) {
|
|
|
- const { activities } = data;
|
|
|
-
|
|
|
- // 👷 1. Gather all workers
|
|
|
- this.workers = activities.flatMap((activity) =>
|
|
|
- activity.resources
|
|
|
- .filter((r) => r.type?.toLowerCase() === 'worker')
|
|
|
- .map((r) => ({
|
|
|
- workerName: r.name,
|
|
|
- activityName: activity.name,
|
|
|
- }))
|
|
|
- );
|
|
|
-
|
|
|
- // 📦 2. Sum total outputs
|
|
|
- this.totalOutput = activities.reduce((sum, activity) => {
|
|
|
- const outputSum = activity.outputs.reduce((a, o) => {
|
|
|
- const qty = Number(o.value?.quantity ?? 0);
|
|
|
- return a + (isNaN(qty) ? 0 : qty);
|
|
|
- }, 0);
|
|
|
- return sum + outputSum;
|
|
|
- }, 0);
|
|
|
-
|
|
|
- // 🎯 3. Sum total targets
|
|
|
- this.totalTarget = activities.reduce((sum, activity) => {
|
|
|
- const targetSum = activity.targets.reduce((a, t) => {
|
|
|
- const qty = Number(t.value?.quantity ?? 0);
|
|
|
- return a + (isNaN(qty) ? 0 : qty);
|
|
|
- }, 0);
|
|
|
- return sum + targetSum;
|
|
|
- }, 0);
|
|
|
-
|
|
|
- // ⏱️ 4. Sum total duration in hours
|
|
|
- this.totalDurationHours = activities.reduce((sum, activity) => {
|
|
|
- const duration = activity.duration?.value;
|
|
|
- if (!duration) return sum;
|
|
|
-
|
|
|
- const qty = Number(duration.quantity ?? 0);
|
|
|
- if (isNaN(qty)) return sum;
|
|
|
-
|
|
|
- let hours = qty;
|
|
|
- const uom = duration.uom?.toLowerCase();
|
|
|
-
|
|
|
- // convert to hours
|
|
|
- if (uom === 'minutes' || uom === 'mins' || uom === 'min') hours = qty / 60;
|
|
|
- else if (uom === 'seconds' || uom === 'sec' || uom === 'secs') hours = qty / 3600;
|
|
|
- else if (uom === 'days' || uom === 'day') hours = qty * 24;
|
|
|
-
|
|
|
- return sum + hours;
|
|
|
- }, 0);
|
|
|
- }
|
|
|
+export class CalculateDialogComponent implements OnInit {
|
|
|
+ filteredActivities: Activity[] = [];
|
|
|
+
|
|
|
+ workerSummary: WorkerSummary[] = [];
|
|
|
+ totalOutputs: Record<string, number> = {};
|
|
|
+ totalOutputUoms: Record<string, string> = {};
|
|
|
+ totalTargets: Record<string, number> = {};
|
|
|
+ totalTargetUoms: Record<string, string> = {};
|
|
|
+ totalDuration: number = 0;
|
|
|
+ durationUom: string = '';
|
|
|
+
|
|
|
+ constructor(
|
|
|
+ private dialogRef: MatDialogRef<CalculateDialogComponent>,
|
|
|
+ @Inject(MAT_DIALOG_DATA) public data: { activities: Activity[] }
|
|
|
+ ) {
|
|
|
+ // assign injected data to local variable
|
|
|
+ this.filteredActivities = data.activities;
|
|
|
+ }
|
|
|
+
|
|
|
+ ngOnInit(): void {
|
|
|
+ this.calculateTotals();
|
|
|
+ }
|
|
|
+
|
|
|
+ calculateTotals(): void {
|
|
|
+ const workerMap: Record<string, { activityName: string; outputs: { name: string; value: number; uom: string }[] }[]> = {};
|
|
|
+ const outputTotals: Record<string, number> = {};
|
|
|
+ const outputUoms: Record<string, string> = {};
|
|
|
+ const targetTotals: Record<string, number> = {};
|
|
|
+ const targetUoms: Record<string, string> = {};
|
|
|
+ let totalDuration = 0;
|
|
|
+ let durationUom = '';
|
|
|
+
|
|
|
+ for (const activity of this.filteredActivities) {
|
|
|
+ // Workers
|
|
|
+ for (const resource of activity.resources) {
|
|
|
+ if (resource.type.toLowerCase() === 'worker') {
|
|
|
+ if (!workerMap[resource.name]) {
|
|
|
+ workerMap[resource.name] = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ const activityOutputs = activity.outputs.map(o => ({
|
|
|
+ name: o.name,
|
|
|
+ value: o.value.quantity,
|
|
|
+ uom: o.value.uom,
|
|
|
+ }));
|
|
|
+
|
|
|
+ workerMap[resource.name].push({
|
|
|
+ activityName: activity.name,
|
|
|
+ outputs: activityOutputs,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Outputs (totals)
|
|
|
+ for (const output of activity.outputs) {
|
|
|
+ const { uom, quantity } = output.value;
|
|
|
+ outputTotals[uom] = (outputTotals[uom] || 0) + quantity;
|
|
|
+ outputUoms[uom] = uom;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Targets (totals)
|
|
|
+ for (const target of activity.targets) {
|
|
|
+ const { uom, quantity } = target.value;
|
|
|
+ targetTotals[uom] = (targetTotals[uom] || 0) + quantity;
|
|
|
+ targetUoms[uom] = uom;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Duration (sum only if hours)
|
|
|
+ const dur = activity.duration.value;
|
|
|
+ if (dur.uom.toLowerCase() === 'hour' || dur.uom.toLowerCase() === 'hours') {
|
|
|
+ totalDuration += dur.quantity;
|
|
|
+ }
|
|
|
+ durationUom = dur.uom;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Map worker data into summary
|
|
|
+ this.workerSummary = Object.keys(workerMap).map(name => ({
|
|
|
+ name,
|
|
|
+ activities: workerMap[name],
|
|
|
+ }));
|
|
|
+
|
|
|
+ this.totalOutputs = outputTotals;
|
|
|
+ this.totalOutputUoms = outputUoms;
|
|
|
+ this.totalTargets = targetTotals;
|
|
|
+ this.totalTargetUoms = targetUoms;
|
|
|
+ this.totalDuration = totalDuration;
|
|
|
+ this.durationUom = durationUom;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ closeDialog(): void {
|
|
|
+ this.dialogRef.close();
|
|
|
+ }
|
|
|
}
|