@veloceapps/sdk 3.1.3 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/bundles/veloce-sdk-cms.umd.js +33 -2
  2. package/bundles/veloce-sdk-cms.umd.js.map +1 -1
  3. package/bundles/veloce-sdk-core.umd.js +7 -1
  4. package/bundles/veloce-sdk-core.umd.js.map +1 -1
  5. package/bundles/veloce-sdk.umd.js +174 -98
  6. package/bundles/veloce-sdk.umd.js.map +1 -1
  7. package/cms/cms.actions.d.ts +12 -0
  8. package/cms/index.d.ts +1 -0
  9. package/cms/services/integration.state.d.ts +1 -4
  10. package/cms/types/index.d.ts +1 -0
  11. package/cms/types/integration.types.d.ts +4 -0
  12. package/cms/vendor-map.d.ts +8 -0
  13. package/core/modules/configuration/services/configuration.service.d.ts +1 -0
  14. package/esm2015/cms/cms.actions.js +17 -0
  15. package/esm2015/cms/index.js +2 -1
  16. package/esm2015/cms/services/integration.state.js +1 -1
  17. package/esm2015/cms/types/index.js +2 -1
  18. package/esm2015/cms/types/integration.types.js +2 -0
  19. package/esm2015/cms/vendor-map.js +4 -3
  20. package/esm2015/core/modules/configuration/services/configuration-runtime.service.js +2 -2
  21. package/esm2015/core/modules/configuration/services/configuration.service.js +7 -1
  22. package/esm2015/src/components/header/cart-overlay/cart-overlay.component.js +4 -4
  23. package/esm2015/src/components/header/header.component.js +3 -2
  24. package/esm2015/src/flow-routing.module.js +21 -3
  25. package/esm2015/src/guards/product-unload.guard.js +30 -0
  26. package/esm2015/src/pages/product/product.component.js +26 -38
  27. package/esm2015/src/services/flow-router.service.js +13 -5
  28. package/esm2015/src/services/flow.service.js +40 -12
  29. package/esm2015/src/services/fow-dialog.service.js +9 -1
  30. package/fesm2015/veloce-sdk-cms.js +28 -3
  31. package/fesm2015/veloce-sdk-cms.js.map +1 -1
  32. package/fesm2015/veloce-sdk-core.js +7 -1
  33. package/fesm2015/veloce-sdk-core.js.map +1 -1
  34. package/fesm2015/veloce-sdk.js +144 -70
  35. package/fesm2015/veloce-sdk.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/components/header/cart-overlay/cart-overlay.component.d.ts +1 -1
  38. package/src/components/header/header.component.d.ts +1 -0
  39. package/src/guards/product-unload.guard.d.ts +13 -0
  40. package/src/pages/product/product.component.d.ts +3 -6
  41. package/src/services/flow-router.service.d.ts +3 -1
  42. package/src/services/flow.service.d.ts +5 -1
  43. package/src/services/fow-dialog.service.d.ts +1 -0
@@ -4,10 +4,10 @@ import * as i0 from '@angular/core';
4
4
  import { Component, ChangeDetectionStrategy, NgModule, Injectable, ViewChild, Input, InjectionToken, Optional, Inject } from '@angular/core';
5
5
  import * as i1$3 from '@veloce/api';
6
6
  import { ApiModule } from '@veloce/api';
7
- import * as i3$1 from '@veloce/components';
7
+ import * as i3 from '@veloce/components';
8
8
  import { LetDirectiveModule, ToastType, LoaderModule } from '@veloce/components';
9
- import * as i1$4 from '@veloce/sdk/cms';
10
- import { PreviewModule, LauncherModule } from '@veloce/sdk/cms';
9
+ import * as i4$1 from '@veloce/sdk/cms';
10
+ import { FlowAction, PreviewModule, LauncherModule } from '@veloce/sdk/cms';
11
11
  import * as i2 from '@veloce/sdk/core';
12
12
  import { RuntimeOperation, SdkCoreModule } from '@veloce/sdk/core';
13
13
  import * as i5 from 'primeng/button';
@@ -26,17 +26,17 @@ import * as i1$2 from '@veloce/core';
26
26
  import { ConfigurationContextMode, UITemplateComponentType, UITemplateType, EntityUtil } from '@veloce/core';
27
27
  import * as i1$1 from '@angular/router';
28
28
  import { NavigationEnd, NavigationStart, NavigationCancel, NavigationError, RouterModule } from '@angular/router';
29
- import * as i3 from 'primeng/api';
30
- import * as i4$1 from 'primeng/dropdown';
29
+ import * as i2$1 from 'primeng/api';
30
+ import * as i4$2 from 'primeng/dropdown';
31
31
  import { DropdownModule } from 'primeng/dropdown';
32
32
  import * as i8 from 'primeng/inputtext';
33
33
  import { InputTextModule } from 'primeng/inputtext';
34
34
  import * as i6$1 from 'primeng/radiobutton';
35
35
  import { RadioButtonModule } from 'primeng/radiobutton';
36
36
  import { first, takeUntil as takeUntil$1, take, map as map$1, switchMap as switchMap$1, tap as tap$1, catchError as catchError$1 } from 'rxjs/operators';
37
- import * as i4$2 from '@veloce/sdk/runtime';
37
+ import * as i4$3 from '@veloce/sdk/runtime';
38
38
  import { RuntimeModule } from '@veloce/sdk/runtime';
39
- import * as i1$5 from 'ngx-bootstrap/tooltip';
39
+ import * as i1$4 from 'ngx-bootstrap/tooltip';
40
40
  import { TooltipModule as TooltipModule$1 } from 'ngx-bootstrap/tooltip';
41
41
  import { HttpErrorResponse } from '@angular/common/http';
42
42
 
@@ -86,6 +86,7 @@ class FlowRouterService {
86
86
  this.router = router;
87
87
  this.route = route;
88
88
  this.contextService = contextService;
89
+ this.urlHistory = [];
89
90
  this.getLastChildRoute = (route) => {
90
91
  return route.firstChild ? this.getLastChildRoute(route.firstChild) : route;
91
92
  };
@@ -121,6 +122,9 @@ class FlowRouterService {
121
122
  e instanceof NavigationCancel ||
122
123
  e instanceof NavigationEnd ||
123
124
  e instanceof NavigationError), map(e => e instanceof NavigationStart), startWith(false), distinctUntilChanged());
125
+ this.router.events.pipe(filter(e => e instanceof NavigationEnd)).subscribe(() => {
126
+ this.urlHistory.push(this.router.url);
127
+ });
124
128
  }
125
129
  getFlowRootRoute(route) {
126
130
  var _a;
@@ -162,8 +166,14 @@ class FlowRouterService {
162
166
  isCatalogRoute$() {
163
167
  return this.getFlowSubpath$().pipe(map(url => url.startsWith('catalog')));
164
168
  }
165
- navigateToProductConfiguration(productId) {
166
- this.contextService.update({ properties: { productId } });
169
+ navigateBack() {
170
+ const prevUrl = this.urlHistory[this.urlHistory.length - 2];
171
+ if (prevUrl) {
172
+ this.router.navigateByUrl(prevUrl);
173
+ }
174
+ }
175
+ navigateToProductConfiguration(productId, lineItemId) {
176
+ this.contextService.update({ properties: { productId, lineItemId } });
167
177
  const routeSnapshot = this.getLastChildRouteSnapshot(this.route.snapshot);
168
178
  const flowRouteUrl = this.getFlowRootPath(routeSnapshot);
169
179
  this.router.navigate([flowRouteUrl, 'product'], {
@@ -171,13 +181,11 @@ class FlowRouterService {
171
181
  });
172
182
  }
173
183
  navigateToShoppingCart() {
174
- this.contextService.update({ properties: { productId: undefined } });
175
184
  const routeSnapshot = this.getLastChildRouteSnapshot(this.route.snapshot);
176
185
  const flowRouteUrl = this.getFlowRootPath(routeSnapshot);
177
186
  this.router.navigate([flowRouteUrl, 'cart'], { queryParams: routeSnapshot.queryParams });
178
187
  }
179
188
  navigateToCatalog() {
180
- this.contextService.update({ properties: { productId: undefined } });
181
189
  const routeSnapshot = this.getLastChildRouteSnapshot(this.route.snapshot);
182
190
  const flowRouteUrl = this.getFlowRootPath(routeSnapshot);
183
191
  this.router.navigate([flowRouteUrl, 'catalog'], { queryParams: routeSnapshot.queryParams });
@@ -230,9 +238,9 @@ class HeaderCartOverlayComponent {
230
238
  }
231
239
  return this.imagesMap$.pipe(map(imagesMap => imagesMap[productId]), distinctUntilChanged());
232
240
  }
233
- navigateToProductConfiguration(productId) {
241
+ navigateToProductConfiguration(productId, lineItemId) {
234
242
  this.overlayPanel.hide();
235
- this.routerService.navigateToProductConfiguration(productId);
243
+ this.routerService.navigateToProductConfiguration(productId, lineItemId);
236
244
  }
237
245
  controlBlurHandler(product) {
238
246
  const control = this.form.controls[product.id];
@@ -292,7 +300,7 @@ class HeaderCartOverlayComponent {
292
300
  }
293
301
  }
294
302
  HeaderCartOverlayComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: HeaderCartOverlayComponent, deps: [{ token: i1$2.BaseHttpService }, { token: i2.FlowConfigurationService }, { token: FlowRouterService }], target: i0.ɵɵFactoryTarget.Component });
295
- HeaderCartOverlayComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: HeaderCartOverlayComponent, selector: "vl-header-cart-overlay", inputs: { products: "products" }, viewQueries: [{ propertyName: "overlayPanel", first: true, predicate: OverlayPanel, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<p-overlayPanel\n styleClass=\"navigation-settings-overlay flow-header-overlay center\"\n showTransitionOptions=\"0ms\"\n hideTransitionOptions=\"0ms\"\n>\n <ng-template pTemplate>\n <div class=\"flow-header-overlay__wrapper\" *vlLet=\"readonlyProductId$ | async as readonlyProductId\">\n <ng-container *ngIf=\"products.length > 0; else empty\">\n <h2 class=\"flow-header-overlay__title\">\n <span>Products ({{ products.length }})</span>\n <i class=\"vl-icon vl-icon-close close-icon\" (click)=\"overlayPanel.hide()\"></i>\n </h2>\n\n <div class=\"product header\">\n <span>Product</span>\n <span class=\"text-right\">Qty</span>\n <span class=\"text-right\">MRR</span>\n <span class=\"text-right\">NRR</span>\n </div>\n\n <div class=\"scrollable-wrapper\">\n <div class=\"product\" *ngFor=\"let product of products\">\n <div class=\"product__info\">\n <div class=\"product__image-wrapper\">\n <div\n *ngIf=\"getImageUrl(product.productId) | async as imageUrl; else noImage\"\n class=\"product__image\"\n [ngStyle]=\"{ 'background-image': 'url(' + imageUrl + ')' }\"\n ></div>\n </div>\n <div class=\"flex flex-column justify-content-center\">\n <div class=\"word-break\">{{ product.name }}</div>\n <div>\n <p-button\n label=\"Configure\"\n [disabled]=\"!product.configurable || readonlyProductId === product.productId\"\n styleClass=\"p-button-link p-button-sm pl-0\"\n (onClick)=\"navigateToProductConfiguration(product.productId)\"\n ></p-button>\n <p-button\n label=\"Delete\"\n [disabled]=\"readonlyProductId === product.productId\"\n styleClass=\"p-button-link p-button-sm p-button-danger pl-0 pr-0\"\n (onClick)=\"deleteHandler(product)\"\n ></p-button>\n </div>\n </div>\n </div>\n\n <span>\n <p-inputNumber\n *ngIf=\"form.controls[product.id] as control\"\n class=\"qty-control\"\n [formControl]=\"$any(control)\"\n [min]=\"1\"\n [required]=\"true\"\n (onBlur)=\"controlBlurHandler(product)\"\n ></p-inputNumber>\n </span>\n <span class=\"text-right pt-3\">$0.00</span>\n <span class=\"text-right pt-3\">$0.00</span>\n </div>\n\n <ng-template #noImage>\n <i class=\"vl-icon vl-icon-no-image no-image-icon\"></i>\n </ng-template>\n </div>\n\n <div class=\"flex justify-content-end mt-3\">\n <p-button\n label=\"Clear cart\"\n styleClass=\"p-button-link p-button-sm p-button-danger pl-0 pr-0\"\n [disabled]=\"readonlyProductId\"\n (onClick)=\"deleteAllHandler()\"\n ></p-button>\n </div>\n </ng-container>\n\n <ng-template #empty>\n <h2 class=\"flow-header-overlay__title\">\n <span>Empty Cart</span>\n <i class=\"vl-icon vl-icon-close close-icon\" (click)=\"overlayPanel.hide()\"></i>\n </h2>\n\n <span class=\"empty-state\">There are no products added to the Shopping Cart yet.</span>\n </ng-template>\n </div>\n </ng-template>\n</p-overlayPanel>\n", styles: [".flow-header-overlay__wrapper{display:flex;flex-direction:column;width:460px;max-height:600px}.flow-header-overlay__wrapper .close-icon{cursor:pointer}.flow-header-overlay__title{display:flex;justify-content:space-between;align-items:center;margin:0 0 16px}.empty-state{color:var(--vl-text-color-deep-accent)}.scrollable-wrapper{overflow:auto}.product{display:grid;grid-template-columns:auto 60px 80px 80px;padding:16px 0}.product:not(.header){border-bottom:1px solid var(--vl-border-color)}.product.header{color:var(--vl-text-color-deep-accent)}.product__info{display:flex;grid-gap:16px;gap:16px}.product__image-wrapper{flex-shrink:0;height:64px;width:64px;display:flex;justify-content:center;align-items:center;background:var(--vl-primary-nav-overlay-bg);border-radius:4px}.product__image{background-size:contain;background-repeat:no-repeat;background-position:center;height:calc(100% - 12px);width:calc(100% - 12px)}.product .qty-control ::ng-deep .p-inputnumber-input{align-self:flex-start;text-align:right;width:100%}.word-break{word-break:break-word}.no-image-icon{color:#b4d1ef;height:18px;width:18px}\n"], components: [{ type: i4.OverlayPanel, selector: "p-overlayPanel", inputs: ["dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { type: i5.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass"], outputs: ["onClick", "onFocus", "onBlur"] }, { type: i6.InputNumber, selector: "p-inputNumber", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "disabled"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown"] }], directives: [{ type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { type: i3$1.LetDirective, selector: "[vlLet]", inputs: ["vlLet"] }, { type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i7.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i7.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
303
+ HeaderCartOverlayComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: HeaderCartOverlayComponent, selector: "vl-header-cart-overlay", inputs: { products: "products" }, viewQueries: [{ propertyName: "overlayPanel", first: true, predicate: OverlayPanel, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<p-overlayPanel\n styleClass=\"navigation-settings-overlay flow-header-overlay center\"\n showTransitionOptions=\"0ms\"\n hideTransitionOptions=\"0ms\"\n>\n <ng-template pTemplate>\n <div class=\"flow-header-overlay__wrapper\" *vlLet=\"readonlyProductId$ | async as readonlyProductId\">\n <ng-container *ngIf=\"products.length > 0; else empty\">\n <h2 class=\"flow-header-overlay__title\">\n <span>Products ({{ products.length }})</span>\n <i class=\"vl-icon vl-icon-close close-icon\" (click)=\"overlayPanel.hide()\"></i>\n </h2>\n\n <div class=\"product header\">\n <span>Product</span>\n <span class=\"text-right\">Qty</span>\n <span class=\"text-right\">MRR</span>\n <span class=\"text-right\">NRR</span>\n </div>\n\n <div class=\"scrollable-wrapper\">\n <div class=\"product\" *ngFor=\"let product of products\">\n <div class=\"product__info\">\n <div class=\"product__image-wrapper\">\n <div\n *ngIf=\"getImageUrl(product.productId) | async as imageUrl; else noImage\"\n class=\"product__image\"\n [ngStyle]=\"{ 'background-image': 'url(' + imageUrl + ')' }\"\n ></div>\n </div>\n <div class=\"flex flex-column justify-content-center\">\n <div class=\"word-break\">{{ product.name }}</div>\n <div>\n <p-button\n label=\"Configure\"\n [disabled]=\"!product.configurable || readonlyProductId === product.productId\"\n styleClass=\"p-button-link p-button-sm pl-0\"\n (onClick)=\"navigateToProductConfiguration(product.productId, product.id)\"\n ></p-button>\n <p-button\n label=\"Delete\"\n [disabled]=\"readonlyProductId === product.productId\"\n styleClass=\"p-button-link p-button-sm p-button-danger pl-0 pr-0\"\n (onClick)=\"deleteHandler(product)\"\n ></p-button>\n </div>\n </div>\n </div>\n\n <span>\n <p-inputNumber\n *ngIf=\"form.controls[product.id] as control\"\n class=\"qty-control\"\n [formControl]=\"$any(control)\"\n [min]=\"1\"\n [required]=\"true\"\n (onBlur)=\"controlBlurHandler(product)\"\n ></p-inputNumber>\n </span>\n <span class=\"text-right pt-3\">$0.00</span>\n <span class=\"text-right pt-3\">$0.00</span>\n </div>\n\n <ng-template #noImage>\n <i class=\"vl-icon vl-icon-no-image no-image-icon\"></i>\n </ng-template>\n </div>\n\n <div class=\"flex justify-content-end mt-3\">\n <p-button\n label=\"Clear cart\"\n styleClass=\"p-button-link p-button-sm p-button-danger pl-0 pr-0\"\n [disabled]=\"readonlyProductId\"\n (onClick)=\"deleteAllHandler()\"\n ></p-button>\n </div>\n </ng-container>\n\n <ng-template #empty>\n <h2 class=\"flow-header-overlay__title\">\n <span>Empty Cart</span>\n <i class=\"vl-icon vl-icon-close close-icon\" (click)=\"overlayPanel.hide()\"></i>\n </h2>\n\n <span class=\"empty-state\">There are no products added to the Shopping Cart yet.</span>\n </ng-template>\n </div>\n </ng-template>\n</p-overlayPanel>\n", styles: [".flow-header-overlay__wrapper{display:flex;flex-direction:column;width:460px;max-height:600px}.flow-header-overlay__wrapper .close-icon{cursor:pointer}.flow-header-overlay__title{display:flex;justify-content:space-between;align-items:center;margin:0 0 16px}.empty-state{color:var(--vl-text-color-deep-accent)}.scrollable-wrapper{overflow:auto}.product{display:grid;grid-template-columns:auto 60px 80px 80px;padding:16px 0}.product:not(.header){border-bottom:1px solid var(--vl-border-color)}.product.header{color:var(--vl-text-color-deep-accent)}.product__info{display:flex;grid-gap:16px;gap:16px}.product__image-wrapper{flex-shrink:0;height:64px;width:64px;display:flex;justify-content:center;align-items:center;background:var(--vl-primary-nav-overlay-bg);border-radius:4px}.product__image{background-size:contain;background-repeat:no-repeat;background-position:center;height:calc(100% - 12px);width:calc(100% - 12px)}.product .qty-control ::ng-deep .p-inputnumber-input{align-self:flex-start;text-align:right;width:100%}.word-break{word-break:break-word}.no-image-icon{color:#b4d1ef;height:18px;width:18px}\n"], components: [{ type: i4.OverlayPanel, selector: "p-overlayPanel", inputs: ["dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { type: i5.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass"], outputs: ["onClick", "onFocus", "onBlur"] }, { type: i6.InputNumber, selector: "p-inputNumber", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "disabled"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown"] }], directives: [{ type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { type: i3.LetDirective, selector: "[vlLet]", inputs: ["vlLet"] }, { type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i9.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i7.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i7.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
296
304
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: HeaderCartOverlayComponent, decorators: [{
297
305
  type: Component,
298
306
  args: [{
@@ -389,6 +397,14 @@ class FlowDialogService {
389
397
  primaryButton: 'OK',
390
398
  });
391
399
  }
400
+ showUnsavedChangesDialog() {
401
+ return this.show({
402
+ title: 'Unsaved Changes',
403
+ description: 'Are you sure you want to leave this page and discard your unsaved changes?',
404
+ primaryButton: 'Keep Editing',
405
+ secondaryButton: 'Discard Changes',
406
+ });
407
+ }
392
408
  }
393
409
  FlowDialogService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowDialogService, deps: [{ token: i1.DialogService }, { token: i2.ContextService }], target: i0.ɵɵFactoryTarget.Injectable });
394
410
  FlowDialogService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowDialogService });
@@ -406,6 +422,7 @@ class FlowHeaderComponent {
406
422
  this.flowConfiguration = flowConfiguration;
407
423
  this.routerService = routerService;
408
424
  this.dialogService = dialogService;
425
+ this.disabledActionButtonTooltip = 'Available from the Shopping Cart';
409
426
  this.objectDetails$ = new BehaviorSubject({});
410
427
  this.isSaveInProgress$ = new BehaviorSubject(false);
411
428
  this.destroyed$ = new Subject();
@@ -547,7 +564,7 @@ class FlowHeaderComponent {
547
564
  }
548
565
  }
549
566
  FlowHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowHeaderComponent, deps: [{ token: i2.ContextService }, { token: i2.QuoteDraftService }, { token: i1$3.QuoteApiService }, { token: i1$3.SalesforceApiService }, { token: i2.FlowConfigurationService }, { token: FlowRouterService }, { token: FlowDialogService }], target: i0.ɵɵFactoryTarget.Component });
550
- FlowHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: FlowHeaderComponent, selector: "vl-flow-header", ngImport: i0, template: "<div class=\"flow-info\" *vlLet=\"objectDetails$ | async as details\">\n <nav class=\"nav-item nav-back\" (click)=\"back()\">\n <i class=\"nav-icon vl-icon vl-icon-arrow-left\"></i>\n\n <span> Back </span>\n <span *ngIf=\"objectName\" class=\"object-name\">&nbsp;To {{ objectName }}</span>\n </nav>\n\n <ng-container *ngIf=\"isAccountMode\">\n <span class=\"dot-separator\"></span>\n\n <span>Account name</span>\n\n <nav class=\"account-name\" [pTooltip]=\"contextProperties.Name ?? ''\" tooltipPosition=\"bottom\" [showDelay]=\"1000\">\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(contextProperties.Id)\">{{ contextProperties.Name }}</a>\n </nav>\n </ng-container>\n\n <ng-container *ngIf=\"isQuoteMode\">\n <span class=\"dot-separator\"></span>\n\n <span>Quote #{{ details.quoteNumber }}</span>\n\n <span class=\"dot-separator\"></span>\n\n <nav class=\"nav-item\" (click)=\"quoteDetails.toggle($event)\">\n <span>{{ contextProperties.Status }}</span>\n\n <i *ngIf=\"!quoteDetails.overlayVisible\" class=\"vl-icon vl-icon-chevron-down icon-with-margin\"></i>\n <i *ngIf=\"quoteDetails.overlayVisible\" class=\"vl-icon vl-icon-chevron-up icon-with-margin\"></i>\n </nav>\n\n <p-overlayPanel styleClass=\"navigation-settings-overlay flow-header-overlay center\" #quoteDetails>\n <ng-template pTemplate>\n <div class=\"flow-header-overlay__wrapper\">\n <h2 class=\"flow-header-overlay__title\">\n <span>Quote Information</span>\n <i class=\"vl-icon vl-icon-close close-icon\" (click)=\"quoteDetails.hide()\"></i>\n </h2>\n\n <ul class=\"info-list\">\n <li class=\"info-list__row\">\n <span>Account Name:</span>\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(details.accountId)\">{{ details.accountName }}</a>\n </li>\n <li class=\"info-list__row\">\n <span>Opportunity Name:</span>\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(details.opportunityId)\">{{\n details.opportunityName\n }}</a>\n </li>\n <li class=\"info-list__row\">\n <span>Quote Name:</span>\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(details.quoteId)\">{{ details.quoteName }}</a>\n </li>\n </ul>\n </div>\n </ng-template>\n </p-overlayPanel>\n </ng-container>\n</div>\n\n<div class=\"flow-navigation\">\n <nav class=\"nav-item\" [ngClass]=\"{ active: isCatalogRoute$ | async }\" (click)=\"navigateToCatalog()\">Catalog</nav>\n <nav class=\"nav-item disabled\" [ngClass]=\"{ active: isConfigurationRoute$ | async }\">Configurator</nav>\n <ng-container *vlLet=\"products$ | async as products\">\n <nav class=\"nav-item\" [ngClass]=\"{ active: isCartRoute$ | async }\" (click)=\"navigateToShoppingCart()\">\n Shopping Cart ({{ products.length }})\n </nav>\n\n <nav class=\"nav-popover-toggle active\" (click)=\"cart?.overlayPanel?.toggle($event)\">\n <i *ngIf=\"!cart?.overlayPanel?.overlayVisible\" class=\"vl-icon vl-icon-chevron-down icon-with-margin\"></i>\n <i *ngIf=\"cart?.overlayPanel?.overlayVisible\" class=\"vl-icon vl-icon-chevron-up icon-with-margin\"></i>\n </nav>\n\n <vl-header-cart-overlay #cart [products]=\"products\"></vl-header-cart-overlay>\n </ng-container>\n</div>\n\n<div class=\"flow-controls\" *vlLet=\"objectDetails$ | async as details\">\n <ng-container *ngIf=\"isQuoteMode\">\n <span *ngIf=\"details.priceListName\">{{ details.priceListName }}</span>\n <span *ngIf=\"contextProperties.StartDate\">{{ contextProperties.StartDate | date: 'MM.dd.yyyy' }}</span>\n\n <span class=\"slash-separator\"></span>\n\n <span>MRR: <span class=\"font-semibold\">$0.00</span></span>\n <span>NRR: <span class=\"font-semibold\">$0.00</span></span>\n </ng-container>\n\n <p-button label=\"Generate Doc\" styleClass=\"p-button-outlined\"></p-button>\n <p-button\n label=\"Save\"\n styleClass=\"p-button-outlined\"\n (onClick)=\"saveButtonClickHandler()\"\n [loading]=\"(isSaveInProgress$ | async) === true\"\n ></p-button>\n <p-button label=\"Submit For Approval\" styleClass=\"p-button\"></p-button>\n</div>\n", styles: [":host{display:flex;align-items:center;height:48px;width:100%;background-color:var(--vl-primary-color);color:#fff;padding:0 32px;flex-shrink:0}::ng-deep .p-overlaypanel.flow-header-overlay .p-overlaypanel-content{background-color:#fff;padding:16px}::ng-deep .p-overlaypanel.flow-header-overlay.left:before{left:6px!important}::ng-deep .p-overlaypanel.flow-header-overlay.right:before{right:6px!important}::ng-deep .p-overlaypanel.flow-header-overlay.left .p-overlaypanel-content{margin-left:-16px}::ng-deep .p-overlaypanel.flow-header-overlay.right .p-overlaypanel-content{margin-right:-16px}::ng-deep .p-overlaypanel.flow-header-overlay:before{background-color:#fff}:host ::ng-deep .p-button{padding:5px 15px;font-size:12px}:host ::ng-deep .p-button{color:var(--vl-primary-color);background-color:#fff;border-color:#fff}:host ::ng-deep .p-button:enabled:hover{background-color:var(--vl-primary-color);color:#fff;border-color:#fff}:host ::ng-deep .p-button.p-button-outlined{background-color:var(--vl-primary-color);color:#fff;border-color:#fff}:host ::ng-deep .p-button.p-button-outlined:enabled:hover{color:var(--vl-primary-color);background-color:#fff;border-color:#fff}:host ::ng-deep .p-button.p-button-loading .p-button-loading-icon{position:absolute;left:calc(50% - 5px)}:host ::ng-deep .p-button.p-button-loading .p-button-label{opacity:0;margin:0}.vl-icon{display:inline-block}.flow-info{flex-shrink:0;display:flex;grid-gap:8px;gap:8px;align-items:center}.flow-info .nav-popover-toggle{margin-left:-8px}.flow-info .object-name{text-transform:capitalize}.flow-info .nav-back{font-weight:bold}.flow-info .nav-item:not(.disabled):hover,.flow-info .nav-popover-toggle:not(.disabled):hover{opacity:.6}nav{display:flex;align-items:center;cursor:pointer;padding:4px 0}nav.disabled{opacity:.6;cursor:default}nav .nav-icon{margin-right:10px}nav .icon-with-margin{margin:0 4px}nav a{color:#fff}nav.account-name{margin-left:4px;display:block;max-width:200px;overflow:hidden;text-overflow:ellipsis}nav.nav-popover-toggle{width:24px;display:flex;justify-content:center}nav.nav-popover-toggle i{pointer-events:none;margin:0}nav i{pointer-events:none}.dot-separator:after{content:\"\";display:block;width:4px;height:4px;border-radius:50%;background:#fff}.slash-separator:after{content:\"\";display:block;background:#fff;width:1px;height:16px}.flow-header-overlay__wrapper{width:360px}.flow-header-overlay__wrapper .close-icon{cursor:pointer}.flow-header-overlay__wrapper .info-list{list-style:none;padding:0;font-size:12px}.flow-header-overlay__wrapper .info-list__row{padding:8px 0;display:flex;justify-content:space-between}.flow-header-overlay__title{display:flex;justify-content:space-between;align-items:center;margin:0 0 24px}.flow-navigation{flex-grow:1;display:flex;grid-gap:16px;gap:16px;justify-content:center;font-weight:600}.flow-navigation .cart-nav-container{display:flex}.flow-navigation .nav-popover-toggle{margin-left:-14px}.flow-navigation .nav-item,.flow-navigation .nav-popover-toggle{opacity:.6}.flow-navigation .nav-item.active,.flow-navigation .nav-item:not(.disabled):hover,.flow-navigation .nav-popover-toggle.active,.flow-navigation .nav-popover-toggle:not(.disabled):hover{opacity:1}.flow-controls{flex-shrink:0;display:flex;align-items:center;grid-gap:8px;gap:8px}\n"], components: [{ type: i4.OverlayPanel, selector: "p-overlayPanel", inputs: ["dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { type: HeaderCartOverlayComponent, selector: "vl-header-cart-overlay", inputs: ["products"] }, { type: i5.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass"], outputs: ["onClick", "onFocus", "onBlur"] }], directives: [{ type: i3$1.LetDirective, selector: "[vlLet]", inputs: ["vlLet"] }, { type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i10.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], pipes: { "async": i9.AsyncPipe, "date": i9.DatePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
567
+ FlowHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: FlowHeaderComponent, selector: "vl-flow-header", ngImport: i0, template: "<div class=\"flow-info\" *vlLet=\"objectDetails$ | async as details\">\n <nav class=\"nav-item nav-back\" (click)=\"back()\">\n <i class=\"nav-icon vl-icon vl-icon-arrow-left\"></i>\n\n <span> Back </span>\n <span *ngIf=\"objectName\" class=\"object-name\">&nbsp;To {{ objectName }}</span>\n </nav>\n\n <ng-container *ngIf=\"isAccountMode\">\n <span class=\"dot-separator\"></span>\n\n <span>Account name</span>\n\n <nav class=\"account-name\" [pTooltip]=\"contextProperties.Name ?? ''\" tooltipPosition=\"bottom\" [showDelay]=\"1000\">\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(contextProperties.Id)\">{{ contextProperties.Name }}</a>\n </nav>\n </ng-container>\n\n <ng-container *ngIf=\"isQuoteMode\">\n <span class=\"dot-separator\"></span>\n\n <span>Quote #{{ details.quoteNumber }}</span>\n\n <span class=\"dot-separator\"></span>\n\n <nav class=\"nav-item\" (click)=\"quoteDetails.toggle($event)\">\n <span>{{ contextProperties.Status }}</span>\n\n <i *ngIf=\"!quoteDetails.overlayVisible\" class=\"vl-icon vl-icon-chevron-down icon-with-margin\"></i>\n <i *ngIf=\"quoteDetails.overlayVisible\" class=\"vl-icon vl-icon-chevron-up icon-with-margin\"></i>\n </nav>\n\n <p-overlayPanel styleClass=\"navigation-settings-overlay flow-header-overlay center\" #quoteDetails>\n <ng-template pTemplate>\n <div class=\"flow-header-overlay__wrapper\">\n <h2 class=\"flow-header-overlay__title\">\n <span>Quote Information</span>\n <i class=\"vl-icon vl-icon-close close-icon\" (click)=\"quoteDetails.hide()\"></i>\n </h2>\n\n <ul class=\"info-list\">\n <li class=\"info-list__row\">\n <span>Account Name:</span>\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(details.accountId)\">{{ details.accountName }}</a>\n </li>\n <li class=\"info-list__row\">\n <span>Opportunity Name:</span>\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(details.opportunityId)\">{{\n details.opportunityName\n }}</a>\n </li>\n <li class=\"info-list__row\">\n <span>Quote Name:</span>\n <a target=\"_blank\" [href]=\"getSalesforceObjectLink(details.quoteId)\">{{ details.quoteName }}</a>\n </li>\n </ul>\n </div>\n </ng-template>\n </p-overlayPanel>\n </ng-container>\n</div>\n\n<div class=\"flow-navigation\">\n <nav class=\"nav-item\" [ngClass]=\"{ active: isCatalogRoute$ | async }\" (click)=\"navigateToCatalog()\">Catalog</nav>\n <nav class=\"nav-item disabled\" [ngClass]=\"{ active: isConfigurationRoute$ | async }\">Configurator</nav>\n <ng-container *vlLet=\"products$ | async as products\">\n <nav class=\"nav-item\" [ngClass]=\"{ active: isCartRoute$ | async }\" (click)=\"navigateToShoppingCart()\">\n Shopping Cart ({{ products.length }})\n </nav>\n\n <nav class=\"nav-popover-toggle active\" (click)=\"cart?.overlayPanel?.toggle($event)\">\n <i *ngIf=\"!cart?.overlayPanel?.overlayVisible\" class=\"vl-icon vl-icon-chevron-down icon-with-margin\"></i>\n <i *ngIf=\"cart?.overlayPanel?.overlayVisible\" class=\"vl-icon vl-icon-chevron-up icon-with-margin\"></i>\n </nav>\n\n <vl-header-cart-overlay #cart [products]=\"products\"></vl-header-cart-overlay>\n </ng-container>\n</div>\n\n<div class=\"flow-controls\" *vlLet=\"objectDetails$ | async as details\">\n <ng-container *ngIf=\"isQuoteMode\">\n <span *ngIf=\"details.priceListName\">{{ details.priceListName }}</span>\n <span *ngIf=\"contextProperties.StartDate\">{{ contextProperties.StartDate | date: 'MM.dd.yyyy' }}</span>\n\n <span class=\"slash-separator\"></span>\n\n <span>MRR: <span class=\"font-semibold\">$0.00</span></span>\n <span>NRR: <span class=\"font-semibold\">$0.00</span></span>\n </ng-container>\n\n <ng-container *vlLet=\"isCartRoute$ | async as isCartRoute\">\n <p-button\n label=\"Generate Doc\"\n [disabled]=\"!isCartRoute\"\n tooltipPosition=\"bottom\"\n [showDelay]=\"300\"\n [pTooltip]=\"isCartRoute ? '' : disabledActionButtonTooltip\"\n styleClass=\"p-button-outlined\"\n ></p-button>\n <p-button\n label=\"Save\"\n styleClass=\"p-button-outlined\"\n (onClick)=\"saveButtonClickHandler()\"\n [loading]=\"(isSaveInProgress$ | async) === true\"\n ></p-button>\n <p-button\n label=\"Submit For Approval\"\n [disabled]=\"!isCartRoute\"\n tooltipPosition=\"bottom\"\n [showDelay]=\"300\"\n [pTooltip]=\"isCartRoute ? '' : disabledActionButtonTooltip\"\n styleClass=\"p-button\"\n ></p-button>\n </ng-container>\n</div>\n", styles: [":host{display:flex;align-items:center;height:48px;width:100%;background-color:var(--vl-primary-color);color:#fff;padding:0 32px;flex-shrink:0}::ng-deep .p-overlaypanel.flow-header-overlay .p-overlaypanel-content{background-color:#fff;padding:16px}::ng-deep .p-overlaypanel.flow-header-overlay.left:before{left:6px!important}::ng-deep .p-overlaypanel.flow-header-overlay.right:before{right:6px!important}::ng-deep .p-overlaypanel.flow-header-overlay.left .p-overlaypanel-content{margin-left:-16px}::ng-deep .p-overlaypanel.flow-header-overlay.right .p-overlaypanel-content{margin-right:-16px}::ng-deep .p-overlaypanel.flow-header-overlay:before{background-color:#fff}:host ::ng-deep .p-button{padding:5px 15px;font-size:12px}:host ::ng-deep .p-button{color:var(--vl-primary-color);background-color:#fff;border-color:#fff}:host ::ng-deep .p-button:enabled:hover{background-color:var(--vl-primary-color);color:#fff;border-color:#fff}:host ::ng-deep .p-button.p-button-outlined{background-color:var(--vl-primary-color);color:#fff;border-color:#fff}:host ::ng-deep .p-button.p-button-outlined:enabled:hover{color:var(--vl-primary-color);background-color:#fff;border-color:#fff}:host ::ng-deep .p-button.p-button-loading .p-button-loading-icon{position:absolute;left:calc(50% - 5px)}:host ::ng-deep .p-button.p-button-loading .p-button-label{opacity:0;margin:0}.vl-icon{display:inline-block}.flow-info{flex-shrink:0;display:flex;grid-gap:8px;gap:8px;align-items:center}.flow-info .nav-popover-toggle{margin-left:-8px}.flow-info .object-name{text-transform:capitalize}.flow-info .nav-back{font-weight:bold}.flow-info .nav-item:not(.disabled):hover,.flow-info .nav-popover-toggle:not(.disabled):hover{opacity:.6}nav{display:flex;align-items:center;cursor:pointer;padding:4px 0}nav.disabled{opacity:.6;cursor:default}nav .nav-icon{margin-right:10px}nav .icon-with-margin{margin:0 4px}nav a{color:#fff}nav.account-name{margin-left:4px;display:block;max-width:200px;overflow:hidden;text-overflow:ellipsis}nav.nav-popover-toggle{width:24px;display:flex;justify-content:center}nav.nav-popover-toggle i{pointer-events:none;margin:0}nav i{pointer-events:none}.dot-separator:after{content:\"\";display:block;width:4px;height:4px;border-radius:50%;background:#fff}.slash-separator:after{content:\"\";display:block;background:#fff;width:1px;height:16px}.flow-header-overlay__wrapper{width:360px}.flow-header-overlay__wrapper .close-icon{cursor:pointer}.flow-header-overlay__wrapper .info-list{list-style:none;padding:0;font-size:12px}.flow-header-overlay__wrapper .info-list__row{padding:8px 0;display:flex;justify-content:space-between}.flow-header-overlay__title{display:flex;justify-content:space-between;align-items:center;margin:0 0 24px}.flow-navigation{flex-grow:1;display:flex;grid-gap:16px;gap:16px;justify-content:center;font-weight:600}.flow-navigation .cart-nav-container{display:flex}.flow-navigation .nav-popover-toggle{margin-left:-14px}.flow-navigation .nav-item,.flow-navigation .nav-popover-toggle{opacity:.6}.flow-navigation .nav-item.active,.flow-navigation .nav-item:not(.disabled):hover,.flow-navigation .nav-popover-toggle.active,.flow-navigation .nav-popover-toggle:not(.disabled):hover{opacity:1}.flow-controls{flex-shrink:0;display:flex;align-items:center;grid-gap:8px;gap:8px}\n"], components: [{ type: i4.OverlayPanel, selector: "p-overlayPanel", inputs: ["dismissable", "showCloseIcon", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { type: HeaderCartOverlayComponent, selector: "vl-header-cart-overlay", inputs: ["products"] }, { type: i5.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass"], outputs: ["onClick", "onFocus", "onBlur"] }], directives: [{ type: i3.LetDirective, selector: "[vlLet]", inputs: ["vlLet"] }, { type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i10.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { type: i2$1.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { type: i9.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], pipes: { "async": i9.AsyncPipe, "date": i9.DatePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
551
568
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowHeaderComponent, decorators: [{
552
569
  type: Component,
553
570
  args: [{
@@ -573,31 +590,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
573
590
  }] });
574
591
 
575
592
  class FlowService {
576
- constructor(integrationState, flowRouterService) {
593
+ constructor(integrationState, flowRouterService, quoteDraftService, configurationService, flowConfigurationService) {
577
594
  this.integrationState = integrationState;
578
595
  this.flowRouterService = flowRouterService;
596
+ this.quoteDraftService = quoteDraftService;
597
+ this.configurationService = configurationService;
598
+ this.flowConfigurationService = flowConfigurationService;
579
599
  this.cleanup$ = new Subject();
580
600
  }
581
601
  initSubscriptions() {
582
602
  this.integrationState
583
- .listen$('FLOW_CONFIGURE_PRODUCT')
584
- .pipe(takeUntil(this.cleanup$))
585
- .subscribe(payload => {
586
- if (!(payload === null || payload === void 0 ? void 0 : payload.productId)) {
587
- return;
603
+ .listen$(FlowAction.FLOW_CONFIGURE_PRODUCT)
604
+ .pipe(takeUntil(this.cleanup$), tap(payload => {
605
+ var _a, _b, _c;
606
+ const productId = (_a = payload.productId) !== null && _a !== void 0 ? _a : (_c = (_b = this.quoteDraftService.quoteSnapshot) === null || _b === void 0 ? void 0 : _b.currentState.find(li => li.id === payload.lineItemId)) === null || _c === void 0 ? void 0 : _c.productId;
607
+ if (productId) {
608
+ this.flowRouterService.navigateToProductConfiguration(productId, payload.lineItemId);
588
609
  }
589
- this.flowRouterService.navigateToProductConfiguration(payload.productId);
590
- });
610
+ else {
611
+ console.warn("Parameter 'productId' is needed to start configuration");
612
+ }
613
+ }))
614
+ .subscribe();
615
+ this.integrationState
616
+ .listen$(FlowAction.FLOW_NAVIGATE_BACK)
617
+ .pipe(takeUntil(this.cleanup$), tap(() => this.flowRouterService.navigateBack()))
618
+ .subscribe();
619
+ this.integrationState
620
+ .listen$(FlowAction.FLOW_APPLY_PRODUCT_CONFIGURATION)
621
+ .pipe(takeUntil(this.cleanup$), switchMap(() => {
622
+ const lineItem = this.configurationService.getSnapshot();
623
+ if (!lineItem) {
624
+ return of(undefined);
625
+ }
626
+ const currentState = this.flowConfigurationService.getSnapshot();
627
+ const updatedState = currentState.map(li => (li.id === lineItem.id ? lineItem : li));
628
+ return this.flowConfigurationService.calculate$(updatedState);
629
+ }), tap(() => {
630
+ this.configurationService.hasUnsavedChanges = false;
631
+ this.flowRouterService.navigateToShoppingCart();
632
+ }))
633
+ .subscribe();
591
634
  }
592
635
  cleanup() {
593
636
  this.cleanup$.next();
594
637
  }
595
638
  }
596
- FlowService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowService, deps: [{ token: i1$4.IntegrationState }, { token: FlowRouterService }], target: i0.ɵɵFactoryTarget.Injectable });
639
+ FlowService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowService, deps: [{ token: i4$1.IntegrationState }, { token: FlowRouterService }, { token: i2.QuoteDraftService }, { token: i2.ConfigurationService }, { token: i2.FlowConfigurationService }], target: i0.ɵɵFactoryTarget.Injectable });
597
640
  FlowService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowService });
598
641
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowService, decorators: [{
599
642
  type: Injectable
600
- }], ctorParameters: function () { return [{ type: i1$4.IntegrationState }, { type: FlowRouterService }]; } });
643
+ }], ctorParameters: function () { return [{ type: i4$1.IntegrationState }, { type: FlowRouterService }, { type: i2.QuoteDraftService }, { type: i2.ConfigurationService }, { type: i2.FlowConfigurationService }]; } });
601
644
 
602
645
  class FlowComponent {
603
646
  constructor(routerService, context, flowService) {
@@ -613,7 +656,7 @@ class FlowComponent {
613
656
  }
614
657
  }
615
658
  FlowComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowComponent, deps: [{ token: FlowRouterService }, { token: i2.ContextService }, { token: FlowService }], target: i0.ɵɵFactoryTarget.Component });
616
- FlowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: FlowComponent, selector: "vl-flow", ngImport: i0, template: "<vl-flow-header *ngIf=\"showHeader$ | async\"></vl-flow-header>\n\n<div class=\"flow-content\">\n <div class=\"loading-overlay\" *ngIf=\"isLoading$ | async\">\n <vl-loader label=\"LOADING\"></vl-loader>\n </div>\n\n <router-outlet></router-outlet>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%}.flow-content{flex-grow:1;position:relative;overflow:hidden}.loading-overlay{position:absolute;height:100%;width:100%;left:0;right:0;top:0;bottom:0;background-color:#ffffff80;z-index:4}\n"], components: [{ type: FlowHeaderComponent, selector: "vl-flow-header" }, { type: i3$1.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate"], exportAs: ["outlet"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
659
+ FlowComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: FlowComponent, selector: "vl-flow", ngImport: i0, template: "<vl-flow-header *ngIf=\"showHeader$ | async\"></vl-flow-header>\n\n<div class=\"flow-content\">\n <div class=\"loading-overlay\" *ngIf=\"isLoading$ | async\">\n <vl-loader label=\"LOADING\"></vl-loader>\n </div>\n\n <router-outlet></router-outlet>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%}.flow-content{flex-grow:1;position:relative;overflow:hidden}.loading-overlay{position:absolute;height:100%;width:100%;left:0;right:0;top:0;bottom:0;background-color:#ffffff80;z-index:4}\n"], components: [{ type: FlowHeaderComponent, selector: "vl-flow-header" }, { type: i3.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate"], exportAs: ["outlet"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
617
660
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowComponent, decorators: [{
618
661
  type: Component,
619
662
  args: [{
@@ -682,6 +725,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
682
725
  type: Injectable
683
726
  }], ctorParameters: function () { return [{ type: i1$1.Router }, { type: FlowRouterService }]; } });
684
727
 
728
+ class ProductUnloadGuard {
729
+ constructor(contextService, configurationService, flowDialogService) {
730
+ this.contextService = contextService;
731
+ this.configurationService = configurationService;
732
+ this.flowDialogService = flowDialogService;
733
+ }
734
+ canDeactivate() {
735
+ let observable = of(true);
736
+ if (!this.contextService.isStandalone && this.configurationService.hasUnsavedChanges) {
737
+ observable = this.flowDialogService.showUnsavedChangesDialog().pipe(map(confirmed => !confirmed));
738
+ }
739
+ return observable.pipe(tap(unload => {
740
+ if (unload) {
741
+ this.contextService.update({ properties: { productId: undefined, lineItemId: undefined } });
742
+ this.configurationService.reset();
743
+ }
744
+ }));
745
+ }
746
+ }
747
+ ProductUnloadGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ProductUnloadGuard, deps: [{ token: i2.ContextService }, { token: i2.ConfigurationService }, { token: FlowDialogService }], target: i0.ɵɵFactoryTarget.Injectable });
748
+ ProductUnloadGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ProductUnloadGuard });
749
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ProductUnloadGuard, decorators: [{
750
+ type: Injectable
751
+ }], ctorParameters: function () { return [{ type: i2.ContextService }, { type: i2.ConfigurationService }, { type: FlowDialogService }]; } });
752
+
685
753
  class RootGuard {
686
754
  constructor(router, routerService) {
687
755
  this.router = router;
@@ -810,8 +878,8 @@ class CatalogComponent {
810
878
  }));
811
879
  }
812
880
  }
813
- CatalogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: CatalogComponent, deps: [{ token: i1$3.UITemplatesApiService }, { token: i2.ContextService }, { token: i0.ChangeDetectorRef }, { token: i3$1.ToastService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
814
- CatalogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: CatalogComponent, selector: "vl-flow-catalog", ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\n <vl-loader *ngIf=\"state.loading; else content\" [label]=\"'Loading UI'\"></vl-loader>\n\n <ng-template #content>\n <ng-container *ngIf=\"!state.failure\">\n <vl-cms-preview [uiDefinition]=\"uiDefinition\"></vl-cms-preview>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [""], components: [{ type: i3$1.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }, { type: i1$4.PreviewComponent, selector: "vl-cms-preview", inputs: ["modelId", "uiDefinition", "clearState"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
881
+ CatalogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: CatalogComponent, deps: [{ token: i1$3.UITemplatesApiService }, { token: i2.ContextService }, { token: i0.ChangeDetectorRef }, { token: i3.ToastService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
882
+ CatalogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: CatalogComponent, selector: "vl-flow-catalog", ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\n <vl-loader *ngIf=\"state.loading; else content\" [label]=\"'Loading UI'\"></vl-loader>\n\n <ng-template #content>\n <ng-container *ngIf=\"!state.failure\">\n <vl-cms-preview [uiDefinition]=\"uiDefinition\"></vl-cms-preview>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [""], components: [{ type: i3.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }, { type: i4$1.PreviewComponent, selector: "vl-cms-preview", inputs: ["modelId", "uiDefinition", "clearState"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
815
883
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: CatalogComponent, decorators: [{
816
884
  type: Component,
817
885
  args: [{
@@ -820,7 +888,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
820
888
  styleUrls: ['./catalog.component.scss'],
821
889
  changeDetection: ChangeDetectionStrategy.OnPush,
822
890
  }]
823
- }], ctorParameters: function () { return [{ type: i1$3.UITemplatesApiService }, { type: i2.ContextService }, { type: i0.ChangeDetectorRef }, { type: i3$1.ToastService }, { type: undefined, decorators: [{
891
+ }], ctorParameters: function () { return [{ type: i1$3.UITemplatesApiService }, { type: i2.ContextService }, { type: i0.ChangeDetectorRef }, { type: i3.ToastService }, { type: undefined, decorators: [{
824
892
  type: Optional
825
893
  }, {
826
894
  type: Inject,
@@ -881,7 +949,7 @@ class DebugComponent {
881
949
  }
882
950
  }
883
951
  DebugComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: DebugComponent, deps: [{ token: i1$3.FlowsApiService }, { token: i1$1.Router }, { token: i1$1.ActivatedRoute }, { token: i2.ContextService }, { token: i2.FlowConfigurationService }, { token: i2.QuoteDraftService }], target: i0.ɵɵFactoryTarget.Component });
884
- DebugComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: DebugComponent, selector: "vl-flow-debug", ngImport: i0, template: "<form [formGroup]=\"form\">\n <div class=\"fields-container\">\n <div class=\"field\">\n <label>SF Object ID</label>\n <input formControlName=\"id\" pInputText type=\"text\" />\n </div>\n\n <div class=\"field\">\n <label>SF Object Name</label>\n <p-dropdown\n appendTo=\"body\"\n formControlName=\"name\"\n [autoDisplayFirst]=\"false\"\n [options]=\"objectNames\"\n ></p-dropdown>\n </div>\n </div>\n\n <p-button\n styleClass=\"p-button-primary\"\n label=\"Run Flow\"\n [disabled]=\"!form.value.id || !selectedFlow\"\n (onClick)=\"runFlow()\"\n ></p-button>\n</form>\n\n<table>\n <thead>\n <tr>\n <th [width]=\"30\"></th>\n <th [width]=\"160\">ID</th>\n <th [width]=\"160\">Entry Path</th>\n <th>QueryParams</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let flow of flows$ | async\" (click)=\"selectedFlow = flow\">\n <td><p-radioButton [inputId]=\"flow.id\" name=\"flow\" [value]=\"flow\" [(ngModel)]=\"selectedFlow\"></p-radioButton></td>\n <td>{{ flow.id }}</td>\n <td>{{ flow.entryPath }}</td>\n <td>{{ flow.queryParamsStr }}</td>\n </tr>\n </tbody>\n</table>\n", styles: [":host{display:block;padding:24px 54px}form{display:flex;align-items:center;justify-content:space-between}.fields-container{display:flex;grid-gap:24px;gap:24px}.field{display:flex;flex-direction:column;width:200px;flex-shrink:0}:host ::ng-deep .p-dropdown{width:100%}table{width:100%;border-collapse:collapse}tr{cursor:pointer}tr:hover{background-color:#f0f5fa}th{text-align:left;font-weight:600}th,td{padding:0 10px;height:30px;border-bottom:1px solid var(--vl-border-color);margin-right:16px}\n"], components: [{ type: i4$1.Dropdown, selector: "p-dropdown", inputs: ["scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "filterPlaceholder", "filterLocale", "inputId", "selectId", "dataKey", "filterBy", "autofocus", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "virtualScroll", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaFilterLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "disabled", "options", "filterValue"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear"] }, { type: i5.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass"], outputs: ["onClick", "onFocus", "onBlur"] }, { type: i6$1.RadioButton, selector: "p-radioButton", inputs: ["value", "formControlName", "name", "disabled", "label", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "labelStyleClass"], outputs: ["onClick", "onFocus", "onBlur"] }], directives: [{ type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i7.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.InputText, selector: "[pInputText]" }, { type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
952
+ DebugComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: DebugComponent, selector: "vl-flow-debug", ngImport: i0, template: "<form [formGroup]=\"form\">\n <div class=\"fields-container\">\n <div class=\"field\">\n <label>SF Object ID</label>\n <input formControlName=\"id\" pInputText type=\"text\" />\n </div>\n\n <div class=\"field\">\n <label>SF Object Name</label>\n <p-dropdown\n appendTo=\"body\"\n formControlName=\"name\"\n [autoDisplayFirst]=\"false\"\n [options]=\"objectNames\"\n ></p-dropdown>\n </div>\n </div>\n\n <p-button\n styleClass=\"p-button-primary\"\n label=\"Run Flow\"\n [disabled]=\"!form.value.id || !selectedFlow\"\n (onClick)=\"runFlow()\"\n ></p-button>\n</form>\n\n<table>\n <thead>\n <tr>\n <th [width]=\"30\"></th>\n <th [width]=\"160\">ID</th>\n <th [width]=\"160\">Entry Path</th>\n <th>QueryParams</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let flow of flows$ | async\" (click)=\"selectedFlow = flow\">\n <td><p-radioButton [inputId]=\"flow.id\" name=\"flow\" [value]=\"flow\" [(ngModel)]=\"selectedFlow\"></p-radioButton></td>\n <td>{{ flow.id }}</td>\n <td>{{ flow.entryPath }}</td>\n <td>{{ flow.queryParamsStr }}</td>\n </tr>\n </tbody>\n</table>\n", styles: [":host{display:block;padding:24px 54px}form{display:flex;align-items:center;justify-content:space-between}.fields-container{display:flex;grid-gap:24px;gap:24px}.field{display:flex;flex-direction:column;width:200px;flex-shrink:0}:host ::ng-deep .p-dropdown{width:100%}table{width:100%;border-collapse:collapse}tr{cursor:pointer}tr:hover{background-color:#f0f5fa}th{text-align:left;font-weight:600}th,td{padding:0 10px;height:30px;border-bottom:1px solid var(--vl-border-color);margin-right:16px}\n"], components: [{ type: i4$2.Dropdown, selector: "p-dropdown", inputs: ["scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "filterPlaceholder", "filterLocale", "inputId", "selectId", "dataKey", "filterBy", "autofocus", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "virtualScroll", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaFilterLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "disabled", "options", "filterValue"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear"] }, { type: i5.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass"], outputs: ["onClick", "onFocus", "onBlur"] }, { type: i6$1.RadioButton, selector: "p-radioButton", inputs: ["value", "formControlName", "name", "disabled", "label", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "labelStyleClass"], outputs: ["onClick", "onFocus", "onBlur"] }], directives: [{ type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i7.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i7.FormControlName, selector: "[formControlName]", inputs: ["disabled", "formControlName", "ngModel"], outputs: ["ngModelChange"] }, { type: i8.InputText, selector: "[pInputText]" }, { type: i9.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
885
953
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: DebugComponent, decorators: [{
886
954
  type: Component,
887
955
  args: [{
@@ -1035,15 +1103,15 @@ class LegacyProductComponent {
1035
1103
  }), switchMap$1(runtimeContext => this.customizeContext(productId, runtimeContext)));
1036
1104
  }
1037
1105
  }
1038
- LegacyProductComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i2.QuoteDraftService }, { token: i1$3.QuoteApiService }, { token: i2.ContextService }, { token: i4$2.RuntimeContextService }, { token: i4$2.RuntimeService }, { token: i4$2.CurrentStateService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1039
- LegacyProductComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: LegacyProductComponent, selector: "ng-component", ngImport: i0, template: "<vl-runtime #runtimeView (solutionUpdated)=\"onSolutionUpdated($event)\"></vl-runtime>\n", styles: [":host{display:block;height:100%}\n"], components: [{ type: i4$2.RuntimeComponent, selector: "vl-runtime", outputs: ["solutionUpdated"] }] });
1106
+ LegacyProductComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: i2.QuoteDraftService }, { token: i1$3.QuoteApiService }, { token: i2.ContextService }, { token: i4$3.RuntimeContextService }, { token: i4$3.RuntimeService }, { token: i4$3.CurrentStateService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1107
+ LegacyProductComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: LegacyProductComponent, selector: "ng-component", ngImport: i0, template: "<vl-runtime #runtimeView (solutionUpdated)=\"onSolutionUpdated($event)\"></vl-runtime>\n", styles: [":host{display:block;height:100%}\n"], components: [{ type: i4$3.RuntimeComponent, selector: "vl-runtime", outputs: ["solutionUpdated"] }] });
1040
1108
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductComponent, decorators: [{
1041
1109
  type: Component,
1042
1110
  args: [{
1043
1111
  templateUrl: './legacy-product.component.html',
1044
1112
  styleUrls: ['./legacy-product.component.scss'],
1045
1113
  }]
1046
- }], ctorParameters: function () { return [{ type: i1$1.ActivatedRoute }, { type: i2.QuoteDraftService }, { type: i1$3.QuoteApiService }, { type: i2.ContextService }, { type: i4$2.RuntimeContextService }, { type: i4$2.RuntimeService }, { type: i4$2.CurrentStateService }, { type: undefined, decorators: [{
1114
+ }], ctorParameters: function () { return [{ type: i1$1.ActivatedRoute }, { type: i2.QuoteDraftService }, { type: i1$3.QuoteApiService }, { type: i2.ContextService }, { type: i4$3.RuntimeContextService }, { type: i4$3.RuntimeService }, { type: i4$3.CurrentStateService }, { type: undefined, decorators: [{
1047
1115
  type: Optional
1048
1116
  }, {
1049
1117
  type: Inject,
@@ -1053,7 +1121,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
1053
1121
  class LegacyProductModule {
1054
1122
  }
1055
1123
  LegacyProductModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1056
- LegacyProductModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductModule, declarations: [LegacyProductComponent], imports: [CommonModule, RuntimeModule, i1$5.TooltipModule], exports: [LegacyProductComponent] });
1124
+ LegacyProductModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductModule, declarations: [LegacyProductComponent], imports: [CommonModule, RuntimeModule, i1$4.TooltipModule], exports: [LegacyProductComponent] });
1057
1125
  LegacyProductModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductModule, imports: [[CommonModule, RuntimeModule, TooltipModule$1.forRoot()]] });
1058
1126
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: LegacyProductModule, decorators: [{
1059
1127
  type: NgModule,
@@ -1065,33 +1133,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
1065
1133
  }] });
1066
1134
 
1067
1135
  class ProductComponent {
1068
- constructor(contextService, runtimeService, conigurationService, flowConfigurationService, quoteDraftService, route, messageService, customizationService) {
1136
+ constructor(contextService, runtimeService, conigurationService, quoteDraftService, messageService, customizationService) {
1069
1137
  this.contextService = contextService;
1070
1138
  this.runtimeService = runtimeService;
1071
1139
  this.conigurationService = conigurationService;
1072
- this.flowConfigurationService = flowConfigurationService;
1073
1140
  this.quoteDraftService = quoteDraftService;
1074
- this.route = route;
1075
1141
  this.messageService = messageService;
1076
1142
  this.customizationService = customizationService;
1077
1143
  this.destroy$ = new Subject();
1078
1144
  this.state$ = new BehaviorSubject({ loading: true, failure: false });
1079
1145
  }
1080
1146
  ngOnInit() {
1081
- this.quoteDraftService.quote$
1082
- .pipe(first$1(), map(quote => {
1083
- var _a, _b;
1084
- const contextProperties = (_b = (_a = this.contextService.resolve()) === null || _a === void 0 ? void 0 : _a.properties) !== null && _b !== void 0 ? _b : {};
1085
- if (contextProperties.standalone === 'true') {
1086
- return quote;
1087
- }
1088
- const productLineItem = this.flowConfigurationService
1089
- .getSnapshot()
1090
- .find(li => li.productId === contextProperties.productId);
1091
- const state = productLineItem ? [productLineItem] : [];
1092
- return Object.assign(Object.assign({}, quote), { initialState: state, currentState: state });
1093
- }), takeUntil(this.destroy$))
1094
- .subscribe(quote => this.init(quote, this.route.snapshot.queryParams));
1147
+ this.quoteDraftService.quote$.pipe(first$1(), takeUntil(this.destroy$)).subscribe(quote => this.init(quote));
1095
1148
  }
1096
1149
  ngOnDestroy() {
1097
1150
  this.destroy$.next();
@@ -1110,11 +1163,15 @@ class ProductComponent {
1110
1163
  }
1111
1164
  }));
1112
1165
  }
1113
- init(quote, queryParams) {
1114
- var _a;
1115
- const lineItemId = this.getLineItemId(quote, queryParams);
1166
+ init(quote) {
1167
+ var _a, _b;
1168
+ const contextProperties = (_b = (_a = this.contextService.resolve()) === null || _a === void 0 ? void 0 : _a.properties) !== null && _b !== void 0 ? _b : {};
1169
+ const productId = contextProperties.productId;
1170
+ if (!productId) {
1171
+ return;
1172
+ }
1173
+ const lineItemId = this.getLineItemId(quote, productId, contextProperties.lineItemId);
1116
1174
  const currentStateItem = EntityUtil.findById(lineItemId, quote.currentState);
1117
- const productId = (_a = currentStateItem === null || currentStateItem === void 0 ? void 0 : currentStateItem.productId) !== null && _a !== void 0 ? _a : queryParams['productId'];
1118
1175
  const { offeringId } = currentStateItem !== null && currentStateItem !== void 0 ? currentStateItem : {};
1119
1176
  if (currentStateItem) {
1120
1177
  this.conigurationService.updateCurrentStates({
@@ -1134,18 +1191,18 @@ class ProductComponent {
1134
1191
  }), takeUntil(this.destroy$))
1135
1192
  .subscribe();
1136
1193
  }
1137
- getLineItemId(quote, queryParams) {
1138
- if (EntityUtil.isPresent(queryParams['lineItemId'])) {
1139
- return queryParams['lineItemId'];
1194
+ getLineItemId(quote, productId, lineItemId) {
1195
+ var _a, _b;
1196
+ // search by lineItemId first
1197
+ let id = (_a = quote.currentState.find(li => li.id === lineItemId)) === null || _a === void 0 ? void 0 : _a.id;
1198
+ if (!id) {
1199
+ id = (_b = quote.currentState.find(li => li.productId === productId)) === null || _b === void 0 ? void 0 : _b.id;
1140
1200
  }
1141
- return quote.currentState
1142
- .filter(lineItem => lineItem.productId === queryParams['productId'])
1143
- .map(lineItem => lineItem.id)
1144
- .find(id => id);
1201
+ return id;
1145
1202
  }
1146
1203
  }
1147
- ProductComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ProductComponent, deps: [{ token: i2.ContextService }, { token: i2.ConfigurationRuntimeService }, { token: i2.ConfigurationService }, { token: i2.FlowConfigurationService }, { token: i2.QuoteDraftService }, { token: i1$1.ActivatedRoute }, { token: i3.MessageService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1148
- ProductComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: ProductComponent, selector: "vl-flow-product", ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\n <vl-loader *ngIf=\"state.loading; else content\" [label]=\"'Loading UI'\"></vl-loader>\n\n <ng-template #content>\n <ng-container *ngIf=\"!state.failure\">\n <vl-cms-preview [uiDefinition]=\"uiDefinition\"></vl-cms-preview>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [""], components: [{ type: i3$1.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }, { type: i1$4.PreviewComponent, selector: "vl-cms-preview", inputs: ["modelId", "uiDefinition", "clearState"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1204
+ ProductComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ProductComponent, deps: [{ token: i2.ContextService }, { token: i2.ConfigurationRuntimeService }, { token: i2.ConfigurationService }, { token: i2.QuoteDraftService }, { token: i2$1.MessageService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1205
+ ProductComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: ProductComponent, selector: "vl-flow-product", ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\n <vl-loader *ngIf=\"state.loading; else content\" [label]=\"'Loading UI'\"></vl-loader>\n\n <ng-template #content>\n <ng-container *ngIf=\"!state.failure\">\n <vl-cms-preview [uiDefinition]=\"uiDefinition\"></vl-cms-preview>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [""], components: [{ type: i3.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }, { type: i4$1.PreviewComponent, selector: "vl-cms-preview", inputs: ["modelId", "uiDefinition", "clearState"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1149
1206
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ProductComponent, decorators: [{
1150
1207
  type: Component,
1151
1208
  args: [{
@@ -1154,7 +1211,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
1154
1211
  styleUrls: ['./product.component.scss'],
1155
1212
  changeDetection: ChangeDetectionStrategy.OnPush,
1156
1213
  }]
1157
- }], ctorParameters: function () { return [{ type: i2.ContextService }, { type: i2.ConfigurationRuntimeService }, { type: i2.ConfigurationService }, { type: i2.FlowConfigurationService }, { type: i2.QuoteDraftService }, { type: i1$1.ActivatedRoute }, { type: i3.MessageService }, { type: undefined, decorators: [{
1214
+ }], ctorParameters: function () { return [{ type: i2.ContextService }, { type: i2.ConfigurationRuntimeService }, { type: i2.ConfigurationService }, { type: i2.QuoteDraftService }, { type: i2$1.MessageService }, { type: undefined, decorators: [{
1158
1215
  type: Optional
1159
1216
  }, {
1160
1217
  type: Inject,
@@ -1303,8 +1360,8 @@ class ShoppingCartComponent {
1303
1360
  }));
1304
1361
  }
1305
1362
  }
1306
- ShoppingCartComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ShoppingCartComponent, deps: [{ token: i1$3.UITemplatesApiService }, { token: i2.ContextService }, { token: i0.ChangeDetectorRef }, { token: i3$1.ToastService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1307
- ShoppingCartComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: ShoppingCartComponent, selector: "vl-flow-shopping-cart", ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\n <vl-loader *ngIf=\"state.loading; else content\" [label]=\"'Loading UI'\"></vl-loader>\n\n <ng-template #content>\n <ng-container *ngIf=\"!state.failure\">\n <vl-cms-preview [uiDefinition]=\"uiDefinition\"></vl-cms-preview>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [""], components: [{ type: i3$1.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }, { type: i1$4.PreviewComponent, selector: "vl-cms-preview", inputs: ["modelId", "uiDefinition", "clearState"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1363
+ ShoppingCartComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ShoppingCartComponent, deps: [{ token: i1$3.UITemplatesApiService }, { token: i2.ContextService }, { token: i0.ChangeDetectorRef }, { token: i3.ToastService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
1364
+ ShoppingCartComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.15", type: ShoppingCartComponent, selector: "vl-flow-shopping-cart", ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\n <vl-loader *ngIf=\"state.loading; else content\" [label]=\"'Loading UI'\"></vl-loader>\n\n <ng-template #content>\n <ng-container *ngIf=\"!state.failure\">\n <vl-cms-preview [uiDefinition]=\"uiDefinition\"></vl-cms-preview>\n </ng-container>\n </ng-template>\n</ng-container>\n", styles: [""], components: [{ type: i3.LoaderComponent, selector: "vl-loader", inputs: ["label", "overlayVisible"] }, { type: i4$1.PreviewComponent, selector: "vl-cms-preview", inputs: ["modelId", "uiDefinition", "clearState"] }], directives: [{ type: i9.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i9.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1308
1365
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: ShoppingCartComponent, decorators: [{
1309
1366
  type: Component,
1310
1367
  args: [{
@@ -1313,7 +1370,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImpo
1313
1370
  styleUrls: ['./shopping-cart.component.scss'],
1314
1371
  changeDetection: ChangeDetectionStrategy.OnPush,
1315
1372
  }]
1316
- }], ctorParameters: function () { return [{ type: i1$3.UITemplatesApiService }, { type: i2.ContextService }, { type: i0.ChangeDetectorRef }, { type: i3$1.ToastService }, { type: undefined, decorators: [{
1373
+ }], ctorParameters: function () { return [{ type: i1$3.UITemplatesApiService }, { type: i2.ContextService }, { type: i0.ChangeDetectorRef }, { type: i3.ToastService }, { type: undefined, decorators: [{
1317
1374
  type: Optional
1318
1375
  }, {
1319
1376
  type: Inject,
@@ -1488,6 +1545,7 @@ const rootRoute = {
1488
1545
  runGuardsAndResolvers: 'paramsOrQueryParamsChange',
1489
1546
  resolve: { context: ContextResolver, quote: QuoteResolver },
1490
1547
  canActivate: [ContextGuard],
1548
+ canDeactivate: [ProductUnloadGuard],
1491
1549
  data: { showHeader: true },
1492
1550
  },
1493
1551
  {
@@ -1520,13 +1578,29 @@ class FlowRoutingModule {
1520
1578
  }
1521
1579
  FlowRoutingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowRoutingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1522
1580
  FlowRoutingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowRoutingModule, imports: [i1$1.RouterModule, ProductModule, LegacyProductModule, ShoppingCartModule, CatalogModule], exports: [RouterModule] });
1523
- FlowRoutingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowRoutingModule, providers: [FlowRouterService, RootGuard, ContextGuard, ContextResolver, FlowResolver, QuoteResolver], imports: [[RouterModule.forChild([rootRoute]), ProductModule, LegacyProductModule, ShoppingCartModule, CatalogModule], RouterModule] });
1581
+ FlowRoutingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowRoutingModule, providers: [
1582
+ FlowRouterService,
1583
+ RootGuard,
1584
+ ContextGuard,
1585
+ ProductUnloadGuard,
1586
+ ContextResolver,
1587
+ FlowResolver,
1588
+ QuoteResolver,
1589
+ ], imports: [[RouterModule.forChild([rootRoute]), ProductModule, LegacyProductModule, ShoppingCartModule, CatalogModule], RouterModule] });
1524
1590
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.15", ngImport: i0, type: FlowRoutingModule, decorators: [{
1525
1591
  type: NgModule,
1526
1592
  args: [{
1527
1593
  imports: [RouterModule.forChild([rootRoute]), ProductModule, LegacyProductModule, ShoppingCartModule, CatalogModule],
1528
1594
  exports: [RouterModule],
1529
- providers: [FlowRouterService, RootGuard, ContextGuard, ContextResolver, FlowResolver, QuoteResolver],
1595
+ providers: [
1596
+ FlowRouterService,
1597
+ RootGuard,
1598
+ ContextGuard,
1599
+ ProductUnloadGuard,
1600
+ ContextResolver,
1601
+ FlowResolver,
1602
+ QuoteResolver,
1603
+ ],
1530
1604
  }]
1531
1605
  }] });
1532
1606