Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select KPMs when adding NEBs from modal #320

Merged
merged 6 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions src/app/indexed-db/key-performance-indicators-idb.service.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, firstValueFrom } from 'rxjs';
import { IdbKeyPerformanceIndicator } from '../models/keyPerformanceIndicator';
import { getNewKeyPerformanceIndicator, IdbKeyPerformanceIndicator } from '../models/keyPerformanceIndicator';
import { NgxIndexedDBService } from 'ngx-indexed-db';
import { KeyPerformanceMetric } from '../shared/constants/keyPerformanceMetrics';
import { KeyPerformanceIndicatorValue } from '../shared/constants/keyPerformanceIndicatorOptions';
import { getPerformanceMetrics, KeyPerformanceMetric, KeyPerformanceMetricOption } from '../shared/constants/keyPerformanceMetrics';
import { KeyPerformanceIndicatorOption, KeyPerformanceIndicatorOptions, KeyPerformanceIndicatorValue } from '../shared/constants/keyPerformanceIndicatorOptions';

@Injectable({
providedIn: 'root'
Expand Down Expand Up @@ -87,4 +87,38 @@ export class KeyPerformanceIndicatorsIdbService {
return kpi.companyId == companyGuid && kpi.optionValue == performanceMetricValue;
});
}

async addKpmToKpi(companyId: string, performanceMetricToAdd: KeyPerformanceMetric | KeyPerformanceMetricOption, userId: string): Promise<KeyPerformanceMetric> {
let addedMetric: KeyPerformanceMetric;
let keyPerformanceIndicator: IdbKeyPerformanceIndicator = this.getKpiFromKpm(companyId, performanceMetricToAdd.kpiValue);
if (keyPerformanceIndicator) {
//check metric is being tracked in existing KPI
addedMetric = keyPerformanceIndicator.performanceMetrics.find(_metric => {
return (_metric.value == performanceMetricToAdd.value);
});
if (!addedMetric) {
//if not being tracked. Add metric to existing KPI
let metrics: Array<KeyPerformanceMetric> = getPerformanceMetrics(keyPerformanceIndicator.optionValue, keyPerformanceIndicator.guid);
addedMetric = metrics.find(_metric => {
return (_metric.value == performanceMetricToAdd.value);
});
if (addedMetric) {
keyPerformanceIndicator.performanceMetrics.push(addedMetric);
await this.asyncUpdate(keyPerformanceIndicator);
}
}
} else {
//add untracked KPI if doesn't exist and all associated metrics
let kpiOption: KeyPerformanceIndicatorOption = KeyPerformanceIndicatorOptions.find(option => {
return option.optionValue == performanceMetricToAdd.kpiValue
});
keyPerformanceIndicator = getNewKeyPerformanceIndicator(userId, companyId, kpiOption, false);
addedMetric = keyPerformanceIndicator.performanceMetrics.find(_metric => {
return (_metric.value == performanceMetricToAdd.value);
});
await firstValueFrom(this.addWithObservable(keyPerformanceIndicator));
await this.setKeyPerformanceIndicators();
}
return addedMetric;
}
}
8 changes: 6 additions & 2 deletions src/app/indexed-db/on-site-visit-idb.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,16 @@ export class OnSiteVisitIdbService {
}

setSelectedFromAssessmentGUID(assessmentGUID: string) {
let onSiteVisits: Array<IdbOnSiteVisit> = this.onSiteVisits.getValue();
let onSiteVisit: IdbOnSiteVisit = onSiteVisits.find(_onSiteVisit => { return _onSiteVisit.assessmentIds.includes(assessmentGUID) });
let onSiteVisit: IdbOnSiteVisit = this.getByAssessmentGUID(assessmentGUID);
this.selectedVisit.next(onSiteVisit);
return onSiteVisit != undefined;
}

getByAssessmentGUID(assessmentGUID: string) {
let onSiteVisits: Array<IdbOnSiteVisit> = this.onSiteVisits.getValue();
let onSiteVisit: IdbOnSiteVisit = onSiteVisits.find(_onSiteVisit => { return _onSiteVisit.assessmentIds.includes(assessmentGUID) });
return onSiteVisit;
}

async asyncUpdate(onSiteVisit: IdbOnSiteVisit) {
onSiteVisit = await firstValueFrom(this.updateWithObservable(onSiteVisit));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { KeyPerformanceIndicatorValue } from '../../shared/constants/keyPerforma
import { KeyPerformanceMetric, KeyPerformanceMetricOption, KeyPerformanceMetricValue } from '../../shared/constants/keyPerformanceMetrics';

@Pipe({
name: 'nebOptionsFilter'
name: 'nebOptionsFilter',
pure: false
})
export class NebOptionsFilterPipe implements PipeTransform {

Expand All @@ -18,14 +19,14 @@ export class NebOptionsFilterPipe implements PipeTransform {
}
if (kpmValue) {
filteredOptions = filteredOptions.filter(option => {
return option.KPM.includes(kpmValue);
return option.KPM.includes(kpmValue) || option.selected;
})
} else if (kpiValue) {
rmroot marked this conversation as resolved.
Show resolved Hide resolved
let kpmOptionValues: Array<KeyPerformanceMetricValue> = keyPerformanceMetricOptions.map(option => {
return option.value;
})
filteredOptions = filteredOptions.filter(option => {
return option.KPM.findIndex(kpmOptionValue => {
return option.selected || option.KPM.findIndex(kpmOptionValue => {
return kpmOptionValues.includes(kpmOptionValue)
}) != -1;
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.add-td{
width: 20px;
}

.bg-success a.click-link{
color: white;
}

.table-hover tr.no-hover td:hover{
background-color: white !important;
}

.metric-column{
padding-left: 24px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,52 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let neb of tableList" (click)="selectNeb(neb)">
<td class="add-td text-center" *ngIf="inAddModal">
<a class="click-link">
<ng-template [ngIf]="!neb.selected" [ngIfElse]="selectedNebBlock">
<fa-icon [icon]="faPlus"></fa-icon>
</ng-template>
<ng-template #selectedNebBlock>
<fa-icon [icon]="faCheck"></fa-icon>
</ng-template>
</a>
</td>
<td>
<span [innerHTML]="neb.htmlLabel"></span>
</td>
</tr>
<ng-container *ngFor="let neb of tableList">
<tr>
<td (click)="selectNeb(neb)" class="add-td text-center" *ngIf="inAddModal"
[ngClass]="{'bg-success': neb.selected}">
<a class="click-link">
<ng-template [ngIf]="!neb.selected" [ngIfElse]="selectedNebBlock">
<fa-icon [icon]="faPlus"></fa-icon>
</ng-template>
<ng-template #selectedNebBlock>
<fa-icon [icon]="faCheck"></fa-icon>
</ng-template>
</a>
</td>
<td>
<div class="w-100" (click)="selectNeb(neb)" [ngClass]="{'bold': neb.selected}">
<span [innerHTML]="neb.htmlLabel"></span>
</div>

<ng-container *ngIf="neb.selected" class="no-hover">
<div class="metric-column">
Select KPMs impacted by this NEB.
<div class="d-flex ps-2 flex-column">
<ng-container *ngFor="let metric of neb.KPM">
<div class="form-check">
<input class="form-check-input" type="checkbox" value=""
id="{{'check_'+metric+neb.optionValue}}" (change)="setChecked(neb, metric)"
[checked]="neb.selectedKPM.includes(metric)">
<label class="form-check-label" for="{{'check_'+metric+neb.optionValue}}">
<div class="d-flex">
<ng-template [ngIf]="companyTrackedKpms.includes(metric)">
<div class="pe-1">
&ast;
</div>
</ng-template>
<span
[innerHTML]="metric | kpmLabel: allKpmOptions: 'metricValue'"></span>
</div>
</label>
</div>
</ng-container>
</div>
</div>
</ng-container>
</td>
</tr>
</ng-container>
</tbody>
</table>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class NebsDatabaseTableComponent {
nebSearchStr: string = '';
kpiValue: KeyPerformanceIndicatorValue;
kpmValue: KeyPerformanceMetricValue;
allKpmOptions: Array<KeyPerformanceMetricOption> = KeyPerformanceMetricOptions;
keyPerformanceIndicatorOptions: Array<KeyPerformanceIndicatorOption> = KeyPerformanceIndicatorOptions;
keyPerformanceMetricOptions: Array<KeyPerformanceMetricOption> = [];

Expand Down Expand Up @@ -74,6 +75,15 @@ export class NebsDatabaseTableComponent {
return option.label;
}, 'asc');
}

if (this.companyTrackedKpis && this.companyTrackedKpms) {
this.keyPerformanceIndicatorOptions = _.orderBy(this.keyPerformanceIndicatorOptions, (option: KeyPerformanceIndicatorOption) => {
return this.companyTrackedKpis.includes(option.optionValue)
}, 'desc');
this.keyPerformanceMetricOptions = _.orderBy(this.keyPerformanceMetricOptions, (option: KeyPerformanceMetricOption) => {
return this.companyTrackedKpms.includes(option.value)
}, 'desc');
}
let selectedIndex: number = this.keyPerformanceMetricOptions.findIndex(option => {
return option.value == this.kpmValue;
})
Expand Down Expand Up @@ -136,5 +146,14 @@ export class NebsDatabaseTableComponent {
this.emitSelectedNebs.emit(selectedNebs);
}

setChecked(neb: NebOption, metric: KeyPerformanceMetricValue) {
if (neb.selectedKPM.includes(metric)) {
neb.selectedKPM = neb.selectedKPM.filter(kpm => {
return kpm != metric;
})
} else {
neb.selectedKPM.push(metric);
}
}

}
4 changes: 3 additions & 1 deletion src/app/nebs-database/nebs-database.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { NebOptionsFilterPipe } from './nebs-database-table/neb-options-filter.pipe';
import { FormsModule } from '@angular/forms';
import { NebsDatabaseTableComponent } from './nebs-database-table/nebs-database-table.component';
import { HelperPipesModule } from '../shared/helper-pipes/_helper-pipes.module';



Expand All @@ -17,7 +18,8 @@ import { NebsDatabaseTableComponent } from './nebs-database-table/nebs-database-
imports: [
CommonModule,
FontAwesomeModule,
FormsModule
FormsModule,
HelperPipesModule
],
exports: [
NebsDatabaseTableComponent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ <h6 class="pt-2 pb-2">
</h6>
<p class="fw-light small">
Use the "<fa-icon [icon]="faPlus"></fa-icon> Add NEB" dropdown to add Non-Energy Benefits
(<fa-icon [icon]="faWeightHanging"></fa-icon>) that
(<fa-icon [icon]="faWeightHanging"></fa-icon>) that
<span class="bold">are not associated with any specific energy efficiency opportunity</span> to this assessment.
</p>

Expand All @@ -34,4 +34,4 @@ <h6 class="pt-2 pb-2">
<hr>


<app-energy-opportunity-nebs-table [assessment]="assessment"></app-energy-opportunity-nebs-table>
<app-energy-opportunity-nebs-table [nonEnergyBenefits]="energyOppNonEnergyBenefits"></app-energy-opportunity-nebs-table>
Original file line number Diff line number Diff line change
@@ -1,60 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { AssessmentNebsFormComponent } from './assessment-nebs-form.component';
import { SetupWizardService } from 'src/app/setup-wizard/setup-wizard.service';
import { BehaviorSubject } from 'rxjs';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { FormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { AssessmentIdbService } from 'src/app/indexed-db/assessment-idb.service';
import { IdbAssessment, getNewIdbAssessment } from 'src/app/models/assessment';
import { NonEnergyBenefitsIdbService } from 'src/app/indexed-db/non-energy-benefits-idb.service';
import { IdbNonEnergyBenefit } from 'src/app/models/nonEnergyBenefit';
import { EnergyOpportunityNebsTableComponent } from './energy-opportunity-nebs-table/energy-opportunity-nebs-table.component';
import { EnergyOpportunityIdbService } from 'src/app/indexed-db/energy-opportunity-idb.service';
import { IdbEnergyOpportunity } from 'src/app/models/energyOpportunity';
import { EnergyOpportunityNebsListPipe } from './energy-opportunity-nebs-table/energy-opportunity-nebs-list.pipe';
import { LocalStorageDataService } from 'src/app/shared/shared-services/local-storage-data.service';
import { ChangeDetectorRef } from '@angular/core';
import { BootstrapService } from 'src/app/shared/shared-services/bootstrap.service';
import { getDefaultUnitSettings } from 'src/app/models/unitSettings';
import { NebSetupFormComponent } from 'src/app/shared/shared-assessment-forms/neb-forms-accordion/neb-setup-form/neb-setup-form.component';
import { NebFormsAccordionComponent } from 'src/app/shared/shared-assessment-forms/neb-forms-accordion/neb-forms-accordion.component';
import { SharedAssessmentFormsModule } from 'src/app/shared/shared-assessment-forms/shared-assessment-forms.module';
import { stubServiceProviders } from 'src/app/spec-helpers/spec-test-service-stub';

describe('AssessmentNebsFormComponent', () => {
let component: AssessmentNebsFormComponent;
let fixture: ComponentFixture<AssessmentNebsFormComponent>;

let setupWizardService: Partial<SetupWizardService> = {
sidebarOpen: new BehaviorSubject<boolean>(false),
};
let assessmentIdbService: Partial<AssessmentIdbService> = {
assessments: new BehaviorSubject<Array<IdbAssessment>>([]),
selectedAssessment: new BehaviorSubject<IdbAssessment>(getNewIdbAssessment('', '', '', getDefaultUnitSettings()))
};
let nonEnergyBenefitsIdbService: Partial<NonEnergyBenefitsIdbService> = {
nonEnergyBenefits: new BehaviorSubject<Array<IdbNonEnergyBenefit>>([])
};

let energyOpportunityIdbService: Partial<EnergyOpportunityIdbService> = {
energyOpportunities: new BehaviorSubject<Array<IdbEnergyOpportunity>>([])
}
let localStorageDataService: Partial<LocalStorageDataService> = {};
let cd: Partial<ChangeDetectorRef> = {};
let bootstrapService: Partial<BootstrapService> = {};
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FontAwesomeModule, FormsModule, RouterTestingModule],
declarations: [AssessmentNebsFormComponent, NebSetupFormComponent, NebFormsAccordionComponent, EnergyOpportunityNebsTableComponent, EnergyOpportunityNebsListPipe],
providers: [
{ provide: SetupWizardService, useValue: setupWizardService },
{ provide: AssessmentIdbService, useValue: assessmentIdbService },
{ provide: NonEnergyBenefitsIdbService, useValue: nonEnergyBenefitsIdbService },
{ provide: EnergyOpportunityIdbService, useValue: energyOpportunityIdbService },
{ provide: LocalStorageDataService, useValue: localStorageDataService },
{ provide: ChangeDetectorRef, useValue: cd },
{ provide: BootstrapService, useValue: bootstrapService }
]
imports: [FontAwesomeModule, FormsModule, RouterTestingModule, SharedAssessmentFormsModule],
declarations: [AssessmentNebsFormComponent, NebSetupFormComponent, NebFormsAccordionComponent],
providers: stubServiceProviders
})
.compileComponents();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,30 @@ export class AssessmentNebsFormComponent {

assessment: IdbAssessment;
assessmentSub: Subscription;
energyOppNonEnergyBenefits: Array<IdbNonEnergyBenefit>;
nonEnergyBenefitsSub: Subscription;

newNebName: string;
displayNebModal: boolean = false;
showAddNebDropdown: boolean = false;
constructor(private assessmentIdbService: AssessmentIdbService,
private sharedDataService: SharedDataService,
private nonEnergyBenefitIdbService: NonEnergyBenefitsIdbService
private nonEnergyBenefitsIdbService: NonEnergyBenefitsIdbService
) {
}

ngOnInit() {
this.assessmentSub = this.assessmentIdbService.selectedAssessment.subscribe(_assessment => {
this.assessment = _assessment;
});
this.nonEnergyBenefitsSub = this.nonEnergyBenefitsIdbService.nonEnergyBenefits.subscribe(_nonEnergyBenefits => {
this.energyOppNonEnergyBenefits = _nonEnergyBenefits.filter(neb => { return neb.assessmentId == this.assessment.guid && neb.energyOpportunityId != undefined });
});
}

ngOnDestroy() {
this.assessmentSub.unsubscribe();
this.nonEnergyBenefitsSub.unsubscribe();
}

openNebModal() {
Expand All @@ -48,8 +54,8 @@ export class AssessmentNebsFormComponent {
async addNEB() {
this.showAddNebDropdown = false;
let newNonEnergyBenefit: IdbNonEnergyBenefit = getNewIdbNonEnergyBenefit(this.assessment.userId, this.assessment.companyId, this.assessment.facilityId, this.assessment.guid, undefined, undefined, true);
await firstValueFrom(this.nonEnergyBenefitIdbService.addWithObservable(newNonEnergyBenefit))
await this.nonEnergyBenefitIdbService.setNonEnergyBenefits();
await firstValueFrom(this.nonEnergyBenefitsIdbService.addWithObservable(newNonEnergyBenefit))
await this.nonEnergyBenefitsIdbService.setNonEnergyBenefits();
}

toggleAddNebDropdown() {
Expand Down

This file was deleted.

Loading
Loading