{ "version": 3, "sources": ["libs/store/src/lib/assets/i18n/en_devel.json", "libs/store/src/lib/shared/constants.ts", "libs/store/src/lib/pricing/base-pricing.component.ts", "libs/store/src/lib/pricing/highlight-pricing/highlight-pricing.component.ts", "libs/store/src/lib/pricing/highlight-pricing/highlight-pricing.component.html", "libs/store/src/lib/shared/format-date.pipe.ts", "libs/store/src/lib/shared/format-discount.pipe.ts", "libs/store/src/lib/pricing/table-pricing/table-pricing.component.ts", "libs/store/src/lib/pricing/table-pricing/table-pricing.component.html", "libs/store/src/lib/pricing/pricing.component.ts", "libs/store/src/lib/pricing/pricing.component.html", "libs/store/src/lib/shared/conversion-utils.ts", "libs/store/src/lib/pricing/pricing.module.ts", "libs/store/src/lib/store-card.component.ts", "libs/store/src/lib/store-card.module.ts", "libs/store/src/lib/header-container/header-container.component.ts", "libs/store/src/lib/header-container/header-container.component.html", "libs/store/src/lib/header-container/header-container.module.ts", "libs/store/src/lib/order-form/dropdown-form-section/temporary-storage.service.ts", "libs/store/src/lib/order-form/fields/field-base.ts", "libs/store/src/lib/order-form/fields/field-checkbox.ts", "libs/store/src/lib/order-form/fields/field.component.ts", "libs/store/src/lib/order-form/fields/field.component.html", "libs/store/src/lib/order-form/dropdown-form-section/dropdown-form-section.component.ts", "libs/store/src/lib/order-form/fields/field.service.ts", "libs/store/src/lib/order-form/dropdown-form-section/dropdown-form-section-data.ts", "libs/store/src/lib/order-form/order-form-section/order-form-section-data.ts", "libs/store/src/lib/order-form/order-form/interface.ts", "libs/store/src/lib/shared/build-temporary-storage-key.pipe.ts", "libs/store/src/lib/order-form/order-form-section/order-form-section.component.ts", "libs/store/src/lib/order-form/order-form-section/order-form-section.component.html", "libs/store/src/lib/order-form/fields/field-dropdown.ts", "libs/store/src/lib/order-form/fields/field-fileuploadgroup.ts", "libs/store/src/lib/order-form/fields/field-textarea.ts", "libs/store/src/lib/order-form/fields/field-textbox.ts", "libs/store/src/lib/order-form/fields/field-vbcuser.ts", "libs/store/src/lib/order-form/order-form/order-form.service.ts", "libs/store/src/lib/order-form/order-form/order-form.component.ts", "libs/store/src/lib/order-form/order-form/order-form.component.html", "libs/store/src/lib/order-form/order-item-list/order-item-compact/order-item-compact.component.ts", "libs/store/src/lib/order-form/order-item-list/order-item-compact/order-item-compact.component.html", "libs/store/src/lib/order-form/order-item-list/discount-helpers.ts", "libs/store/src/lib/order-form/order-item-list/order-item-list.component.ts", "libs/store/src/lib/order-form/order-item-list/order-item-list.component.html", "libs/store/src/lib/order-form/order-form.module.ts", "libs/store/src/lib/stencils/list-stencil.component.ts", "libs/store/src/lib/stencils/stencils.module.ts", "libs/store/src/lib/salesperson-details/salesperson-details.module.ts", "libs/store/src/lib/addon-list/addon-list.component.ts", "libs/store/src/lib/addon-list/addon-list.component.html", "libs/store/src/lib/addon-list/addon-list.module.ts", "libs/store/src/lib/faqs/faqs.component.ts", "libs/store/src/lib/faqs/faqs.module.ts", "libs/store/src/lib/files/files.component.ts", "libs/store/src/lib/files/files.module.ts", "libs/store/src/lib/products-nav/products-nav-v2/products-nav-v2.component.ts", "libs/store/src/lib/products-nav/products-nav-v2/products-nav-v2.component.html", "libs/store/src/lib/files/shared/file.model.ts", "libs/store/src/lib/shared/sellable.ts", "libs/store/src/lib/shared/case-transform.ts", "libs/store/src/lib/shared/product.ts", "libs/store/src/lib/products-nav/products-nav.module.ts", "libs/store/src/lib/selling-info/selling-info.component.ts", "libs/store/src/lib/selling-info/selling-info.module.ts", "libs/store/src/lib/package-details-v2/package.ts", "libs/store/src/lib/lmi-categories.ts", "libs/store/src/lib/package-details-v2/package-details-v2.component.ts", "libs/store/src/lib/package-details-v2/package-details-v2.component.html", "libs/store/src/lib/package-details-v2/package-details-v2.module.ts", "libs/store/src/lib/product-details-v2/product-details-v2.interface.ts", "libs/store/src/lib/store-item.ts", "libs/store/src/lib/product-details-v2/screenshots-files/screenshots-files.component.ts", "libs/store/src/lib/product-details-v2/screenshots-files/screenshots-files.component.html", "libs/store/src/lib/product-details-v2/form-preview/form-preview.component.ts", "libs/store/src/lib/product-details-v2/form-preview/form-preview.component.html", "libs/store/src/lib/product-details-v2/need-help/need-help.component.ts", "libs/store/src/lib/product-details-v2/videos/video-parser.ts", "libs/store/src/lib/product-details-v2/videos/videos.component.ts", "libs/store/src/lib/product-details-v2/videos/videos.component.html", "libs/store/src/lib/product-details-v2/addon-list/addon-list.component.ts", "libs/store/src/lib/product-details-v2/addon-list/addon-list.component.html", "libs/store/src/lib/restrictions/country-v2/supported-countries-v2.component.ts", "libs/store/src/lib/restrictions/country-v2/supported-countries-v2.component.html", "libs/store/src/lib/product-details-v2/product-info/required-products-list/required-products-list.component.ts", "libs/store/src/lib/product-details-v2/product-info/required-products-list/required-products-list.component.html", "libs/store/src/lib/product-details-v2/product-info/product-requirements/app-product-requirements.component.ts", "libs/store/src/lib/product-details-v2/product-info/product-requirements/app-product-requirements.component.html", "libs/store/src/lib/product-details-v2/product-info/product-info.component.ts", "libs/store/src/lib/product-details-v2/product-info/product-info.component.html", "libs/store/src/lib/product-details-v2/editions-marketing/editions-marketing.component.ts", "libs/store/src/lib/product-details-v2/editions-marketing/editions-marketing.component.html", "libs/store/src/lib/product-details-v2/product-details-v2.component.ts", "libs/store/src/lib/product-details-v2/product-details-v2.component.html", "libs/store/src/lib/marketplace-product/marketplace-product.component.ts", "libs/store/src/lib/marketplace-product/marketplace-product.component.html", "libs/store/src/lib/restrictions/country/supported-countries.component.ts", "libs/store/src/lib/restrictions/restrictions.module.ts", "libs/store/src/lib/product-details-v2/edition-selector/edition-selector.types.ts", "libs/store/src/lib/product-details-v2/edition-selector/edition-selector.component.ts", "libs/store/src/lib/product-details-v2/edition-selector/edition-selector.component.html", "libs/store/src/lib/product-details-v2/product-details-v2.module.ts", "libs/store/src/lib/marketplace-product/marketplace-product.module.ts", "libs/store/src/lib/store.component.ts", "libs/store/src/lib/store.service.ts", "libs/store/src/lib/storefront/storefront.component.ts", "libs/store/src/lib/storefront/storefront.component.html", "libs/store/src/lib/store.module.ts", "libs/store/src/lib/product-details/product-details.component.ts", "libs/store/src/lib/product-details/product-details.component.html", "libs/store/src/lib/product-details/product-details.module.ts", "libs/store/src/lib/order-summary/order-summary.service.ts", "libs/store/src/lib/order-summary/contract-estimated-total/contract-estimated-total.component.ts", "libs/store/src/lib/order-summary/contract-estimated-total/contract-estimated-total.component.html", "libs/store/src/lib/order-summary/order-summarized-charges/order-summarized-charges.component.ts", "libs/store/src/lib/order-summary/order-summarized-charges/order-summarized-charges.component.html", "libs/store/src/lib/order-summary/order-summarized-totals/order-summarized-totals.component.ts", "libs/store/src/lib/order-summary/order-summarized-totals/order-summarized-totals.component.html", "libs/store/src/lib/order-summary/order-summary.component.ts", "libs/store/src/lib/order-summary/order-summary.component.html", "libs/store/src/lib/order-summary/order-summary.module.ts", "libs/store/src/lib/package-details/utils.ts", "libs/store/src/lib/package-details-v2/index.ts", "libs/store/src/lib/product-details-v2/edition-selector/edition-selector.service.ts", "libs/store/src/lib/product-details-v2/index.ts", "libs/store/src/lib/utils/billing-utils.ts", "libs/store/src/lib/index.ts", "libs/store/src/index.ts"], "sourcesContent": ["{\n \"FRONTEND\": {\n \"STORE\": {\n \"TOTAL\": \"Total\",\n \"SUBTOTAL\": \"Subtotal\",\n \"TAX\": \"Tax ({{percentage}}%)\",\n \"RECURRING_CHARGES_SUMMARY\": {\n \"TITLE\": \"Recurring charges summary\",\n \"NO_RECURRING_CHARGES\": \"No recurring charges\"\n },\n \"CANNOT_ADD_TO_CART_TOOLTIP\": \"This product can't be added to your cart right now. Please contact us directly to purchase this product.\",\n \"CAN_ENABLE_PRODUCTS_PERMISSION_DISABLED_TOOLTIP\": \"Contact an admin to start selling this product or update your user permissions.\",\n \"CONTRACT_DURATION\": \"Contract duration\",\n \"CONTACT_SALES\": \"Contact Sales\",\n \"CONTACT_US\": \"Contact us\",\n \"MESSAGE_US\": \"Message us\",\n \"FREE\": \"Free\",\n \"STARTING_AT\": \"Starting at\",\n \"ESTIMATED_VALUE\": \"Estimated value\",\n \"ENABLED_UPPER\": \"ENABLED\",\n \"ENABLE_UPPER\": \"ENABLE\",\n \"MIN_TO_MAX\": \"{{minRange}} to {{maxRange}}\",\n \"PRODUCT_PRICING_WITH_FREQUENCY\": \"{{pricingTier}} accounts {{frequency}}\",\n \"COMMITMENT_WITH_RENEWAL\": \"*{{initial}} {{frequencyString}} minimum, renews for {{recurring}} {{frequencyString}} periods\",\n \"COMMITMENT\": \"${{initial}} ${{frequencyString}} commitment\",\n \"PRICING_FREQUENCIES\": {\n \"MONTH\": \"month\",\n \"YEAR\": \"year\"\n },\n \"REQUIRES_DESCRIPTOR\": \"(Requires {{requirementName}})\",\n \"ADMINISTRATIVE_QUESTIONS\": \"Administrative Questions\",\n \"AUTO_TITLE_TEXT\": {\n \"SOME_FIELDS_INVALID\": \"Fields require your attention\",\n \"OPTIONAL_FIELDS_UNANSWERED\": \"Optional fields unanswered\",\n \"COMPLETE\": \"Complete\"\n },\n \"REQUIRES\": \"Requires\",\n \"ENABLED_WITH_PREREQUISITE\": \"Enabled with {{prerequisite}}\",\n \"ENABLE_WITH_PREREQUISITE\": \"Enable with {{prerequisite}}\",\n \"PRICE_APPLIES_PER_UNIT\": \"Price applies per unit within a range\",\n \"PRICE_APPLIES_TO_ALL_UNITS\": \"Price applies to all units once range is met\",\n \"PRICING\": \"Pricing\",\n \"PRICE\": \"Price\",\n \"WHOLESALE_COST\": \"Wholesale Cost\",\n \"FAQS\": \"FAQs\",\n \"GALLERY\": \"Gallery\",\n \"FILES\": \"Files\",\n \"GET_IT_NOW\": \"Get It Now\",\n \"CONTAINS_NUM_ITEMS\": \"Contains {{itemCount}} items\",\n \"ENABLED_STATE\": {\n \"ENABLED\": \"Enabled\",\n \"ENABLE\": \"Enable\",\n \"ADD_ON\": {\n \"ENABLE\": \"Enable Add-on\"\n }\n },\n \"STORE_STATE\": {\n \"START_SELLING\": \"Start selling\",\n \"STOP_SELLING\": \"Stop selling\",\n \"SELLING\": \"Selling\",\n \"ADD_ON\": {\n \"START_SELLING\": \"Start selling Add-on\"\n }\n },\n \"MORE\": \"More\",\n \"TAGS\": \"Tags\",\n \"COMMIT\": \"commitment\",\n \"INITIAL\": \"Initial\",\n \"RECURRING\": \"recurring every\",\n \"ACTIVATIONS\": \"Activations\",\n \"ACCOUNTS\": \"accounts\",\n \"ADD_ONS\": \"Add-Ons\",\n \"REQUIRED\": \"Required\",\n \"PERIODS\": {\n \"YEARLY\": \"Yearly\",\n \"MONTHLY\": \"Monthly\",\n \"WEEKLY\": \"Weekly\",\n \"ONE_TIME\": \"One time\",\n \"BIWEEKLY\": \"Bi-weekly\",\n \"DAILY\": \"Daily\"\n },\n \"DURATION\": {\n \"DAY_CONTRACT\": \"The duration of this contract is {{value}} day(s)\",\n \"WEEK_CONTRACT\": \"The duration of this contract is {{value}} week(s)\",\n \"MONTH_CONTRACT\": \"The duration of this contract is {{value}} month(s)\",\n \"YEAR_CONTRACT\": \"The duration of this contract is {{value}} year(s)\"\n },\n \"ORDER_FORM\": {\n \"CONTACT_DESCRIPTION\": \"They may be contacted regarding fulfillment\",\n \"CONTACT_LABEL\": \"Who is the main point of contact?\",\n \"FIELD_TYPE_REQUIRED\": \"Form field type is required\",\n \"FOR_OFFICE_USE_ONLY\": \"For office use only\",\n \"HIDDEN_FROM_END_USERS\": \"Hidden from end users\",\n \"FOR_OFFICE_USE_ONLY_TOOLTIP\": \"This question will not be shown to end users\",\n \"OFFICE_EDITABLE_ONLY\": \"Office editable only\",\n \"OFFICE_EDITABLE_ONLY_TOOLTIP\": \"Answers to this question cannot be changed by end users\",\n \"OPTION\": \"Option\",\n \"VALUE\": \"Value\",\n \"ASSIGN_VALUE\": \"Assign value\",\n \"CLEAR_BUTTON\": \"Clear button\",\n \"ALLOW_MULTIPLES\": \"Allow multiples\",\n \"ALLOW_DUPLICATES\": \"Allow duplicates\",\n \"MAX_NUM_CHOICES\": \"Maximum number of choices\",\n \"CHOICES_HINT\": \"Must be greater than {{minChoices}}\",\n \"CHOICES_ERROR\": \"Max Choices must be a number larger than {{minChoices}}\",\n \"LABEL_HINT\": \"Keep it short. Recommended: Max {{maxCharacters}} characters\",\n \"LABEL_ERROR\": \"Label is required\",\n \"HIDE_PREFIX_SUFFIX\": \"Hide Prefix/Suffix\",\n \"PREFIX_SUFFIX\": \"Prefix/Suffix\",\n \"HIDDEN_NOTE\": \"Values will apply even though currently hidden\",\n \"ID_HINT\": \"ID must be unique\",\n \"ID_ERROR\": \"ID is required\",\n \"UPLOAD_URL\": \"Upload URL\",\n \"UPLOAD_URL_HINT\": \"An upload url will be provided if this field is left blank\",\n \"REGEX_VALIDATOR\": \"Regex validator\",\n \"REGEX_VALIDATOR_ERROR\": \"Must be a valid regular expression\",\n \"REGEX_ERROR_MESSAGE\": \"Regex error message\",\n \"REGEX_ERROR_MESSAGE_HINT\": \"Error displayed to the user when the regular expression is not matched\",\n \"VALIDATION\": \"Validation\",\n \"HIDE_VALIDATION\": \"Hide validation\",\n \"HINT_TEXT\": \"Hint text\",\n \"HINT_TEXT_HINT\": \"Hint text appears below the field. Use it to offer context or examples of the information to provide.\",\n \"DELETE_FIELD\": \"Delete field\",\n \"NO_USERS_INSTRUCTIONS\": \"No Users \u2014 Please add one to this account\",\n \"FIELD_TYPES\": {\n \"FILES\": \"Files\",\n \"DROP_DOWN\": \"Drop Down\",\n \"CHECK_BOX\": \"Check Box\",\n \"TEXT_AREA\": \"Text Area\",\n \"TEXT_BOX\": \"Text Box\",\n \"END_USER\": \"End User\"\n },\n \"LABELS\": {\n \"COMMON_FORM_HEADER_TITLE\": \"Gather activation information\",\n \"COMMON_FORM_HEADER_TEXT\": \"The following information will be provided to the products that require it.\",\n \"COMMON_FORM_EDITING_HINT\": \"Editing this information does not update the account\",\n \"BUSINESS_SECTION_TITLE\": \"Business\",\n \"SALESPERSON_SECTION_TITLE\": \"Salesperson\",\n \"CONTACT_SECTION_TITLE\": \"Contact\",\n \"BUSINESS_NAME\": \"Business Name\",\n \"BUSINESS_ADDRESS\": \"Business Address\",\n \"BUSINESS_PHONE_NUMBER\": \"Business Phone Number\",\n \"BUSINESS_WEBSITE\": \"Business Website\",\n \"BUSINESS_ID\": \"Business ID\",\n \"SALESPERSON_NAME\": \"Salesperson Name\",\n \"SALESPERSON_PHONE_NUMBER\": \"Salesperson Phone Number\",\n \"SALESPERSON_EMAIL\": \"Salesperson Email\",\n \"CONTACT_NAME\": \"Contact Name\",\n \"CONTACT_PHONE_NUMBER\": \"Contact Phone Number\",\n \"CONTACT_EMAIL\": \"Contact Email\"\n },\n \"ACCURATE_INFO_PROMPT\": \"Review to ensure accurate information\",\n \"ACCOUNT_INFO_TITLE\": \"{{ name }}'s information\",\n \"ACCOUNT_DETAILS\": \"Account details\",\n \"EDIT_BUSINESS_DETAILS_DISCLAIMER\": \"Editing this information does not update the business details\",\n \"EDIT_RESELLER_DETAILS_DISCLAIMER\": \"Editing this information does not update the contact details\",\n \"PLEASE_REVIEW\": \"Please review\",\n \"ACCOUNT_CONTACT\": \"Account contact\",\n \"RESELLER_INFO_TITLE\": \"{{ name }}'s primary contact\",\n \"PARTNER_CONTACT\": \"Partner contact\",\n \"ADMINISTRATIVE_INFO\": \"Administrative information\",\n \"ORDER_FORMS\": \"Order forms\",\n \"ORDER_FORMS_SUBTITLE\": \"Additional information is needed for items in this order\",\n \"ACCOUNT\": \"Account\",\n \"RESELLER\": \"Reseller\"\n },\n \"ACTIVATION_STATUS\": {\n \"ACTIVATED\": \"Activated\",\n \"ALREADY_ACTIVATED\": \"Already Activated\",\n \"ACTIVATION_ERRORS\": \"Activation Errors\",\n \"ACTIVATION_ERRORS_OCCURRED\": \"Activation Errors Occured\",\n \"ACTIVATION_WARNINGS\": \"Activation Warnings\"\n },\n \"SEE_ALL\": \"See all\",\n \"NOT_AVAILABLE_IN_YOUR_COUNTRY\": \"Not available in your country\",\n \"AVAILABLE_IN\": \"AVAILABLE IN\",\n \"ALL_COUNTRIES\": \"All countries\",\n \"NEED_HELP\": \"Need help\",\n \"VIDEOS\": \"Videos\",\n \"STOREFRONT_FILTERS\": {\n \"TITLE\": \"Store Filters\",\n \"CATEGORIES\": \"Categories\",\n \"LMI_CATEGORY\": \"LMI Category\"\n },\n \"LMI_CATEGORIES\": {\n \"LISTINGS\": \"Listings\",\n \"SOCIAL\": \"Social\",\n \"REPUTATION\": \"Reputation\",\n \"SEO\": \"SEO\",\n \"WEBSITE\": \"Website\",\n \"ADVERTISING\": \"Advertising\",\n \"CONTENT_AND_EXPERIENCE\": \"Content + Experience\"\n },\n \"PRODUCTS_AND_ADDONS\": \"Related Products & Add-ons\",\n \"ADD_TO_CART\": \"Add to cart\",\n \"BUY_IT_NOW\": \"Buy it now\",\n \"ERROR_PRODUCT\": \"There was a problem loading the product\",\n \"PRODUCT_DETAILS\": {\n \"TAB_LABELS\": {\n \"PRODUCT_INFORMATION\": \"Product Information\",\n \"SCREENSHOTS_AND_FILES\": \"Screenshots & Files\",\n \"EDITIONS_AND_PRICING\": \"Editions & Pricing\"\n },\n \"PRODUCT_REQUIREMENTS\": {\n \"LABEL\": \"REQUIRED PRODUCTS\",\n \"TOOLTIP\": {\n \"TITLE\": \"Required products\",\n \"INTERNAL_DESCRIPTION\": \"Required products need to be already active on a customer's account before they can buy or use this product.\",\n \"EXTERNAL_DESCRIPTION\": \"You\u2019ll need these required products before you can buy or use this product.\"\n }\n },\n \"PREVIEW_FORMS\": {\n \"LABEL\": \"REQUIRED FORMS\",\n \"ORDER_FORM\": \"Order form\",\n \"FULFILLMENT_FORM\": \"Fulfillment form\",\n \"ORDER_FORM_PREVIEW\": \"Order form preview\",\n \"ORDER_FORM_PREVIEW_ALERT\": \"This is a preview of the order form used when purchasing this product. This preview is for display purposes only. No input in this preview will be saved.\",\n \"TOOLTIP\": {\n \"TITLE\": \"Required forms\",\n \"DESCRIPTION\": \"Order form information is required at the time of purchase. Fulfillment form information is required after purchase.\"\n }\n }\n },\n \"EDITION_SELECTOR\": {\n \"ADD_APP_SELECTION\": {\n \"TITLE\": \"Choose an edition\"\n },\n \"ADD_DEPENDANT_SELECTION\": {\n \"TITLE\": \"Choose an edition of {{productName}}\",\n \"EXPLANATION\": \"{{childName}} is a dependent of {{productName}}, which you haven\u2019t already purchased. Choose an edition of {{productName}} to add both to your cart.\"\n },\n \"ADD_ADDON_SELECTION\": {\n \"TITLE\": \"Choose an edition of {{productName}}\",\n \"EXPLANATION\": \"{{childName}} is an add-on to {{productName}}, which you haven\u2019t already purchased. Choose an edition of {{productName}} to add both to your cart.\"\n },\n \"COMPARE_BUTTON_LABEL\": \"Compare editions\"\n },\n \"ORDER_SUMMARY\": {\n \"REQUIRES\": \"Requires {{parentName}}\",\n \"ADDON_OF\": \"Add-on of {{parentName}}\"\n },\n \"MANAGE_PRODUCT\": {\n \"MANAGE_PRODUCT_TABLE\": {\n \"SHOW_GROWTH_OVER\": \"* Show growth over\",\n \"PARENT_REQUIREMENT\": \"Requires {{name}}\",\n \"TOOLBAR_TEXT\": \"{{numShowing}} of {{numTotal}} products\",\n \"COLUMNS\": {\n \"PRODUCT\": \"Product\",\n \"ACTIVE_ACCOUNTS\": \"Active accounts\",\n \"ACTIVATIONS\": \"Activations*\",\n \"PENDING_DEACTIVATIONS\": \"Pending deactivations*\",\n \"DEACTIVATIONS\": \"Deactivations*\",\n \"GROWTH\": \"Growth*\",\n \"SELLING_IN_STORE\": \"Selling in store\"\n },\n \"ROW_ACTIONS\": {\n \"VIEW_MARKETING_MATERIAL\": \"View marketing material\",\n \"EDIT_IN_MARKETPLACE\": \"Edit in Marketplace\"\n }\n }\n }\n }\n }\n}\n", "export const WEBLATE_COMPONENT_NAME = 'common/store';\n", "import { Component, Input, OnChanges, SimpleChanges, Inject } from '@angular/core';\nimport { BilledProduct, PricingTier } from '@vendasta/shared';\nimport { MarketplaceBillingFrequency, DisplayPriceService } from '@vendasta/shared';\nimport { Pricing, Price } from './pricing';\nimport { BehaviorSubject, combineLatest, Observable, of, EMPTY } from 'rxjs';\nimport { TranslateService } from '@ngx-translate/core';\nimport { map, switchMap, expand, reduce, catchError, publishReplay, refCount, filter } from 'rxjs/operators';\nimport { Discount, ListDiscountsRequestFiltersInterface, DiscountService } from '@galaxy/billing';\nimport { HttpErrorResponse } from '@angular/common/http';\n\n@Component({\n selector: 'store-base-pricing',\n template: '',\n standalone: false,\n})\nexport class VaBasePricingComponent implements OnChanges {\n @Input() pricing: Pricing = null;\n @Input() billedProduct: BilledProduct;\n @Input() wrapFrequency = false;\n @Input() isAddon = false;\n @Input() hasVerifiedContract = false;\n @Input() highlightPrice = true;\n @Input() loaded = true;\n @Input() showAllPrices = false; // When false this will only show the first element in the pricing.prices list\n @Input() useAbbreviatedFrequency = false;\n @Input() showIsStartingAt = false;\n\n pricing$$ = new BehaviorSubject(null);\n billedProduct$$ = new BehaviorSubject(null);\n hasVerifiedContract$$ = new BehaviorSubject(false);\n\n isFree$: Observable;\n shouldContactSales$: Observable;\n isFlatPrice$: Observable;\n\n pricingTierData$: Observable<\n {\n isStartingPrice: boolean;\n pricingTierString: string;\n pricingTierForProduct: string;\n pricingTierForAddon: string;\n priceStringForTier: string;\n priceStringForTierWithoutFreq: string;\n }[]\n >;\n\n priceData$: Observable<\n {\n isStartingPrice: boolean;\n priceStringForPricingWithoutFrequency: string;\n priceStringForPricingWithFrequency: string;\n frequencyString: string;\n abbreviatedFrequencyString: string;\n }[]\n >;\n\n commitmentMessage$: Observable;\n setupFeeString$: Observable;\n isFirstTierFree$: Observable;\n showPricingPopover = false;\n discounts$: Observable;\n\n get pricing$(): Observable {\n return this.pricing$$.asObservable();\n }\n\n get billedProduct$(): Observable {\n return this.billedProduct$$.asObservable();\n }\n\n get hasVerifiedContract$(): Observable {\n return this.hasVerifiedContract$$.asObservable();\n }\n\n constructor(\n private translateService: TranslateService,\n private displayPriceService: DisplayPriceService,\n @Inject('PARTNER_ID') readonly partnerId$: Observable,\n private discountService: DiscountService,\n ) {\n this.isFree$ = combineLatest([this.pricing$, this.billedProduct$, this.hasVerifiedContract$]).pipe(\n map(([pricing, billedProduct, hasVerifiedContract]) => {\n const isFreeHelper = (prices: { price: number }[]): boolean => {\n return prices ? prices.every((p) => p.price === 0 || p.price === undefined) : false;\n };\n\n if (hasVerifiedContract && billedProduct) {\n return billedProduct.pricingTiers.length === 1 ? isFreeHelper(billedProduct.pricingTiers) : false;\n }\n return !!pricing && isFreeHelper(pricing.prices);\n }),\n );\n\n this.shouldContactSales$ = combineLatest([this.pricing$, this.billedProduct$, this.hasVerifiedContract$]).pipe(\n map(([pricing, billedProduct, hasVerifiedContract]) => {\n const nestedPricesIsContactSales = (prices: { price: number }[]) => {\n return prices && prices.length > 0 ? prices.some((p) => p.price === null || p.price < 0) : true;\n };\n\n if (hasVerifiedContract && billedProduct) {\n return nestedPricesIsContactSales(billedProduct.pricingTiers);\n }\n if (!pricing) {\n return true;\n }\n return nestedPricesIsContactSales(pricing.prices);\n }),\n );\n\n this.isFlatPrice$ = this.billedProduct$.pipe(map((billedProduct) => billedProduct.pricingTiers.length === 1));\n this.pricingTierData$ = this.billedProduct$.pipe(\n switchMap((billedProduct) => {\n const pricingTierObservables = billedProduct.pricingTiers.map((pricingTier) => {\n return combineLatest([\n of(pricingTier.isStartingPrice),\n this.buildPricingTierString(pricingTier),\n this.buildPricingTierForProduct(pricingTier, billedProduct.billingFrequency),\n this.buildPricingTierForAddon(pricingTier),\n this.buildPriceStringForTier(pricingTier, billedProduct.billingFrequency, pricingTier.isStartingPrice),\n this.buildPriceStringForTier(pricingTier),\n ]).pipe(\n map(\n ([\n isStartingPrice,\n pricingTierString,\n pricingTierForProduct,\n pricingTierForAddon,\n priceStringForTier,\n priceStringForTierWithoutFreq,\n ]) => {\n return {\n isStartingPrice: isStartingPrice,\n pricingTierString: pricingTierString,\n pricingTierForProduct: pricingTierForProduct,\n pricingTierForAddon: pricingTierForAddon,\n priceStringForTier: priceStringForTier,\n priceStringForTierWithoutFreq: priceStringForTierWithoutFreq,\n };\n },\n ),\n );\n });\n return combineLatest([...pricingTierObservables]);\n }),\n );\n\n this.priceData$ = this.pricing$.pipe(\n switchMap((pricing) => {\n let filteredPrices = pricing.prices;\n if (pricing.prices.length > 1) {\n filteredPrices = pricing.prices.filter((price) => price.price > 0).sort(this.sortPricesByFrequency);\n }\n const priceObservables = filteredPrices.map((price) => {\n return combineLatest([\n of(price.isStartingPrice),\n this.buildPriceStringForPricing(price, pricing.currency, true, false),\n this.buildPriceStringForPricing(price, pricing.currency, false, true),\n this.buildFrequencyString(price.frequency),\n of(this.buildAbbreviatedFrequencyString(price.frequency)),\n ]).pipe(\n map(\n ([\n isStartingPrice,\n priceStringForPricingWithoutFrequency,\n priceStringForPricingWithFrequency,\n frequencyString,\n abbrevFreq,\n ]) => {\n return {\n isStartingPrice: isStartingPrice,\n priceStringForPricingWithoutFrequency: priceStringForPricingWithoutFrequency,\n priceStringForPricingWithFrequency: priceStringForPricingWithFrequency,\n frequencyString: frequencyString,\n abbreviatedFrequencyString: abbrevFreq,\n };\n },\n ),\n );\n });\n return combineLatest([...priceObservables]);\n }),\n );\n\n this.commitmentMessage$ = this.buildCommitmentMessage();\n this.setupFeeString$ = this.displayPriceService.getSetupFeeString();\n this.isFirstTierFree$ = this.billedProduct$.pipe(\n map((billedProduct) => {\n return billedProduct.pricingTiers.length > 1 && billedProduct.pricingTiers.some((item) => item.price === 0);\n }),\n );\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (Object.prototype.hasOwnProperty.call(changes, 'pricing')) {\n this.pricing$$.next(changes.pricing.currentValue);\n }\n if (Object.prototype.hasOwnProperty.call(changes, 'billedProduct')) {\n this.billedProduct$$.next(changes.billedProduct.currentValue);\n }\n if (Object.prototype.hasOwnProperty.call(changes, 'hasVerifiedContract')) {\n this.hasVerifiedContract$$.next(changes.hasVerifiedContract.currentValue);\n }\n }\n\n buildPricingTierString(tier: PricingTier): Observable {\n let max = String(tier.rangeMax);\n if (tier.rangeMax === -1) {\n max = '∞';\n if (tier.rangeMin === 0 || tier.rangeMin === 1) {\n return of('');\n }\n }\n return this.translateService.stream('FRONTEND.STORE.MIN_TO_MAX', {\n minRange: String(tier.rangeMin),\n maxRange: max,\n });\n }\n\n buildPricingTierForProduct(tier: PricingTier, frequency?: string): Observable {\n return combineLatest([this.buildPricingTierString(tier), this.buildFrequencyString(frequency)]).pipe(\n switchMap(([pricingTier, formattedFrequency]) => {\n if (pricingTier) {\n return this.translateService.stream('FRONTEND.STORE.PRODUCT_PRICING_WITH_FREQUENCY', {\n pricingTier: pricingTier,\n frequency: formattedFrequency,\n });\n }\n return of(formattedFrequency);\n }),\n );\n }\n\n buildPricingTierForAddon(tier: PricingTier): Observable {\n return this.buildPricingTierString(tier).pipe(map((pricingRange) => (pricingRange ? pricingRange : '')));\n }\n\n sortPricesByFrequency(priceA: Price, priceB: Price): number {\n // this map is coded based on frequency values described by the enums described in the marketplace packages vendasta\n // apis and the corresponding translations to strings laced throughout galaxy\n const priceFrequencyComparisonMap: Map> = new Map>([\n [\n 'MONTHLY',\n new Map([\n ['MONTHLY', 0],\n ['YEARLY', -1],\n ['ONCE', -1],\n ['ONE TIME', -1],\n ['ONE_TIME', -1],\n ]),\n ],\n [\n 'YEARLY',\n new Map([\n ['MONTHLY', 1],\n ['YEARLY', 0],\n ['ONCE', -1],\n ['ONE TIME', -1],\n ['ONE_TIME', -1],\n ]),\n ],\n [\n 'ONCE',\n new Map([\n ['MONTHLY', 1],\n ['YEARLY', 1],\n ['ONCE', 0],\n ['ONE TIME', 0],\n ['ONE_TIME', 0],\n ]),\n ],\n [\n 'ONE TIME',\n new Map([\n ['MONTHLY', 1],\n ['YEARLY', 1],\n ['ONCE', 0],\n ['ONE TIME', 0],\n ['ONE_TIME', 0],\n ]),\n ],\n [\n 'ONE_TIME',\n new Map([\n ['MONTHLY', 1],\n ['YEARLY', 1],\n ['ONCE', 0],\n ['ONE TIME', 0],\n ['ONE_TIME', 0],\n ]),\n ],\n ]);\n\n if (priceFrequencyComparisonMap.get(priceA.frequency.toUpperCase()) === undefined) {\n return 0;\n }\n\n const compareVal = priceFrequencyComparisonMap\n .get(priceA.frequency.toUpperCase())\n .get(priceB.frequency.toUpperCase());\n return compareVal ? compareVal : 0;\n }\n\n buildPriceStringForPricing(\n price: Price,\n currency: string,\n excludeFrequency: boolean,\n canIncludeStartingAtPrefix: boolean,\n ): Observable {\n return this.displayPriceService.formatDisplayPrice(\n price.price,\n currency,\n (excludeFrequency ? '' : price.frequency) as any,\n true,\n true,\n true,\n price.isStartingPrice && canIncludeStartingAtPrefix,\n );\n }\n\n buildPriceStringForTier(\n tier: PricingTier,\n frequency?: MarketplaceBillingFrequency,\n isStartingPrice?: boolean,\n ): Observable {\n return this.displayPriceService.formatDisplayPrice(\n tier.price,\n this.billedProduct.currency,\n frequency as any,\n undefined,\n undefined,\n undefined,\n isStartingPrice,\n );\n }\n\n buildFrequencyString(frequency?: string): Observable {\n return this.displayPriceService.formatBillingFrequency(frequency);\n }\n\n buildAbbreviatedFrequencyString(frequency?: string): string {\n switch ((frequency || '').toLowerCase()) {\n case 'daily':\n return 'dy';\n case 'weekly':\n return 'wk';\n case 'monthly':\n return 'mo';\n case 'yearly':\n return 'yr';\n }\n return null;\n }\n\n buildCommitmentMessage(): Observable {\n return combineLatest([\n this.translateService.stream('FRONTEND.STORE.PRICING_FREQUENCIES'),\n this.billedProduct$,\n this.pricing$,\n this.isFree$,\n this.shouldContactSales$,\n ]).pipe(\n switchMap(([frequencyTranslations, billedProduct, pricing, isFree, shouldContactSales]) => {\n const frequency = billedProduct\n ? billedProduct.billingFrequency.toString().toLowerCase()\n : pricing && pricing.prices.length > 0\n ? pricing.prices[0].frequency.toLowerCase()\n : '';\n let frequencyString = '';\n if (frequency === 'yearly') {\n frequencyString = frequencyTranslations.YEAR;\n } else if (frequency === 'monthly') {\n frequencyString = frequencyTranslations.MONTH;\n }\n if (!frequencyString || isFree || shouldContactSales) {\n return of('');\n }\n if (billedProduct && billedProduct.commitment) {\n const initial = billedProduct.commitment.initial;\n const recurring = billedProduct.commitment.recurring;\n return this.translateService.stream('FRONTEND.STORE.COMMITMENT_WITH_RENEWAL', {\n initial: initial,\n frequencyString: frequencyString,\n recurring: recurring,\n });\n }\n return of('');\n }),\n );\n }\n\n private fetchAllDiscounts(pid: string, sku: string): Observable {\n const pageSize = 50;\n const filters: ListDiscountsRequestFiltersInterface = {\n merchantId: pid,\n expiry: new Date(),\n skus: [sku],\n };\n\n return this.discountService.list(filters, '', pageSize).pipe(\n expand((resp) => {\n if ((resp?.results || []).length >= pageSize) {\n return this.discountService.list(filters, resp.nextCursor, pageSize);\n } else {\n return EMPTY;\n }\n }),\n reduce((prev, curr) => {\n const discounts = curr?.results || [];\n return prev.concat(discounts);\n }, [] as Discount[]),\n );\n }\n\n private getDiscounts(): Observable {\n return combineLatest([this.partnerId$, this.billedProduct$]).pipe(\n filter(([pid, billedProduct]) => !!pid && !!billedProduct),\n switchMap(([pid, billedProduct]) => {\n return this.fetchAllDiscounts(pid, billedProduct.productId);\n }),\n catchError((err: HttpErrorResponse) => {\n console.error('error getting discount information:', err);\n return of([]);\n }),\n publishReplay(1),\n refCount(),\n );\n }\n\n itemInfoIconEnter(): void {\n if (this.discounts$ === undefined) {\n this.discounts$ = this.getDiscounts();\n }\n\n this.showPricingPopover = true;\n }\n\n itemInfoIconLeave(): void {\n this.showPricingPopover = false;\n }\n}\n", "import { Component } from '@angular/core';\nimport { VaBasePricingComponent } from '../base-pricing.component';\n\n@Component({\n selector: 'store-highlight-pricing',\n templateUrl: './highlight-pricing.component.html',\n styleUrls: ['./highlight-pricing.component.scss'],\n standalone: false,\n})\nexport class HighlightPricingComponent extends VaBasePricingComponent {}\n", "\n \n {{ 'FRONTEND.STORE.CONTACT_SALES' | translate }}\n \n \n
\n {{ 'FRONTEND.STORE.FREE' | translate }}\n
\n \n \n \n
\n \n \n {{ 'FRONTEND.STORE.STARTING_AT' | translate }}\n \n \n {{ tier.priceStringForTierWithoutFreq }}\n \n \n \n {{ tier.pricingTierForProduct }}\n \n
\n
\n \n \n \n \n \n {{ 'FRONTEND.STORE.STARTING_AT' | translate }}\n \n \n 0\">+\n {{ price.priceStringForPricingWithoutFrequency }}\n \n \n /{{ price.abbreviatedFrequencyString }}\n \n \n \n {{ price.frequencyString }}\n \n \n \n \n
\n \n
\n
\n \n {{ tier.pricingTierForAddon }}\n \n \n \n {{ 'FRONTEND.STORE.STARTING_AT' | translate }}\n \n \n {{ tier.priceStringForTier }}\n \n \n
\n
\n \n
\n \n {{ (priceData$ | async)[0]?.frequencyString }}\n \n \n \n {{ 'FRONTEND.STORE.STARTING_AT' | translate }}\n \n \n {{\n (priceData$ | async)[0]?.priceStringForPricingWithoutFrequency\n }}\n \n \n
\n
\n
\n 0\"\n >\n + {{ billedProduct.setupFee | price$: billedProduct.currency | async }}\n {{ setupFeeString$ | async }}\n \n 1\n \"\n >\n {{ commitmentMessage$ | async }}\n \n \n \n\n\n
\n
\n", "import { Pipe, PipeTransform } from '@angular/core';\nimport moment from 'moment';\n\nexport enum formatting {\n datetime = 'Y-MM-DD h:mm:ss A', //2018-01-25 11:54:39 AM\n date = 'Y-MM-DD', //2018-01-25\n month = 'MMMM Y', //January 2018\n utc = 'YYYY-MM-DD[T00:00:00Z]', //2018-01-25T00:00:00Z\n longDate = 'dddd MMMM Do, YYYY', //Thursday January 25th, 2018\n shortSpoken = 'MMM D, Y', //Jan 25, 2018\n}\n\nexport function formatDate(\n date: Date | string,\n format: formatting,\n translateEmpty?: string,\n useLocalTime?: boolean,\n): string {\n translateEmpty = translateEmpty ? translateEmpty : '';\n if (!date) {\n return translateEmpty;\n }\n\n if (typeof date === 'string') {\n date = new Date(date);\n if (date.toString() === 'Invalid Date') {\n return date.toString();\n }\n }\n\n let m = moment(date.toISOString());\n if (format === formatting.utc || !useLocalTime) {\n m = moment.utc(date.toISOString());\n }\n\n return m.format(format);\n}\n\n@Pipe({\n name: 'formatDate',\n standalone: false,\n})\nexport class FormatDatePipe implements PipeTransform {\n transform(date: Date | string, format: formatting, translateEmpty?: string, useLocalTime?: boolean): string {\n return formatDate(date, format, translateEmpty, useLocalTime);\n }\n}\n", "import { Pipe, PipeTransform } from '@angular/core';\nimport { Discount, DiscountType, Currency } from '@galaxy/billing';\nimport { formatDate, formatting } from './format-date.pipe';\nimport { formatDisplayPrice } from '@vendasta/shared';\n\n/*\n * Format a discount for display.\n *\n * Usage:\n * discount | formatDiscount\n * Examples:\n * {{ { amount: 100, discountType: 'FIXED_AMOUNT', start: '2019-12-12' } | formatDiscount: 'USD' }}\n * formats to: $1.00 off starting 2019-12-12\n *\n * {{ { amount: 15, discountType: 'PERCENT', start: '2019-08-01' end: '2019-09-01' } | formatDiscount: 'USD' }}\n * formats to: 15% off starting 2019-08-01 to 2019-09-01\n */\n@Pipe({ standalone: true, name: 'formatDiscount' })\nexport class FormatDiscountPipe implements PipeTransform {\n transform(discount: Discount, currency: Currency): string {\n if (!discount) {\n return 'N/A';\n }\n\n const amount = formatDiscountAmount(discount.amount, discount.discountType, currency);\n\n let off = 'off';\n switch (discount.discountType) {\n case DiscountType.FIXED_NUMBER_OF_UNITS: {\n off = 'free units';\n if (discount.resetEachPeriod) {\n off += ' per period';\n }\n break;\n }\n case DiscountType.FIXED_AMOUNT_PER_UNIT: {\n off = 'off each unit';\n break;\n }\n }\n\n const start = formatDate(discount.start, formatting.date, '', true);\n const dateRange =\n discount.end.valueOf() !== new Date('0001-01-01T00:00:00Z').valueOf()\n ? `${start} to ${formatDate(discount.end, formatting.date, '', true)}`\n : start;\n\n return `${amount} ${off} starting ${dateRange}`;\n }\n}\n\nfunction formatDiscountAmount(amount: number, rule: DiscountType, currency: Currency): string {\n if ([DiscountType.FIXED_AMOUNT, DiscountType.FIXED_AMOUNT_PER_UNIT].includes(rule)) {\n return formatDisplayPrice(amount, currency, null, true, false, true, false);\n } else if (rule === DiscountType.PERCENT_AMOUNT) {\n return amount.toString() + '%';\n }\n return amount.toString();\n}\n", "import { Component } from '@angular/core';\nimport { VaBasePricingComponent } from '../base-pricing.component';\n\n@Component({\n selector: 'store-table-pricing',\n templateUrl: './table-pricing.component.html',\n styleUrls: ['./table-pricing.component.scss'],\n standalone: false,\n})\nexport class TablePricingComponent extends VaBasePricingComponent {}\n", "\n \n {{ 'FRONTEND.STORE.STARTING_AT' | translate }}\n \n
\n \n
\n {{ (pricingTierData$ | async)[0]?.priceStringForTier }}\n
\n
\n \n \n
Starting at
\n {{ 'FRONTEND.STORE.FREE' | translate }}\n \n info_outline\n \n\n \n
\n
\n {{\n 'FRONTEND.TABLE_PRICING.WHOLESALE_PRICING_INFORMATION'\n | translate\n }}\n
\n\n
\n \n
\n {{ tier.pricingTierString }}\n
\n
\n {{ tier.priceStringForTier }}\n
\n
\n
0\">\n
\n
\n +\n {{\n billedProduct.setupFee\n | price$: billedProduct.currency\n | async\n }}\n {{ setupFeeString$ | async }}\n
\n
\n
\n\n
\n
\n \n {{ 'FRONTEND.TABLE_PRICING.ACTIVE_DISCOUNTS' | translate }}\n \n
\n
    \n
  • \n {{ disc | formatDiscount: billedProduct?.currency }}\n
  • \n
\n
\n \n \n
\n\n \n
\n \n
{{ tier.pricingTierString }}
\n
\n {{ tier.priceStringForTier }}\n
\n
\n
0\">\n
\n
\n +\n {{\n billedProduct.setupFee | price$: billedProduct.currency | async\n }}\n {{ setupFeeString$ | async }}\n
\n
\n \n
\n
\n 0 && isFlatPrice$ | async\"\n >\n + {{ billedProduct.setupFee | price$: billedProduct.currency | async }}\n {{ setupFeeString$ | async }}\n \n 1\n \"\n >\n {{ commitmentMessage$ | async }}\n \n \n \n
\n \n {{ 'FRONTEND.STORE.CONTACT_SALES' | translate }}\n \n \n \n {{ 'FRONTEND.STORE.FREE' | translate }}\n \n \n \n \n \n 1 }\"\n >\n {{ priceData.priceStringForPricingWithFrequency }}\n \n \n + {{ priceData.priceStringForPricingWithFrequency }}\n \n \n \n \n {{ priceDatas[0].priceStringForPricingWithFrequency }}\n \n \n
0\">\n +\n {{\n billedProduct.setupFee | price$: billedProduct.currency | async\n }}\n {{ setupFeeString$ | async }}\n
\n 1\n \"\n >\n {{ commitmentMessage$ | async }}\n
\n
\n \n \n \n
\n\n
\n
\n", "import { Component } from '@angular/core';\nimport { VaBasePricingComponent } from './base-pricing.component';\n\n@Component({\n selector: 'store-pricing',\n templateUrl: './pricing.component.html',\n styleUrls: ['./pricing.component.scss'],\n standalone: false,\n})\nexport class VaPricingComponent extends VaBasePricingComponent {}\n", "\n \n\n\n \n\n", "import { Currency, RevenuePeriod } from '@vendasta/sales-orders';\nimport { BillingFrequency } from '@vendasta/shared';\n\nexport function convertSalesOrderCurrencyToString(currency: Currency): string {\n return Currency[currency] ? Currency[currency] : Currency[Currency.USD];\n}\n\nexport function getPeriodTranslationKey(period: RevenuePeriod): string {\n switch (period || RevenuePeriod.ONETIME) {\n case RevenuePeriod.ONETIME:\n return 'FRONTEND.STORE.PERIODS.ONE_TIME';\n case RevenuePeriod.DAILY:\n return 'FRONTEND.STORE.PERIODS.DAILY';\n case RevenuePeriod.WEEKLY:\n return 'FRONTEND.STORE.PERIODS.WEEKLY';\n case RevenuePeriod.BIWEEKLY:\n return 'FRONTEND.STORE.PERIODS.BIWEEKLY';\n case RevenuePeriod.MONTHLY:\n return 'FRONTEND.STORE.PERIODS.MONTHLY';\n case RevenuePeriod.YEARLY:\n return 'FRONTEND.STORE.PERIODS.YEARLY';\n default:\n return '';\n }\n}\n\nexport function salesOrderPeriodToBillingFrequency(period: RevenuePeriod): BillingFrequency {\n switch (period || RevenuePeriod.ONETIME) {\n case RevenuePeriod.ONETIME:\n return 'once';\n case RevenuePeriod.DAILY:\n return 'daily';\n case RevenuePeriod.WEEKLY:\n return 'weekly';\n case RevenuePeriod.BIWEEKLY:\n return 'other';\n case RevenuePeriod.MONTHLY:\n return 'monthly';\n case RevenuePeriod.YEARLY:\n return 'yearly';\n default:\n return 'other';\n }\n}\n", "import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MatListModule } from '@angular/material/list';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { CoreSharedModule } from '@vendasta/shared';\nimport { GalaxyFrequencyModule } from '@vendasta/galaxy/frequency';\nimport { GalaxyPipesModule } from '@vendasta/galaxy/pipes';\nimport { LexiconModule } from '@galaxy/lexicon';\nimport baseTranslation from '../assets/i18n/en_devel.json';\nimport { WEBLATE_COMPONENT_NAME } from '../shared/constants';\nimport { HighlightPricingComponent } from './highlight-pricing/highlight-pricing.component';\nimport { FormatBillingFrequencyPipe, PricePipe } from './pricing-pipes';\nimport { VaPricingComponent } from './pricing.component';\nimport { SimplePriceDisplayComponent } from './simple-price-display.component';\nimport { StorePriceComponent } from './store-price/store-price.component';\nimport { TablePricingComponent } from './table-pricing/table-pricing.component';\nimport { MatIconModule } from '@angular/material/icon';\nimport { GalaxyPopoverModule } from '@vendasta/galaxy/popover';\nimport { FormatDiscountPipe } from '../shared/format-discount.pipe';\n\n@NgModule({\n imports: [\n CommonModule,\n CoreSharedModule,\n TranslateModule,\n LexiconModule.forChild({\n componentName: WEBLATE_COMPONENT_NAME,\n baseTranslation: baseTranslation,\n }),\n MatListModule,\n GalaxyPipesModule,\n MatIconModule,\n GalaxyPopoverModule,\n GalaxyFrequencyModule,\n FormatDiscountPipe,\n ],\n declarations: [\n VaPricingComponent,\n HighlightPricingComponent,\n TablePricingComponent,\n StorePriceComponent,\n SimplePriceDisplayComponent,\n PricePipe,\n FormatBillingFrequencyPipe,\n ],\n exports: [\n VaPricingComponent,\n SimplePriceDisplayComponent,\n PricePipe,\n FormatBillingFrequencyPipe,\n StorePriceComponent,\n ],\n})\nexport class VaPricingModule {}\n", "import { Component, EventEmitter, Input, Output } from '@angular/core';\n\nimport { ImageTransformationService } from '@vendasta/image-transformation';\nimport { StoreItem } from './store-item';\n\n@Component({\n selector: 'store-card',\n template: `\n \n
\n \n \n
\n
\n \n \n {{ item.name }}\n \n \n \n \n \n \n {{ item.tagline }}\n
\n \n add\n check\n \n {{ (item.purchased ? 'FRONTEND.STORE.ENABLED_UPPER' : 'FRONTEND.STORE.ENABLE_UPPER') | translate }}\n \n \n \n
\n `,\n styleUrls: ['./store-card.component.scss'],\n standalone: false,\n})\nexport class StoreCardComponent {\n @Input() item: StoreItem;\n @Input() currencyCode: string;\n @Input() showAllPrices = false; // TODO: get rid of this\n @Output() purchasedClicked = new EventEmitter();\n @Output() cardClicked = new EventEmitter();\n @Output() descriptionClicked = new EventEmitter();\n @Output() bannerClicked = new EventEmitter();\n\n constructor(private imageTransformationService: ImageTransformationService) {}\n\n getBannerColorForName(): string {\n // determine an icon color for a product with no icon by using the product name\n const COLOR_CODES = [\n '#EF5350',\n '#42A5F5',\n '#66BB6A',\n '#FFA726',\n '#AB47BC',\n '#FFCA28',\n '#EC407A',\n '#26C6DA',\n '#FF7B57',\n ];\n let nameSum = 0;\n const defaultColor = '#808080';\n if (!this.item.name) {\n return defaultColor;\n }\n for (let i = 0; i < this.item.name.length; i++) {\n nameSum += this.item.name[i].charCodeAt(0);\n }\n const index = nameSum % COLOR_CODES.length;\n return COLOR_CODES[index];\n }\n\n getSrcsetHeaderUrls(imageUrl: string): string {\n return this.imageTransformationService.getSrcSetForImage(imageUrl, [680, 1360, 2720]);\n }\n}\n", "import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatCardModule } from '@angular/material/card';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatMenuModule } from '@angular/material/menu';\nimport { ImageTransformationModule } from '@vendasta/image-transformation';\nimport { VaIconModule } from '@vendasta/uikit';\nimport { VaPricingModule } from './pricing/pricing.module';\nimport { StoreCardComponent } from './store-card.component';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { LexiconModule } from '@galaxy/lexicon';\nimport baseTranslation from './assets/i18n/en_devel.json';\nimport { WEBLATE_COMPONENT_NAME } from './shared/constants';\nimport { GalaxyTooltipModule } from '@vendasta/galaxy/tooltip';\nimport { BillingUiModule } from '@vendasta/billing-ui';\n\n@NgModule({\n imports: [\n CommonModule,\n VaIconModule,\n MatCardModule,\n MatButtonModule,\n MatIconModule,\n MatMenuModule,\n ImageTransformationModule,\n VaPricingModule,\n TranslateModule,\n GalaxyTooltipModule,\n LexiconModule.forChild({\n componentName: WEBLATE_COMPONENT_NAME,\n baseTranslation: baseTranslation,\n }),\n BillingUiModule,\n ],\n declarations: [StoreCardComponent],\n exports: [StoreCardComponent],\n})\nexport class StoreCardModule {}\n", "import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { AppPrice } from '@galaxy/marketplace-apps';\n\n@Component({\n selector: 'store-header-container',\n templateUrl: './header-container.component.html',\n styleUrls: ['./header-container.component.scss'],\n standalone: false,\n})\nexport class VaHeaderContainerComponent {\n @Input() iconUrl: string;\n @Input() title: string;\n @Input() tagline: string;\n @Input() prerequisite: string;\n @Input() chipLabels: string[];\n @Input() appPrice: AppPrice;\n @Input() partnerCurrency = 'USD';\n @Input() loaded = true;\n @Input() hasVerifiedContract: boolean;\n @Input() primaryPricingActionLabel: string;\n @Input() pricingActionLabel: string;\n @Input() pricingActionEnabled: boolean;\n @Input() actionEnabled: boolean;\n @Input() actionLabel: string;\n @Input() showAction: boolean;\n @Input() showPricing: boolean;\n @Input() showEnableAddon = false;\n @Input() prerequisiteLabel: string;\n @Input() hideTags = false;\n @Output() prerequisiteSelected = new EventEmitter();\n @Output() actionSelected = new EventEmitter();\n @Output() primaryPricingActionSelected = new EventEmitter();\n @Output() pricingActionSelected = new EventEmitter();\n @Output() contactActionClick = new EventEmitter();\n\n onActionSelected(): void {\n this.actionSelected.emit();\n }\n\n onPrerequisiteSelected(): void {\n this.prerequisiteSelected.emit();\n }\n\n handleContactActionClick(): void {\n this.contactActionClick.emit();\n }\n}\n", "
\n
\n
\n \n\n
\n \n {{ title }}\n \n\n \n {{ tagline }}\n \n\n
\n \n {{ 'FRONTEND.STORE.REQUIRES' | translate }}\n \n {{ prerequisite }}\n
\n\n \n \n {{ chip | translate }}\n \n \n
\n
\n\n
\n \n {{ actionLabel }}\n \n\n \n\n \n {{ actionLabel }}\n \n\n
\n {{ 'FRONTEND.STORE.ENABLED_WITH_PREREQUISITE' | translate : { prerequisite: prerequisiteLabel } }}\n
\n\n
\n \n
\n\n

\n \n {{ primaryPricingActionLabel }}\n \n {{ pricingActionLabel }}\n

\n
\n
\n
\n", "import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatCardModule } from '@angular/material/card';\nimport { MatChipsModule } from '@angular/material/chips';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatTooltipModule } from '@angular/material/tooltip';\nimport { LexiconModule } from '@galaxy/lexicon';\nimport { TranslateModule } from '@ngx-translate/core';\nimport { BillingUiModule } from '@vendasta/billing-ui';\nimport { VaIconModule } from '@vendasta/uikit';\nimport baseTranslation from '../assets/i18n/en_devel.json';\nimport { VaPricingModule } from '../pricing/pricing.module';\nimport { WEBLATE_COMPONENT_NAME } from '../shared/constants';\nimport { VaHeaderContainerComponent } from './header-container.component';\n\n@NgModule({\n imports: [\n CommonModule,\n MatIconModule,\n VaPricingModule,\n VaIconModule,\n MatChipsModule,\n MatButtonModule,\n MatTooltipModule,\n MatCardModule,\n TranslateModule,\n LexiconModule.forChild({\n componentName: WEBLATE_COMPONENT_NAME,\n baseTranslation: baseTranslation,\n }),\n BillingUiModule,\n ],\n declarations: [VaHeaderContainerComponent],\n exports: [VaHeaderContainerComponent],\n})\nexport class VaHeaderContainerModule {}\n", "import { Injectable } from '@angular/core';\n\ninterface StorageCache {\n [key: string]: any;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class TemporaryStorageService {\n private readonly cache: StorageCache;\n private readonly isSessionStorageAvailable: boolean;\n\n constructor() {\n this.cache = Object.create(null);\n this.isSessionStorageAvailable = !!sessionStorage;\n }\n\n set(key: string, objectToCache: any): void {\n try {\n const serializedCache = JSON.stringify(objectToCache);\n if (this.isSessionStorageAvailable) {\n sessionStorage.setItem(key, serializedCache);\n } else {\n this.cache[key] = serializedCache;\n }\n } catch (error) {\n console.warn('Unable to write to SessionStorage API.');\n console.error(error);\n }\n }\n\n get(key: string): any {\n try {\n let serializedCache = null;\n if (this.isSessionStorageAvailable) {\n serializedCache = sessionStorage.getItem(key);\n } else {\n serializedCache = this.cache[key];\n }\n\n if (serializedCache) {\n return JSON.parse(serializedCache);\n }\n } catch (error) {\n console.warn('Unable to read from SessionStorage API.');\n console.error(error);\n }\n }\n}\n", "import { ValidatorFn } from '@angular/forms';\n\nexport const FILES = 'file';\nexport const DROP_DOWN = 'dropdown';\nexport const CHECK_BOX = 'checkbox';\nexport const TEXT_AREA = 'textarea';\nexport const TEXT_BOX = 'textbox';\nexport const BUSINESS_USER = 'vbcuser';\n\nexport type ControlType = 'checkbox' | 'dropdown' | 'file' | 'textbox' | 'textarea' | 'vbcuser';\n\nexport interface FieldBaseOptions {\n // TODO This and marketplace-apps OrderFormFieldInterface should share a common base\n id: string;\n label: string;\n required?: boolean;\n description?: string;\n type?: string;\n prefix?: string;\n suffix?: string;\n regexValidator?: string;\n regexErrorMessage?: string;\n disabled?: boolean;\n forOfficeUseOnly?: boolean;\n officeEditableOnly?: boolean;\n hidden?: boolean;\n displayOnly?: boolean;\n}\n\nexport abstract class FieldBase implements FieldBaseOptions {\n value: T;\n id: string;\n label: string;\n required: boolean;\n order: number;\n description: string;\n controlType: ControlType;\n prefix: string;\n suffix: string;\n regexValidator: string;\n regexErrorMessage: string;\n disabled: boolean;\n validator: ValidatorFn;\n forOfficeUseOnly: boolean;\n officeEditableOnly: boolean;\n hidden: boolean;\n displayOnly: boolean;\n\n constructor(options: FieldBaseOptions) {\n this.id = options.id;\n this.label = options.label;\n this.required = !!options.required;\n this.description = options.description || null;\n options.type = options.type === 'text' ? 'textbox' : options.type;\n this.controlType = options.type as ControlType;\n this.prefix = options.prefix;\n this.suffix = options.suffix;\n this.regexValidator = options.regexValidator;\n this.regexErrorMessage = options.regexErrorMessage;\n this.disabled = options.disabled || false;\n this.validator = this.validatorBuilder();\n this.forOfficeUseOnly = !!options.forOfficeUseOnly;\n this.officeEditableOnly = !!options.officeEditableOnly;\n this.hidden = options.hidden;\n this.displayOnly = options.displayOnly;\n }\n\n protected validatorBuilder(): ValidatorFn {\n return (): { [key: string]: any } => {\n return null;\n };\n }\n}\n", "import { ControlType, FieldBase } from './field-base';\nimport { Pipe, PipeTransform, SecurityContext } from '@angular/core';\nimport { DomSanitizer } from '@angular/platform-browser';\nimport { TranslateService } from '@ngx-translate/core';\n\nexport class CheckboxField extends FieldBase {\n readonly controlType: ControlType = 'checkbox';\n}\n\n@Pipe({\n name: 'sanitizeCheckboxLabel',\n standalone: true,\n pure: true,\n})\nexport class SanitizeCheckboxLabelPipe implements PipeTransform {\n constructor(\n private sanitizer: DomSanitizer,\n private translateService: TranslateService,\n ) {}\n\n transform(value: string, required: boolean): string {\n const translatedValue = this.translateService.instant(value);\n let sanitizedValue = this.sanitizer.sanitize(SecurityContext.HTML, translatedValue);\n if (required) {\n sanitizedValue = sanitizedValue.concat(' *');\n }\n return sanitizedValue;\n }\n}\n", "import { Component, Input, ViewChild } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { ImageTransformationService } from '@vendasta/image-transformation';\nimport { SanitizeCheckboxLabelPipe } from './field-checkbox';\n\n@Component({\n selector: 'store-order-field',\n styleUrls: ['./field.component.scss'],\n templateUrl: './field.component.html',\n providers: [SanitizeCheckboxLabelPipe],\n standalone: false,\n})\nexport class FieldComponent {\n @Input() field: any; // avoid checking union type in template\n @Input() form: FormGroup;\n readonly MAX_FILE_SIZE = 26214400; // 25MB\n\n @ViewChild('glxyUploader') glxyUploader;\n\n constructor(private imageTransformationService: ImageTransformationService) {}\n\n get isValid(): boolean {\n return this.form.controls[this.field.id].valid || this.form.controls[this.field.id].pristine;\n }\n\n showCheckboxError(field): boolean {\n return (\n this.form.controls[field].errors && this.form.controls[field].errors.required && this.form.controls[field].touched\n );\n }\n\n getValue(): any {\n return this.form.controls[this.field.id].value;\n }\n\n dropdownAnswer(): string {\n const answer = this.getValue();\n return ((this.field.options || []).find((option) => option.value === answer) || { label: answer }).label;\n }\n\n multidropdownAnswer(): string {\n const answer = this.getValue();\n return (answer || [])\n .map((a) => ((this.field.options || []).find((option) => option.value === a) || { name: a }).name)\n .join(', ');\n }\n\n checkboxAnswer(): string {\n const answer = this.getValue();\n return answer ? 'Yes' : 'No';\n }\n\n fileUploadAnswer(): string {\n const answer = this.getValue() || [];\n return answer.map((a) => (a.name ? a.name : a.url ? a.url : a)).join(', ');\n }\n\n // Handle deleting file from both galaxy uploader component, and order-form form values\n deleteFile(event: any): void {\n const filterOutDeletedFile = this.form.controls[this.field.id].value.filter(\n (file) => file.name !== event.name && file.url !== event.url,\n );\n\n this.form.controls[this.field.id].setValue(filterOutDeletedFile);\n // Tell galaxy uploader about delete so it can handle maxFiles properly\n this.glxyUploader.deleteFile(event);\n }\n\n // Manually update order-form form with events from galaxy file uploader\n onUpload(event: any): void {\n const uploadedFiles = this.form.controls[this.field.id].value;\n let fileUrl = event.url;\n // retain original scale for images\n if (this.imageTransformationService.isServingUrl(event.url)) {\n fileUrl += '=s0';\n }\n\n uploadedFiles.push({\n name: event.name,\n url: fileUrl,\n });\n\n this.form.controls[this.field.id].setValue(uploadedFiles);\n }\n}\n", "\n \n
\n {{ 'FRONTEND.STORE.ORDER_FORM.HIDDEN_FROM_END_USERS' | translate }}:\n
\n
\n {{ 'FRONTEND.STORE.ORDER_FORM.OFFICE_EDITABLE_ONLY' | translate }}:\n
\n\n \n \n
\n \n {{ field.label | translate }}{{ field.required ? '*' : '' }}\n \n \n {{ option.label }}\n \n \n \n {{ field.description }}\n \n \n
\n
\n
{{ field.label | translate }}:
\n
{{ dropdownAnswer() }}
\n
\n
\n \n
\n \n
\n
\n
{{ field.label | translate }}:
\n
{{ multidropdownAnswer() }}
\n
\n
\n
\n\n \n
\n \n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n \n \n {{ field.description }}\n \n \n {{ field.regexErrorMessage }}\n \n \n
\n
\n
{{ field.label | translate }}:
\n
{{ getValue() }}
\n
\n
\n\n \n
\n \n \n \n \n {{ field.description }}\n \n \n \n {{ 'FRONTEND.STORE.REQUIRED' | translate }}\n \n \n
\n
\n
{{ field.label | translate }}:
\n
{{ checkboxAnswer() }}
\n
\n
\n\n \n \n \n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n \n \n {{ field.description }}\n \n \n \n
\n
{{ field.label | translate }}:
\n
{{ getValue() }}
\n
\n
\n\n \n \n \n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n \n {{ field.description }}\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n
{{ field.label | translate }}:
\n
{{ fileUploadAnswer() }}
\n
\n
\n\n \n
\n \n {{ field.label | translate }}{{ field.required ? ' *' : '' }}\n \n \n {{ option.label | translate }}\n \n \n \n {{ field.description }}\n \n \n
\n
\n
{{ field.label | translate }}:
\n
{{ dropdownAnswer() }}
\n
\n
\n
\n
\n", "import { Component, Input, OnDestroy, OnInit, TemplateRef } from '@angular/core';\nimport { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';\nimport { TranslateService } from '@ngx-translate/core';\nimport { Subscription, combineLatest } from 'rxjs';\nimport { debounceTime, skip } from 'rxjs/operators';\nimport { FieldBase } from '../fields/field-base';\nimport { Option } from '../fields/field-dropdown';\nimport { VBCUserField } from '../fields/field-vbcuser';\nimport { TemporaryStorageService } from './temporary-storage.service';\n\n@Component({\n selector: 'store-dropdown-form-section',\n template: `\n \n \n \n
\n \n {{ iconName }}\n \n
{{ titleText }}
\n \n
{{ titleText }}
\n
\n {{ autoTitleText }}\n
\n
\n \n
\n \n
\n {{ autoDescriptionText }}\n
\n
\n {{ descriptionText }}\n
\n
\n
\n
\n \n

\n {{ editingHint }}\n

\n
\n \n
\n
\n
{{ titleText }}
\n \n
\n `,\n styleUrls: ['./dropdown-form-section.component.scss'],\n standalone: false,\n})\nexport class DropDownFormSectionComponent implements OnInit, OnDestroy {\n @Input() prepopulatedData: object;\n @Input() startOpen = false;\n @Input() parentForm: UntypedFormGroup;\n @Input() displayAutoTitle = false;\n @Input() titleText = '';\n @Input() displayAutoDescription = true;\n @Input() descriptionText = '';\n @Input() fields: FieldBase[];\n @Input() editingHint = '';\n @Input() expandable = true;\n @Input() temporaryStorageKey = '';\n @Input() bottomActionsContent: TemplateRef;\n\n autoDescriptionText = '';\n iconName = 'help_outline';\n subscriptions: Subscription[] = [];\n uniqueIndex = 1;\n autoTitleText = '';\n contactIdField: VBCUserField;\n protected dropDownForm: UntypedFormGroup;\n\n constructor(\n private translateService: TranslateService,\n private temporaryStorage: TemporaryStorageService,\n ) {}\n\n ngOnInit(): void {\n const allFieldsHidden = this.fields.reduce((p, c) => p && c.hidden, true);\n if (allFieldsHidden) {\n this.expandable = false;\n }\n while (Object.prototype.hasOwnProperty.call(this.parentForm.controls, this.titleText + this.uniqueIndex)) {\n this.uniqueIndex += 1;\n }\n this.dropDownForm = this.toFormGroup(this.fields);\n this.parentForm.addControl(this.titleText + this.uniqueIndex, this.dropDownForm);\n const form = this.parentForm.controls[this.titleText + this.uniqueIndex] as UntypedFormGroup;\n\n // Check if a field with id 'contact_id' exists\n // This is only used within the common form data when the vendor has enabled the \"contact\" data fields\n // If the business has more than a single smb user then a dynamic dropdown will be displayed\n // Show the form as open so that the data can be selected\n this.contactIdField = this.fields.find((field) => field.id === 'contact_id') as VBCUserField;\n\n // set form values with prepopulated field data\n for (const key in form.controls) {\n if (Object.prototype.hasOwnProperty.call(form.controls, key)) {\n if (this.prepopulatedData != null && Object.prototype.hasOwnProperty.call(this.prepopulatedData, key)) {\n form.controls[key].setValue(this.prepopulatedData[key]);\n }\n }\n }\n\n // temporary storage key to use for session storage\n if (this.temporaryStorageKey != '') {\n // check to see if an existing value exists in the temporary storage\n const existingFormData = this.temporaryStorage.get(this.temporaryStorageKey);\n if (existingFormData) {\n for (const key in form.controls) {\n // if the form control exists check to see if it has an existing value (that was previously saved)\n const field = this.fields.find((f) => f.id === key);\n if (field?.value) {\n form.controls[key].setValue(field.value);\n } else {\n // there is no existing value set the value from the temporary storage\n if (Object.prototype.hasOwnProperty.call(form.controls, key)) {\n if (Object.prototype.hasOwnProperty.call(existingFormData, key)) {\n form.controls[key].setValue(existingFormData[key]);\n }\n }\n }\n }\n }\n\n // save the latest form values to temporary storage\n this.subscriptions.push(\n form.valueChanges.pipe(skip(1), debounceTime(300)).subscribe((value) => {\n this.temporaryStorage.set(this.temporaryStorageKey, value);\n }),\n );\n }\n\n this.subscriptions.push(\n combineLatest([form.statusChanges, this.translateService.stream('FRONTEND.STORE.AUTO_TITLE_TEXT')]).subscribe(\n ([change, autoTitleText]) => {\n let missingFields = false;\n for (const control in form.controls) {\n if (this.isFormControlEmpty(form, control)) {\n this.iconName = 'help_outline';\n missingFields = true;\n if (change === 'INVALID') {\n this.autoTitleText = autoTitleText.SOME_FIELDS_INVALID;\n this.startOpen = true;\n if (form.controls[control].dirty || form.controls[control].touched) {\n this.iconName = 'warning';\n break;\n }\n } else {\n this.autoTitleText = autoTitleText.OPTIONAL_FIELDS_UNANSWERED;\n }\n }\n }\n if (!missingFields) {\n this.iconName = 'check_circle';\n this.autoTitleText = autoTitleText.COMPLETE;\n }\n },\n ),\n );\n\n // The drop down form section is used by the common form data section as well as vendor order forms\n // The following code handles the \"contact_id\" fields which is part of the common order form data\n // TODO: refactor the common order form data into dedicated components\n if (this.contactIdField) {\n this.subscriptions.push(\n form.get('contact_id').valueChanges.subscribe((contactIdValue) => {\n const selectedContact = JSON.parse(contactIdValue);\n\n if (selectedContact.firstName) {\n let fullName = selectedContact.firstName;\n if (selectedContact.lastName) {\n fullName += ' ' + selectedContact.lastName;\n }\n form.controls['contact_name'].setValue(fullName, { emitEvent: true });\n }\n\n if (selectedContact.email) {\n form.controls['contact_email'].setValue(selectedContact.email, { emitEvent: true });\n }\n\n if (selectedContact.phoneNumber) {\n form.controls['contact_phone_number'].setValue(selectedContact.phoneNumber, { emitEvent: true });\n }\n }),\n );\n }\n\n this.subscriptions.push(\n form.valueChanges.subscribe((changes) => {\n let description = '';\n for (const key in changes) {\n // As per above we need to skip change detection for the contact_id field\n if (key === 'contact_id') {\n continue;\n }\n\n if (Object.prototype.hasOwnProperty.call(changes, key) && changes[key] != null && changes[key].length > 0) {\n if (changes[key][0].name) {\n for (const fileKey in changes[key]) {\n if (changes[key][fileKey] != null) {\n description += changes[key][fileKey].name;\n description += ', ';\n }\n }\n } else {\n description += changes[key];\n description += ', ';\n }\n }\n }\n if (this.displayAutoDescription) {\n this.autoDescriptionText = description.substring(0, description.length - 2);\n }\n }),\n );\n\n if (this.contactIdField) {\n this.startOpen = true;\n const contacts = this.contactIdField.options as Option[];\n const validContact = contacts.find((contact) => {\n if (contact?.disabled) {\n return false;\n }\n const currentContact = JSON.parse(contact.value);\n return currentContact.email === form.controls['contact_email'].value;\n });\n if (validContact) {\n form.controls['contact_id'].setValue(validContact.value, { emitEvent: true });\n }\n }\n\n form.updateValueAndValidity({ onlySelf: false, emitEvent: true });\n }\n\n toFormGroup(formFields: FieldBase[]): UntypedFormGroup {\n const group: any = {};\n formFields.forEach((field) => {\n let validations;\n if (!field.required || field.hidden) {\n validations = field.validator;\n } else if (field.controlType === 'checkbox') {\n validations = [Validators.requiredTrue, field.validator];\n } else {\n validations = [Validators.required, field.validator];\n }\n\n const formControl = new UntypedFormControl({ value: field.value, disabled: field.disabled }, validations);\n group[field.id] = formControl;\n this.subscriptions.push(formControl.valueChanges.subscribe((value) => (field.value = value)));\n });\n\n return new UntypedFormGroup(group);\n }\n\n isFormControlEmpty(form: UntypedFormGroup, control: string): boolean {\n // hidden fields should not need to be filled in\n if (this.fields.find((field) => field.id === control)?.hidden) {\n return false;\n }\n\n return (\n !form.controls[control].value ||\n (form.controls[control].value.constructor === Array && !form.controls[control].value[0])\n );\n }\n\n ngOnDestroy(): void {\n this.parentForm.removeControl(this.titleText + this.uniqueIndex);\n this.subscriptions.forEach((subscription) => subscription.unsubscribe());\n }\n}\n", "import { Injectable } from '@angular/core';\nimport { FieldBase } from './field-base';\nimport { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';\nimport { Subscription } from 'rxjs';\n\n@Injectable()\nexport class FieldService {\n createFormControl(field: FieldBase): UntypedFormControl {\n if (field.required) {\n return new UntypedFormControl(field.value, Validators.required);\n } else {\n return new UntypedFormControl(field.value);\n }\n }\n\n toFormGroup(formFields: FieldBase[], subscriptions: Subscription[]): UntypedFormGroup {\n const group: any = {};\n formFields.forEach((field) => {\n let formControl: UntypedFormControl;\n if (field.controlType === 'checkbox') {\n formControl = new UntypedFormControl(field.value);\n } else {\n formControl = this.createFormControl(field);\n }\n group[field.id] = formControl;\n if (subscriptions) {\n subscriptions.push(formControl.valueChanges.subscribe((value) => (field.value = value)));\n }\n });\n return new UntypedFormGroup(group);\n }\n}\n", "import { FieldBase } from '../fields/field-base';\nimport { UntypedFormGroup } from '@angular/forms';\n\nexport class DropDownFormSectionData {\n prepopulatedData: any;\n startOpen: boolean;\n parentForm: UntypedFormGroup;\n displayAutoTitle: boolean;\n titleText: string;\n displayAutoDescription: boolean;\n descriptionText: string;\n fields: FieldBase[];\n editingHint: string;\n /* tslint:disable */\n expandable? = true;\n /* tslint:enable */\n}\n", "import { UntypedFormGroup } from '@angular/forms';\nimport { DropDownFormSectionData } from '../dropdown-form-section/dropdown-form-section-data';\nexport class OrderFormSectionData {\n parentForm: UntypedFormGroup;\n titleText: string;\n subtitleText: string;\n descriptionText: string;\n iconUrl: string;\n primarySection: DropDownFormSectionData;\n subsections: DropDownFormSectionData[];\n footerText?: string;\n}\n", "import { DropDownFormSectionData } from '../dropdown-form-section/dropdown-form-section-data';\nimport { OrderFormSectionData } from '../order-form-section/order-form-section-data';\nimport { FieldBase, FieldBaseOptions } from '../fields/field-base';\nimport { DropDownFieldOptions } from '../fields/field-dropdown';\nimport { FileUploadGroupFieldOptions } from '../fields/field-fileuploadgroup';\nimport { TextBoxFieldOptions } from '../fields/field-textbox';\nimport { User, VBCUserFieldOptions } from '../fields/field-vbcuser';\n\nexport type OrderFormFieldOptionsType =\n | FieldBaseOptions\n | DropDownFieldOptions\n | FileUploadGroupFieldOptions\n | TextBoxFieldOptions\n | VBCUserFieldOptions;\n\nexport interface OrderFormInterface {\n appId: string;\n addonId?: string;\n commonForm?: IncludedCommonFormFieldsInterface;\n commonFormRequiredFields?: IncludedCommonFormFieldsInterface;\n customFields?: OrderFormFieldOptionsType[];\n footerText?: string;\n}\n\nexport interface IncludedCommonFormFieldsInterface {\n businessName?: boolean;\n businessAddress?: boolean;\n businessPhoneNumber?: boolean;\n businessAccountGroupId?: boolean;\n businessWebsite?: boolean;\n salespersonName?: boolean;\n salespersonPhoneNumber?: boolean;\n salespersonEmail?: boolean;\n contactName?: boolean;\n contactPhoneNumber?: boolean;\n contactEmail?: boolean;\n}\n\nexport interface CommonFormSectionInterface {\n fields: CommonFormFieldInterface[];\n sectionName?: string;\n populatedData?: CommonFormData;\n}\n\nexport interface AddonKeyInterface {\n addonId?: string;\n appId?: string;\n}\n\nexport interface CommonFormFieldInterface extends FieldBase {\n productIds?: string[];\n addonKeys?: AddonKeyInterface[];\n}\n\nexport interface CommonFieldIdsInterface {\n fieldId: string;\n required: boolean;\n}\n\n// Keys are snake cased here because that is the format in which we submit this data to vendors\nexport interface CommonFormData {\n user_options?: User[];\n contact_email?: string;\n contact_name?: string;\n contact_phone_number?: string;\n business_account_group_id?: string;\n business_name?: string;\n business_address?: string;\n business_phone_number?: string;\n business_website?: string;\n salesperson_name?: string;\n salesperson_email?: string;\n salesperson_phone_number?: string;\n}\n\nexport class ProductOrderFormSectionData extends OrderFormSectionData {\n businessId: string;\n productId: string;\n subsections: AddonDropDownFormSectionData[];\n}\n\nexport class AddonDropDownFormSectionData extends DropDownFormSectionData {\n productId: string;\n addonId: string;\n}\n\nexport interface ProductInfoInterface {\n productId: string;\n name?: string;\n tagline?: string;\n icon?: string;\n addonInfo?: AddonInfoInterface[];\n}\n\nexport interface AddonInfoInterface {\n addonId: string;\n name?: string;\n}\n\nexport interface CustomFieldsAnswers {\n productID: string;\n addonKey?: AddonKeyInterface;\n customFieldsAnswers: CustomFieldsAnswer[];\n}\n\nexport interface CustomFieldsAnswer {\n fieldId: string;\n answer?: string;\n displayOnly?: boolean;\n}\n\nexport interface OrderFormOptionsInterface {\n bypassRequiredQuestions?: boolean;\n readOnly?: boolean;\n showOfficeUseQuestions?: boolean;\n}\n", "import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'buildTemporaryStorageKey',\n standalone: true,\n})\nexport class BuildTemporaryStorageKeyPipe implements PipeTransform {\n transform(args: { businessId: string; id: string; index?: number }): string {\n return buildTemporaryStorageKey(args);\n }\n}\n\nexport function buildTemporaryStorageKey(args: { businessId: string; id: string; index?: number }): string {\n if (!args) {\n return '';\n }\n const parts = [args.businessId, args.id];\n const indexAsString = args.index?.toString();\n if (indexAsString) {\n parts.push(indexAsString);\n }\n return parts.join('-');\n}\n", "import { Component, Input, OnInit, TemplateRef } from '@angular/core';\nimport { DropDownFormSectionData } from '../dropdown-form-section/dropdown-form-section-data';\nimport { ProductOrderFormSectionData } from '../order-form/interface';\n\n@Component({\n selector: 'store-order-form-section',\n templateUrl: 'order-form-section.component.html',\n styleUrls: ['./order-form-section.component.scss'],\n standalone: false,\n})\nexport class OrderFormSectionComponent implements OnInit {\n @Input() data: ProductOrderFormSectionData;\n @Input() extraHeaderContent: TemplateRef;\n @Input() bottomActionsContent: TemplateRef;\n\n ngOnInit(): void {\n // The first section should always be expanded.\n const topSection = this.getTopSection();\n if (topSection) {\n topSection.startOpen = true;\n }\n }\n\n getTopSection(): DropDownFormSectionData {\n if (!this.data) {\n return null;\n }\n if (this.data.primarySection) {\n return this.data.primarySection;\n }\n if (this.data.subsections && this.data.subsections.length > 0) {\n return this.data.subsections[0];\n }\n return null;\n }\n}\n", "
\n
\n
\n
\n \n
\n

{{ data.titleText }}

\n \n {{ data.subtitleText }}\n \n
\n
\n
\n {{ data.descriptionText }}\n
\n \n
\n
\n \n 0\">\n \n \n \n \n \n

Additional information

\n
\n
\n
\n
\n
\n \n
\n
\n", "import { ControlType, FieldBase, FieldBaseOptions } from './field-base';\nimport { Option as InputOption } from '@vendasta/forms';\nimport { AbstractControl, ValidatorFn } from '@angular/forms';\n\nexport interface Option {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport interface DropDownFieldOptions extends FieldBaseOptions {\n options: Option[] | InputOption[] | string[];\n allowMultiples?: boolean;\n allowDuplicates?: boolean;\n maxChoices?: number;\n}\n\nexport class DropdownField extends FieldBase {\n readonly controlType: ControlType = 'dropdown';\n options: Option[] | InputOption[];\n allowMultiples: boolean;\n allowDuplicates: boolean;\n maxChoices: number;\n\n constructor(options: DropDownFieldOptions) {\n super(options);\n this.options = [];\n if (!!options.options && options.options.length > 0) {\n if (typeof options.options[0] === 'string') {\n if (options.allowMultiples) {\n this.options = options.options.map((o) => { value: o, name: o });\n } else {\n this.options = options.options.map((o) =>