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

Show Service plan cost when selecting a service plan (if not free) #2959

Merged
merged 9 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from 8 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
8 changes: 8 additions & 0 deletions src/frontend/app/core/cf-api-svc.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ export interface IServicePlan {
export interface IServicePlanExtra {
displayName: string;
bullets: string[];
costs: IServicePlanCost[];
}

export interface IServicePlanCost {
amount: {
[key: string]: number;
};
unit: string;
}
export interface IService {
label: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<app-step *ngIf="modeService.viewDetail.showSelectCf && !isSpaceScoped()" title="Cloud Foundry" [onEnter]="resetStoreData" [valid]="selectCF.validate | async" [onNext]="onNext" [blocked]="cfOrgSpaceService.isLoading$ | async">
<app-create-application-step1 [stepperText]="stepperText" [isMarketplaceMode]="inMarketplaceMode" #selectCF></app-create-application-step1>
</app-step>
<app-step title="Select Service" *ngIf="modeService.viewDetail.showSelectService" [valid]="selectService.validate | async" [onNext]="selectService.onNext">
<app-step title="Select Service" *ngIf="modeService.viewDetail.showSelectService" [valid]="selectService.validate | async" [onNext]="selectService.onNext" [blocked]="selectService.isFetching$ | async">
<app-select-service #selectService></app-select-service>
</app-step>
<app-step title="Select Plan" [onNext]="selectPlan.onNext" [blocked]="initialisedService$ | async" [onEnter]="selectPlan.onEnter" [valid]="selectPlan.validate | async" cancelButtonText="Cancel">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</mat-select>
</mat-form-field>
</form>
<mat-card class="select-plan__details" *ngIf="selectedService$ | async as selPlan">
<mat-card class="select-plan__details" *ngIf="selectedPlan$ | async as selPlan">
<app-card-status *ngIf="(getPlanAccessibility(selPlan.entity) | async)" [status$]="getPlanAccessibility(selPlan.entity)"></app-card-status>
<app-metadata-item label="Name"> {{ getDisplayName(selPlan)}} </app-metadata-item>
<app-metadata-item label="Description"> {{selPlan.entity.entity.description}} </app-metadata-item>
Expand All @@ -16,6 +16,14 @@
<span *ngIf="(getPlanAccessibility(selPlan.entity) | async) !== 'ok'"> ({{ getAccessibilityMessage(selPlan.entity) | async }})</span>
</app-metadata-item>
<app-metadata-item label="Free"> {{ isFree(selPlan) | titlecase}} </app-metadata-item>
<!-- Show costs if plan is not free, we have a costs object and the format is from the open service broker -->
<ng-container *ngIf="!selPlan.entity.entity.free && selPlan.extra.costs && selPlan.extra.costs[0] && selPlan.extra.costs[0].amount">
<app-metadata-item label="Cost per unit">
<div *ngFor="let cost of selPlan.extra.costs">
{{ cost.unit | titlecase }}: {{ getCostValue(cost) | currency:getCostCurrency(cost):'symbol-narrow':'1.2-2':getCurrencyLocale(cost, false) }}
</div>
</app-metadata-item>
</ng-container>
<app-metadata-item label="Additional Information" *ngIf="hasAdditionalInfo(selPlan)">
<ul>
<li *ngFor="let bulletPoint of selPlan.extra.bullets">{{bulletPoint}}</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TitleCasePipe } from '@angular/common';
import { TitleCasePipe, getCurrencySymbol, registerLocaleData } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
Expand All @@ -7,6 +7,7 @@ import {
ViewChild,
ViewContainerRef,
} from '@angular/core';
import localeFr from '@angular/common/locales/fr';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
Expand All @@ -30,7 +31,7 @@ import {
withLatestFrom,
} from 'rxjs/operators';

import { IServicePlan, IServicePlanExtra } from '../../../../core/cf-api-svc.types';
import { IServicePlan, IServicePlanExtra, IServicePlanCost } from '../../../../core/cf-api-svc.types';
import { EntityServiceFactory } from '../../../../core/entity-service-factory.service';
import { safeUnsubscribe } from '../../../../features/service-catalog/services-helper';
import { ServicePlanAccessibility } from '../../../../features/service-catalog/services.service';
Expand Down Expand Up @@ -66,7 +67,7 @@ interface ServicePlan {
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SelectPlanStepComponent implements OnDestroy {
selectedService$: Observable<ServicePlan>;
selectedPlan$: Observable<ServicePlan>;
cSIHelperService: CreateServiceInstanceHelper;
@ViewChild('noplans', { read: ViewContainerRef })
noPlansDiv: ViewContainerRef;
Expand All @@ -88,6 +89,7 @@ export class SelectPlanStepComponent implements OnDestroy {
private modeService: CsiModeService

) {
registerLocaleData(localeFr);

this.stepperForm = new FormGroup({
servicePlans: new FormControl('', Validators.required),
Expand Down Expand Up @@ -123,7 +125,7 @@ export class SelectPlanStepComponent implements OnDestroy {
refCount(),
);

this.selectedService$ = observableCombineLatest(
this.selectedPlan$ = observableCombineLatest(
this.stepperForm.statusChanges.pipe(startWith(true)),
this.servicePlans$).pipe(
filter(([p, q]) => !!q && q.length > 0),
Expand Down Expand Up @@ -208,6 +210,34 @@ export class SelectPlanStepComponent implements OnDestroy {
isPublic = (selPlan: EntityInfo<APIResource<IServicePlan>>) => this.isYesOrNo(selPlan.entity.entity.public);
isFree = (selPlan: EntityInfo<APIResource<IServicePlan>>) => this.isYesOrNo(selPlan.entity.entity.free);

/*
* Pick the first country listed in the amount object. It's unclear whether there could be a different number of these depending on
* which region the CF is being served in (IBM seem to charge different amounts per country)
*/
private getCountryCode = (cost: IServicePlanCost): string => {
return Object.keys(cost.amount)[0];
}

/*
* Find the charge for the chosen country
*/
getCostValue = (cost: IServicePlanCost) => cost.amount[this.getCountryCode(cost)];

/*
* Determine the currency for the chosen country
*/
getCostCurrency = (cost: IServicePlanCost) => {
return this.getCountryCode(cost).toUpperCase();
}

/*
* Artificially supply a locale for the chosen country.
*/
getCurrencyLocale(cost: IServicePlanCost) {
// This will be updated once with do i18n
return this.getCostCurrency(cost) === 'EUR' ? 'fr' : 'en-US';
}

private createNoPlansComponent() {
const component = this.componentFactoryResolver.resolveComponentFactory(
NoServicePlansComponent
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
<b>Select the service</b>
<div class="select-service">
<form class="stepper-form" [formGroup]="stepperForm">
<div class="select-service__select-wrapper">
<div class="select-service__select-wrapper__fields">
<mat-form-field>
<mat-select class="form-control" placeholder="Service" formControlName="service">
<mat-option *ngFor="let service of services$ | async" [value]="service.metadata.guid">{{ service.entity.label }}</mat-option>
</mat-select>
</mat-form-field>
<app-cf-service-card disableCardClick="true" [row]="selectedService$ | async"></app-cf-service-card>
</div>
<mat-progress-spinner class="service-busy-indicator" diameter="20" [ngClass]="{'service-busy-indicator__show': isFetching$ | async}" mode="indeterminate"></mat-progress-spinner>
</div>
<mat-form-field>
<mat-select class="form-control" placeholder="Service" formControlName="service" [disabled]="isFetching$ | async">
<mat-option *ngFor="let service of services$ | async" [value]="service.metadata.guid">{{ service.entity.label }}</mat-option>
</mat-select>
</mat-form-field>
<app-cf-service-card disableCardClick="true" [row]="selectedService$ | async"></app-cf-service-card>
</form>
</div>
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
:host {
flex: 1
}

.select-service__select-wrapper {
align-items: center;
display: flex;
&__fields {
display: inherit;
flex-direction: column;
width: 500px;
}
}

.service-busy-indicator {
opacity: 0;
&__show {
opacity: 1;
}
flex: 1;
}