Browse Source

measuremnet update

Dr-Swopt 4 weeks ago
parent
commit
f4306d7288

+ 17 - 8
src/app/components/calculate-dialog/calculate-dialog.component.css

@@ -1,15 +1,24 @@
-.dialog-content {
+.worker-row {
   display: flex;
   flex-direction: column;
-  gap: 1rem;
+  margin-bottom: 8px;
 }
 
-table {
-  width: 100%;
+.activity-row {
+  display: flex;
+  gap: 16px;
+  padding: 2px 0;
+}
+
+.worker-name {
+  width: 120px;
+  font-weight: 600;
+}
+
+.activity-name {
+  width: 180px;
 }
 
-.totals {
-  border-top: 1px solid #ddd;
-  padding-top: 1rem;
-  margin-top: 1rem;
+.activity-output {
+  width: 80px;
 }

+ 63 - 29
src/app/components/calculate-dialog/calculate-dialog.component.html

@@ -1,32 +1,66 @@
-<h2 mat-dialog-title>Calculation Summary</h2>
-
-<mat-dialog-content class="dialog-content">
-    <!-- 👷 Workers Section -->
-    <h3>Workers</h3>
-    <table mat-table [dataSource]="workers" class="mat-elevation-z2">
-        <ng-container matColumnDef="workerName">
-            <th mat-header-cell *matHeaderCellDef>Worker</th>
-            <td mat-cell *matCellDef="let w">{{ w.workerName }}</td>
-        </ng-container>
-
-        <ng-container matColumnDef="activityName">
-            <th mat-header-cell *matHeaderCellDef>Activity</th>
-            <td mat-cell *matCellDef="let w">{{ w.activityName }}</td>
-        </ng-container>
-
-        <tr mat-header-row *matHeaderRowDef="['workerName', 'activityName']"></tr>
-        <tr mat-row *matRowDef="let row; columns: ['workerName', 'activityName']"></tr>
-    </table>
-
-    <!-- 📦 Totals -->
-    <div class="totals">
-        <h3>Totals</h3>
-        <p><strong>Total Output Quantity:</strong> {{ totalOutput }}</p>
-        <p><strong>Total Target Quantity:</strong> {{ totalTarget }}</p>
-        <p><strong>Total Duration (hours):</strong> {{ totalDurationHours | number: '1.2-2' }}</p>
-    </div>
+<h2 mat-dialog-title>Activity Quantitative Report</h2>
+
+<mat-dialog-content>
+  <!-- WORKERS -->
+  <section>
+    <h3>👷 Workers ({{ workerSummary.length }})</h3>
+
+    <!-- Single collapsible panel for all workers -->
+    <mat-accordion>
+      <mat-expansion-panel>
+        <mat-expansion-panel-header>
+          <mat-panel-title>
+            Show Worker Details
+          </mat-panel-title>
+        </mat-expansion-panel-header>
+
+        <!-- Worker rows -->
+        <div *ngFor="let worker of workerSummary" class="worker-row">
+          <div *ngFor="let act of worker.activities" class="activity-row">
+            <span class="worker-name">{{ worker.name }}</span>
+            <span class="activity-name">{{ act.activityName }}</span>
+            <span class="activity-output" *ngFor="let out of act.outputs">
+              {{ out.value }} {{ out.uom }}
+            </span>
+          </div>
+        </div>
+      </mat-expansion-panel>
+    </mat-accordion>
+  </section>
+
+  <hr />
+
+  <!-- OUTPUT TOTALS -->
+  <section>
+    <h3>📦 Total Outputs</h3>
+    <ul>
+      <li *ngFor="let uom of (totalOutputs | keyvalue)">
+        {{ uom.value }} {{ totalOutputUoms[uom.key] }}
+      </li>
+    </ul>
+  </section>
+
+  <hr />
+
+  <!-- TARGET TOTALS -->
+  <section>
+    <h3>🎯 Total Targets</h3>
+    <ul>
+      <li *ngFor="let uom of (totalTargets | keyvalue)">
+        {{ uom.value }} {{ totalTargetUoms[uom.key] }}
+      </li>
+    </ul>
+  </section>
+
+  <hr />
+
+  <!-- DURATION -->
+  <section>
+    <h3>⏱️ Total Duration</h3>
+    <p>{{ totalDuration }} {{ durationUom }}</p>
+  </section>
 </mat-dialog-content>
 
 <mat-dialog-actions align="end">
-    <button mat-flat-button color="primary" mat-dialog-close>Close</button>
-</mat-dialog-actions>
+  <button mat-button (click)="closeDialog()">Close</button>
+</mat-dialog-actions>

+ 115 - 68
src/app/components/calculate-dialog/calculate-dialog.component.ts

@@ -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();
+    }
 }