UNPKG

@vendasta/store

Version:

Components and data for Store

726 lines (714 loc) 407 kB
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\">&nbsp;</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\"> &nbsp;</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}} &nbsp;</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\"> &nbsp;{{ 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 }],