Kaynağa Gözat

with automcomplete

Dr-Swopt 2 hafta önce
ebeveyn
işleme
7fcc1c9b1a

+ 42 - 0
src/app/components/ffb-calculation/ffb-harvest-calculate-dialog.component.css

@@ -0,0 +1,42 @@
+mat-dialog-content {
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+  max-height: 70vh;
+  overflow-y: auto;
+  font-family: Roboto, sans-serif;
+}
+
+section {
+  border: 1px solid #e0e0e0;
+  padding: 12px;
+  border-radius: 8px;
+  background-color: #fafafa;
+}
+
+h3 {
+  margin-top: 0;
+  margin-bottom: 8px;
+  font-size: 16px;
+  font-weight: 600;
+  color: #3f51b5;
+}
+
+ul {
+  padding-left: 20px;
+  margin: 0;
+}
+
+ul li {
+  margin-bottom: 4px;
+  font-size: 14px;
+}
+
+div {
+  font-size: 14px;
+  margin-bottom: 4px;
+}
+
+mat-dialog-actions {
+  padding: 12px 24px;
+}

+ 31 - 0
src/app/components/ffb-calculation/ffb-harvest-calculate-dialog.component.html

@@ -0,0 +1,31 @@
+<h2 mat-dialog-title>FFB Harvest Summary</h2>
+
+<mat-dialog-content>
+  <section>
+    <h3>📦 Total Weight</h3>
+    <ul>
+      <li *ngFor="let uom of weightKeys">{{ totalWeight[uom] }} {{ uom }}</li>
+    </ul>
+  </section>
+
+  <section>
+    <h3>🎯 Total Quantity</h3>
+    <ul>
+      <li *ngFor="let uom of quantityKeys">{{ totalQuantity[uom] }} {{ uom }}</li>
+    </ul>
+  </section>
+
+  <section>
+    <h3>📊 Average</h3>
+    <div *ngFor="let uom of weightKeys">
+      Avg Weight ({{ uom }}): {{ averageWeight[uom] | number:'1.0-2' }}
+    </div>
+    <div *ngFor="let uom of quantityKeys">
+      Avg Quantity ({{ uom }}): {{ averageQuantity[uom] | number:'1.0-2' }}
+    </div>
+  </section>
+</mat-dialog-content>
+
+<mat-dialog-actions align="end">
+  <button mat-button (click)="closeDialog()">Close</button>
+</mat-dialog-actions>

+ 89 - 0
src/app/components/ffb-calculation/ffb-harvest-calculate-dialog.component.ts

@@ -0,0 +1,89 @@
+import { Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { CommonModule } from '@angular/common';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatButtonModule } from '@angular/material/button';
+
+export interface FFBHarvest {
+  _id?: string;
+  harvestDate: Date | string;
+  site: string;
+  phase: string;
+  block: string;
+  harvester: string;
+  daysOfWork: number;
+  weight: number;
+  weightUom: string;
+  quantity: number;
+  quantityUom: string;
+}
+
+@Component({
+  selector: 'app-ffb-harvest-calculate-dialog',
+  standalone: true,
+  imports: [CommonModule, MatDialogModule, MatButtonModule],
+  templateUrl: './ffb-harvest-calculate-dialog.component.html',
+  styleUrls: ['./ffb-harvest-calculate-dialog.component.css'],
+})
+export class FfbHarvestCalculateDialogComponent implements OnInit {
+  totalWeight: Record<string, number> = {};
+  totalQuantity: Record<string, number> = {};
+  averageWeight: Record<string, number> = {};
+  averageQuantity: Record<string, number> = {};
+  weightKeys: string[] = [];
+  quantityKeys: string[] = [];
+
+  constructor(
+    private dialogRef: MatDialogRef<FfbHarvestCalculateDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: { harvests: FFBHarvest[] }
+  ) {}
+
+  ngOnInit(): void {
+    this.calculateTotals();
+  }
+
+  calculateTotals() {
+    const weightTotals: Record<string, number> = {};
+    const quantityTotals: Record<string, number> = {};
+    const weightCounts: Record<string, number> = {};
+    const quantityCounts: Record<string, number> = {};
+
+    this.data.harvests.forEach(h => {
+      // Weight
+      if (!weightTotals[h.weightUom]) {
+        weightTotals[h.weightUom] = 0;
+        weightCounts[h.weightUom] = 0;
+      }
+      weightTotals[h.weightUom] += h.weight;
+      weightCounts[h.weightUom] += 1;
+
+      // Quantity
+      if (!quantityTotals[h.quantityUom]) {
+        quantityTotals[h.quantityUom] = 0;
+        quantityCounts[h.quantityUom] = 0;
+      }
+      quantityTotals[h.quantityUom] += h.quantity;
+      quantityCounts[h.quantityUom] += 1;
+    });
+
+    this.totalWeight = weightTotals;
+    this.totalQuantity = quantityTotals;
+
+    // Calculate averages
+    this.averageWeight = {};
+    this.averageQuantity = {};
+    Object.keys(weightTotals).forEach(uom => {
+      this.averageWeight[uom] = weightTotals[uom] / weightCounts[uom];
+    });
+    Object.keys(quantityTotals).forEach(uom => {
+      this.averageQuantity[uom] = quantityTotals[uom] / quantityCounts[uom];
+    });
+
+    this.weightKeys = Object.keys(this.totalWeight);
+    this.quantityKeys = Object.keys(this.totalQuantity);
+  }
+
+  closeDialog() {
+    this.dialogRef.close();
+  }
+}

+ 34 - 31
src/app/components/ffb-harvest-dialog/create-ffb-harvest-dialog.component.html

@@ -1,45 +1,58 @@
 <h2 mat-dialog-title>
-  {{ data ? 'View FFB Harvest' : 'Create FFB Harvest' }}
+  {{ data?.harvest ? 'View/Edit FFB Harvest' : 'Create FFB Harvest' }}
 </h2>
 
 <form [formGroup]="form" (ngSubmit)="onSubmit()" class="dialog-form">
   <div class="form-section">
+
     <mat-form-field appearance="outline" class="flex-1">
       <mat-label>Harvest Date</mat-label>
-      <input matInput [matDatepicker]="picker" formControlName="harvestDate" [readonly]="!!data" />
+      <input matInput [matDatepicker]="picker" formControlName="harvestDate" [readonly]="!!data?.harvest" />
       <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
       <mat-datepicker #picker></mat-datepicker>
     </mat-form-field>
 
-    <mat-form-field appearance="outline" class="flex-1">
+    <mat-form-field appearance="outline">
       <mat-label>Site</mat-label>
-      <input matInput formControlName="site" [readonly]="!!data" />
+      <input matInput [formControl]="siteControl" [matAutocomplete]="siteAuto" [readonly]="!!data?.harvest" />
+      <mat-autocomplete #siteAuto="matAutocomplete">
+        <mat-option *ngFor="let option of filteredSites | async" [value]="option">{{ option }}</mat-option>
+      </mat-autocomplete>
     </mat-form-field>
 
-    <mat-form-field appearance="outline" class="flex-1">
+    <mat-form-field appearance="outline">
       <mat-label>Phase</mat-label>
-      <input matInput formControlName="phase" [readonly]="!!data" />
+      <input matInput [formControl]="phaseControl" [matAutocomplete]="phaseAuto" [readonly]="!!data?.harvest" />
+      <mat-autocomplete #phaseAuto="matAutocomplete">
+        <mat-option *ngFor="let option of filteredPhases | async" [value]="option">{{ option }}</mat-option>
+      </mat-autocomplete>
     </mat-form-field>
 
-    <mat-form-field appearance="outline" class="flex-1">
+    <mat-form-field appearance="outline">
       <mat-label>Block</mat-label>
-      <input matInput formControlName="block" [readonly]="!!data" />
+      <input matInput [formControl]="blockControl" [matAutocomplete]="blockAuto" [readonly]="!!data?.harvest" />
+      <mat-autocomplete #blockAuto="matAutocomplete">
+        <mat-option *ngFor="let option of filteredBlocks | async" [value]="option">{{ option }}</mat-option>
+      </mat-autocomplete>
+    </mat-form-field>
+
+    <mat-form-field appearance="outline">
+      <mat-label>Harvester</mat-label>
+      <input matInput [formControl]="harvesterControl" [matAutocomplete]="harvesterAuto" [readonly]="!!data?.harvest" />
+      <mat-autocomplete #harvesterAuto="matAutocomplete">
+        <mat-option *ngFor="let option of filteredHarvesters | async" [value]="option">{{ option }}</mat-option>
+      </mat-autocomplete>
     </mat-form-field>
 
     <mat-form-field appearance="outline" class="flex-1">
       <mat-label>Quantity</mat-label>
-      <input matInput type="number" formControlName="quantity" [readonly]="!!data" />
+      <input matInput type="number" formControlName="quantity" [readonly]="!!data?.harvest" />
     </mat-form-field>
 
     <mat-form-field appearance="outline" class="flex-1">
       <mat-label>Quantity UOM</mat-label>
-      <input
-        type="text"
-        matInput
-        formControlName="quantityUom"
-        [matAutocomplete]="quantityUomAuto"
-        [readonly]="!!data"
-      />
+      <input type="text" matInput formControlName="quantityUom" [matAutocomplete]="quantityUomAuto"
+        [readonly]="!!data?.harvest" />
       <mat-autocomplete #quantityUomAuto="matAutocomplete">
         <mat-option *ngFor="let u of quantityUomOptions" [value]="u">{{ u }}</mat-option>
       </mat-autocomplete>
@@ -47,36 +60,26 @@
 
     <mat-form-field appearance="outline" class="flex-1">
       <mat-label>Weight</mat-label>
-      <input matInput type="number" formControlName="weight" [readonly]="!!data" />
+      <input matInput type="number" formControlName="weight" [readonly]="!!data?.harvest" />
     </mat-form-field>
 
     <mat-form-field appearance="outline" class="flex-1">
       <mat-label>Weight UOM</mat-label>
-      <input
-        type="text"
-        matInput
-        formControlName="weightUom"
-        [matAutocomplete]="weightUomAuto"
-        [readonly]="!!data"
-      />
+      <input type="text" matInput formControlName="weightUom" [matAutocomplete]="weightUomAuto" [readonly]="!!data?.harvest" />
       <mat-autocomplete #weightUomAuto="matAutocomplete">
         <mat-option *ngFor="let u of weightUomOptions" [value]="u">{{ u }}</mat-option>
       </mat-autocomplete>
     </mat-form-field>
 
-    <mat-form-field appearance="outline" class="flex-1">
-      <mat-label>Harvester</mat-label>
-      <input matInput formControlName="harvester" [readonly]="!!data" />
-    </mat-form-field>
-
     <mat-form-field appearance="outline" class="flex-1">
       <mat-label>Days of Work</mat-label>
-      <input matInput type="number" formControlName="daysOfWork" [readonly]="!!data" />
+      <input matInput type="number" formControlName="daysOfWork" [readonly]="!!data?.harvest" />
     </mat-form-field>
+
   </div>
 
   <div class="dialog-footer">
     <button mat-stroked-button type="button" (click)="cancel()">Close</button>
-    <button *ngIf="!data" mat-flat-button color="primary" type="submit">Save</button>
+    <button *ngIf="!data?.harvest" mat-flat-button color="primary" type="submit">Save</button>
   </div>
 </form>

+ 62 - 36
src/app/components/ffb-harvest-dialog/create-ffb-harvest-dialog.component.ts

@@ -1,5 +1,6 @@
 import { CommonModule } from '@angular/common';
-import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
+import { Component, Inject, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
 import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
 import { MatFormFieldModule } from '@angular/material/form-field';
 import { MatInputModule } from '@angular/material/input';
@@ -8,10 +9,10 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
 import { MatNativeDateModule } from '@angular/material/core';
 import { MatIconModule } from '@angular/material/icon';
 import { HttpClient, HttpClientModule } from '@angular/common/http';
-import { webConfig } from '../../config';
-import { Component, Inject } from '@angular/core';
 import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
 import { MatAutocompleteModule } from '@angular/material/autocomplete';
+import { Observable, startWith, map } from 'rxjs';
+import { webConfig } from '../../config';
 
 @Component({
   selector: 'app-create-ffb-harvest-dialog',
@@ -33,14 +34,25 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete';
   templateUrl: './create-ffb-harvest-dialog.component.html',
   styleUrls: ['./create-ffb-harvest-dialog.component.css'],
 })
-export class CreateFfbHarvestDialogComponent {
+export class CreateFfbHarvestDialogComponent implements OnInit {
   form: FormGroup;
   saving = false;
 
-  // Options for UOMs
-  weightUomOptions = ['Kg', 'Ton',];
+  weightUomOptions = ['Kg', 'Ton'];
   quantityUomOptions = ['Bunch', 'Bundle', 'Bag'];
 
+  allSites: string[] = [];
+  allPhases: string[] = [];
+  allBlocks: string[] = [];
+  allHarvesters: string[] = [];
+
+  filteredSites!: Observable<string[]>;
+  filteredPhases!: Observable<string[]>;
+  filteredBlocks!: Observable<string[]>;
+  filteredHarvesters!: Observable<string[]>;
+
+  private conversionMap: Record<string, number> = { Bunch: 10, Bundle: 25, Bag: 100 };
+
   constructor(
     private fb: FormBuilder,
     private http: HttpClient,
@@ -48,6 +60,13 @@ export class CreateFfbHarvestDialogComponent {
     private snackBar: MatSnackBar,
     @Inject(MAT_DIALOG_DATA) public data: any
   ) {
+    // Assign lists from parent
+    this.allSites = data?.allSites || [];
+    this.allPhases = data?.allPhases || [];
+    this.allBlocks = data?.allBlocks || [];
+    this.allHarvesters = data?.allHarvesters || [];
+    console.log(data)
+
     this.form = this.fb.group({
       harvestDate: [new Date(), Validators.required],
       site: ['', Validators.required],
@@ -61,47 +80,49 @@ export class CreateFfbHarvestDialogComponent {
       daysOfWork: [0, Validators.required],
     });
 
-    // Watch for changes on quantity or quantityUom to auto-calculate weight
+    // Auto-update weight
     this.form.get('quantity')!.valueChanges.subscribe(() => this.updateWeight());
     this.form.get('quantityUom')!.valueChanges.subscribe(() => this.updateWeight());
   }
 
   ngOnInit() {
-    if (this.data) {
-      this.form.patchValue({
-        harvestDate: this.data.harvestDate,
-        site: this.data.site,
-        phase: this.data.phase,
-        block: this.data.block,
-        quantity: this.data.quantity,
-        quantityUom: this.data.quantityUom || 'Bunch',
-        weight: this.data.weight,
-        weightUom: this.data.weightUom || 'Kg',
-        harvester: this.data.harvester,
-        daysOfWork: this.data.daysOfWork,
-      });
+    // Patch data if editing
+    if (this.data?.harvest) {
+      this.form.patchValue(this.data.harvest);
     }
+
+    // Autocomplete observables
+    this.filteredSites = this.siteControl.valueChanges.pipe(
+      startWith(this.siteControl.value || ''),
+      map(val => this.filterOptions(val, this.allSites))
+    );
+
+    this.filteredPhases = this.phaseControl.valueChanges.pipe(
+      startWith(this.phaseControl.value || ''),
+      map(val => this.filterOptions(val, this.allPhases))
+    );
+
+    this.filteredBlocks = this.blockControl.valueChanges.pipe(
+      startWith(this.blockControl.value || ''),
+      map(val => this.filterOptions(val, this.allBlocks))
+    );
+
+    this.filteredHarvesters = this.harvesterControl.valueChanges.pipe(
+      startWith(this.harvesterControl.value || ''),
+      map(val => this.filterOptions(val, this.allHarvesters))
+    );
   }
 
-  // Conversion map (quantityUom -> weight in kg)
-  private conversionMap: Record<string, number> = {
-    Bunch: 10,
-    Bundle: 25,
-    Bag: 100,
-  };
+  private filterOptions(value: string, options: string[]): string[] {
+    const filterValue = (value || '').toLowerCase();
+    return options.filter(opt => opt.toLowerCase().includes(filterValue));
+  }
 
-  /** Automatically update weight based on quantity and quantityUom */
   private updateWeight() {
     const quantity = this.form.get('quantity')!.value || 0;
     const quantityUom = this.form.get('quantityUom')!.value;
     const baseWeight = this.conversionMap[quantityUom] || 0;
-
-    const totalWeightKg = quantity * baseWeight;
-
-    this.form.patchValue(
-      { weight: totalWeightKg },
-      { emitEvent: false } // avoid infinite loop
-    );
+    this.form.patchValue({ weight: quantity * baseWeight }, { emitEvent: false });
   }
 
   onSubmit() {
@@ -115,7 +136,7 @@ export class CreateFfbHarvestDialogComponent {
     this.saving = true;
     this.http.post(`${webConfig.exposedUrl}/api/ffb-harvest`, payload).subscribe({
       next: () => {
-        this.snackBar.open('FFB Harvest created!', 'Close', { duration: 3000 });
+        this.snackBar.open('FFB Harvest saved!', 'Close', { duration: 3000 });
         this.dialogRef.close('refresh');
       },
       error: (err) => {
@@ -129,5 +150,10 @@ export class CreateFfbHarvestDialogComponent {
   cancel() {
     this.dialogRef.close();
   }
-}
 
+  // FormControl getters
+  get siteControl(): FormControl { return this.form.get('site') as FormControl; }
+  get phaseControl(): FormControl { return this.form.get('phase') as FormControl; }
+  get blockControl(): FormControl { return this.form.get('block') as FormControl; }
+  get harvesterControl(): FormControl { return this.form.get('harvester') as FormControl; }
+}

+ 20 - 0
src/app/ffb/ffb-harvest.component.html

@@ -40,6 +40,22 @@
       <mat-datepicker #endPicker></mat-datepicker>
     </mat-form-field>
 
+    <mat-form-field appearance="outline">
+      <mat-label>Weight UOM</mat-label>
+      <mat-select [formControl]="weightUomControl">
+        <mat-option value="">All</mat-option>
+        <mat-option *ngFor="let w of weightUomOptions" [value]="w">{{ w }}</mat-option>
+      </mat-select>
+    </mat-form-field>
+
+    <mat-form-field appearance="outline">
+      <mat-label>Quantity UOM</mat-label>
+      <mat-select [formControl]="quantityUomControl">
+        <mat-option value="">All</mat-option>
+        <mat-option *ngFor="let q of quantityUomOptions" [value]="q">{{ q }}</mat-option>
+      </mat-select>
+    </mat-form-field>
+
     <button mat-icon-button color="primary" (click)="refresh()" [disabled]="loading" [class.spin]="loading">
       <mat-icon>refresh</mat-icon>
     </button>
@@ -52,6 +68,10 @@
       <mat-icon>clear_all</mat-icon>
       Reset Filters
     </button>
+
+    <button mat-stroked-button color="primary" (click)="openCalculateDialog()">
+      Calculate Totals & Averages
+    </button>
   </div>
 </div>
 

+ 54 - 3
src/app/ffb/ffb-harvest.component.ts

@@ -17,6 +17,7 @@ import { combineLatest, startWith } from 'rxjs';
 import { FFBHarvest } from './ffb-harvest.interface';
 import { webConfig } from '../config';
 import { CreateFfbHarvestDialogComponent } from '../components/ffb-harvest-dialog/create-ffb-harvest-dialog.component';
+import { FfbHarvestCalculateDialogComponent } from '../components/ffb-calculation/ffb-harvest-calculate-dialog.component';
 
 @Component({
   selector: 'app-ffb-harvest',
@@ -45,6 +46,12 @@ export class FfbHarvestComponent implements OnInit {
   private snack = inject(MatSnackBar);
   private dialog = inject(MatDialog);
 
+  weightUomControl = new FormControl('');
+  quantityUomControl = new FormControl('');
+
+  weightUomOptions = ['Kg', 'Ton'];
+  quantityUomOptions = ['Bunch', 'Bundle', 'Bag'];
+
   searchControl = new FormControl('');
   siteControl = new FormControl('');
   phaseControl = new FormControl('');
@@ -53,8 +60,11 @@ export class FfbHarvestComponent implements OnInit {
 
   harvests: FFBHarvest[] = [];
   filteredHarvests: FFBHarvest[] = [];
+
   uniqueSites: string[] = [];
   uniquePhases: string[] = [];
+  uniqueBlocks: string[] = [];
+  uniqueHarvesters: string[] = [];
 
   displayedColumns: string[] = [
     'harvestDate',
@@ -78,6 +88,8 @@ export class FfbHarvestComponent implements OnInit {
       this.phaseControl.valueChanges.pipe(startWith(this.phaseControl.value)),
       this.startDateControl.valueChanges.pipe(startWith(this.startDateControl.value)),
       this.endDateControl.valueChanges.pipe(startWith(this.endDateControl.value)),
+      this.weightUomControl.valueChanges.pipe(startWith(this.weightUomControl.value)),
+      this.quantityUomControl.valueChanges.pipe(startWith(this.quantityUomControl.value)),
     ]).subscribe(() => this.applyFilters());
   }
 
@@ -87,8 +99,13 @@ export class FfbHarvestComponent implements OnInit {
       next: (data) => {
         this.harvests = data.map(h => ({ ...h, harvestDate: new Date(h.harvestDate) }));
         this.filteredHarvests = [...this.harvests];
+
+        // populate unique arrays for filters and autocompletes
         this.uniqueSites = [...new Set(this.harvests.map(h => h.site))];
         this.uniquePhases = [...new Set(this.harvests.map(h => h.phase))];
+        this.uniqueBlocks = [...new Set(this.harvests.map(h => h.block))];
+        this.uniqueHarvesters = [...new Set(this.harvests.map(h => h.harvester))];
+
         this.loading = false;
       },
       error: (err) => {
@@ -105,22 +122,30 @@ export class FfbHarvestComponent implements OnInit {
     const phase = this.phaseControl.value;
     const startDate = this.startDateControl.value;
     const endDate = this.endDateControl.value;
+    const weightUom = this.weightUomControl.value;
+    const quantityUom = this.quantityUomControl.value;
 
     this.filteredHarvests = this.harvests.filter(h => {
       const matchesKeyword =
         !keyword ||
         h.site.toLowerCase().includes(keyword) ||
         h.phase.toLowerCase().includes(keyword) ||
-        h.block.toLowerCase().includes(keyword);
+        h.block.toLowerCase().includes(keyword) ||
+        h.harvester.toLowerCase().includes(keyword) ||
+        h.weight.toString().includes(keyword) ||
+        h.quantity.toString().includes(keyword);
 
       const matchesSite = !site || h.site === site;
       const matchesPhase = !phase || h.phase === phase;
+      const matchesWeightUom = !weightUom || h.weightUom === weightUom;
+      const matchesQuantityUom = !quantityUom || h.quantityUom === quantityUom;
 
       const hDate = new Date(h.harvestDate);
       const matchesDate =
         (!startDate || hDate >= startDate) && (!endDate || hDate <= endDate);
 
-      return matchesKeyword && matchesSite && matchesPhase && matchesDate;
+      return matchesKeyword && matchesSite && matchesPhase &&
+        matchesWeightUom && matchesQuantityUom && matchesDate;
     });
   }
 
@@ -130,6 +155,8 @@ export class FfbHarvestComponent implements OnInit {
     this.phaseControl.setValue('');
     this.startDateControl.setValue(null);
     this.endDateControl.setValue(null);
+    this.weightUomControl.setValue('');
+    this.quantityUomControl.setValue('');
     this.filteredHarvests = [...this.harvests];
   }
 
@@ -162,6 +189,12 @@ export class FfbHarvestComponent implements OnInit {
   createHarvest() {
     const dialogRef = this.dialog.open(CreateFfbHarvestDialogComponent, {
       width: '800px',
+      data: {
+        allSites: this.uniqueSites,
+        allPhases: this.uniquePhases,
+        allBlocks: this.uniqueBlocks,
+        allHarvesters: this.uniqueHarvesters
+      }
     });
 
     dialogRef.afterClosed().subscribe(result => {
@@ -172,11 +205,29 @@ export class FfbHarvestComponent implements OnInit {
   editHarvest(harvest: FFBHarvest) {
     const dialogRef = this.dialog.open(CreateFfbHarvestDialogComponent, {
       width: '800px',
-      data: harvest
+      data: {
+        harvest,
+        allSites: this.uniqueSites,
+        allPhases: this.uniquePhases,
+        allBlocks: this.uniqueBlocks,
+        allHarvesters: this.uniqueHarvesters
+      }
     });
 
     dialogRef.afterClosed().subscribe(result => {
       if (result === 'refresh') this.loadHarvests();
     });
   }
+
+  openCalculateDialog() {
+    this.dialog.open(FfbHarvestCalculateDialogComponent, {
+      data: {
+        allSites: this.uniqueSites,
+        allPhases: this.uniquePhases,
+        allBlocks: this.uniqueBlocks,
+        allHarvesters: this.uniqueHarvesters
+      },
+      width: '400px'
+    });
+  }
 }