@vendasta/store
Version:
Components and data for Store
726 lines (714 loc) • 407 kB
JavaScript
import { Component, Input, NgModule, EventEmitter, Output, Injectable, ChangeDetectorRef } from '@angular/core';
import { formatDisplayPrice, formatBillingFrequency, Addon } from '@vendasta/core/shared';
import { __extends, __values, __spread, __read } from 'tslib';
import { CommonModule } from '@angular/common';
import { ImageTransformationService, ImageTransformationModule } from '@vendasta/core/image-transformation';
import { MatButtonModule, MatCardModule, MatIconModule, MatMenuModule, MatChipsModule, MatTooltipModule, MatCheckboxModule, MatExpansionModule, MatInputModule, MatOptionModule, MatProgressSpinnerModule, MatSelectModule, MatDividerModule, MatListModule } from '@angular/material';
import { VaIconModule, VaSafeHtmlModule, VaBreadcrumbsModule, VaImageGalleryModule, VaListModule, UIKitModule } from '@vendasta/uikit';
import { FormControl, FormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BillingModel, BillingService, buildBilledProductFromProductPricingAndAddon, BillingModule } from '@vendasta/core/billing';
import { VaFormsModule } from '@vendasta/forms';
import { MatProgressSpinnerModule as MatProgressSpinnerModule$1 } from '@angular/material/progress-spinner';
import { isNullOrUndefined } from 'util';
import { BehaviorSubject, ReplaySubject, combineLatest, merge, zip } from 'rxjs';
import { skipWhile, shareReplay, map, take, filter, startWith } from 'rxjs/operators';
import { trigger, transition, animate, style, state } from '@angular/animations';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var VaPricingComponent = /** @class */ (function () {
function VaPricingComponent() {
this.pricing = null;
this.wrapFrequency = false;
this.isAddon = false;
this.hasVerifiedContract = false;
this.highlightPrice = true;
this.loaded = true;
}
Object.defineProperty(VaPricingComponent.prototype, "isFree", {
get: /**
* @return {?}
*/
function () {
/** @type {?} */
var isFreeHelper = function (prices) {
return prices
? prices.some(function (p) { return p.price === 0 || p.price === undefined; })
: false;
};
if (this.hasVerifiedContract && this.billedProduct) {
return this.billedProduct.pricingTiers.length === 1 ? isFreeHelper(this.billedProduct.pricingTiers) : false;
}
return this.pricing && isFreeHelper(this.pricing.prices) ? true : false;
},
enumerable: true,
configurable: true
});
Object.defineProperty(VaPricingComponent.prototype, "shouldContactSales", {
get: /**
* @return {?}
*/
function () {
/** @type {?} */
var nestedPricesIsContactSales = function (prices) {
return prices && prices.length > 0
? prices.some(function (p) { return p.price === null || p.price < 0; })
: true;
};
if (this.hasVerifiedContract && this.billedProduct) {
return nestedPricesIsContactSales(this.billedProduct.pricingTiers) ? true : false;
}
if (!this.pricing) {
return true;
}
return nestedPricesIsContactSales(this.pricing.prices);
},
enumerable: true,
configurable: true
});
/**
* @param {?} billedProduct
* @return {?}
*/
VaPricingComponent.prototype.isFlatPrice = /**
* @param {?} billedProduct
* @return {?}
*/
function (billedProduct) {
return billedProduct.pricingTiers.length === 1;
};
/**
* @param {?} tier
* @return {?}
*/
VaPricingComponent.prototype.buildPricingTierString = /**
* @param {?} tier
* @return {?}
*/
function (tier) {
/** @type {?} */
var max = String(tier.rangeMax);
if (tier.rangeMax === -1) {
max = '∞';
if (tier.rangeMin === 0 || tier.rangeMin === 1) {
return '';
}
}
return String(tier.rangeMin) + ' to ' + max;
};
/**
* @param {?} tier
* @param {?=} frequency
* @return {?}
*/
VaPricingComponent.prototype.buildPricingTierForProduct = /**
* @param {?} tier
* @param {?=} frequency
* @return {?}
*/
function (tier, frequency) {
/** @type {?} */
var pricingTier = this.buildPricingTierString(tier);
/** @type {?} */
var formattedFrequency = formatBillingFrequency(frequency);
return pricingTier ? pricingTier + ' accounts ' + formattedFrequency : formattedFrequency;
};
/**
* @param {?} tier
* @return {?}
*/
VaPricingComponent.prototype.buildPricingTierForAddon = /**
* @param {?} tier
* @return {?}
*/
function (tier) {
/** @type {?} */
var pricingRange = this.buildPricingTierString(tier);
return pricingRange ? pricingRange : '';
};
/**
* @param {?} price
* @param {?} currency
* @param {?=} excludeFrequency
* @return {?}
*/
VaPricingComponent.prototype.buildPriceStringForPricing = /**
* @param {?} price
* @param {?} currency
* @param {?=} excludeFrequency
* @return {?}
*/
function (price, currency, excludeFrequency) {
return formatDisplayPrice(price.price, currency, (/** @type {?} */ ((excludeFrequency ? '' : price.frequency))), true, true, true, price.isStartingPrice);
};
/**
* @param {?} tier
* @param {?=} frequency
* @param {?=} isStartingPrice
* @return {?}
*/
VaPricingComponent.prototype.buildPriceStringForTier = /**
* @param {?} tier
* @param {?=} frequency
* @param {?=} isStartingPrice
* @return {?}
*/
function (tier, frequency, isStartingPrice) {
return formatDisplayPrice(tier.price, this.billedProduct.currency, (/** @type {?} */ (frequency)), undefined, undefined, undefined, isStartingPrice);
};
/**
* @param {?=} frequency
* @return {?}
*/
VaPricingComponent.prototype.buildFrequencyString = /**
* @param {?=} frequency
* @return {?}
*/
function (frequency) {
return formatBillingFrequency(frequency);
};
/**
* @return {?}
*/
VaPricingComponent.prototype.buildCommitmentMessage = /**
* @return {?}
*/
function () {
/** @type {?} */
var frequency = this.billedProduct ? this.billedProduct.billingFrequency.toString().toLowerCase() :
this.pricing && this.pricing.prices.length > 0 ? this.pricing.prices[0].frequency.toLowerCase() : '';
/** @type {?} */
var frequencyString = '';
if (frequency === 'yearly') {
frequencyString = 'year';
}
else if (frequency === 'monthly') {
frequencyString = 'month';
}
if (!frequencyString || this.isFree || this.shouldContactSales) {
return '';
}
if (this.billedProduct && this.billedProduct.commitment) {
/** @type {?} */
var initial = this.billedProduct.commitment.initial;
/** @type {?} */
var recurring = this.billedProduct.commitment.recurring;
if (this.highlightPrice) {
return "*" + initial + " " + frequencyString + " minimum, renews for " + recurring + " " + frequencyString + " periods";
}
else {
return initial + " " + frequencyString + " commitment";
}
}
return '';
};
VaPricingComponent.decorators = [
{ type: Component, args: [{
selector: 'va-pricing',
template: "<ng-container *ngIf=\"highlightPrice\">\n <highlight-pricing [pricing]=\"pricing\"\n [billedProduct]=\"billedProduct\"\n [highlightPrice]=\"highlightPrice\"\n [isAddon]=\"isAddon\"\n [hasVerifiedContract]=\"hasVerifiedContract\"\n [wrapFrequency]=\"wrapFrequency\"\n [loaded]=\"loaded\">\n </highlight-pricing>\n</ng-container>\n<ng-container *ngIf=\"!highlightPrice\">\n <table-pricing [pricing]=\"pricing\"\n [highlightPrice]=\"highlightPrice\"\n [billedProduct]=\"billedProduct\"\n [hasVerifiedContract]=\"hasVerifiedContract\"\n [loaded]=\"loaded\">\n </table-pricing>\n</ng-container>\n",
styles: [""]
}] }
];
VaPricingComponent.propDecorators = {
pricing: [{ type: Input }],
billedProduct: [{ type: Input }],
wrapFrequency: [{ type: Input }],
isAddon: [{ type: Input }],
hasVerifiedContract: [{ type: Input }],
highlightPrice: [{ type: Input }],
loaded: [{ type: Input }]
};
return VaPricingComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var HighlightPricingComponent = /** @class */ (function (_super) {
__extends(HighlightPricingComponent, _super);
function HighlightPricingComponent() {
return _super !== null && _super.apply(this, arguments) || this;
}
HighlightPricingComponent.decorators = [
{ type: Component, args: [{
selector: 'highlight-pricing',
template: "<ng-container *ngIf=\"loaded; else loading\">\n <div class=\"no-price\" *ngIf=\"shouldContactSales; else dontContactSales\">\n Contact Sales\n </div>\n <ng-template #dontContactSales>\n <div class=\"no-price\" *ngIf=\"isFree; else notFree\">\n <b>Free</b>\n </div>\n <ng-template #notFree>\n <ng-container *ngIf=\"!isAddon\">\n <ng-container *ngIf=\"hasVerifiedContract && billedProduct; else usePricing\">\n <div *ngFor=\"let tier of billedProduct.pricingTiers\" class=\"price-box\">\n <span>\n <span *ngIf=\"tier.isStartingPrice\" class=\"starting-at\">Starting at</span>\n <b class=\"price-number\">{{buildPriceStringForTier(tier)}}</b>\n </span>\n <span class=\"tier-billing-freq\" [ngClass]=\"{'va-wrap': wrapFrequency}\">\n {{buildPricingTierForProduct(tier, billedProduct.billingFrequency)}}\n </span>\n </div>\n </ng-container>\n <ng-template #usePricing>\n <ng-container *ngIf=\"pricing?.prices\">\n <div *ngFor=\"let price of pricing.prices; let i = index\" class=\"price-box\">\n <span>\n <span *ngIf=\"price?.isStartingPrice\" class=\"starting-at\">Starting at</span>\n <b class=\"price-number\">\n <ng-container *ngIf=\"i == 1\">+</ng-container>\n {{buildPriceStringForPricing(price, pricing?.currency, true)}}\n </b>\n </span>\n <span *ngIf=\"price.frequency as frequency\" class=\"billing-freq\" [ngClass]=\"{'va-wrap': wrapFrequency}\">\n {{buildFrequencyString(frequency)}}\n </span>\n </div>\n </ng-container>\n </ng-template>\n </ng-container>\n <ng-container *ngIf=\"isAddon\">\n <div *ngIf=\"hasVerifiedContract && billedProduct; else useAddonPricing\">\n <div *ngFor=\"let tier of billedProduct.pricingTiers\" class=\"price-box\">\n <span class=\"addon-billing-freq\">\n {{buildPricingTierForAddon(tier)}}\n </span>\n <span>\n <span *ngIf=\"tier.isStartingPrice\" class=\"starting-at\">Starting at</span>\n <b class=\"price-number\">\n {{buildPriceStringForTier(tier, billedProduct.billingFrequency)}}\n </b>\n </span>\n\n </div>\n </div>\n <ng-template #useAddonPricing>\n <div class=\"price-box\">\n <span *ngIf=\"pricing?.prices[0].frequency\" class=\"addon-billing-freq\">\n {{buildFrequencyString(pricing.prices[0].frequency)}}\n </span>\n <span>\n <span *ngIf=\"pricing?.prices[0]?.isStartingPrice\" class=\"starting-at\">Starting at</span>\n <b class=\"price-number\">\n {{buildPriceStringForPricing(pricing?.prices[0], pricing?.currency, true)}}\n </b>\n </span>\n </div>\n </ng-template>\n </ng-container>\n <div class=\"commitment\" *ngIf=\"billedProduct && billedProduct.commitment && billedProduct.commitment.initial > 1\">\n {{ buildCommitmentMessage() }}\n </div>\n </ng-template>\n </ng-template>\n</ng-container>\n<ng-template #loading>\n <div class=\"stencil-pricing stencil-shimmer\"></div>\n</ng-template>\n",
styles: [":host{color:#9e9e9e}.starting-at{margin-right:5px}.price-box{display:flex;align-items:baseline;flex-direction:row-reverse}.no-price{text-align:center}b{color:#212121;font-size:20px}@media screen and (max-width:600px){.no-price,.price-box,b{font-size:16px}}.billing-freq{text-transform:capitalize;flex:1}.tier-billing-freq{flex:1}.addon-billing-freq{padding-left:5px}.va-wrap{display:block}.stencil-pricing{height:1em}.commitment{color:#9e9e9e;font-size:12px;font-style:italic}"]
}] }
];
return HighlightPricingComponent;
}(VaPricingComponent));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var TablePricingComponent = /** @class */ (function (_super) {
__extends(TablePricingComponent, _super);
function TablePricingComponent() {
return _super !== null && _super.apply(this, arguments) || this;
}
TablePricingComponent.decorators = [
{ type: Component, args: [{
selector: 'table-pricing',
template: "<ng-container *ngIf=\"loaded; else loading\">\n <div *ngIf=\"hasVerifiedContract && billedProduct; else usePricing\">\n <div class=\"price-container\" *ngIf=\"isFlatPrice(billedProduct); else notFlatPrice\">\n <div class=\"price\">\n {{buildPriceStringForTier(billedProduct.pricingTiers[0], billedProduct.billingFrequency, billedProduct.pricingTiers[0].isStartingPrice)}}\n </div>\n </div>\n <ng-template #notFlatPrice>\n <div class=\"price-container--tiered\" *ngIf=\"!isFlatPrice(billedProduct)\">\n <div class=\"pricing-tier\" *ngFor=\"let tier of billedProduct.pricingTiers\">\n <div class=\"pricing-tier__range\">{{buildPricingTierString(tier)}}</div>\n <div class=\"pricing-tier__price\">\n {{buildPriceStringForTier(tier, billedProduct.billingFrequency, tier.isStartingPrice)}}\n </div>\n </div>\n </div>\n </ng-template>\n <div class=\"commitment\" *ngIf=\"billedProduct && billedProduct.commitment && billedProduct.commitment.initial > 1\">\n {{ buildCommitmentMessage() }}\n </div>\n </div>\n <ng-template #usePricing>\n <div class=\"gray-font\">\n <ng-container *ngIf=\"shouldContactSales; else dontContactSales\">\n Contact Sales\n </ng-container>\n <ng-template #dontContactSales>\n <ng-container *ngIf=\"isFree; else notFree\">\n Free\n </ng-container>\n <ng-template #notFree>\n {{buildPriceStringForPricing(pricing?.prices[0], pricing?.currency)}}\n <div class=\"commitment\" *ngIf=\"billedProduct && billedProduct.commitment && billedProduct.commitment.initial > 1\">\n {{ buildCommitmentMessage() }}\n </div>\n </ng-template>\n </ng-template>\n </div>\n </ng-template>\n</ng-container>\n<ng-template #loading>\n <div class=\"stencil-pricing stencil-shimmer\"></div>\n</ng-template>\n",
styles: [":host{color:#616161}.price-container--tiered{font-size:12px;flex-direction:column;display:flex;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.price-container--tiered .pricing-tier{border-bottom:1px solid #e0e0e0;padding:5px 0;display:flex}.price-container--tiered .pricing-tier:first-child{padding-top:0}.price-container--tiered .pricing-tier:last-child{padding-bottom:0;border-bottom:none}.price-container--tiered .pricing-tier .pricing-tier__range{padding-right:20px;flex:1}.stencil-pricing{height:1em}.commitment{color:#9e9e9e;font-size:12px;font-style:italic}"]
}] }
];
return TablePricingComponent;
}(VaPricingComponent));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var VaPricingModule = /** @class */ (function () {
function VaPricingModule() {
}
VaPricingModule.decorators = [
{ type: NgModule, args: [{
imports: [CommonModule],
declarations: [VaPricingComponent, HighlightPricingComponent, TablePricingComponent],
exports: [VaPricingComponent]
},] }
];
return VaPricingModule;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var StoreCardComponent = /** @class */ (function () {
function StoreCardComponent(imageTransformationService) {
this.imageTransformationService = imageTransformationService;
this.purchasedClicked = new EventEmitter();
this.cardClicked = new EventEmitter();
this.descriptionClicked = new EventEmitter();
this.bannerClicked = new EventEmitter();
}
/**
* @return {?}
*/
StoreCardComponent.prototype.getBannerColorForName = /**
* @return {?}
*/
function () {
// determine an icon color for a product with no icon by using the product name
/** @type {?} */
var COLOR_CODES = [
'#EF5350', '#42A5F5', '#66BB6A', '#FFA726', '#AB47BC', '#FFCA28', '#EC407A', '#26C6DA',
'#FF7B57'
];
/** @type {?} */
var nameSum = 0;
/** @type {?} */
var defaultColor = '#808080';
if (!this.item.name) {
return defaultColor;
}
for (var i = 0; i < this.item.name.length; i++) {
nameSum += this.item.name[i].charCodeAt(0);
}
/** @type {?} */
var index = nameSum % COLOR_CODES.length;
return COLOR_CODES[index];
};
/**
* @param {?} imageUrl
* @return {?}
*/
StoreCardComponent.prototype.getSrcsetHeaderUrls = /**
* @param {?} imageUrl
* @return {?}
*/
function (imageUrl) {
return this.imageTransformationService.getSrcSetForImage(imageUrl, [680, 1360, 2720]);
};
StoreCardComponent.decorators = [
{ type: Component, args: [{
selector: 'va-store-card',
template: "\n<mat-card class=\"hover-card\" *ngIf=\"item\" (click)=\"cardClicked.emit(item)\">\n<div class=\"hover-area\">\n <div class=\"product-banner\" (click)=\"bannerClicked.emit(item)\"\n [style.background-color]=\"item.headerImageUrl ? '': getBannerColorForName()\">\n <img class=\"img-container\" *ngIf=\"item.headerImageUrl\"\n [src]=\"item.headerImageUrl\" [srcset]=\"getSrcsetHeaderUrls(item.headerImageUrl)\">\n </div>\n\n <div class=\"description\" (click)=\"descriptionClicked.emit(item)\">\n <mat-card-header>\n <va-icon mat-card-avatar [diameter]=\"40\" [name]=\"item.name\" [iconUrl]=\"item.iconUrl\"></va-icon>\n <mat-card-title>{{item.name}}</mat-card-title>\n <mat-card-subtitle>\n <ng-container *ngIf=\"item.pricing; else formatted\">\n <va-pricing [pricing]=\"item.pricing\"\n [highlightPrice]=\"false\"></va-pricing>\n </ng-container>\n <ng-template #formatted>{{item.formattedPrice}}</ng-template>\n </mat-card-subtitle>\n </mat-card-header>\n <mat-card-content> {{ item.tagline }}\n </mat-card-content>\n </div>\n\n <button *ngIf=\"item.purchased !== undefined\"\n mat-button color=\"primary\" class=\"enabled-indicator\" (click)=\"purchasedClicked.emit(item)\" [disabled]=\"item.purchased\">\n <i *ngIf=\"!item.purchased\" class=\"material-icons\">add</i>\n <i *ngIf=\"item.purchased\" class=\"material-icons\" style=\"color: #39B74A\">check</i>\n <span>{{(item.purchased) ? 'ENABLED' : 'ENABLE'}}</span>\n </button>\n </div>\n</mat-card>\n ",
styles: [":host{position:relative}::ng-deep .mat-card-header-text{width:100%}mat-card.hover-card{overflow:hidden;padding:0;margin-bottom:0}mat-card.hover-card mat-card-subtitle,mat-card.hover-card mat-card-title{margin:0 80px 0 0;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}mat-card.hover-card mat-card-subtitle{font-size:12px;margin-top:4px}.hover-area{position:relative;cursor:pointer}.product-banner{max-height:133px;overflow:hidden;display:flex;width:100%;height:100px;align-items:center;justify-content:center}.product-banner img{max-width:100%}@media screen and (min-width:480px){.hover-area{padding-top:55%}.hover-area:hover .description{top:0}.hover-area:hover .enabled-indicator span{width:70px}.product-banner{max-height:none;position:absolute;height:60%;top:0}}.description{box-sizing:border-box;padding:10px 16px 0;overflow:hidden;background:#fff;color:#212121;transition:.3s}.description:after{content:'';display:block;width:100%;height:40%;position:absolute;bottom:0;left:0;background:linear-gradient(rgba(255,255,255,0) 40%,#fff 70%)}mat-card-header{box-sizing:border-box;padding-bottom:16px;margin:0;height:40%;display:flex;align-items:center}mat-card-content{min-height:40px;max-height:80px;padding:16px;margin:0 -16px;border-top:1px solid #e0e0e0;font-size:12px}.enabled-indicator{position:absolute;right:8px;bottom:8px}.enabled-indicator span{display:inline-block;width:70px;overflow:hidden;transition:.3s}@media screen and (min-width:480px){.description{position:absolute;top:60%;width:100%;height:100%}.description:after{height:70%}mat-card-content{min-height:0;max-height:none}.enabled-indicator span{width:0}}button[mat-button]{padding:0 8px;min-width:0}mat-card-actions{position:relative;padding:8px!important;margin:0!important;text-align:right;border-top:1px solid #e0e0e0;background-color:#fff;color:#212121}.status{font-size:14px}.img-container{height:100%;width:100%}"]
}] }
];
/** @nocollapse */
StoreCardComponent.ctorParameters = function () { return [
{ type: ImageTransformationService }
]; };
StoreCardComponent.propDecorators = {
item: [{ type: Input }],
purchasedClicked: [{ type: Output }],
cardClicked: [{ type: Output }],
descriptionClicked: [{ type: Output }],
bannerClicked: [{ type: Output }]
};
return StoreCardComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var StoreCardModule = /** @class */ (function () {
function StoreCardModule() {
}
StoreCardModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule,
VaIconModule,
MatCardModule,
MatButtonModule,
MatIconModule,
MatMenuModule,
ImageTransformationModule,
VaPricingModule
],
declarations: [StoreCardComponent],
exports: [StoreCardComponent]
},] }
];
return StoreCardModule;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var StoreComponent = /** @class */ (function () {
function StoreComponent() {
this.items = [];
this.searchable = true;
this.itemClicked = new EventEmitter();
}
Object.defineProperty(StoreComponent.prototype, "filteredItems", {
get: /**
* @return {?}
*/
function () {
var _this = this;
if (this.filterTerm) {
return this.items.filter(function (pkg) { return pkg.name.toLowerCase().indexOf(_this.filterTerm.toLowerCase()) !== -1; });
}
return this.items;
},
enumerable: true,
configurable: true
});
StoreComponent.decorators = [
{ type: Component, args: [{
selector: 'va-store',
template: "\n <div class=\"toolbar\">\n <div *ngIf=\"searchable\" class=\"table-controls-row\">\n <va-search-box (update)=\"filterTerm = $event\"></va-search-box>\n </div>\n </div>\n <div class=\"row row-gutters\">\n <div *ngFor=\"let item of filteredItems\" class=\"col-flex\">\n <va-store-card [item]=\"item\" (cardClicked)=\"this.itemClicked.emit(item)\"></va-store-card>\n </div>\n </div>\n ",
styles: [".flex-row{display:flex;flex-direction:row}.toolbar{padding:0;background-color:#fff;color:#616161}.toolbar .disabled{cursor:default}.toolbar .disabled mat-icon{cursor:default;color:#9e9e9e}.toolbar va-search-box{margin-right:10px;width:350px}.toolbar .table-controls-row{padding:0 10px 10px;display:flex;flex-direction:row;align-items:center}.toolbar .table-controls-row:first-of-type{padding-top:10px}.top-border{border-top:1px solid #fff}.selected{background-color:#fff}.row{display:flex;flex-wrap:wrap}.row+.row-gutters{margin-top:0}.row-gutters{margin-top:-20px;margin-left:-20px}.row-gutters>.col-flex{padding-top:20px;padding-left:20px}.col-flex{position:relative;max-width:100%;box-sizing:border-box;flex:0 0 auto;width:100%}@media screen and (min-width:480px){.col-flex{width:50%}}@media screen and (min-width:1200px){.col-flex{width:33.333333%}}"]
}] }
];
StoreComponent.propDecorators = {
items: [{ type: Input }],
searchable: [{ type: Input }],
itemClicked: [{ type: Output }]
};
return StoreComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var DropDownFormSectionComponent = /** @class */ (function () {
function DropDownFormSectionComponent() {
this.startOpen = false;
this.displayAutoTitle = false;
this.titleText = '';
this.displayAutoDescription = true;
this.descriptionText = '';
this.editingHint = '';
this.expandable = true;
this.autoDescriptionText = '';
this.iconName = 'help_outline';
this.subscriptions = [];
this.uniqueIndex = 1;
this.autoTitleText = '';
}
/**
* @return {?}
*/
DropDownFormSectionComponent.prototype.ngOnInit = /**
* @return {?}
*/
function () {
var _this = this;
while (this.parentForm.controls.hasOwnProperty(this.titleText + this.uniqueIndex)) {
this.uniqueIndex += 1;
}
this.parentForm.addControl(this.titleText + this.uniqueIndex, this.toFormGroup(this.fields));
/** @type {?} */
var form = (/** @type {?} */ (this.parentForm.controls[this.titleText + this.uniqueIndex]));
for (var key in form.controls) {
if (form.controls.hasOwnProperty(key)) {
if (this.prepopulatedData != null && this.prepopulatedData.hasOwnProperty(key)) {
form.controls[key].setValue(this.prepopulatedData[key]);
}
}
}
this.subscriptions.push(form.statusChanges.subscribe(function (change) {
/** @type {?} */
var missingFields = false;
for (var control in form.controls) {
if (!form.controls[control].value || (form.controls[control].value.constructor === Array && !form.controls[control].value[0])) {
_this.iconName = 'help_outline';
missingFields = true;
if (change === 'INVALID') {
_this.autoTitleText = '* Please fill out all required fields';
if (form.controls[control].dirty || form.controls[control].touched) {
_this.iconName = 'warning';
break;
}
}
else {
_this.autoTitleText = 'Optional fields unanswered';
}
}
}
if (!missingFields) {
_this.iconName = 'check_circle';
_this.autoTitleText = 'Complete';
}
}));
if (this.displayAutoDescription) {
this.subscriptions.push(form.valueChanges.subscribe(function (changes) {
/** @type {?} */
var description = '';
for (var key in changes) {
if (changes.hasOwnProperty(key) && changes[key] !== null && changes[key].length > 0) {
if (changes[key][0].name) {
for (var fileKey in changes[key]) {
if (changes[key][fileKey] != null) {
description += changes[key][fileKey].name;
description += ', ';
}
}
}
else {
description += changes[key];
description += ', ';
}
}
}
_this.autoDescriptionText = description.substring(0, description.length - 2);
}));
}
form.updateValueAndValidity({ onlySelf: false, emitEvent: true });
};
/**
* @param {?} formFields
* @return {?}
*/
DropDownFormSectionComponent.prototype.toFormGroup = /**
* @param {?} formFields
* @return {?}
*/
function (formFields) {
var _this = this;
/** @type {?} */
var group = {};
formFields.forEach(function (field) {
/** @type {?} */
var formControl;
if (field.controlType === 'checkbox') {
formControl = new FormControl(field.value);
}
else {
formControl = field.required ? new FormControl(field.value, Validators.required) : new FormControl(field.value);
}
group[field.id] = formControl;
_this.subscriptions.push(formControl.valueChanges.subscribe(function (value) { return (field.value = value); }));
});
return new FormGroup(group);
};
/**
* @return {?}
*/
DropDownFormSectionComponent.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this.subscriptions.forEach(function (subscription) { return subscription.unsubscribe(); });
};
DropDownFormSectionComponent.decorators = [
{ type: Component, args: [{
selector: 'va-dropdown-form-section',
template: "\n <mat-card *ngIf=\"!expandable && !(expandable == undefined)\" class=\"not-expandable-card\">\n <mat-icon class=\"not-expandable-icon valid\"> check_circle</mat-icon>\n <mat-card-header *ngIf=\"!displayAutoTitle\" class=\"not-expandable-header\">\n {{ titleText }}\n </mat-card-header>\n <mat-card-header *ngIf=\"displayAutoTitle\" class=\"not-expandable-header valid\">\n <div class=\"title\"> {{ titleText }}</div>\n <div *ngIf=\"titleText && autoTitleText\"> </div>\n <ng-container><i> Complete </i></ng-container>\n </mat-card-header>\n <mat-panel-description class=\"not-expandable-description\">\n {{ descriptionText }}\n </mat-panel-description>\n </mat-card>\n <mat-expansion-panel *ngIf=\"expandable || expandable == undefined\" [expanded]=\"startOpen\">\n <mat-expansion-panel-header>\n <div class=\"dropdown-form-header\">\n <mat-icon\n [ngClass]=\"{invalid: iconName=='warning', valid: iconName=='check_circle', question: iconName=='help_outline'}\">\n {{ iconName }}\n </mat-icon>\n <mat-panel-title *ngIf=\"!displayAutoTitle\">\n {{ titleText }}\n </mat-panel-title>\n <mat-panel-title *ngIf=\"displayAutoTitle\"\n [ngClass]=\"{valid: iconName=='check_circle', invalid: iconName=='warning'}\">\n <div class=\"title\"> {{ titleText }}</div>\n <div *ngIf=\"titleText && autoTitleText\"> </div>\n <ng-container><i> {{autoTitleText}} </i></ng-container>\n </mat-panel-title>\n <mat-panel-description *ngIf=\"displayAutoDescription\" [ngClass]=\"{invalid: iconName=='warning'}\">\n {{ autoDescriptionText }}\n </mat-panel-description>\n <mat-panel-description *ngIf=\"!displayAutoDescription\" [ngClass]=\"{invalid: iconName=='warning'}\">\n <i> {{descriptionText}} </i>\n </mat-panel-description>\n </div>\n </mat-expansion-panel-header>\n <div class=\"expansion-panel-body\">\n <va-field *ngFor=\"let field of fields\" [field]=\"field\"\n [form]=\"parentForm.controls[titleText + uniqueIndex]\"></va-field>\n <p *ngIf=\"editingHint != ''\" class=\"editing-hint\"><i>{{ editingHint }}</i></p>\n </div>\n </mat-expansion-panel>\n ",
styles: [":host-context(va-dropdown-form-section){font-size:14px}:host-context(va-dropdown-form-section) .expansion-panel-body{margin-top:-10px;display:block;width:60%}.mat-expanded,.mat-expansion-panel{transition:margin .4s}.dropdown-form-header{width:100%;display:flex}mat-panel-description{align-self:center;flex:inherit;display:initial;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}mat-panel-description.invalid{color:#c62828}mat-icon{margin-right:7px;-ms-grid-row-align:center;align-self:center}mat-icon.valid{color:#4caf50}mat-icon.invalid{color:#c62828}mat-icon.question{color:#9e9e9e}mat-panel-title{-ms-grid-row-align:center;align-self:center;flex:none;margin-right:20px}mat-panel-title.valid{color:#4caf50}mat-panel-title.invalid{color:#c62828}.editing-hint{color:#9e9e9e}.title{color:#212121}.not-expandable-card{background:#fff;cursor:default;font-size:15px;display:flex;height:48px;align-items:center;box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.not-expandable-card .not-expandable-icon{margin-left:24px}.not-expandable-card .not-expandable-header{display:flex}.not-expandable-card .not-expandable-description{margin-left:22px}.not-expandable-card .valid{color:#4caf50}"]
}] }
];
/** @nocollapse */
DropDownFormSectionComponent.ctorParameters = function () { return []; };
DropDownFormSectionComponent.propDecorators = {
prepopulatedData: [{ type: Input }],
startOpen: [{ type: Input }],
parentForm: [{ type: Input }],
displayAutoTitle: [{ type: Input }],
titleText: [{ type: Input }],
displayAutoDescription: [{ type: Input }],
descriptionText: [{ type: Input }],
fields: [{ type: Input }],
editingHint: [{ type: Input }],
expandable: [{ type: Input }]
};
return DropDownFormSectionComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var FieldComponent = /** @class */ (function () {
function FieldComponent() {
}
Object.defineProperty(FieldComponent.prototype, "isValid", {
get: /**
* @return {?}
*/
function () {
return this.form.controls[this.field.id].valid || this.form.controls[this.field.id].pristine;
},
enumerable: true,
configurable: true
});
FieldComponent.decorators = [
{ type: Component, args: [{
selector: 'va-field',
template: "<ng-container [ngSwitch]=\"field.controlType\" [formGroup]=\"form\">\n\n <ng-container *ngSwitchCase=\"'dropdown'\">\n <mat-form-field class=\"form-field-container\">\n <mat-select matInput [formControlName]=\"field.id\" [id]=\"field.id\" [placeholder]=\"field.getLabel()\" [disabled]=\"field.disabled\">\n <mat-option *ngFor=\"let option of field.options\" [value]=\"option.value\" [disabled]=\"option.disabled\">{{ option.label }}</mat-option>\n </mat-select>\n <mat-hint *ngIf=\"field.description\"> {{ field.description }} </mat-hint>\n </mat-form-field>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textbox'\">\n <mat-form-field class=\"form-field-container\">\n <span matPrefix *ngIf=\"field.prefix\"> {{ field.prefix}} </span>\n <input matInput [type]=\"field.textboxType\" [id]=\"field.id\" [formControlName]=\"field.id\" [placeholder]=\"field.getLabel()\" [pattern]=\"field.regexValidator || ''\" [readonly]=\"field.disabled\">\n <span matSuffix *ngIf=\"field.suffix\"> {{ field.suffix }} </span>\n <mat-hint *ngIf=\"field.description\"> {{ field.description }} </mat-hint>\n <mat-error *ngIf=\"form.controls[field.id].hasError('pattern')\"> {{field.regexErrorMessage}} </mat-error>\n </mat-form-field>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'checkbox'\">\n <div class=\"form-field-container checkbox\">\n <mat-checkbox [formControlName]=\"field.id\" [id]=\"field.id\" ngControlDefault [disabled]=\"field.disabled\"></mat-checkbox>\n <div class=\"checkbox-placeholder\"> {{field.label}}</div>\n </div>\n <div class=\"checkbox-description\" *ngIf=\"field.description\">{{ field.description }}</div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'textarea'\">\n <mat-form-field class=\"form-field-container\">\n <textarea matInput [formControlName]=\"field.id\" [placeholder]=\"field.getLabel()\" [id]=\"field.id\" [readonly]=\"field.disabled\"></textarea>\n <mat-hint *ngIf=\"field.description\"> {{ field.description }} </mat-hint>\n </mat-form-field>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'file'\">\n <div class=\"form-field-container\">\n <file-group-uploader [uploadUrl]=\"field.uploadUrl\" [label]=\"field.getLabel()\" [description]=\"field.description\" [formGroup]=\"form\" [formControlName]=\"field.id\" [disabled]=\"field.disabled\"\n [numFiles]=\"field.numFiles\" class=\"form-field-container\"></file-group-uploader>\n </div>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'vbcuser'\">\n <mat-form-field class=\"form-field-container\">\n <mat-select matInput [formControlName]=\"field.id\" [id]=\"field.id\" [placeholder]=\"field.getLabel()\" [disabled]=\"field.disabled\">\n <mat-option *ngFor=\"let option of field.options\" [value]=\"option.value\" [disabled]=\"option.disabled\">{{ option.label }}</mat-option>\n </mat-select>\n <mat-hint *ngIf=\"field.description\"> {{ field.description }} </mat-hint>\n </mat-form-field>\n </ng-container>\n\n</ng-container>\n",
styles: [".form-field-container{font-size:16px;width:100%;margin:10px 0}.checkbox{display:flex;padding:5px 0;color:rgba(0,0,0,.54);margin-top:24px}.checkbox .checkbox-placeholder{margin-left:10px}.checkbox-description{margin-top:-14px;margin-left:32px;color:rgba(0,0,0,.54);font-size:12px}"]
}] }
];
FieldComponent.propDecorators = {
field: [{ type: Input }],
form: [{ type: Input }]
};
return FieldComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var FieldService = /** @class */ (function () {
function FieldService() {
}
/**
* @param {?} field
* @return {?}
*/
FieldService.prototype.createFormControl = /**
* @param {?} field
* @return {?}
*/
function (field) {
if (field.required) {
return new FormControl(field.value, Validators.required);
}
else {
return new FormControl(field.value);
}
};
/**
* @param {?} formFields
* @param {?} subscriptions
* @return {?}
*/
FieldService.prototype.toFormGroup = /**
* @param {?} formFields
* @param {?} subscriptions
* @return {?}
*/
function (formFields, subscriptions) {
var _this = this;
/** @type {?} */
var group = {};
formFields.forEach(function (field) {
/** @type {?} */
var formControl;
if (field.controlType === 'checkbox') {
formControl = new FormControl(field.value);
}
else {
formControl = _this.createFormControl(field);
}
group[field.id] = formControl;
if (subscriptions) {
subscriptions.push(formControl.valueChanges.subscribe(function (value) { return (field.value = value); }));
}
});
return new FormGroup(group);
};
FieldService.decorators = [
{ type: Injectable }
];
return FieldService;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var VaHeaderContainerComponent = /** @class */ (function () {
function VaHeaderContainerComponent() {
this.loaded = true;
this.showEnableAddon = false;
this.prerequisiteSelected = new EventEmitter();
this.actionSelected = new EventEmitter();
this.pricingActionSelected = new EventEmitter();
}
/**
* @return {?}
*/
VaHeaderContainerComponent.prototype.onActionSelected = /**
* @return {?}
*/
function () {
this.actionSelected.emit();
};
/**
* @return {?}
*/
VaHeaderContainerComponent.prototype.onPrerequisiteSelected = /**
* @return {?}
*/
function () {
this.prerequisiteSelected.emit();
};
/**
* @param {?} billedProduct
* @return {?}
*/
VaHeaderContainerComponent.prototype.showPricingModel = /**
* @param {?} billedProduct
* @return {?}
*/
function (billedProduct) {
return billedProduct && [BillingModel.Tiered, BillingModel.Stairstep].includes(billedProduct.billingModel);
};
/**
* @param {?} billingModel
* @return {?}
*/
VaHeaderContainerComponent.prototype.getPricingModelTooltips = /**
* @param {?} billingModel
* @return {?}
*/
function (billingModel) {
switch (billingModel) {
case BillingModel.Stairstep:
return 'Price applies per unit within a range';
case BillingModel.Tiered:
return 'Price applies to all units once range is met';
default:
return '';
}
};
VaHeaderContainerComponent.decorators = [
{ type: Component, args: [{
selector: 'va-header-container',
template: "<div class=\"header-container\">\n <div class=\"product-overview\">\n <div class=\"product-id\">\n\n <va-icon [iconUrl]=\"iconUrl\" [name]=\"title\" [diameter]=\"120\"></va-icon>\n\n <div class=\"product-id-text\">\n\n <h1 [ngClass]=\"{'stencil-title stencil-shimmer': !title, 'product-title': title}\">\n {{ title }}\n </h1>\n\n <span [ngClass]=\"{'stencil-tagline stencil-shimmer': !title && !tagline, 'tagline': tagline}\">\n {{ tagline }}\n </span>\n\n <div *ngIf=\"prerequisite\" class=\"prerequisite\">\n <span class=\"requires-text\">Requires </span>\n <span>{{ prerequisite }}</span>\n </div>\n\n <mat-chip-list>\n <mat-chip *ngFor=\"let chip of chipLabels\">{{ chip }}</mat-chip>\n </mat-chip-list>\n\n </div>\n </div>\n\n <div class=\"pricing\">\n\n <button *ngIf=\"showAction && !showEnableAddon\" mat-raised-button class=\"app-enable-button\" [disabled]=\"!actionEnabled\" (click)=\"onActionSelected()\">\n {{ actionLabel }}\n </button>\n\n <button *ngIf=\"showEnableAddon && !showAction\" mat-raised-button class=\"app-enable-button\" [disabled]=\"!showEnableAddon\" (click)=\"onActionSelected()\">\n {{ actionLabel }}\n </button>\n\n <div *ngIf=\"prerequisiteLabel && !showEnableAddon\" class=\"addon-enable\" (click)=\"onPrerequisiteSelected()\">\n Enabled with {{prerequisiteLabel}}\n </div>\n\n <div *ngIf=\"showPricing\" class=\"price-box\">\n <div *ngIf=\"pricing?.prices?.length\" class=\"wholesale-price\">{{ pricingLabel }}\n <div *ngIf=\"showPricingModel(billedProduct) && hasVerifiedContract\"\n class=\"pricing-model\"\n matTooltip=\"{{getPricingModelTooltips(billedProduct.billingModel)}}\">({{ billedProduct.billingModel }})\n </div>\n </div>\n <va-pricing [pricing]=\"pricing\"\n [billedProduct]=\"billedProduct\"\n [hasVerifiedContract]=\"hasVerifiedContract\"\n [loaded]=\"loaded\"></va-pricing>\n </div>\n\n <p *ngIf=\"pricingActionEnabled\" class=\"pricing-action-container\">\n <a (click)=\"pricingActionSelected.emit()\">{{ pricingActionLabel }}</a>\n </p>\n\n </div>\n\n </div>\n</div>\n",
styles: [":host{font-size:16px}.product-title{font-size:24px}.product-overview{display:flex;flex-wrap:wrap;border-bottom:1px solid #e0e0e0}.product-overview h1{margin:0;font-weight:400;line-height:1.2}.product-overview mat-chip{margin-bottom:3px}.product-id{display:flex;width:100%;padding:24px;flex-grow:1}.product-id va-icon{margin-right:20px}@media screen and (max-width:600px){.product-id va-icon ::ng-deep .va-icon-container{width:40px!important;height:40px!important}.product-id va-icon ::ng-deep .va-icon-container span{line-height:40px!important;font-size:15px!important}}.product-id .product-id-text{display:flex;flex-direction:column;justify-content:center}.product-id span{overflow:hidden}.product-id .tagline{color:#616161;margin:.5em 0 1em;font-size:16px}@media screen and (min-width:600px){.product-title{font-size:32px}.product-id .tagline{font-size:20px}.product-id{width:66%;padding-right:20px}}.product-id .prerequisite{margin:.5em 0 1em;font-size:14px}.product-id .requires-text{color:#9e9e9e}.inline-link{display:inline-flex!important;color:#1e88e5;cursor:pointer;padding-top:5px}.pricing{display:flex;flex-direction:column;width:100%;padding:0 24px 24px;color:#616161}@media screen and (min-width:600px){.pricing{width:34%;padding-top:24px;padding-left:20px}}.pricing span{display:block}.pricing span:nth-child(2){margin:.5em 0 1em}.pricing .price{font-size:24px;font-weight:700;line-height:1;color:#4caf50}.pricing .price-box{padding-top:10px}.pricing .pricing-action-container{margin:8px 0}.pricing .pricing-action-container mat-icon{vertical-align:middle;margin-right:6px}.pricing .pricing-action-container a{cursor:pointer}.pricing .pricing-model{display:inline-block;font-size:.8rem;color:#9e9e9e;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.app-enable-button{height:inherit;color:#fff;background-color:#4caf50;font-size:20px;padding:14px 16px;line-height:1}.addon-enable{height:inherit;background-color:#e0e0e0;font-size:14px;padding:14px 16px;line-height:1;color:#1e88e5;cursor:pointer;text-align:center}.wholesale-price{margin-top:0;padding-bottom:8px;margin-bottom:4px;border-bottom:1px solid #e0e0e0}.stencil-title{height:32px;width:200px;margin-bottom:5px!important}.stencil-tagline{height:32px;width:250px}"]
}] }
];
VaHeaderContainerComponent.propDecorators = {
iconUrl: [{ type: Input }],
title: [{ type: Input }],
tagline: [{ type: Input }],
prerequisite: [{ type: Input }],